Commit 2a508a8f authored by 贾慧斌's avatar 贾慧斌

feat: 转换代码临时更新

parent 343da196
...@@ -21,7 +21,8 @@ if ( ...@@ -21,7 +21,8 @@ if (
const input = normalizePath(process.env.UNI_INPUT_DIR); const input = normalizePath(process.env.UNI_INPUT_DIR);
try { try {
plugins.push([ plugins.push(
[
require("@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console"), require("@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console"),
{ {
file(file) { file(file) {
...@@ -32,7 +33,20 @@ if ( ...@@ -32,7 +33,20 @@ if (
return false; return false;
} }
} }
]); ],
[
"import",
{
libraryName: "@qg/cherry-ui",
libraryDirectory: "src",
style: name => {
// eslint-disable-next-line no-useless-escape
const lessName = name.match(/[^\/]+$/)[0];
return `${name}/${lessName}.less`;
}
}
]
);
} catch (e) {} } catch (e) {}
} }
......
<template>
<view class="home">这里是test 页面</view>
</template>
<script></script>
/*eslint-disable*/
import { stringTrim } from './utils.service';
// 判断输入内容是否为空
export function isNull(str) {
return str === undefined || str.length === 0 || str === null;
}
// 判断输入内容去掉空格是否为空
export function isTrimNull(str) {
if (str === undefined || str.length === 0 || str === null) {
return true;
}
return stringTrim(str).length === 0;
}
// 判断日期类型是否为YYYY-MM-DD格式的类型
export function isDate(str) {
if (!isNull(str)) {
const reg = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/;
const r = str.match(reg);
return r !== null;
}
}
// 判断日期类型是否为YYYY-MM-DD hh:mm:ss格式的类型
export function isDateTime(str) {
if (!isNull(str)) {
const reg = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/;
const r = str.match(reg);
return r !== null;
}
return false;
}
// 判断日期类型是否为hh:mm:ss格式的类型
export function isTime(str) {
if (!isNull(str)) {
const reg = /^((20|21|22|23|[0-1]\d)\:[0-5][0-9])(\:[0-5][0-9])?$/;
return reg.test(str);
}
return false;
}
// 校验是否合法日期
export function isValidDate(date) {
return date instanceof Date && !isNaN(date.getTime());
}
// 判断输入的字符是否为英文字母
export function isLetter(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z]+$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为整数
export function isInteger(str) {
if (!isNull(str)) {
const reg = /^[-+]?\d*$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为身份证号
export function isIdNo(str) {
if (!isNull(str)) {
const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为中文姓名最少两个中文字符
export function isChineseName(str) {
if (!isNull(str)) {
const reg = /^[\u0391-\uFFE5\·]{2,}$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否以数字开头
export function isStartWithInteger(str) {
if (!isNull(str)) {
const reg = /^[0-9].*$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为双精度
export function isDouble(str) {
if (!isNull(str)) {
const reg = /^[-\+]?\d+(\.\d+)?$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为:a-z,A-Z,0-9,_,并以字母开头
export function isProgramVar(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z][a-zA-Z0-9_]*$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为:a-z,A-Z,0-9,_,并以大写字母开头
export function isProgramClassName(str) {
if (!isNull(str)) {
const reg = /^[A-Z][a-zA-Z0-9_]*$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为中文
export function isChinese(str) {
if (!isNull(str)) {
const reg = /^[\u0391-\uFFE5]+$/;
return reg.test(str);
}
return false;
}
// 判断输入的EMAIL格式是否正确
export function isEmail(str) {
if (!isNull(str)) {
const reg = /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/g;
return reg.test(str);
}
return false;
}
// 判断输入的邮编(只能为六位)是否正确
export function isZIP(str) {
if (!isNull(str)) {
const reg = /^\d{6}$/;
return reg.test(str);
}
}
// 判断字符串的长度是否满足条件
export function isLengthValidate(str, len) {
if (str) {
if (str.length <= len) {
return true;
} else {
return false;
}
} else {
return true;
}
}
// 判断输入的字符是否为:a-z,A-Z,0-9,_,汉字
export function isProgramName(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z0-9_\u4e00-\u9fa5]+$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为:a-z,A-Z,0-9,_,汉字
export function isProgramCode(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z0-9_\u4e00-\u9fa5]+$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否以http://或者https://开头,且必须是个网址
export function isProgramWeb(str) {
if (!isNull(str)) {
let reg = /^((https|http)?:\/\/)[^\s]+/;
return reg.test(str);
}
return false;
}
export function isValueTypeMatched(type, value) {
switch (type) {
case 'Integer':
if (!/^\-?\d+$/.test(value)) {
return false;
}
break;
case 'Double':
if (!/^\-?\d+\.\d+$/.test(value)) {
return false;
}
break;
case 'Long':
if (!/^\-?\d+$/.test(value)) {
return false;
}
break;
case 'Boolean':
if (value !== 'true' && value !== 'false') {
return false;
}
break;
default:
return true;
}
return true;
}
export function isProperties(str) {
if (!isNull(str)) {
let reg = /^[a-zA-Z\u4e00-\u9fa5][a-zA-Z_0-9\u4e00-\u9fa5]*\s*=\s*[a-zA-Z_0-9\u4e00-\u9fa5]+/;
return reg.test(str);
}
return false;
}
// 拒绝码以大写字母开头,包含数字、大写字母、下划线,且为四段式
export function isUppercase(str) {
const reg = /^[A-Z]([A-Z0-9]*_){1}([A-Z0-9]+_){2}[A-Z0-9]+$/;
return reg.test(str);
}
//判断用户名
export function isUserName(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z\d_]{4,20}$/;
return reg.test(str);
}
return false;
}
//判断密码
export function isPassword(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z\d]{6,14}$/;
return reg.test(str);
}
return false;
}
//判断手机号
export function isPhone(str) {
if (!isNull(str)) {
const reg = /^1[3456789]\d{9}$/;
return reg.test(str);
}
return false;
}
// 判断税号
export function isTax(str) {
if (!isNull(str)) {
const reg = /^[A-Z0-9]{15}$|^[A-Z0-9]{17}$|^[A-Z0-9]{18}$|^[A-Z0-9]{20}$/;
return reg.test(str);
}
return false;
}
// 判断银行号
export function isBankNumber(str) {
if (!isNull(str)) {
const reg = /^[0-9]{16}$|^[0-9]{17}$|^[0-9]{19}$/;
return reg.test(str);
}
return false;
}
// 判断中文地址不能少于5个汉字,且必须有一位数字
export function isChnAddress(str) {
const isNum = /[0-9]\d*/;
const isChinese_var = /[\u4e00-\u9fa5]/g;
if (!isNull(str)) {
return isNum.test(str) && str.match(isChinese_var).length >= 5;
}
return false;
}
const ua = uni.getSystemInfoSync().ua
// 判断微信环境
export const isWechat = ua.match(/MicroMessenger/i) == 'micromessenger';
// 是否信用钱包
export const isXYQB = ua.indexOf("xyqb") > -1;
// 判断微信小程序环境
export const isWxMp = uni.getSystemInfoSync().platform === 'mp-weixin'
// 判断羊小咩(信用钱包)环境
export const isApp = ua.match(/xyqb/i) == 'xyqb';
// 判断真享生活
export const isVcc = ua.match(/VCC/i) == 'vcc';
// 判断IOS环境
export const isIOS = /iphone|ipad|ipod/.test(ua);
// 判读Android环境
export const isAndroid = /android/.test(ua);
// 判断
export const appVersion = ua.match(/xyqb\/([\d|.]+)/) ? ua.match(/xyqb\/([\d|.]+)/)[1] : '8.8.00';
export const isQQ = ua.match(/QQ/i) == 'qq';
export const isWeiBo = ua.match(/Weibo/i) == 'weibo';
export const isDingTalk = ua.match(/DingTalk/i) == 'dingtalk';
// 判读非微信浏览器和appwebview和小程序webview
export const isH5Normal = !isWechat && !isWxMp && !isApp;
// 这里是测试
@font-face {
font-family: "iconfont"; /* Project id 2314957 */
src:
url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
url('//at.alicdn.com/t/font_2314957_i2934lpwxv.woff?t=1646303283345') format('woff'),
url('//at.alicdn.com/t/font_2314957_i2934lpwxv.ttf?t=1646303283345') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-saoyisao:before {
content: "\e644";
}
.icon-qrcode:before {
content: "\e629";
}
.icon-edit:before {
content: "\e643";
}
.icon-cart:before {
content: "\e642";
}
.icon-photo-line-bold:before {
content: "\e6b9";
}
.icon-qq:before {
content: "\e6ba";
}
.icon-download-line-bold:before {
content: "\e6bb";
}
.icon-weixin:before {
content: "\e6bc";
}
.icon-mini-apps-o:before {
content: "\e6bd";
}
.icon-qrcode-bold:before {
content: "\e6be";
}
.icon-weibo:before {
content: "\e6c1";
}
.icon-qzone:before {
content: "\e6c2";
}
.icon-moments:before {
content: "\e6c3";
}
.icon-link:before {
content: "\e6c4";
}
.icon-back-top:before {
content: "\e6b6";
}
.icon-fenxiang:before {
content: "\e6b7";
}
.icon-gouwuche:before {
content: "\e6b8";
}
.icon-order-line:before {
content: "\e6b5";
}
.icon-location:before {
content: "\e602";
}
.icon-sort-down-round:before {
content: "\e74d";
}
.icon-sort-up-round:before {
content: "\e641";
}
.icon-share-line:before {
content: "\e63e";
}
.icon-yuan:before {
content: "\e63f";
}
.icon-setting-line:before {
content: "\e640";
}
.icon-arrow:before {
content: "\e612";
}
.icon-arrow-left:before {
content: "\e613";
}
.icon-minus:before {
content: "\e614";
}
.icon-close-plane:before {
content: "\e615";
}
.icon-photo-plane:before {
content: "\e616";
}
.icon-arrow-up:before {
content: "\e617";
}
.icon-trash:before {
content: "\e618";
}
.icon-tianjia:before {
content: "\e619";
}
.icon-sort-up:before {
content: "\e61a";
}
.icon-setting-plane:before {
content: "\e61b";
}
.icon-plus:before {
content: "\e61c";
}
.icon-back-top-line:before {
content: "\e61d";
}
.icon-location-plane:before {
content: "\e61e";
}
.icon-arrow-down:before {
content: "\e61f";
}
.icon-cart-card:before {
content: "\e620";
}
.icon-sort-down:before {
content: "\e621";
}
.icon-info-plane:before {
content: "\e622";
}
.icon-info-line:before {
content: "\e623";
}
.icon-search:before {
content: "\e624";
}
.icon-home-plane:before {
content: "\e625";
}
.icon-user-plane:before {
content: "\e626";
}
.icon-location-line:before {
content: "\e627";
}
.icon-weinxin:before {
content: "\e628";
}
.icon-camera-line:before {
content: "\e62a";
}
.icon-warning-line:before {
content: "\e62b";
}
.icon-cart-line:before {
content: "\e62c";
}
.icon-found-plane:before {
content: "\e62d";
}
.icon-success:before {
content: "\e62e";
}
.icon-warning-plane:before {
content: "\e62f";
}
.icon-home:before {
content: "\e630";
}
.icon-loading:before {
content: "\e631";
}
.icon-checked:before {
content: "\e632";
}
.icon-fail:before {
content: "\e633";
}
.icon-volume:before {
content: "\e634";
}
.icon-close-line:before {
content: "\e635";
}
.icon-user:before {
content: "\e636";
}
.icon-photo-line:before {
content: "\e637";
}
.icon-circle:before {
content: "\e638";
}
.icon-close:before {
content: "\e639";
}
.icon-found-line:before {
content: "\e63a";
}
.icon-home-line:before {
content: "\e63b";
}
.icon-customer:before {
content: "\e63c";
}
.icon-cart-plane:before {
content: "\e63d";
}
.good-del{
::v-deep .cancel .uni-dialog-button-text {
color: $font-color-search !important;
}
::v-deep .confirm .uni-dialog-button-text {
color: $font-color-base !important;
}
}
.shopping{
::v-deep .uni-swipe{
box-sizing: border-box;
// border-right: 1px solid #fff;
border-radius: $border-radius-base;
}
}
.good {
.good-footer-num{
::v-deep .uni-numbox{
width: 96px;
height: 24px;
}
::v-deep .uni-numbox__value{
font-size: 14px;
height: 24px;;
line-height: 24px;
width: 45px;
}
::v-deep .uni-numbox__minus, ::v-deep .uni-numbox__plus{
height: 24px;;
line-height: 24px;
width: 24px;
}
}
}
// 全局设置复选框样式
.global-radio {
.wx-checkbox-input {
width: 28rpx;
height: 28rpx;
}
}
.global-checkbox {
.wx-checkbox-input {
margin-top: 0;
width: 28rpx;
height: 28rpx;
border-radius: 50%;
&.wx-checkbox-input-checked {
background: #ec1500;
border-color: #ec1500;
&::before {
width: 28rpx;
height: 28rpx;
line-height: 28rpx;
text-align: center;
font-size: 20rpx;
color: #fff;
background: transparent;
transform: translate(-50%, -50%) scale(1);
-webkit-transform: translate(-50%, -50%) scale(1);
}
}
}
}
.one-hide{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
\ No newline at end of file
// Color Palette
$black: #333333;
$white: #fff;
$gray-1: #f7f8fa;
$gray-2: #dcdcdc;
$gray-3: #c8c9cc;
$gray-4: #999999;
$gray-5: #666666;
$gray-6: #D8D8D8;
$red: #ec1500;
$red-light: #ec3333;
$red-dark: #ee0a24;
$orange: #faab0c;
$pink: #FFECE6;
$grey-border: #f2f3f5;
// Gradient Colors
$gradient-red: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
$gradient-red-reverse: linear-gradient(270deg, #FF4B00 0%, #FF7705 100%);;
$gradient-pink: linear-gradient(180deg, #fff7f0 0%, #ffe4dc 100%);
// Component Colors
$text-color: $black;
$text-grey: $gray-4;
$active-opacity: 0.8;
$disabled-opacity: 0.7;
$background-color: $gray-1;
$line-height-sm: 32rpx;
$line-height-md: 44rpx;
$line-height-lg: 48rpx;
// Border
$border-width-base: 1rpx;
$border-radius-sm: 12rpx;
$border-radius-md: 16rpx;
$border-radius-lg: 32rpx;
$border-radius-lx: 40rpx;
$border-radius-max: 999rpx;
// Padding
$padding-unit: 8rpx;
$padding-xs: $padding-unit * 2;
$padding-sm: $padding-unit * 3;
$padding-md: $padding-unit * 4;
$padding-lg: $padding-unit * 5;
$padding-xl: $padding-unit * 8;
// Font
$font-size-list: 10, 11, 12, 13, 14, 16, 17, 18, 20, 26, 28, 30, 52;
@mixin text-size($f) {
$font: $f;
font-size: #{$font}rpx;
line-height: #{($font + 12)}rpx;
};
$font-weight-bold: 600;
$font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
// 页面内边距
$page-padding: $padding-sm;
$page-padding-lg: $padding-lg;
// ios底部防遮挡高度
$ios-bottom-height: 120rpx;
// 页面顶部header高度
$nav-bar-height: 96rpx;
// 多行...
@mixin mx_multline_overwrite($line: 2) {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
word-wrap: break-word;
white-space: normal !important;
-webkit-line-clamp: $line;
-webkit-box-orient: vertical;
}
const fs = require("fs");
const path = require("path");
const less = require("less");
// 设置需要转换的目录路径和输出目录路径
const srcDir = "./source";
const outDir = "./out";
// 递归遍历 srcDir 目录下的所有 less 文件,并进行转换
const convertLessToScss = (dir, out) => {
const files = fs.readdirSync(dir);
for (const file of files) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
convertLessToScss(filePath, path.join(out, file));
} else if (stat.isFile() && path.extname(file) === ".less") {
const scss = convertLessFile(filePath);
const outPath = path.join(out, path.basename(file, ".less") + ".scss");
fs.writeFileSync(outPath, scss);
console.log(`Converted ${filePath} to ${outPath}`);
}
}
};
// 将单个 less 文件进行转换
const convertLessFile = filePath => {
const lessContent = fs.readFileSync(filePath, "utf-8");
return less.renderSync(lessContent, { syntax: "scss" }).css.toString();
};
// 创建输出目录
if (!fs.existsSync(outDir)) {
fs.mkdirSync(outDir);
}
// 开始转换
convertLessToScss(srcDir, outDir);
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -71,7 +71,11 @@ ...@@ -71,7 +71,11 @@
"sa-sdk-smartprogram": "0.4.0-rc", "sa-sdk-smartprogram": "0.4.0-rc",
"uuid": "3.4.0", "uuid": "3.4.0",
"vue": "^2.6.11", "vue": "^2.6.11",
"vuex": "^3.2.0" "vuex": "^3.2.0",
"@qg/cherry-ui": "3.4.5-beta.1",
"@qg/js-bridge": "1.1.12",
"@qg/ui-request": "0.0.24",
"@qg/ui-track-web": "0.0.8"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
...@@ -101,6 +105,8 @@ ...@@ -101,6 +105,8 @@
"husky": "^4.2.5", "husky": "^4.2.5",
"inquirer": "^8.2.0", "inquirer": "^8.2.0",
"jest": "^25.4.0", "jest": "^25.4.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"lint-staged": "^10.2.11", "lint-staged": "^10.2.11",
"mini-types": "*", "mini-types": "*",
"miniprogram-api-typings": "*", "miniprogram-api-typings": "*",
...@@ -108,9 +114,10 @@ ...@@ -108,9 +114,10 @@
"postcss-comment": "^2.0.0", "postcss-comment": "^2.0.0",
"sass": "^1.26.11", "sass": "^1.26.11",
"sass-loader": "^10.0.2", "sass-loader": "^10.0.2",
"less": "^3.0.4", "style-resources-loader": "^1.5.0",
"less-loader": "^5.0.0", "vue-template-compiler": "^2.6.11",
"vue-template-compiler": "^2.6.11" "dingtalk-jsapi": "^2.13.53",
"js-cookie": "^2.2.1"
}, },
"browserslist": [ "browserslist": [
"Android >= 4", "Android >= 4",
......
...@@ -133,10 +133,11 @@ export default { ...@@ -133,10 +133,11 @@ export default {
} }
}; };
</script> </script>
<style lang="less">
@import "@/style/index.less";
</style>
<style lang="scss"> <style lang="scss">
@import "@/style/icon.scss"; @import "@/style/icon.scss";
@import "@/style/uni-ui.scss";
page { page {
background: $page-color-base; background: $page-color-base;
height: 100%; height: 100%;
......
<template>
<cr-popup v-model="popupShow" class="popup-head" closeable position="bottom">
<view class="popup-title">配送至</view>
<view class="goods-area">
<template v-if="addressList && addressList.length">
<view
v-for="(item, index) in addressList"
:key="index"
class="goods-area-item "
:class="{
'goods-area-item_selected': item.addrReceiverId === selectedAddressId
}"
@click="changeAddress(item)"
>
<span class="iconfont icon-location-line" />
<span class="secondText">{{ item.addrFullName }}</span>
</view>
</template>
<span v-else class="goods-area-none">暂未添加地址哦~</span>
<view class="goods-area-button" @click="addAddress">
<cr-button block type="primary" shape="circle">添加新地址</cr-button>
</view>
</view>
</cr-popup>
</template>
<script>
import goods from '@/api/goods.api.js';
import localStorage from '@/service/localStorage.service';
const EVENT_ADDRESS_SELECT = 'address-select';
const EVENT_ADDRESS_SHOW = 'input';
export default {
name: 'AddressListPopup',
props: {
value: Boolean,
selectedAddressId: {
type: [String, Number],
default: ''
}
},
data() {
return {
popupShow: this.value,
addressList: [],
hasLogin: false
};
},
watch: {
popupShow(val) {
this.$emit(EVENT_ADDRESS_SHOW, val);
},
value(val) {
this.popupShow = val;
}
},
created() {
this.hasLogin = !!localStorage.get('vccToken');
this.getAddr();
},
methods: {
changeAddress(item) {
this.$emit(EVENT_ADDRESS_SELECT, item);
this.$emit(EVENT_ADDRESS_SHOW, false);
},
addAddress() {
if (!this.hasLogin) {
this.$router.push({ name: 'Login' });
return;
}
this.$router.push({ name: 'addressManage' });
},
async getAddr() {
if (!this.hasLogin) {
return;
}
const [addressInfo] = await goods.addrList();
if (addressInfo) {
this.addressList = (addressInfo && addressInfo.addrReceiverList) || [];
const selectedAddr = this.selectedAddressId
? this.addressList.find(item => item.addrReceiverId === this.selectedAddressId)
: this.addressList.find(item => item.addrDefault === 1);
this.$emit(EVENT_ADDRESS_SELECT, selectedAddr);
}
}
}
};
</script>
<style lang="less" scoped>
// 弹出框头部
.popup-head {
border-radius: 20px 20px 0 0;
.popup-title {
.text-size(16);
font-weight: @font-weight-bold;
color: @black;
text-align: center;
padding: 10px 0;
}
}
.goods-area {
height: 65vh;
overflow: scroll;
padding: @padding-md;
position: relative;
&-item {
display: flex;
align-items: center;
margin-bottom: @padding-lg;
span {
.text-size(13);
color: @gray-4;
&:first-child {
width: 20px;
height: 20px;
line-height: 20px;
.text-size(16);
}
&:second-child {
flex: 1;
}
}
&_selected {
span {
&:first-child {
color: @red;
}
&.secondText {
color: @black;
font-weight: @font-weight-bold;
}
}
}
}
&-none {
display: inline-block;
width: 100%;
line-height: 65vh;
.text-size(13);
color: @gray-5;
text-align: center;
}
&-button {
display: flex;
justify-content: center;
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: calc(100% - @padding-md * 2);
margin: 0 auto;
}
}
.goods-bottom-buy {
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
width: 335px;
height: 40px;
.text-size(14);
font-weight: bold;
border-radius: @padding-lg;
color: @white;
background-image: @gradient-red;
&.disabled {
opacity: 0.7;
}
}
</style>
<template>
<cr-overlay custom-class="net-error-mask" :show="showError">
<!-- https://img.lkbang.net/ufo.svg -->
<cr-image
src="https://img.lkbang.net/ufo.1758f833.png"
width="160px"
height="160px"
class="ufo-icon"
/>
<p class="net-error-title">网络竟然崩溃了,试试看刷新页面~</p>
<cr-button type="default" hairline shape="circle" @click="refresh">
刷新
</cr-button>
<!-- <cr-button type="danger" size="large" @click="refresh">刷新试试</cr-button> -->
</cr-overlay>
</template>
<script>
export default {
name: 'NetError',
data() {
return {
showError: false
};
},
mounted() {
this.init();
},
methods: {
refresh() {
window.location.reload();
},
init() {
window.addEventListener(
'online',
() => {
this.showError = false;
},
true
);
window.addEventListener(
'offline',
() => {
this.showError = true;
},
true
);
}
}
};
</script>
<style lang="less" scoped>
.net-error {
&-mask {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 101;
background-color: @gray-1;
.ufo-icon {
margin-top: -120px;
}
.cr-button {
color: @black;
margin-top: 13px;
width: 132px;
// border-radius: 6px;
}
}
&-title {
color: @black;
.text-size(14);
margin-top: 14px;
}
}
</style>
<template>
<view class="goods">
<template v-for="item in data">
<view v-if="item.goods" :key="item.goodsId" :class="['card']" @click="toDetail(item.goods)">
<view class="card__top">
<view class="card__head">
<image class="card__head__image" object-fit="contain" :src="item.goods.goodsImage" />
</view>
<p class="card__name">
{{ item.goods.goodsName }}
</p>
<p v-if="item.goods.serviceTypeList" class="card__service">
"{{ item.goods.serviceTypeList[0] }}"
</p>
<view class="card__tag">
<view v-for="(tag, index) in item.goods.tagList" :key="index" class="card__tag-wrap">
<span v-if="tag.type == 2" :key="index" class="card__tag-normal">{{ tag.name }}</span>
<image v-if="tag.type == 1" class="card__tag-icon" :src="tag.icon" alt="" />
</view>
</view>
</view>
<view class="card__bottom">
<view class="price">
<p>
<span class="price__icon">¥</span>
<span class="price__text">{{
item.goods.goodsSalePrice && item.goods.goodsSalePrice.replace('', '')
}}</span>
</p>
<p class="sale">已售{{ item.goods.saleCount }}</p>
</view>
</view>
</view>
</template>
</view>
</template>
<script>
export default {
props: {
data: {
type: Array,
default: () => []
}
},
methods: {
toDetail(item) {
const params = {
count: 1,
goodsName: item.goodsName,
goodsimg: item.goodsImage
};
const query = {
skuNo: item.goodsId
};
this.$router.push({ name: 'goodDetail', params, query });
}
}
};
</script>
<style lang="less" scoped>
.goods {
height: 100%;
}
.card {
// width: 49%;
font-size: 0;
background-color: #fff;
border-radius: 6px;
margin-bottom: 10px;
display: flex;
flex-direction: column;
position: relative;
justify-content: space-between;
&__head {
height: 173px;
border-radius: 6px;
overflow: hidden;
&__image {
height: 100%;
width: 100%;
}
}
&__name {
font-size: 13px;
line-height: 18px;
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin: 8px 5px 0px 14px;
.shop-tag {
vertical-align: middle;
margin-top: -2px;
}
}
&__service {
font-size: 13px;
color: #e1a069;
margin: 5px 14px;
}
&__tag {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
margin: 3px 5px 0 14px;
&-wrap {
margin-bottom: 5px;
}
&-text {
color: #e1a069;
font-size: 13px;
}
&-normal {
display: inline-block;
font-size: 10px;
box-sizing: border-box;
border: 1px solid #ff5a4b;
color: #ff5a4b;
padding: 0px 4px;
border-radius: 3px;
margin-right: 5px;
line-height: 14px;
}
&-icon {
height: 15px;
margin-right: 5px;
}
&-warn {
color: #ff4b00;
border: 1px solid #ff4b00;
}
}
&__bottom {
padding: 5px 5px 6px 14px;
.activity {
display: flex;
align-items: bottom;
&__free {
height: 14px;
margin-right: 3px;
}
}
.price__raw {
float: left;
color: #999;
font-size: 10px;
line-height: 14px;
text-decoration: line-through;
}
.sale {
color: #999;
font-size: 10px;
height: 20px;
display: flex;
align-items: flex-end;
margin-left: 5px;
}
.price {
display: flex;
align-items: flex-start;
&__icon {
font-size: 12px;
color: #ec3333;
}
&__text {
font-size: 18px;
line-height: 25px;
color: #ec3333;
}
}
}
&::after {
clear: both;
}
}
</style>
<template>
<view class="reco">
<cr-divider v-show="list.length" :hairline="false">{{ desc }}</cr-divider>
<cr-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
offset="100"
@load="onLoad"
>
<view class="list">
<view class="left">
<Goods :data="leftList" />
</view>
<view class="right">
<Goods :data="rightList" />
</view>
</view>
</cr-list>
</view>
</template>
<script>
import { getGoodsList } from '@/api/pay.api.js';
import Goods from './Goods.vue';
export default {
components: {
Goods
},
props: {
desc: {
type: String,
default: '猜你喜欢'
},
pageSize: {
type: Number,
default: 20
}
},
data() {
return {
finished: false,
loading: false,
list: [],
pageNo: 1,
leftList: [],
rightList: []
};
},
mounted() {},
methods: {
async loadReco() {
this.loading = true;
try {
const [data] = await getGoodsList({
pageType: 6,
phoneNo: this.phoneNo,
pageSize: this.pageSize,
pageNo: this.pageNo
});
if (data) {
this.loading = false;
this.list = [...this.list, ...data.goodsList] || [];
this.leftList = this.list.filter((item, index) => {
if (index % 2 === 0) {
return item;
}
});
this.rightList = this.list.filter((item, index) => index % 2);
if (!data.hasNext) {
this.finished = true;
} else {
this.pageNo++;
}
} else {
this.loading = false;
this.finished = true;
}
} catch (error) {
this.loading = false;
this.finished = true;
}
},
onLoad() {
this.loadReco();
}
}
};
</script>
<style lang="less" scoped>
.reco {
width: 100%;
height: 100%;
.cr-divider {
margin: 0;
margin-bottom: 12px;
padding: 0 60px;
color: #999;
border: 0 solid #dcdcdc;
font-size: 12px;
}
& /deep/ .cr-list__finished-text {
display: none;
}
& /deep/ .cr-list__loading {
margin: 0 auto;
}
.cr-list {
box-sizing: border-box;
padding: 10px 0;
height: 100%;
.list {
height: 100%;
overflow: auto;
clear: both;
}
.left {
float: left;
width: 49%;
height: 100%;
display: flex;
flex-direction: column;
}
.right {
float: right;
width: 49%;
height: 100%;
display: flex;
flex-direction: column;
}
}
}
</style>
<template>
<view>
<view v-if="showShareOverlay" class="share-overlay" @click.self="onShareOverlayClick" />
</view>
</template>
<script>
import { isWechat, isWxMp, isH5Normal } from '@/service/validation.service';
import localStorageService from '@/service/localStorage.service';
// import { queryStringify } from '@/service/utils.service';
import cfg from '@/config';
import qs from 'qs';
const APP_PATH = 'xyqb://openHttp';
export default {
props: {
nWeb: {
type: Boolean,
default: false
},
params: Object,
appUrl: String
},
data() {
return {
showShareOverlay:
((isWechat && !isWxMp) || isH5Normal) && !localStorageService.get('vccChannel')
};
},
methods: {
openAppSchemeUrl() {
if (isH5Normal) {
window.location.href = this.appUrl;
setTimeout(() => {
this.navToDlApp();
}, 2000);
} else if (isWechat && !isWxMp) {
window.location.href = `${
cfg.mallUIHost
}/common/launch?jumpUrl=${APP_PATH}&terminal=2&extraInfo=${encodeURIComponent(
JSON.stringify({ url: this.appUrl })
)}`;
}
},
onShareOverlayClick() {
if (this.nWeb) {
this.openAppSchemeUrl();
return;
}
let url = `${window.location.origin}${
window.location.pathname
}?vccToken={token}&${qs.stringify(this.params)}`;
console.log(url, '000000');
if (isH5Normal) {
url += `&exposure_source=${this.$route.query.exposure_source}`;
window.location.href = `${APP_PATH}?jumpUrl=${this.appUrl || url}`;
} else if (isWechat && !isWxMp) {
url += `&exposure_source=wechat`;
window.location.href = `${
cfg.mallUIHost
}/common/launch?jumpUrl=${APP_PATH}&terminal=2&extraInfo=${encodeURIComponent(
JSON.stringify({ url: this.appUrl || url })
)}`;
}
setTimeout(() => {
this.navToDlApp();
}, 6000);
},
navToDlApp() {
if (process.server) return;
// window.location.href = 'xyqb://openApp';
window.location.href = cfg.appDownUrl;
const nextPage = document.createElement('a');
nextPage.setAttribute('href', cfg.appDownUrl);
nextPage.click();
}
}
};
</script>
<style lang="less" scoped>
.share-overlay {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 999;
}
</style>
<template>
<svg :class="[className, 'svg-icon']" aria-hidden="true">
<use :xlink:href="iconName" />
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: [String, Array],
required: true
},
className: {
type: [String, Array],
default: ''
}
},
computed: {
iconName() {
return `#icon-${this.iconClass}`;
}
}
};
</script>
<style>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
<template>
<view class="tag-item">
<view v-if="item.type === 1" class="tag-item--icon">
<image v-if="item.icon" :src="item.icon" />
</view>
<view v-else-if="item.type === 2" class="tag-item--text">{{ item.name }}</view>
<view v-else-if="item.type === 3" class="tag-item--text tag-item--radius">{{ item.name }}</view>
<view v-else-if="item.type === 4" class="tag-item--text tag-item--coupon">
<view class="tag-item--coupon__label">{{ item.head }}</view>
<view class="tag-item--coupon__content">{{ item.name }}</view>
</view>
</view>
</template>
<script>
export default {
props: {
item: {
type: Object,
default: () => ({})
}
},
computed: {
imgWidth() {
return 12 * +this.item.iconRate + 'px';
}
}
};
</script>
<style lang="less">
@itemHeight: 12px;
.tag-item {
display: flex;
align-items: center;
justify-content: flex-start;
height: 14px;
margin-right: 3px;
.text-size(8px);
overflow: hidden;
&--icon {
img {
display: block;
height: @itemHeight;
}
}
&--text {
border-radius: 3px;
border: 1px solid @red;
height: @itemHeight;
line-height: @itemHeight;
box-sizing: border-box;
padding: 0 5px;
color: @red;
}
&--radius {
position: relative;
&::after,
&::before {
content: '';
position: absolute;
right: 0;
top: 50%;
width: 6px;
height: 6px;
border-radius: 50%;
box-sizing: border-box;
border: 1px solid @red;
background-color: #fff;
transform: translate(4px, -50%);
}
&::before {
left: 0;
transform: translate(-4px, -50%);
}
}
&--coupon {
display: flex;
padding: 0;
&__label {
height: 100%;
width: @itemHeight;
background-color: @red;
color: #fff;
text-align: center;
}
&__content {
flex: 1;
text-align: center;
padding: 0 2px;
}
}
}
</style>
<template>
<view class="x-page-container">
<template v-if="showOption.showFirst">
<slot name="first-screen" />
<!-- 首屏分割线-->
<view ref="first-line" />
</template>
<template v-if="showOption.showTwo">
<slot name="two-screen" />
</template>
<template v-if="showOption.other">
<slot name="other-screen" />
</template>
</view>
</template>
<script>
/**
* 1. showFirst 首屏渲染开关
* 2. showTwo other 非首屏渲染开关
*思路:
* 通过定时器轮训首屏分割线距离顶部的距离,距离不发生变化或者超过首屏高度后,骨架屏消失
* 调整刷新频率为30ms 最大重试次数为15次
*/
export default {
data() {
return {
showOption: {
showFirst: true,
showTwo: false,
other: false
}
};
},
mounted() {
const windowHeight = window.screen.height;
let equalCount = 0; // 距离顶部距离相同计数器
let showOther = false; // 展示非首屏逻辑
let lineTop = -1; // 首屏分割线距离顶部的距离
let count = 0; // 重试计时器 超过10次之后,设置为true
const timer = setInterval(
() => {
const data = this.$refs['first-line']?.getBoundingClientRect();
count++;
if (!data?.top) return;
if (showOther) {
return;
}
if (data?.top) {
if (lineTop !== data?.top) {
lineTop = data?.top;
} else {
equalCount++;
// 超过首屏高度,给展示
if (data?.top > windowHeight) {
showOther = true;
}
// 高度连续2次不变化,设置为true
if (equalCount > 2) {
showOther = true;
}
}
}
if (count > 15) {
showOther = true;
}
if (showOther) {
Object.assign(this.showOption, {
showTwo: true,
other: true
});
console.log('移除遮罩');
this.$emit('loadFirstScreen');
clearInterval(timer);
}
// 这个
},
30,
true
);
}
};
</script>
<style lang="less" scoped>
#first-line {
height: 1px;
//background: red; // 这里是测试
background: transparent;
}
</style>
.baseInfo {
color: #999999;
font-size: 12px;
text-align: center;
font-weight: bold;
padding: 30px 24px 30px 24px;
box-sizing: border-box;
&-title {
margin-bottom: 8px;
}
&-agreement-item {
margin-bottom: 8px;
font-size: 10px;
}
&-item {
line-height: 17px;
&-jump {
line-height: 14px;
font-size: 10px;
color: #999;
text-decoration: underline !important;
}
}
&-des {
line-height: 14px;
margin-bottom: 8px;
font-size: 10px;
// transform: scale(0.83, 0.83);
// -webkit-transform: scale(0.83, 0.83);
// -moz-transform: scale(0.83, 0.83);
// -o-transform: scale(0.83, 0.83);
}
}
.baseInfo {
color: #999999;
font-size: 12px;
text-align: center;
font-weight: bold;
padding: 30px 24px 30px 24px;
box-sizing: border-box;
&-title {
margin-bottom: 8px;
}
&-agreement-item {
margin-bottom: 8px;
font-size: 10px;
}
&-item {
line-height: 17px;
&-jump {
line-height: 14px;
font-size: 10px;
color: #999;
text-decoration: underline !important;
}
}
&-des {
line-height: 14px;
margin-bottom: 8px;
font-size: 10px;
// transform: scale(0.83, 0.83);
// -webkit-transform: scale(0.83, 0.83);
// -moz-transform: scale(0.83, 0.83);
// -o-transform: scale(0.83, 0.83);
}
}
<template>
<view class="baseInfo">
<view class="baseInfo-title">
<p class="baseInfo-item">羊小咩·美好生活更从容</p>
<p class="baseInfo-item">北京量化派科技有限公司</p>
</view>
<p class="baseInfo-agreement-item">
您可以点击查看相关:
<a class="baseInfo-item-jump" href="https://mall.91xr.cn/spreadApplication">应用权限</a>
<a
class="baseInfo-item-jump"
href="https://appsync.lkbang.net/agreement-three.html?contractTemplateId=8&title=信用钱包隐私政策"
>隐私政策</a
>
<a
class="baseInfo-item-jump"
href="https://appsync.lkbang.net/agreement-three.html?contractTemplateId=280&title=%E6%B3%A8%E5%86%8C%E5%8D%8F%E8%AE%AE"
>
用户注册协议</a
>
</p>
<view>
<view class="baseInfo-des">
羊小咩是北京量化派科技有限公司旗下产品,其面向追求美好生活的年轻人,为他们提供便捷且高性价比的商品及生活服务。
</view>
<view class="baseInfo-des">北京市海淀区丹棱街3号电子大厦B座701-705,1707-1712</view>
</view>
</view>
</template>
<script>
export default {
props: {
isBaiduChannel: {
type: Boolean,
default: false
}
}
};
</script>
<style lang="less" scoped src="./index.less" />
<template> <template>
<view> <view>
<view v-if="type === 'shoppingCar'" class="goods-bottom"> <view v-if="type === 'shoppingCar'" class="goods-bottom goods-car">
<!-- <navigator url="/pages/index/index" class="goods-bottom-icon" @click="goHome" hover-class="none"> <view v-if="noStock" class="no-stock-tip">
<text class="iconfont icon-home"></text> 抱歉,当前商品无库存,可查看相似商品
<text>首页</text>
</navigator> -->
<!-- <navigator v-if="type === 'shoppingCar'" url="/pages/cart/cart" class="goods-bottom-icon">
<text class="iconfont icon-cart-card" />
<text>购物车</text>
</navigator>
<button class="goods-bottom-car">加入购物车</button> -->
<button class="goods-bottom-buy" :class="{ disabled: disabled }" @click="buy">
{{ shopBtnName }}
</button>
</view> </view>
<view v-if="type === 'settlement'" class="goods-bottom"> <view class="goods-car-icon" @click="goShopCart">
<radio-group class="goods-bottom-radio" @change="radioChange"> <image class="goods-car-icon-img" src="https://img.lkbang.net/cart.b2b405fb.png" alt="car" />
<label> <span class="goods-car-icon-name">购物车</span>
<radio /> <span v-if="cartCount" class="badge">{{ cartCount }}</span>
<text>全选</text>
</label>
</radio-group>
<view class="goods-bottom-text">
<view class="Gb-text-top">
<text>合计:</text>
<text>¥</text>
<text>627.00</text>
</view> </view>
<text class="Gb-text-bottom">免运费</text> <view class="goods-car-bottom-group">
<button
v-if="!noStock"
:class="['goods-bottom-car', disabled && 'disabled']"
@click="addToCart"
>
加入购物车
</button>
<button v-if="!noStock" :class="['goods-bottom-buy', disabled && 'disabled']" @click="buy">
{{ shopBtnName }}
</button>
<button v-if="noStock" class="similar" @click="goSimilar">
查看相似
</button>
</view> </view>
<button class="goods-bottom-buy" @click="buy">结算(5)</button>
</view> </view>
<view v-if="type === 'submitOrder'" class="goods-bottom"> <view v-if="type === 'submitOrder'" class="goods-bottom">
<view class="goods-bottom-text"> <view class="goods-bottom-text">
<view class="Gb-text-top"> <view class="Gb-text-top">
<text>合计:</text> <span>合计:</span>
<text>¥</text> <span>¥</span>
<text>{{ info.totalPayFee || "0.00" }}</text> <span>{{ info.totalPayFee || '0.00' }}</span>
</view> </view>
</view> </view>
<button class="goods-bottom-buy confirm-order-btn" @click="buy">提交订单</button> <cr-button
class="goods-bottom-buy confirm-order-btn"
:disabled="goodsList.length === 0"
type="primary"
@click="buy"
>提交订单</cr-button
>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import { saTrackEvent } from "@/utils/sa.js"; import { mapGetters as ShopCartMapGetters } from '@/pages/shopCart/shopCartModules.js';
export default { export default {
name: "BottomNav", name: 'BottomNav',
props: { props: {
noStock: {
type: Boolean,
default: false
},
type: { type: {
type: String, type: String,
default: "shopCar" // shoppingCar 购物车;settlement 结算;submitOrder 确认订单 default: 'shopCar' // shoppingCar 购物车;settlement 结算;submitOrder 确认订单
}, },
shopBtnName: { shopBtnName: {
type: String, type: String,
default: "立即购买" // shoppingCar 购物车;settlement 结算;submitOrder 确认订单 default: '立即购买' // shoppingCar 购物车;settlement 结算;submitOrder 确认订单
}, },
info: { info: {
type: Object, type: Object,
...@@ -68,56 +73,74 @@ export default { ...@@ -68,56 +73,74 @@ export default {
}, },
goodsId: { goodsId: {
type: String, type: String,
default: "" default: ''
},
goodsList: {
type: Array,
default() {
return [];
}
} }
}, },
computed: {
...ShopCartMapGetters(['cartCount'])
},
methods: { methods: {
buy() { buy() {
this.$emit("buy"); // 如果操作为提交订单
if (this.type === 'submitOrder') {
// 如果购物车有商品
if (this.goodsList.length > 0) {
// 触发打开商品弹窗事件
this.$emit('buy', 'openGoodsPopup');
}
} else {
// 如果操作为购买商品
// 触发打开商品弹窗事件
this.$emit('buy', 'openGoodsPopup');
}
},
goSimilar() {
this.$emit('goSimilar');
}, },
goHome() { addToCart() {
const that = this; this.$emit('addToCart', 'openGoodsPopup');
// const currentPage = getCurrentPages(); },
saTrackEvent("PD_YXMMAEC_UserClickCommodityDetailHomePageBtn", { goShopCart() {
commodity_id: that.goodsId
});
uni.reportAnalytics("c_commoditydetailhomepagebtn", {
commodity_id: that.goodsId
});
setTimeout(() => { setTimeout(() => {
uni.switchTab({ this.$router.push({ name: 'Cart' });
url: "/pages/index/index"
});
}, 500); }, 500);
} }
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="less" scoped>
@import "@/style/icon.scss";
.goods-bottom { .goods-bottom {
position: fixed; position: fixed;
left: 0; left: 0;
bottom: 0; bottom: 0;
display: flex; display: flex;
justify-content: space-between; justify-content: space-evenly;
align-items: center; align-items: center;
width: 100%; width: 100%;
height: 120rpx; // height: 33px;
padding: 30rpx 15rpx 30rpx 30rpx; padding-top: 8px;
background: $white; padding-bottom: calc(8px + constant(safe-area-inset-bottom));
border-top: $border-sm solid $bg-color-g1; padding-bottom: calc(8px + env(safe-area-inset-bottom));
background: @white;
border-top: 2px solid #f7f7f7;
// box-sizing: border-box;
&-radio { &-radio {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-around; justify-content: space-around;
padding-top: 8rpx; padding-top: 8px;
width: 140rpx; width: 140px;
radio { radio {
transform: scale(0.7); transform: scale(0.7);
} }
text { span {
font-size: 24rpx; font-size: 24px;
color: #999999; color: #999999;
} }
} }
...@@ -126,72 +149,132 @@ export default { ...@@ -126,72 +149,132 @@ export default {
flex-direction: column; flex-direction: column;
align-items: flex-end; align-items: flex-end;
flex: 1; flex: 1;
margin: 0 20rpx; margin: 0 20px;
.Gb-text-top { .Gb-text-top {
display: flex; display: flex;
align-items: center; align-items: center;
text { span {
&:nth-child(1) { &:nth-child(1) {
padding-top: 8rpx; padding-top: 4px;
font-size: 24rpx; .text-size(12);
color: #333333; color: #333333;
} }
&:nth-child(2) { &:nth-child(2) {
padding-top: 8rpx; padding-top: 4px;
font-size: 24rpx; .text-size(12);
color: #ec3333; color: #ec3333;
} }
&:nth-child(3) { &:nth-child(3) {
font-size: 38rpx; .text-size(18);
font-weight: bold; font-weight: bold;
color: #ec3333; color: #ec3333;
} }
} }
} }
.Gb-text-bottom { .Gb-text-bottom {
font-size: 24rpx; .text-size(12);
color: #999999; color: #999999;
} }
} }
&-icon {
display: flex;
align-items: center;
flex-direction: column;
text {
&:first-child {
font-size: $font-2;
}
&:last-child {
font-size: $font-sm;
color: $text-color-n1;
}
}
}
&-car { &-car {
border: $border-sm solid $border-color-search; position: relative;
background: $white; // border: @border-sm solid @border-color-search;
color: $font-color-search; // .mx_order_one(@border-color-search, solid, 40px);
border: 1.5px solid @border-color-search;
background: @white;
color: @font-color-search;
} }
&-buy { &-buy {
color: $white; color: @white;
background-image: $background-primary; background-image: @background-primary;
} }
button { button {
margin: 0; margin: 0;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
width: 100%; // width: 305px;
height: 80rpx; height: 40px;
font-size: 34rpx; .text-size(14);
// font-weight: bold; font-weight: bold;
border-radius: $border-radius-2; border-radius: 20px;
&.disabled { &.disabled {
opacity: 0.7; opacity: 0.7;
} }
} }
} }
.confirm-order-btn { .confirm-order-btn {
width: 200rpx !important; width: 130px !important;
margin-right: 10px !important;
}
.goods-car {
width: 100%;
display: flex;
.no-stock-tip {
position: absolute;
background: #ffece6;
color: #ec1500;
font-size: 14px;
line-height: 25px;
padding-left: 10px;
width: 100%;
box-sizing: border-box;
top: -25px;
}
&-icon {
width: 70px;
position: relative;
height: 100%;
text-align: center;
&-img {
max-width: 24px;
width: 24px;
height: 24px;
display: block;
margin: 0 auto;
object-fit: contain;
position: relative;
left: -2px;
}
&-name {
.text-size(11);
color: #999999;
display: block;
}
.badge {
position: absolute;
right: 10px;
top: -8px;
min-width: 16px;
border-radius: 16px;
padding: 2px 3px;
font-size: 12px;
color: #fff;
font-weight: 500;
text-align: center;
box-sizing: border-box;
margin-top: 2px;
background-color: #ec1500;
}
}
&-bottom-group {
width: 305px;
display: flex;
box-sizing: border-box;
padding-right: 10px;
justify-content: space-between;
.similar {
width: 100%;
color: @white;
background-image: @background-primary;
}
.goods-bottom-car,
.goods-bottom-buy {
width: 48.5%;
}
}
} }
</style> </style>
<template> <template>
<view class="coupon-list"> <view class="coupon-list">
<view class="coupon-title">选择{{ feeTitle }}</view> <h3 class="coupon-title">选择{{ feeTitle }}</h3>
<view class="coupon-list__list"> <view class="coupon-list__list">
<template v-if="list.length"> <template v-if="list.length">
<scroll-view :scroll-y="true" class="coupon-list__scroll">
<view v-for="(info, index) in list" :key="index" @click="handleSelectCoupon(info.id)"> <view v-for="(info, index) in list" :key="index" @click="handleSelectCoupon(info.id)">
<view v-if="couponType == 4" class="minus-list__item"> <view v-if="couponType == 4" class="minus-list__item">
<view class="minus-list__left"> <view class="minus-list__left">
<view>{{ info.activityDesc }}</view> <p>{{ info.activityDesc }}</p>
<text>活动有效期:{{ info.startDate }}-{{ info.endDate }}</text> <span>活动有效期:{{ info.startDate }}-{{ info.endDate }}</span>
</view> </view>
<view class="minus-list__right"> <view class="minus-list__right">
<radio :value="index" color="#EC1500" :checked="info.isSelect" /> <cr-icon v-if="info.isSelect" type="checked" color="#ec3333" size="25px" />
<view class="coupon-list__radio--cover" /> <cr-icon v-else type="circle" color="#dcdcdc" size="25px" />
</view> </view>
</view> </view>
<view v-else class="coupon-list__item"> <view v-else class="coupon-list__item">
<image v-if="info.iconUrl" :src="info.iconUrl" class="coupon-list__tag" /> <image :src="info.iconUrl" class="coupon-list__tag" />
<view class="coupon-list__left"> <view class="coupon-list__left">
<view class="coupon-list__amount"> <view class="coupon-list__amount">
<text>{{ currency }}</text> <span>{{ currency }}</span>
{{ info.faceValue }} {{ info.faceValue }}
</view> </view>
<view class="coupon-list__limit">{{ info.limitDesc }}</view> <view class="coupon-list__limit">{{ info.limitDesc }}</view>
...@@ -29,14 +28,13 @@ ...@@ -29,14 +28,13 @@
<view class="coupon-list__date">{{ info.couponValidTime }}</view> <view class="coupon-list__date">{{ info.couponValidTime }}</view>
</view> </view>
<view class="coupon-list__right"> <view class="coupon-list__right">
<radio :value="index" color="#EC1500" :checked="info.isSelect" /> <cr-icon v-if="info.isSelect" type="checked" color="#ec3333" size="25px" />
<view class="coupon-list__radio--cover" /> <cr-icon v-else type="circle" color="#dcdcdc" size="25px" />
</view> </view>
</view> </view>
</view> </view>
</scroll-view>
</template> </template>
<view v-else class="coupon-list__empty"><empty text="暂无优惠券"/></view> <view v-else class="coupon-list__empty"><empty text="暂无优惠券" /></view>
</view> </view>
<view v-if="list.length" class="coupon-list__bottom"> <view v-if="list.length" class="coupon-list__bottom">
<button @click="handleRadioSubmit">确定</button> <button @click="handleRadioSubmit">确定</button>
...@@ -44,11 +42,11 @@ ...@@ -44,11 +42,11 @@
</view> </view>
</template> </template>
<script> <script>
import { getCouponChooseList } from "../api/home.api"; import { getCouponChooseList } from '@/api/home.api';
import Empty from "./empty"; import { TITLE_LIST } from '@/constants/order';
import { TITLE_LIST } from "@/constants/order.js"; import Empty from './empty';
export default { export default {
name: "CouponList", name: 'CouponList',
components: { components: {
Empty Empty
}, },
...@@ -60,7 +58,7 @@ export default { ...@@ -60,7 +58,7 @@ export default {
couponType: [String, Number], couponType: [String, Number],
currency: { currency: {
type: String, type: String,
default: "¥" default: '¥'
}, },
goodsInfo: { goodsInfo: {
type: Array, type: Array,
...@@ -70,12 +68,15 @@ export default { ...@@ -70,12 +68,15 @@ export default {
type: Array, type: Array,
default: () => [] default: () => []
}, },
commonPopup: Number isShow: {
type: Boolean,
default: false
}
}, },
data() { data() {
return { return {
list: [], list: [],
selectedCouponIndex: null couponList: []
}; };
}, },
computed: { computed: {
...@@ -89,31 +90,10 @@ export default { ...@@ -89,31 +90,10 @@ export default {
} }
}, },
watch: { watch: {
couponActivityInfoList: { isShow(v) {
handler() { v && this.getCouponChooseList();
this.getCouponChooseList();
},
deep: true,
immediate: true
},
couponType: {
handler: function() {
this.getCouponChooseList();
},
deep: true,
immediate: true
},
couponId: {
handler: function() {
this.getCouponChooseList();
},
deep: true,
immediate: true
} }
}, },
mounted() {
this.getCouponChooseList();
},
methods: { methods: {
handleSelectCoupon(num) { handleSelectCoupon(num) {
this.list.map(item => { this.list.map(item => {
...@@ -125,7 +105,7 @@ export default { ...@@ -125,7 +105,7 @@ export default {
}); });
}, },
handleRadioSubmit() { handleRadioSubmit() {
this.$emit("select", this.selectedCoupon); this.$emit('coupon-select', this.selectedCoupon);
}, },
async getCouponChooseList() { async getCouponChooseList() {
if (!this.goodsInfo.length) return; if (!this.goodsInfo.length) return;
...@@ -154,7 +134,6 @@ export default { ...@@ -154,7 +134,6 @@ export default {
const data = this.couponType == 4 ? res.activityList : res.coupons; const data = this.couponType == 4 ? res.activityList : res.coupons;
data.forEach(u => { data.forEach(u => {
u.id = this.couponType == 4 ? u.activityId : u.pickupId; u.id = this.couponType == 4 ? u.activityId : u.pickupId;
u.couponCategory = this.couponType == 4 ? 4 : u.couponCategory;
if (u.id == this.couponId) u.isSelect = true; if (u.id == this.couponId) u.isSelect = true;
else u.isSelect = false; else u.isSelect = false;
}); });
...@@ -164,30 +143,32 @@ export default { ...@@ -164,30 +143,32 @@ export default {
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="less" scoped>
.coupon-title { .coupon-title {
text-align: center; text-align: center;
margin: 0 auto; margin: 0 auto;
padding-top: 30rpx; margin-top: 15px;
width: 50%; width: 50%;
font-size: 36rpx; .text-size(18);
} }
.coupon-list { .coupon-list {
&__bottom { &__bottom {
padding: 20rpx 40rpx 30rpx; padding: 10px 20px 15px 20px;
position: relative; position: relative;
box-sizing: border-box;
button { button {
width: 100%;
background-image: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%); background-image: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
border-radius: 160rpx; border-radius: 80px;
height: 80rpx; height: 40px;
font-size: 28rpx; .text-size(14);
line-height: 80rpx; line-height: 40px;
color: #fff; color: #fff;
} }
} }
&__list { &__list {
padding: 20rpx 20rpx 0; padding: 10px 10px 0;
overflow-y: scroll; overflow-y: scroll;
overflow-x: hidden; overflow-x: hidden;
height: 50vh; height: 50vh;
...@@ -196,7 +177,7 @@ export default { ...@@ -196,7 +177,7 @@ export default {
height: 100%; height: 100%;
} }
&__empty { &__empty {
padding-top: 100rpx; padding-top: 50px;
} }
&__item { &__item {
...@@ -204,9 +185,9 @@ export default { ...@@ -204,9 +185,9 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
background: #ffece6; background: #ffece6;
border-radius: 12rpx; border-radius: 6px;
padding: 37.5rpx 20rpx; padding: 18px 10px;
margin-bottom: 20rpx; margin-bottom: 10px;
&--disabled { &--disabled {
-webkit-filter: grayscale(100%) opacity(0.8); /* Chrome, Safari, Opera */ -webkit-filter: grayscale(100%) opacity(0.8); /* Chrome, Safari, Opera */
...@@ -217,20 +198,12 @@ export default { ...@@ -217,20 +198,12 @@ export default {
} }
} }
} }
&__radio--cover {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
}
&__tag { &__tag {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 88rpx; width: 44px;
height: 32rpx; height: 16px;
} }
&__left { &__left {
text-align: center; text-align: center;
...@@ -238,78 +211,77 @@ export default { ...@@ -238,78 +211,77 @@ export default {
} }
&__amount { &__amount {
font-size: 60rpx; font-size: 30px;
font-weight: 500; font-weight: 500;
line-height: 72rpx; line-height: 36px;
margin: 0; margin: 0;
text { text {
font-size: 32rpx; font-size: 16px;
line-height: 44rpx; line-height: 22px;
} }
} }
&__limit { &__limit {
font-size: 24rpx; .text-size(12);
color: #ec3333; color: #ec3333;
line-height: 34rpx; line-height: 17px;
margin: 0; margin: 0;
} }
&__content { &__content {
padding: 0 36rpx; padding: 0 18px;
} }
&__desc { &__desc {
font-size: 28rpx; .text-size(14);
line-height: 40rpx; line-height: 20px;
font-weight: 500; font-weight: 500;
color: #333; color: #333;
margin-bottom: 6rpx; margin-bottom: 3px;
} }
&__date { &__date {
font-size: 24rpx; .text-size(12);
color: #666666; color: #666666;
line-height: 34rpx; line-height: 17px;
} }
&__right { &__right {
margin-left: auto; margin-left: auto;
position: relative; .radio {
&.wx-radio-input { width: 30px;
background-color: #ffece6 !important; height: 30px;
} display: block;
radio {
transform: scale(0.8); transform: scale(0.8);
background-color: red !important;
} }
} }
} }
::v-deep .cr-icon {
line-height: 28px !important;
}
.minus-list { .minus-list {
&__list {
padding: 10px 10px 0;
overflow-y: scroll;
overflow-x: hidden;
height: 50vh;
}
&__item { &__item {
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
border-radius: 12rpx; border-radius: 6px;
padding: 12rpx 20rpx; padding: 6px 10px;
margin-bottom: 20rpx; margin-bottom: 10px;
} }
&__left { &__left {
font-size: 28rpx; .text-size(14);
span { span {
color: $font-color-base; color: @font-color-base;
font-size: 24rpx; .text-size(12);
}
}
&__right {
margin-left: auto;
position: relative;
&.wx-radio-input {
background-color: #ffece6 !important;
}
radio {
transform: scale(0.8);
} }
} }
} }
......
...@@ -4,20 +4,20 @@ ...@@ -4,20 +4,20 @@
<view class="Gc-item-left"> <view class="Gc-item-left">
<image class="Gci-left-type" :src="item.iconUrl" /> <image class="Gci-left-type" :src="item.iconUrl" />
<view class="Gci-left-amount"> <view class="Gci-left-amount">
<view class="Gcil-amount-price" <view class="Gcil-amount-price">
><text>{{ item.faceValue }}</text></view <span>{{ item.faceValue }}</span>
> </view>
<view class="Gci-amount-desc">{{ item.limitDesc }}</view> <view class="Gci-amount-desc">{{ item.limitDesc }}</view>
</view> </view>
<view class="Gci-left-desc"> <view class="Gci-left-desc">
<text class="Gcil-desc-name">{{ item.name }}</text> <span class="Gcil-desc-name">{{ item.name }}</span>
<!-- <text v-if="!item.pickupAble" class="Gcil-desc-time" <!-- <span v-if="!item.pickupAble" class="Gcil-desc-time"
>{{ item.startDate }}-{{ item.endDate }}</text >{{ item.startDate }}-{{ item.endDate }}</span
> --> > -->
<text class="Gcil-desc-time">{{ item.couponValidTime }}</text> <span class="Gcil-desc-time">{{ item.couponValidTime }}</span>
<view> <view>
<text class="Gcil-desc-detail" /> <span class="Gcil-desc-detail" />
<text /> <span />
</view> </view>
</view> </view>
</view> </view>
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
<button <button
class="Gci-right-button" class="Gci-right-button"
:class="{ 'Gci-right-button_received': item.pickupAble }" :class="{ 'Gci-right-button_received': item.pickupAble }"
@click="pickupCoupon(item)" @click="pickupCoupon(item, index)"
> >
{{ item.pickupAble ? "已领取" : "立即领取" }} {{ item.pickupAble ? '已领取' : '立即领取' }}
</button> </button>
</view> </view>
</view> </view>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
</template> </template>
<script> <script>
export default { export default {
name: "CouponCard", name: 'CouponCard',
props: { props: {
couponList: { couponList: {
type: Array, type: Array,
...@@ -49,85 +49,75 @@ export default { ...@@ -49,85 +49,75 @@ export default {
}, },
data() { data() {
return { return {
list: [] // list: []
}; };
}, },
computed: { computed: {
// list() { list() {
// const coupon = [] return this.couponList.map(el => {
// this.couponList.map(el => { el.startDate = (el.startDate && el.startDate.replace(/-/g, '.').slice(0, 10)) || '';
// el.startDate = el.startDate && el.startDate.replace(/-/g, '.').slice(0,10) || '' el.endDate = (el.endDate && el.endDate.replace(/-/g, '.').slice(0, 10)) || '';
// el.endDate = el.endDate && el.endDate.replace(/-/g, '.').slice(0,10) || '' return el;
// coupon.push(el)
// });
// return coupon
// }
},
watch: {
couponList: {
handler() {
this.list = [];
this.couponList.map(el => {
el.startDate = (el.startDate && el.startDate.replace(/-/g, ".").slice(0, 10)) || "";
el.endDate = (el.endDate && el.endDate.replace(/-/g, ".").slice(0, 10)) || "";
this.list.push(el);
}); });
},
immediate: true
} }
}, },
methods: { methods: {
pickupCoupon(coupon) { pickupCoupon(coupon, index) {
if (coupon.pickupAble) { if (coupon.pickupAble) {
return; return;
} }
this.$emit("pickupCoupon", coupon); this.$emit('pickupCoupon', coupon, index);
} }
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="less" scoped>
.goods-coupon { .goods-coupon {
margin: 0 24rpx; // margin: 0 12px;
// padding-bottom: 30px;
// padding-top: 20px;
// height: 350px;
// overflow-y: scroll;
&-item { &-item {
position: relative; position: relative;
margin-bottom: 20rpx; margin-bottom: 10px;
width: 100%; // width: 100%;
height: 180rpx; height: 90px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 0 $padding-md; padding: 0 @padding-md;
border-radius: $border-radius-base; border-radius: 6px;
.Gc-item-left { .Gc-item-left {
display: flex; display: flex;
flex: 1; flex: 1;
padding-right: 16rpx; padding-right: 12rpx;
.Gci-left-type { .Gci-left-type {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 88rpx; width: 44px;
height: 32rpx; height: 16px;
} }
.Gci-left-amount { .Gci-left-amount {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 140rpx; width: 70px;
margin-right: $margin-1 - 4; margin-right: 18px;
align-items: center; align-items: center;
.Gcil-amount-price { .Gcil-amount-price {
font-size: $font-lg; .text-size(16);
color: $font-color-red; color: #f23e33;
font-weight: bold; font-weight: bold;
text { span {
font-size: $font-1; font-size: 30px;
} }
} }
.Gci-amount-desc { .Gci-amount-desc {
font-size: $font-sm; // font-size: 12px;
color: $font-color-red; .text-size(12);
width: 150rpx; color: #f23e33;
width: 75px;
text-align: center; text-align: center;
} }
} }
...@@ -137,12 +127,15 @@ export default { ...@@ -137,12 +127,15 @@ export default {
justify-content: center; justify-content: center;
.Gcil-desc-name { .Gcil-desc-name {
font-weight: bold; font-weight: bold;
font-size: $font-base; // font-size: 14px;
color: $text-color-n5; .text-size(14);
color: #333;
text-align: left;
} }
.Gcil-desc-time { .Gcil-desc-time {
font-size: $font-sm; // font-size: 12px;
color: $text-color-n3; .text-size(12);
color: #666;
} }
} }
} }
...@@ -150,31 +143,32 @@ export default { ...@@ -150,31 +143,32 @@ export default {
.Gci-right-receive { .Gci-right-receive {
position: absolute; position: absolute;
top: 0; top: 0;
right: 20rpx; right: 10px;
width: 120rpx; width: 60px;
height: 100rpx; // height: 25px;
} }
.Gci-right-button { .Gci-right-button {
width: 164rpx; width: 82px;
height: 48rpx; height: 24px;
line-height: 48rpx; line-height: 24px;
text-align: center; text-align: center;
font-size: $font-sm; font-size: 12px;
color: $white; color: @white;
background-image: $background-primary; background: @background-primary;
border-radius: $border-radius-2; border-radius: 20px;
vertical-align: super;
&_received { &_received {
opacity: 0.6; opacity: 0.6;
// background-image: $background-primary; // background-img: @background-primary;
} }
} }
} }
} }
.Gc-item_pink { .Gc-item_pink {
background: $bg-color-pink; background: #ffece6;
} }
.Gc-item_white { .Gc-item_white {
background: $white; background: @white;
} }
} }
</style> </style>
<template> <template>
<view class="empty-content" :style="{ background: backColor }"> <view class="empty-content">
<image src="https://img.lkbang.net/xcx/empty@2x.png" mode="aspectFit" /> <image src="https://img.lkbang.net/xcx/empty@2x.png" mode="aspectFit" />
<text v-if="text">{{ text }}</text> <text v-if="text">{{ text }}</text>
</view> </view>
...@@ -8,24 +8,20 @@ ...@@ -8,24 +8,20 @@
<script> <script>
export default { export default {
props: { props: {
backColor: {
type: String,
default: "#fff"
},
src: { src: {
type: String, type: String,
default: "empty" default: 'empty'
}, },
text: { text: {
type: String, type: String,
default: "暂无订单~" default: '暂无订单~'
} }
}, },
data() { data() {
return { return {
typeSrc: { typeSrc: {
empty: "" empty: ''
} }
}; };
}, },
...@@ -37,24 +33,25 @@ export default { ...@@ -37,24 +33,25 @@ export default {
}; };
</script> </script>
<style lang="scss"> <style lang="less">
.empty-content { .empty-content {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
margin: 0 20rpx 20rpx; margin: 0 10px 10px;
padding: 20rpx; padding: 10px;
height: 422rpx; height: 211px;
border-radius: 12rpx; background: @white;
border-radius: 6px;
image { image {
margin-bottom: 20rpx; margin-bottom: 10px;
width: 300rpx; width: 150px;
height: 300rpx; height: 150px;
} }
text { text {
font-size: 32rpx; font-size: 16px;
color: #666666; color: #333333;
} }
} }
</style> </style>
<template>
<view class="page error">
<cr-image src="@/static/images/error/error404.png" width="298px" height="153px" />
<p>你要访问的页面找不到了</p>
<cr-button type="primary" block shape="circle" @click="backurl">返回</cr-button>
</view>
</template>
<script>
export default {
name: '',
data() {
return {};
},
mounted() {},
methods: {
backurl() {
this.$router.go(-1);
}
}
};
</script>
<style lang="less" scoped>
.error {
text-align: center;
padding-top: 0;
padding-bottom: 0;
.cr-image {
margin-top: @padding-sm * 3;
}
p {
color: @black;
.text-size(14);
margin: @padding-unit * 7 0;
}
}
</style>
<template>
<view class="page error">
<cr-image src="@/static/images/error/error.png" width="298px" height="153px" />
<p>oh,no…出错了</p>
<cr-button type="primary" block shape="circle" @click="backurl">返回</cr-button>
</view>
</template>
<script>
export default {
name: '',
data() {
return {};
},
mounted() {},
methods: {
backurl() {
this.$router.go(-1);
}
}
};
</script>
<style lang="less" scoped>
.error {
text-align: center;
padding-top: 0;
padding-bottom: 0;
.cr-image {
margin-top: @padding-sm * 3;
}
p {
color: @black;
.text-size(14);
margin: @padding-unit * 7 0;
}
}
</style>
<template> <template>
<div class="gfcard" :class="{ 'gfcard-disabled': isDisabled }" @click="bindGiftClick"> <view class="gfcard" :class="{ 'gfcard-disabled': isDisabled }">
<div class="gfcard-header"> <view v-if="cardItem" class="gfcard-header">
<div class="gfcard-header-top gfcard-flex"> <view class="gfcard-header-top gfcard-flex">
<text class="gfcard-header-title">{{ <span class="gfcard-header-title">{{
cardItem.createModeDesc || cardItem.cardName || "" cardItem.createModeDesc || cardItem.cardName || ''
}}</text> }}</span>
<template v-if="showRecord"> <!-- 移除使用记录外显功能-->
<text <!-- <template v-if="showRecord">-->
v-if="cardItem.giftStatus != 0" <!-- <span-->
class="gfcard-header-record" <!-- v-if="cardItem.giftStatus != 0"-->
@click.stop="bindRecordClick" <!-- class="gfcard-header-record"-->
>消费记录</text <!-- @click.stop="bindRecordClick"-->
> <!-- >使用记录</span-->
<text v-else>确认收货后即可激活</text> <!-- >-->
</template> <!-- <span v-else>确认收货后即可激活</span>-->
</div> <!-- </template>-->
<div class="gfcard-header-bottom gfcard-flex"> </view>
<text class="gfcard-header-amount"> <view class="gfcard-header-bottom gfcard-flex">
<span class="gfcard-header-amount">
面值:{{ (+cardItem.denomination || 0).toFixed(2) }}元 面值:{{ (+cardItem.denomination || 0).toFixed(2) }}元
</text> </span>
<text class="gfcard-header-time"> <span class="gfcard-header-time">
<template v-if="$config('qinghai') && cardItem.validTimeStart && cardItem.validTimeEnd"> <template v-if="$config.qinghai">
{{ cardItem.validTimeStart | format }} - {{ cardItem.validTimeEnd | format }} {{ cardItem.validTimeStart | format }} - {{ cardItem.validTimeEnd | format }}
</template> </template>
<template v-if="$config('yxm') && cardItem.validDateStart && cardItem.validDateEnd"> <template v-else>
<template v-if="cardItem.validDateStart && cardItem.validDateEnd">
{{ cardItem.validDateStart }} - {{ cardItem.validDateEnd }} {{ cardItem.validDateStart }} - {{ cardItem.validDateEnd }}
</template> </template>
</text> </template>
</div> </span>
</div> </view>
<div class="gfcard-bottom"> </view>
<div class="gfcard-bottom-money"> <view class="gfcard-bottom">
<text class="gfcard-bottom-balance">余额</text> <view class="gfcard-bottom-money">
<text class="gfcard-bottom-num"> <span class="gfcard-bottom-balance">余额</span>
¥<text class="gfcard-bottom-bold">{{ formatPrice[0] }}</text> <span class="gfcard-bottom-num">
<text class="gfcard-bottom-zero">.{{ formatPrice[1] }}</text> ¥<b class="gfcard-bottom-bold">{{ formatPrice[0] }}</b>
</text> <b class="gfcard-bottom-zero">.{{ formatPrice[1] }}</b>
</div> </span>
<p class="gfcard-bottom-describe">{{ cardItem.cardDesc || "" }}</p> </view>
<p class="gfcard-bottom-describe">{{ cardItem.cardDesc || '' }}</p>
<view class="gfcard-checkbox-click" />
<!-- 1-未到期2-使用中3-已失效4-已使用 --> <!-- 1-未到期2-使用中3-已失效4-已使用 -->
<div v-if="cardItem.status !== 2" :class="['gfcard-bg', `bg-${cardItem.status}`]" /> <view v-if="cardItem.status !== 2" :class="['gfcard-bg', `bg-${cardItem.status}`]" />
<radio <cr-checkbox v-if="showCheckbox" :value="selectChecked" shape="round" class="gfcard-check" />
v-if="showCheckbox" </view>
class="gfcard-checkbox" </view>
color="#EC1500"
style="transform: scale(0.7)"
:checked="selectChecked"
/>
</div>
</div>
</template> </template>
<script> <script>
const BINDRECORD_CLICK = "bind-record-click"; const BINDRECORD_CLICK = 'bind-record-click';
const BINDGIFT_CLICK = "bind-gift-click"; import { parseTime } from '@/service/utils.service';
import { parseTime } from "@/utils";
export default { export default {
filters: { filters: {
format(time) { format(time) {
return parseTime(time, "{y}.{m}.{d}"); return parseTime(time, '{y}.{m}.{d}');
} }
}, },
props: { props: {
...@@ -72,7 +69,7 @@ export default { ...@@ -72,7 +69,7 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
// 是否显示消费记录文案 // 是否显示使用记录文案
showRecord: { showRecord: {
type: Boolean, type: Boolean,
default: true default: true
...@@ -90,10 +87,10 @@ export default { ...@@ -90,10 +87,10 @@ export default {
formatPrice() { formatPrice() {
const balance = this.cardItem.balance; const balance = this.cardItem.balance;
let price = !isNaN(balance) ? +balance : 0; let price = !isNaN(balance) ? +balance : 0;
return price.toFixed(2).split("."); return price.toFixed(2).split('.');
}, },
showCheckbox() { showCheckbox() {
return typeof this.checked === "boolean"; return this.checked !== undefined;
} }
}, },
watch: { watch: {
...@@ -105,88 +102,92 @@ export default { ...@@ -105,88 +102,92 @@ export default {
} }
}, },
methods: { methods: {
bindGiftClick() {
this.$emit(BINDGIFT_CLICK, this.cardItem);
},
bindRecordClick() { bindRecordClick() {
this.$emit(BINDRECORD_CLICK, this.cardItem); this.$emit(BINDRECORD_CLICK, this.cardItem);
} }
} }
}; };
</script> </script>
<style lang="scss"> <style scoped lang="less">
.gfcard { .gfcard {
font-size: $uni-font-size-sm; border-radius: 8px;
border-radius: 16rpx; margin-bottom: 8px;
margin-bottom: 16rpx;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
margin-bottom: 16rpx; margin-bottom: 8px;
&-checkbox { .text-size(12);
&-check {
position: absolute; position: absolute;
right: 20rpx; right: 0;
} }
&-checkbox-click {
position: absolute;
right: 0;
height: 20px;
width: 40px;
z-index: 3;
}
&-flex { &-flex {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
&-header { &-header {
color: $white; color: @white;
height: 112rpx; height: 56px;
padding: 16rpx 24rpx; padding: 8px 12px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
background: url(https://img.lkbang.net/xcx/gift-header.png) no-repeat; background: url(~@/static/images/gift/gift-header.png) no-repeat;
background-size: 101%; background-size: 101%;
border-radius: 16rpx 16rpx 0 0; border-radius: 8px 8px 0 0;
box-sizing: border-box; box-sizing: border-box;
&-title { &-title {
font-size: $uni-font-size-base; .text-size(14);
} }
&-record { &-record {
padding-left: 32rpx; padding-left: 16px;
background: url(https://img.lkbang.net/xcx/gift-header-record.png) no-repeat left center; background: url(~@/static/images/gift/gift-header-record.png) no-repeat left center;
background-size: 24rpx 28rpx; background-size: 12px 14px;
} }
&-time { &-time {
opacity: 0.7; opacity: 0.7;
} }
} }
&-bottom { &-bottom {
height: 180rpx; overflow: hidden;
height: 90px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
text-align: center; text-align: center;
background: url(https://img.lkbang.net/xcx/gift-bottom.png) no-repeat; background: url(~@/static/images/gift/gift-bottom.png) no-repeat;
background-size: 102%; background-size: 102%;
border: 1px solid #ebebeb; border: 1px solid #ebebeb;
border-top: 0; border-top: 0;
box-sizing: border-box; box-sizing: border-box;
border-radius: 0 0 16rpx 16rpx; border-radius: 0 0 8px 8px;
position: relative; position: relative;
overflow: hidden;
&-money { &-money {
font-size: $uni-font-size-base; .text-size(14);
color: $font-color-red; color: @red-light;
} }
&-num { &-num {
font-weight: bold; font-weight: bold;
font-size: $font-lg; .text-size(16);
margin-left: 10rpx;
} }
&-bold { &-bold {
font-size: 60rpx; font-size: 30px;
} }
&-zero { &-zero {
font-size: 40rpx; font-size: 20px;
} }
&-describe { &-describe {
font-size: $font-sm; .text-size(12);
color: $uni-text-color-grey; color: @gray-4;
margin-top: 10rpx; margin-top: 5px;
} }
} }
} }
...@@ -199,26 +200,29 @@ export default { ...@@ -199,26 +200,29 @@ export default {
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 100%; background-size: 100%;
&.bg-1 { &.bg-1 {
background-image: url(https://img.lkbang.net/xcx/gift-use-v2.png); background-image: url(~@/static/images/gift/gift-use-v2.png);
} }
&.bg-3 { &.bg-3 {
background-image: url(https://img.lkbang.net/xcx/gift-overdue-v2.png); background-image: url(~@/static/images/gift/gift-overdue-v2.png);
} }
&.bg-4 { &.bg-4 {
background-image: url(https://img.lkbang.net/xcx/gift-used-v2.png); background-image: url(~@/static/images/gift/gift-used-v2.png);
} }
} }
.gfcard-disabled { .gfcard-disabled {
.gfcard-header { .gfcard-header {
background-image: url(https://img.lkbang.net/xcx/gift-header-dis.png); background-image: url(~@/static/images/gift/gift-header-dis.png);
} }
.gfcard-bottom { .gfcard-bottom {
background-image: url(https://img.lkbang.net/xcx/gift-bottom-dis.png); background-image: url(~@/static/images/gift/gift-bottom-dis.png);
position: relative; position: relative;
overflow: hidden; overflow: hidden;
&-money { &-money {
color: $text-color-n3; color: @gray-5;
} }
} }
} }
::v-deep .cr-icon {
line-height: inherit !important;
}
</style> </style>
...@@ -3,29 +3,85 @@ ...@@ -3,29 +3,85 @@
<view v-if="showHeader" class="home-list-header"> <view v-if="showHeader" class="home-list-header">
<view v-if="headerType === 'left'"> <view v-if="headerType === 'left'">
<image src="https://img.lkbang.net/xcx/guess_like.png" /> <image src="https://img.lkbang.net/xcx/guess_like.png" />
<text>猜你喜欢</text> <span>{{ title }}</span>
</view> </view>
<view v-if="headerType === 'center'" class="Hl-header-center">猜你喜欢</view> <view v-if="headerType === 'center'" class="Hl-header-center">{{ title }}</view>
<cr-image
v-if="headerType === 'image'"
:src="'https://img.lkbang.net/icon-recommend.465d832f185840eaa.465d832f.png' | imogr"
width="4.53rem"
height="0.96rem"
class="Hl-header-image"
/>
</view> </view>
<view class="home-list-container"> <!-- <view class="home-list-container"> -->
<view class="left"> <transition-group name="list-complete" tag="div" class="home-list-container">
<Card :list="leftList" :is-delete="isDelete" :no-share="noShare" /> <view
v-for="(item, index) in goodsList"
:key="item.goods.goodsId"
class="Hl-container-item"
@click="handleToDetail(item.goods, index)"
>
<view class="Hl-container-item-img">
<cr-image
class="Hlc-item-img"
:src="item.goods.goodsOrgImage | imogr({ w: 173, h: 173 })"
lazy-load
fit="contain"
/>
<!-- 不感兴趣 -->
<span v-if="noShare" class="Hlc-item-close" @click.stop="setReport(index, item.goods)">
×
</span>
</view> </view>
<view class="right"> <view class="Hlc-item-title">
<Card :list="rightList" :is-delete="isDelete" :no-share="noShare" /> <span>{{ item.goods.goodsName }}</span>
</view> </view>
<view v-if="item.goods.tagList && item.goods.tagList.length" class="Hlc-item-active">
<view v-for="(itm, idx) in item.goods.tagList" :key="idx">
<span v-if="itm.name">{{ itm.name }} </span>
</view> </view>
</view> </view>
<view v-if="item.goods.sellPoint" class="Hlc-item-gray">{{ item.goods.sellPoint }}</view>
<view class="Hlc-item-info">
<view class="Hlcu-info-left">
<view class="Hlcu-info-left-price" v-html="goodsSalePrice(item.goods.goodsSalePrice)" />
<view v-if="item.goods.discountShow" class="Hlcu-info-left-activity">
<span
:style="{
color: colorJudgment(item.goods.discountShow)
}"
{{ item.goods.discountShow.discountPrice }}</span
>
<image :src="item.goods.discountShow.icon | imogr" />
</view>
</view>
<!-- 加入购物车 -->
<view class="Hlcu-info-shopRight">
<cr-image :src="shopcart" @click.stop="addShopCart(item.goods)" />
</view>
</view>
</view>
</transition-group>
<!-- </view> -->
</view>
</template> </template>
<script> <script>
import Card from "./card.vue"; import { Img2Thumb } from '@/filters/img2Thumb.filter';
import { colorJudgment } from '../constants/max.js';
import shopcart from '@/static/images/goods/shopcart.png';
import { mapActions as ShopCartMapActions } from '@/pages/shopCart/shopCartModules.js';
import { getReport } from '@/api/home.api';
export default { export default {
name: "GoodsCard", name: 'GoodsCard',
filters: {
components: { Img2Thumb
Card
}, },
props: { props: {
title: {
type: String,
default: '猜你喜欢'
},
goodsList: { goodsList: {
type: Array, type: Array,
default: () => [] default: () => []
...@@ -40,90 +96,254 @@ export default { ...@@ -40,90 +96,254 @@ export default {
}, },
headerType: { headerType: {
type: String, type: String,
default: "left" default: 'left'
}, },
noShare: { noShare: {
type: Boolean, type: Boolean,
default: false default: false
},
// 商品点击埋点事件名称
eventClickName: {
type: String,
default: 'H5_2BSelectionPageCommodityCardClick'
},
// 商品曝光埋点事件名称
eventExposureName: {
type: String,
default: 'H5_2BSelectionPageCommodityCardExposure'
},
// 埋点默认参数
exposureParams: {
type: Object,
default: () => ({})
},
top: {
type: Number,
default: 0
}
},
data() {
return {
goodsMaskIdx: -1,
shopcart,
colorJudgment
};
},
watch: {
top() {
this.timeOutExposure();
},
goodsList(v, prev) {
if (prev.length < 1) {
this.timeOutExposure();
}
} }
}, },
computed: { beforeDestroy() {
leftList() { clearTimeout(this.timer);
return this.goodsList.filter((item, index) => index % 2 === 0); },
methods: {
...ShopCartMapActions({
addToCart: 'add_to_cart'
}),
goodsSalePrice(price) {
let priceList = [];
if (price.indexOf('.') > -1) {
priceList = price.split('.');
return `<span>¥</span><span>${priceList[0]}</span><span>.${priceList[1]}</span>`;
}
return `<span>¥</span><span>${price}</span>`;
},
addShopCart(params) {
const { goodsId, skuSource } = params;
this.addToCart({ skuId: goodsId, skuNum: 1, skuSource });
},
delGoods(index) {
const { goodsList } = this;
goodsList.splice(index, 1);
this.$toast('已减少此类信息推荐!');
this.$emit('update:goodsList', goodsList);
},
async setReport(index, goods) {
const data = {
dataType: 1, // 数据类型 1:商品不感兴趣
reportData: {
skuUnInterestData: {
pageType: 1, //页面类型,1 - 首页综合信息流(精选页) 2 - 电商首页商品流(发现页)
selectOption: 1, //1:不感兴趣,2:分享好友
sourceType: 1, // 1:商品,4:视频 5:图文段子
sourceId: goods.goodsId || '',
skuSource: goods.skuSource || ''
}
},
userDeviceInfoData: null
};
await getReport(data);
this.delGoods(index);
},
timeOutExposure() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
clearTimeout(this.timer);
this.countItemExposure();
}, 500);
},
// 商品曝光
exposureGood(item, index) {
this.$track.registeredEvents(
this.eventExposureName,
Object.assign({}, this.exposureParams, {
commodity_id: item.goods?.goodsId,
position_number: index
})
);
},
// 判断是否在可视区域
getIsView(elTop, elHeight) {
const viewHeight = window.innerHeight || document.documentElement.clientHeight - 150;
if (elTop + 100 >= this.top && elTop + elHeight / 2 <= this.top - 100 + viewHeight) {
return true;
}
return false;
},
// 计算可曝光商品卡片
countItemExposure() {
const els = this.$el.querySelectorAll('.Hl-container-item');
els.forEach((el, i) => {
const elTop = el.offsetTop;
const elHeight = el.offsetHeight;
const res = this.getIsView(elTop, elHeight);
if (res) {
this.exposureGood(this.goodsList[i], i + 1);
}
});
}, },
rightList() { handleToDetail(item, index) {
return this.goodsList.filter((item, index) => index % 2 === 1); this.$track.registeredEvents(
this.eventClickName,
Object.assign({}, this.exposureParams, {
commodity_id: item.goodsId,
position_number: index + 1
}),
() => {
const params = {
count: 1,
goodsName: item.goodsName,
goodsOrgImage: item.goodsOrgImage
};
const query = {
skuNo: item.goodsId
};
this.$router.push({ name: 'goodDetail', params, query });
}
);
} }
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="less" scoped>
.home-list { .home-list {
&-header { &-header {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 20rpx 20rpx 0; padding: @padding-sm @padding-sm 0;
height: 96rpx; height: 24px;
font-size: 36rpx; .text-size(18);
color: #333333; color: @black;
image { img {
margin-right: 10rpx; margin-right: @padding-x;
width: 40rpx; width: 20px;
height: 40rpx; height: 20px;
vertical-align: text-top;
}
.Hl-header-image {
display: block;
margin: 0 auto @padding-lg;
} }
.Hl-header-center { .Hl-header-center {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin: 30rpx 0; margin: @padding-md 0;
width: 100%; width: 100%;
font-size: 24rpx; .text-size(12);
color: #999999; color: @gray-4;
text-align: center; text-align: center;
&:before, &:before,
&:after { &:after {
display: inline-block; display: inline-block;
content: ""; content: '';
width: 100rpx; width: 50px;
height: 0; height: 0;
border-top: 2rpx solid #d8d8d8; border-top: 2px solid @gray-2;
margin-right: 10rpx; margin-right: @padding-x;
} }
&:after { &:after {
margin-left: 10rpx; margin-left: @padding-x;
margin-right: 0; margin-right: 0;
} }
} }
} }
&-container { &-container {
padding-top: 20rpx; padding-top: @padding-sm;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap; flex-wrap: wrap;
height: 100%;
.Hl-container-item { .Hl-container-item {
position: relative; position: relative;
margin-bottom: 25rpx; margin-bottom: @padding-xs;
width: 339rpx; width: 172px;
background: #fff; background: @white;
border-radius: 12rpx; border-radius: @border-radius-md;
// padding-bottom: 36px;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
transition: all 0.3s;
&.list-complete {
&-enter,
&-leave-to {
opacity: 0;
transform: translateY(30px);
}
&-active {
position: absolute;
}
}
.Hlc-item-close {
position: absolute;
top: 8px;
right: 8px;
width: 12px;
height: 12px;
background: rgba(0, 0, 0, 0.02);
// background: red;
font-size: 10px;
color: #c8c9cc;
border-radius: 50%;
text-align: center;
}
&-img { &-img {
height: 340rpx; height: 170px;
display: flex; display: flex;
align-items: center; align-items: center;
overflow: hidden;
} }
.Hlc-item-img { .Hlc-item-img {
width: 100%; width: 100%;
height: 346rpx; height: 173px;
border-radius: 12rpx; border-radius: @border-radius-md;
overflow: hidden;
} }
.Hlc-item-title { .Hlc-item-title {
height: 76rpx; height: 38px;
margin: 10rpx 20rpx 0rpx 14rpx; padding: @padding-x @padding-xs 0 @padding-xs;
text { span {
font-size: 26rpx; .text-size(13);
line-height: 36rpx; color: @black;
color: #333333;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; display: -webkit-box;
...@@ -131,78 +351,69 @@ export default { ...@@ -131,78 +351,69 @@ export default {
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
} }
.Hlc-item-active {
.Hlc-item-tag { font-size: 0;
display: flex; margin: @border-radius-sm + 2 @padding-xs 0;
flex-wrap: wrap; div {
justify-content: flex-start;
align-items: center;
margin: -10rpx 0rpx 0rpx 14rpx;
&-normal {
display: inline-block; display: inline-block;
span {
display: inline-block;
border: 1px solid @border-red;
font-size: 10px; font-size: 10px;
box-sizing: border-box; color: @red;
border: 1rpx solid #ff5a4b;
color: #ff5a4b;
padding: 0px 4px;
border-radius: 3px; border-radius: 3px;
margin-right: 5px; padding: 3px 5px 2px;
line-height: 14px; margin-right: 3px;
margin-top: 2px;
} }
&-icon {
height: 14px;
margin-right: 5px;
} }
} }
.Hlc-item-gray {
.text-size(12);
color: @gray-4;
padding: 0 @padding-xs;
}
.Hlc-item-info { .Hlc-item-info {
margin: 16rpx 20rpx 14rpx; margin: 0 @padding-xs @border-radius-sm + 2 @padding-xs;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
// position: absolute;
// bottom: 0;
margin-top: auto;
.Hlcu-info-left { .Hlcu-info-left {
display: flex; &-price {
align-items: flex-end; /deep/ span {
text { font-weight: 500;
color: @red-light;
&:nth-child(1) { &:nth-child(1) {
font-size: 20rpx; .text-size(12);
color: #ec3333;
font-weight: bold;
} }
&:nth-child(2) { &:nth-child(2) {
margin-right: 4rpx; .text-size(18);
font-size: 30rpx;
line-height: 34rpx;
color: #ec3333;
font-weight: bold;
} }
&:nth-child(3) { &:nth-child(3) {
font-size: 19rpx; .text-size(12);
line-height: 26rpx;
color: #999999;
text-align: right;
} }
} }
} }
.Hlcu-info-right { &-activity {
display: flex; display: flex;
justify-content: space-between; align-items: flex-end;
align-items: center; margin-top: 3px;
padding: 0 6rpx; span {
// width: 66rpx; font-size: 12px;
width: 40rpx; color: #ed7d08;
height: 40rpx; }
.Hlcui-right-dot { img {
width: 6rpx; width: auto;
height: 6rpx; height: 12px;
background: #d8d8d8; }
border-radius: 50%; }
} }
// font-size: 35rpx; .Hlcu-info-shopRight {
// line-height: 26rpx; width: 24px;
// letter-spacing: -6rpx; height: 24px;
// color: #D8D8D8;
} }
} }
.Hlc-item-mask { .Hlc-item-mask {
...@@ -216,23 +427,23 @@ export default { ...@@ -216,23 +427,23 @@ export default {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background: rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.4);
border-radius: 12rpx; border-radius: @border-radius-sm;
.Hlci-mask-button { .Hlci-mask-button {
padding: 0 60rpx; padding: 0 @padding-xl - 4;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
width: 266rpx; width: 133px;
height: 60rpx; height: 30px;
border-radius: 31rpx; border-radius: @border-radius-lg;
font-size: 24rpx; .text-size(12);
color: #333333; color: @black;
&:first-child { &:first-child {
margin-bottom: 40rpx; margin-bottom: @padding-lg;
} }
image { img {
width: 36rpx; width: 18px;
height: 36rpx; height: 18px;
} }
} }
} }
......
...@@ -5,44 +5,28 @@ ...@@ -5,44 +5,28 @@
v-for="(item, index) in goodsList" v-for="(item, index) in goodsList"
:key="index" :key="index"
class="Hl-container-item" class="Hl-container-item"
@click="goDetail(item, index)" @click="goDetail(item.goods, index)"
> >
<image lazy-load class="Hlc-item-img" mode="aspectFit" :src="item.goods.goodsImage" /> <cr-image class="Hlc-item-img" :src="item.goods.goodsImage | Img2Thumb" lazy-load />
<!-- <image :src="item." -->
<view class="Hlc-item-info"> <view class="Hlc-item-info">
<view>
<view class="Hlc-item-info-title"> <view class="Hlc-item-info-title">
<text>{{ item.goods.goodsName }}</text> <span class="Hlc-item-info-title-name">{{ item.goods.goodsName }}</span>
</view> <view
<!-- <img v-if="item.goods.tagList && item.goods.tagList.length"
v-if="item.goods.userBenefitsLabelImgUrl" class="Hlc-item-info-title-active"
:src="item.goods.userBenefitsLabelImgUrl" >
class="memberImg" <view v-for="(itm, idx) in item.goods.tagList" :key="idx">
/> --> <span>{{ itm.name }}</span>
<!-- 商品列表商品标签 -->
<view class="Hlc-item-tag">
<view v-for="(tag, i) in item.goods.tagList" :key="i" class="Hlc-item-tag-wrap">
<span v-if="tag.type == 2" :key="i" class="Hlc-item-tag-normal">{{
tag.name
}}</span>
<img
v-if="tag.type == 1"
mode="heightFix"
class="Hlc-item-tag-icon"
:src="tag.icon"
alt=""
/>
</view> </view>
</view> </view>
</view> </view>
<!-- 商品列表商品标签 -->
<view class="Hlc-item-info-count"> <view class="Hlc-item-info-count">
<view class="Hlc-item-info-count-left"> <view class="Hlc-item-info-count-left">
<text>¥{{ item.goods.goodsSalePrice }}</text> <span>¥{{ item.goods.goodsSalePrice }}</span>
<!-- <text v-if="item.goods.goodsPrice">¥{{ item.goods.goodsPrice }}</text> --> <!-- <span v-if="item.goods.goodsPrice">¥{{ item.goods.goodsPrice }}</span> -->
</view> </view>
<view class="Hlc-item-info-count-right"> <view class="Hlc-item-info-count-right">
<text v-if="item.goods.saleCount">已售{{ item.goods.saleCount }}</text> <span>已售{{ item.goods.saleCount }}</span>
</view> </view>
</view> </view>
</view> </view>
...@@ -51,10 +35,12 @@ ...@@ -51,10 +35,12 @@
</view> </view>
</template> </template>
<script> <script>
import { saTrackEvent } from "@/utils/sa.js"; import { Img2Thumb } from '@/filters/img2Thumb.filter';
import { debounce } from "@/utils";
export default { export default {
name: "GoodsCard", name: 'GoodsCard',
filters: {
Img2Thumb
},
props: { props: {
goodsList: { goodsList: {
type: Array, type: Array,
...@@ -65,140 +51,114 @@ export default { ...@@ -65,140 +51,114 @@ export default {
return {}; return {};
}, },
methods: { methods: {
goDetail(good, index) { goDetail(item, index) {
const currentPage = getCurrentPages(); console.log(item);
saTrackEvent("PD_YXMMAEC_UserClickProductlistPageCommodityCard", { this.$track.registeredEvents(
page_id: currentPage[currentPage.length - 1].route, 'H5_2B_CommodityListPageCommodityClick',
commodity_id: good.goods.goodsId, {
position_number: index, commodity_id: item.goodsId,
is_landingpage: uni.getStorageSync("is_landingpage") || 0
});
uni.reportAnalytics("c_productlistpagecommoditycard", {
page_id: currentPage[currentPage.length - 1].route,
commodity_id: good.goods.goodsId,
position_number: index position_number: index
}); },
debounce( () => {
uni.navigateTo({ setTimeout(() => {
url: `/pages/product/goodDetail?skuNo=${ const params = {
good.goods.goodsId count: 1,
}&count=1&receiverId=&goodsName=${encodeURIComponent(good.goods.goodsName)}&goodsImage=${ goodsName: item.goodsName,
good.goods.goodsImage goodsimg: item.goodsImage
}` };
}), const query = {
300 skuNo: item.goodsId
};
this.$router.push({ name: 'goodDetail', params, query });
}, 300);
}
); );
} }
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="less" scoped>
.home-list { .home-list {
background: $white; background: @white;
padding: 0 $space-md * 2; padding: 0 @padding-md - 2;
// background: @gray-6;
&-container { &-container {
.Hl-container-item { .Hl-container-item {
display: flex; display: flex;
margin: 40rpx 0; margin: @padding-lg 0;
&:last-child {
margin-bottom: 0;
}
.Hlc-item-img { .Hlc-item-img {
width: 270rpx; width: 135px !important;
height: 270rpx; height: 135px !important;
border-radius: 12rpx; border-radius: @border-radius-sm;
// background: #aaa;
} }
.Hlc-item-info { .Hlc-item-info {
width: 450rpx; width: 225px;
height: 260rpx; height: 130px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
margin-left: 20rpx; margin-left: @padding-sd;
&-title { &-title {
text { &-name {
font-size: 26rpx; .text-size(13);
line-height: 36rpx; line-height: 18px;
color: #333333; color: @black;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
&-active {
font-size: 0;
padding-top: @padding-unit;
overflow: hidden;
height: 43px;
div {
display: inline-block;
span {
display: inline-block;
border: 1px solid @border-red;
font-size: 10px;
color: @red;
border-radius: 5px;
padding: 2px 5px;
margin: 2px 2px 2px 0;
}
}
}
} }
&-count { &-count {
&-left { &-left {
color: #ec3333; color: @red-light;
margin: 1px; margin: 1px;
text { font-size: 0;
span {
&:nth-child(1) { &:nth-child(1) {
margin-right: 10rpx; margin-right: 5px;
font-size: $uni-font-size-lg; .text-size(16);
line-height: 34rpx; line-height: 17px;
color: #ec3333; .text-size(16);
font-weight: bold; color: @red-light;
font-weight: @font-weight-bold;
} }
&:nth-child(2) { &:nth-child(2) {
font-size: $uni-font-size-tiny; .text-size(11);
line-height: 24rpx; line-height: 12px;
color: #999999; color: @gray-4;
text-align: right; text-align: right;
text-decoration: line-through; text-decoration: line-through;
} }
} }
} }
&-right { &-right {
font-size: $uni-font-size-tiny; .text-size(11);
line-height: 24rpx; line-height: 12px;
color: #999999; color: @gray-4;
}
}
} }
.Hlc-item-tag {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
align-items: flex-start;
height: 60rpx;
// margin-top: -40rpx;
&-normal {
display: inline-block;
font-size: 22rpx;
box-sizing: border-box;
border: none;
color: #ec1500;
padding: 0px 4px;
// border-radius: 3px;
margin-right: 5px;
position: relative;
&::after {
display: flex;
box-sizing: border-box;
align-items: center;
content: "";
position: absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: 0 0;
/* #ifndef MP-ALIPAY */
border: 1rpx solid #ff5a4b;
/* #endif */
/* #ifdef MP-ALIPAY */
border: 1px solid #ff5a4b;
/* #endif */
border-radius: 14rpx;
pointer-events: none;
}
// line-height: 14px;
}
&-icon {
height: 28rpx;
margin-right: 5px;
vertical-align: middle;
} }
} }
} }
......
<template>
<!-- 可用于切换布局方式 1行1 1行2 -->
<view
class="multi-layout-list"
:class="{
'multi-list': layoutType == 2
}"
>
<view
v-for="(item, index) in goodsList"
:key="index"
class="goods-item"
:class="{
multi: layoutType == 2
}"
@click="goDetail(item.goods, index)"
>
<cr-image class="goods-item-img" :src="item.goods.goodsImage | Img2Thumb" lazy-load />
<view class="goods-item-info">
<view class="goods-item-info-title">
<span
class="goods-item-info-title-name"
:class="{
'double-line': !item.goods.sellPoint || layoutType == 2,
normal: item.goods.sellPoint && layoutType == 1
}"
>{{ item.goods.goodsName }}</span
>
<view v-if="item.goods && item.goods.sellPoint" class="sellpoint">
{{ item.goods.sellPoint }}
</view>
<view
v-if="item.goods.tagList && item.goods.tagList.length"
class="goods-item-info-title-active"
>
<view v-for="(itm, idx) in item.goods.tagList" :key="idx">
<span>{{ itm.name }}</span>
</view>
</view>
</view>
<!-- discountType 8-新人专享、9-max会员价、10-抢购活动 -->
<view class="goods-item-info-count">
<view class="goods-item-info-count-left">
<view class="goods-item-info-count-left-top">
<span class="goods-item-info-count-left-top-sale"
>¥<a>{{ item.goods.goodsSalePrice }}</a></span
>
<view v-if="item.goods.discountShow" class="goods-item-info-count-left-top-activity">
<span
:style="{
color: colorJudgment(item.goods.discountShow)
}"
{{ item.goods.discountShow.discountPrice }}</span
>
<image :src="item.goods.discountShow.icon" />
</view>
</view>
<view class="goods-item-info-count-left-bottom">
<span>已售{{ item.goods.saleCount }}</span>
</view>
</view>
<view v-if="item.goods" class="goods-item-info-count-right">
<cr-image
v-show="item.goods.shopcartIconType == 1"
src="https://img.lkbang.net/shopcart.ec1a992c.png"
width="24px"
height="24px"
@click.stop="addSkuToCart(item.goods)"
/>
<cr-image
v-show="item.goods.shopcartIconType == 2"
src="https://img.lkbang.net/multi-sec.ec1a992c.png"
width="24px"
height="24px"
@click.stop="showMultiSecPreview(item.goods.sameSpu)"
/>
</view>
</view>
</view>
</view>
<cr-popup v-model="showMultiSec" class="secPopup" @close="closeMultiModal">
<secSwiper v-if="showMultiSec" :sec-arr="secArr" />
<cr-icon type="close" size="34px" color="#FFF" @click="closeMultiModal" />
</cr-popup>
</view>
</template>
<script>
import { Img2Thumb } from '@/filters/img2Thumb.filter';
import secSwiper from '@/components/secSwiper.vue';
import { colorJudgment } from '../constants/max';
export default {
name: 'GoodsCard',
components: {
secSwiper
},
filters: {
Img2Thumb
},
props: {
goodsList: {
type: Array,
default: () => []
},
layoutType: {
type: Number,
default: 1
}
},
data() {
return {
showMultiSec: false,
secArr: [],
colorJudgment
};
},
methods: {
closeMultiModal() {
this.showMultiSec = false;
this.secArr = [];
},
showMultiSecPreview(sameSpu) {
console.log(sameSpu);
this.secArr = sameSpu;
this.showMultiSec = true;
},
goDetail(item, index) {
console.log(item);
this.$track.registeredEvents(
'H5_2B_CommodityListPageCommodityClick',
{
commodity_id: item.goodsId,
position_number: index
},
() => {
setTimeout(() => {
const query = {
skuNo: item.goodsId
};
this.$router.push({ name: 'goodDetail', query });
}, 300);
}
);
},
async addSkuToCart(goods) {
const { goodsId: skuId, goodsType: skuSource, goodsName } = goods;
this.$track.registeredEvents(
'H5_SearchingSecPageAddShoppingCartBtnClick',
{
commodity_id: skuId,
commodity_name: goodsName
},
async () => {
const [res, error] = await this.$store.dispatch('shopCart/good_add', {
type: 'ADD_CART',
goodInfo: { selected: true, skuId, skuSource, skuNum: 1 }
});
if (!error) {
this.$emit('addProduct', goods.goodsSalePrice);
this.$toast('购物车添加成功');
this.$store.dispatch('shopCart/saveCartCount', res?.count);
}
}
);
}
}
};
</script>
<style lang="less" scoped>
.multi-layout-list {
background: @white;
padding: 6px @padding-sm;
box-sizing: border-box;
&.multi-list {
background: #f7f8fa;
display: flex;
flex-flow: row wrap;
justify-content: space-between;
}
.goods-item {
background: @white;
min-height: 116px;
margin-bottom: 10px;
display: flex;
align-items: center;
&.multi {
width: 172px;
height: auto;
flex-shrink: 0;
flex-direction: column;
border-radius: @padding-x;
.goods-item-img {
flex-shrink: 0;
width: 172px !important;
height: 172px !important;
margin-bottom: @padding-unit;
margin-right: 0;
text-align: center;
border-radius: @padding-x;
overflow: hidden;
/deep/ img {
margin: 0 auto;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
}
.goods-item-info {
width: 100%;
&-count {
margin-top: @padding-sm;
}
}
}
&-img {
flex-shrink: 0;
width: 116px !important;
height: 100% !important;
// margin-right: @padding-x;
border-radius: 7px;
overflow: hidden;
/deep/ img {
margin: 0 auto;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
}
&-info {
min-height: 116px;
padding: 0 5px 5px;
box-sizing: border-box;
width: calc(100% - 110px);
flex: 1;
.text-size(13);
display: flex;
flex-direction: column;
justify-content: space-between;
overflow: hidden;
&-title {
width: 100%;
&-name {
display: block;
color: @black;
font-size: 13px;
word-break: break-all;
&.double-line {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
word-break: break-all;
}
&.normal {
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
&-active {
font-size: 0;
padding-top: @padding-unit;
overflow: hidden;
div {
display: inline-block;
span {
height: 12px;
display: flex;
align-items: center;
border: 1px solid @border-red;
font-size: 12px;
color: @red;
border-radius: 3px;
padding: 1px 3px;
margin: 0 3px 0 0;
}
}
}
.sellpoint {
color: #999;
font-size: 12px;
}
}
&-count {
display: flex;
align-items: center;
&-left {
flex: 1;
&-top {
display: flex;
align-items: flex-end;
&-sale {
font-weight: bold;
color: @red;
font-size: 12px;
a {
color: @red;
font-size: 18px;
}
}
&-activity {
padding-left: 3px;
span {
font-size: 14px;
padding-right: 3px;
}
img {
width: auto;
height: 10px;
}
}
}
&-bottom {
color: @gray-4;
.text-size(12);
}
}
&-right {
width: 24px;
flex-shrink: 0;
margin-right: @padding-unit;
}
}
}
}
}
.secPopup {
width: 100%;
background: transparent;
overflow: hidden;
}
.cr-icon {
display: block;
margin: 20px auto 0;
}
</style>
<template>
<view class="load-more">
<span class="load-more__text" :style="{ color: color }">{{
status === 'more'
? contentText.contentdown
: status === 'loading'
? contentText.contentrefresh
: contentText.contentnomore
}}</span>
</view>
</template>
<script>
export default {
name: 'LoadMore',
props: {
status: {
//上拉的状态:more-loading前;loading-loading中;noMore-没有更多了
type: String,
default: 'more'
},
showIcon: {
type: Boolean,
default: true
},
color: {
type: String,
default: '#999'
},
contentText: {
type: Object,
default() {
return {
contentdown: '上拉显示更多',
contentrefresh: '正在加载...',
contentnomore: '没有更多数据了'
};
}
}
},
data() {
return {};
}
};
</script>
<style lang="less">
@charset "UTF-8";
.load-more {
display: flex;
height: 40px;
align-items: center;
justify-content: center;
}
.load-more__text {
.text-size(12);
color: @gray-4;
}
</style>
<template>
<cr-popup
v-model="show"
class="cp-login"
:style="{ height: '60%' }"
round
closeable
position="bottom"
>
<image :src="'https://img.lkbang.net/tenant/yxm-logo.5h67.png' | imogr" alt="" class="img" />
<p class="yxm">羊小咩</p>
<view class="checkbox-content">
<cr-checkbox v-model="checked" icon-size="14px" shape="round" class="agreement">
<span class="text">我已阅读并同意 </span>
</cr-checkbox>
<a :href="$config.privacyRreaty.url" class="link">{{ $config.privacyRreaty.label }}</a>
<a :href="$config.registerRreaty.url" class="link">{{ $config.registerRreaty.label }}</a>
<a :href="configTmd.tianmeidaiRreaty.url" class="link"
>{{ configTmd.tianmeidaiRreaty.label }}</a
>
</view>
<cr-button
shape="circle"
block
type="primary"
native-type="submit"
class="login-form-submit login-now"
@click="handelNowLogin"
>
立即授权
</cr-button>
<p class="login-more" @click="handelLogin">更多登录方式</p>
</cr-popup>
</template>
<script>
import localStorage from '@/service/localStorage.service';
import { getTmdToken } from '@/api/tianmeidai.api';
import TMDConfig from '@/customize/tmd-config';
export default {
name: 'LoginAuthorize',
data() {
return {
show: false,
checked: false,
phoneNum: '',
configTmd: ''
};
},
watch: {
$route(to) {
if (to.query[this.configTmd.channelId.lable]) {
this.handelPopupShow(
to.query[this.configTmd.channelId.lable] || '',
to.query[this.configTmd.channelPhone.lable]
);
}
}
},
created() {
const config = new TMDConfig();
this.configTmd = config;
},
mounted() {
if (this.$route.query[this.configTmd.channelId.lable]) {
this.handelPopupShow(
this.$route.query[this.configTmd.channelId.lable],
this.$route.query[this.configTmd.channelPhone.lable]
);
}
},
methods: {
handelLogin() {
this.show = false;
this.$router.replace({ name: 'Login', query: { backUrl: location.href } });
},
handelPopupShow(id, phone) {
if (id == this.configTmd.channelId.id && !localStorage.get('vccToken')) {
this.show = true;
localStorage.set('vccChannel', this.configTmd.channelId.id);
// 种 获取天美贷 提供的参数 调取接口获取token
localStorage.set('vccPhone', phone);
this.phoneNum = phone;
}
},
async handelNowLogin() {
if (this.checked) {
this.show = false;
const [data] = await getTmdToken(this.phoneNum);
if (!data.token) {
// 无 token 跳转到登录页
this.$router.replace({ name: 'Login', query: { backUrl: location.href } });
return;
}
localStorage.set('vccToken', data.token);
} else {
this.$toast('请仔细阅读并同意相关协议');
}
}
}
};
</script>
<style lang="less" scoped>
.img {
width: 120px;
height: 120px;
display: block;
margin: 0 auto;
margin-top: 68px;
}
.yxm {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 25px;
text-align: center;
margin-top: 4px;
}
.checkbox-content {
text-align: center;
margin-bottom: 16px;
margin-top: 28px;
.link {
font-size: 12px;
}
}
.agreement {
display: inline-block;
.text {
font-size: 12px;
color: @gray-5;
}
}
.cp-login {
height: 406px;
}
::v-deep {
.cr-checkbox__icon {
display: inline-block;
}
.login-now {
width: 335px;
margin: 0 auto;
display: block;
}
.login-more {
text-align: center;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
margin-top: 20px;
// margin-bottom: 30px;
}
}
</style>
<template>
<view ref="loginGuide" class="login-guide">
<svg-icon icon-class="closeLoginGuide" class="closeLoginGuide" @click.native="close" />
<cr-image src="https://img.lkbang.net/auth-logo.1c5fddec.png" />
<span class="desc">登录羊小咩打开美好生活</span>
<cr-button shape="circle" type="primary" @click="handleLogin">立即登录</cr-button>
</view>
</template>
<style lang="less" scoped>
.login-guide {
width: 355px;
height: 54px;
background: rgba(0, 0, 0, 0.7);
position: absolute;
bottom: 12px;
left: 50%;
transform: translateX(-50%);
border-radius: 8px 47px 47px 8px;
padding: 0 5px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
.closeLoginGuide {
position: absolute;
width: 18px;
height: 18px;
top: -7px;
left: -7px;
z-index: 2;
}
/deep/ .cr-image {
width: 44px !important;
height: 44px !important;
img {
width: 44px;
height: 44px;
border-radius: 6px;
}
}
.desc {
color: @white;
font-size: 14px;
}
/deep/ .cr-button {
width: 115px;
}
}
</style>
<script>
import { mapState } from 'vuex';
export default {
data() {
return {};
},
computed: {
...mapState({
userInfo: state => state.pay.userInfo || {}
})
},
methods: {
handleLogin() {
if (!this.userInfo.phoneNumber && (this.$config.qinghai || this.$config.yxm)) {
this.$track.registeredEvents('H5_HomePageLoginSuspendedWindowClick');
this.$router.push({ path: '/login', query: { backUrl: location.href } });
}
},
close() {
// console.log(this.$refs.loginGuide)
if (this.$refs.loginGuide) {
this.$refs.loginGuide.style.display = 'none';
}
}
}
};
</script>
<template> <template>
<view class="login-container"> <view v-if="isLoginPopup" class="login-popup">
<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear"> <image class="login-popup--img" :src="popupInfo.img" alt="login-popup" @click="handleToLogin" />
<uni-transition <view class="login-popup__close">
v-if="maskShow" <image
:mode-class="['fade']" class="login-popup__close--icon"
:styles="maskClass" src="@/static/images/home/loginPopupClose.png"
:duration="duration" alt="close"
:show="showTrans" @click="isLoginPopup = false"
@click="onTap"
/> />
<uni-transition
:mode-class="ani"
:styles="transClass"
:duration="duration"
:show="showTrans"
@click="onTap"
>
<view v-if="loginState" class="uni-popup__wrapper-box" @click.stop="clear">
<view class="login-popup">
<image class="login-img" :src="$config('logoImg')" mode="aspectFit" />
<view class="login-title">
<text>授权登录</text>
</view> </view>
<!-- #ifdef MP-ALIPAY -->
<button
class="goods-bottom-buy"
:open-type="isSelect ? 'getAuthorize' : ''"
scope="phoneNumber"
@click="loginSelect"
@getAuthorize="getAlipayPhoneNumber"
>
{{ loginBtnText }}
</button>
<!-- #endif -->
<!-- #ifndef MP-ALIPAY -->
<button
class="goods-bottom-buy"
:open-type="isSelect ? 'getPhoneNumber' : ''"
@click="loginSelect"
@getphonenumber="getPhoneNumber"
>
{{ loginBtnText }}
</button>
<!-- #endif -->
<view class="login_agreement">
<view class="login_radio">
<radio color="#EE0A24" :checked="isSelect" @click="select" />
</view>
<view class="login_text">
<text>我已阅读并同意</text>
<text class="NTR_red" @click="navTo($config('zhuCeUrl'))">《注册协议》</text>
<text></text>
<text class="NTR_red" @click="navTo($config('yinSiUrl'))">《隐私协议》</text></view
>
</view>
</view>
<slot />
</view>
</uni-transition>
</view>
<user-info-popup
ref="authPopup"
@get-user-info="handleUserInfo"
@get-user-close="handleUserClose"
/>
<subscribeDialog ref="subscribe-dialog" />
</view> </view>
</template> </template>
<script> <script>
import { uniTransition } from "@dcloudio/uni-ui"; import { sStorage } from '@/service/sessionStorage.service';
import { h5Mixin } from "@/utils/h5Mixin"; import localStorage from '@/service/localStorage.service';
import loginMixin from "@/mixins/login.mixin"; import { getLoginPopup } from '@/api/home.api';
import subscribeDialog from "@/components/subscribeDialog";
import userInfoPopup from "@/components/userInfoPopup";
const config = {
// 顶部弹出
top: "top",
// 底部弹出
bottom: "bottom",
// 居中弹出
center: "center",
// 消息提示
message: "top",
// 对话框
dialog: "center",
// 分享
share: "bottom"
};
export default { export default {
name: "UniPopup", name: 'LoginPopup',
components: {
uniTransition,
subscribeDialog,
userInfoPopup
},
mixins: [h5Mixin(), loginMixin],
provide() {
return {
popup: this
};
},
props: { props: {
// 开启动画 value: {
animation: {
type: Boolean, type: Boolean,
default: true default: true
},
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
// message: 消息提示 ; dialog : 对话框
type: {
type: String,
default: "center"
},
// maskClick
maskClick: {
type: Boolean,
default: true
},
title: {
type: String,
default: ""
},
desc: {
type: String,
default: ""
},
callback: {
type: Boolean,
default: false
} }
}, },
data() { data() {
return { return {
loginType: 1, // loginType: 1~ 登录弹窗,0~登录页 isLoginPopup: false,
isCommon: true, popupInfo: {}
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",
config,
loginState: true,
isSelect: false
}; };
}, },
watch: { mounted() {
/** this.init();
* 监听type类型
*/
type: {
handler: function(newVal) {
this[this.config[newVal]]();
},
immediate: true
},
/**
* 监听遮罩是否可点击
* @param {Object} val
*/
maskClick(val) {
this.mkclick = val;
}
}, },
methods: { methods: {
loginSelect() { async init() {
if (!this.isSelect) { const [data] = await getLoginPopup('home');
this.$api.msg("请勾选下方协议后登录"); if (!data) return;
this.popupInfo = data;
if (data.img) {
this.showLoginPopup();
}
},
showLoginPopup() {
// this.$config.yxm
if (localStorage.get('vccToken')) return;
if (!sStorage.getItem('loginPopup')) {
this.isLoginPopup = true;
sStorage.setItem('loginPopup', 'loginPopup');
}
},
handleToLogin() {
this.isLoginPopup = false;
if (this.popupInfo.jumpUrl) {
window.location.href = this.popupInfo.jumpUrl;
return; return;
} }
}, this.$router.push({ name: 'Login' });
navTo(jumpUrl) {
uni.navigateTo({
url: `/pages/webview/webview?url=${encodeURIComponent(JSON.stringify(jumpUrl))}`
});
},
select() {
this.isSelect = !this.isSelect;
},
clear(e) {
// TODO nvue 取消冒泡
e.stopPropagation();
},
open() {
this.showPopup = true;
this.$nextTick(() => {
new Promise(resolve => {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.showTrans = true;
// 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.isSelect = 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.maskClick) 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> </script>
<style lang="scss" scoped> <style lang="less" scoped>
.login-title {
position: relative;
margin-bottom: 30rpx;
&::before {
content: "";
width: 100%;
height: 1rpx;
display: block;
background: #ebebeb;
}
text {
width: 200rpx;
margin: 0 auto;
display: block;
text-align: center;
position: relative;
top: -22rpx;
background: #fff;
font-size: 28rpx;
color: #999;
}
}
.goods-bottom-buy {
width: 526rpx;
height: 80rpx;
line-height: 80rpx;
border: none;
color: $white;
background-image: $background-primary;
border-radius: $border-radius-2;
}
.login-img {
width: 480rpx;
height: 228rpx;
margin: 100rpx auto;
display: block;
}
.login-popup { .login-popup {
padding: 20rpx 50rpx;
}
.footer-btn {
display: flex;
button {
justify-content: space-between;
margin: 0;
width: 50%;
}
}
.uni-popup__wrapper-box {
width: 622rpx;
// height: 762rpx;0
}
.uni-popup {
position: fixed; position: fixed;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-popup__mask {
position: absolute;
top: 0;
bottom: 0;
left: 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; top: 0;
/* #endif */ right: 0;
}
.bottom {
bottom: 0; bottom: 0;
} z-index: 100;
background: rgba(0, 0, 0, 0.5);
.uni-popup__wrapper-box { display: flex;
/* #ifndef APP-NVUE */ justify-content: center;
align-items: center;
flex-direction: column;
&--img {
width: 80%;
display: block; display: block;
/* #endif */ margin: 0 auto;
position: relative;
/* iphonex 等安全区设置,底部安全区适配 */
/* #ifndef APP-NVUE */
// padding-bottom: constant(safe-area-inset-bottom);
// padding-bottom: env(safe-area-inset-bottom);
/* #endif */
// padding: 40rpx 40rpx 0;
border-radius: 12rpx;
overflow: hidden;
background-color: #fff;
.uni-popup-icon {
position: absolute;
right: 40rpx;
top: 32rpx;
height: 28rpx;
width: 28rpx;
}
.uni-popup-header {
margin-bottom: 40rpx;
text {
display: inline-block;
width: 100%;
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;
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;
}
.center .uni-popup__wrapper-box {
border-radius: 32rpx;
overflow: hidden;
}
.login {
&_agreement {
text-align: center;
font-size: 28rpx;
margin-top: 42rpx;
margin-bottom: 74rpx;
color: #666666;
position: relative;
.NTR_red {
color: #ec1500;
}
}
&_radio {
position: absolute;
left: 0;
top: -3rpx;
radio {
transform: scale(0.7);
} }
&__close {
color: #fff;
margin: 50px auto 0 auto;
&--icon {
width: 33px;
display: block;
} }
&_text {
padding-left: 48rpx;
} }
} }
</style> </style>
<template>
<view class="address-picker-wrap">
<view
:class="[
'address-picker-wrap-txt',
{ placeholder: !pickerValShow && placeholder === '省市区县、乡镇等' }
]"
@click="openPopup"
>
{{ pickerValShow || placeholder }}
</view>
<cr-popup
v-model="show"
position="bottom"
closeable
:close-on-click-overlay="false"
class="popup-head"
>
<view class="popup-title">请选择所在地区</view>
<cr-tabs
ref="tabs"
v-model="active"
class="popup-tab"
:ellipsis="true"
color="#ee4155"
@click="handleTabClick"
>
<cr-tab :title="provinceName">
<ul class="area-panel">
<li
v-for="(it, idx) in areaData[0]"
:key="idx"
:class="['area-panel__item', { active: provinceTag.addrId === it.addrId }]"
@click.self="handleItemSelect(0, it)"
>
{{ it.addrName }}
</li>
</ul>
</cr-tab>
<cr-tab :title="cityName">
<ul class="area-panel">
<li
v-for="(it, idx) in areaData[1]"
:key="idx"
:class="['area-panel__item', { active: cityTag.addrId === it.addrId }]"
@click.self="handleItemSelect(1, it)"
>
{{ it.addrName }}
</li>
</ul>
</cr-tab>
<cr-tab :title="distName">
<ul class="area-panel">
<li
v-for="(it, idx) in areaData[2]"
:key="idx"
:class="['area-panel__item', { active: distTag.addrId === it.addrId }]"
@click.self="handleItemSelect(2, it)"
>
{{ it.addrName }}
</li>
</ul>
</cr-tab>
<cr-tab :title="townName">
<ul class="area-panel">
<li
v-for="(it, idx) in areaData[3]"
:key="idx"
:class="['area-panel__item', { active: townTag.addrId === it.addrId }]"
@click.self="handleItemSelect(3, it)"
>
{{ it.addrName }}
</li>
</ul>
</cr-tab>
</cr-tabs>
</cr-popup>
</view>
</template>
<script>
import address from '@/api/address.api.js';
const areaDefault = ['请选择', '请选择', '请选择', '请选择'];
const tagMap = ['provinceTag', 'cityTag', 'distTag', 'townTag'];
export default {
name: 'PopupAreaTabPicker',
props: {
value: null,
placeholder: [String, Array]
// placeholder: {
// type: String,
// default: '请选择'
// }
},
data() {
return {
show: false,
active: 1,
selectData: [],
cityTag: {},
provinceTag: {},
distTag: {},
townTag: {},
areaData: [[], [], [], []],
pickerValShow: '',
addressValue: []
};
},
computed: {
provinceName() {
return this.areaData[0].length > 0 ? this.provinceTag.addrName : '';
},
cityName() {
return this.areaData[1].length > 0 ? this.cityTag.addrName : '';
},
distName() {
return this.areaData[2].length > 0 ? this.distTag.addrName : '';
},
townName() {
return this.areaData[3].length > 0 ? this.townTag.addrName : '';
}
},
watch: {
show: {
immediate: true,
handler(val) {
this.$emit('popup', val);
}
}
},
mounted() {
this.init();
},
methods: {
handleTabClick(name) {
for (let i = name + 1; i < 4; i++) {
this[tagMap[i]] = {
addrId: '',
addrLevel: i,
addrName: areaDefault[i]
};
}
},
handleItemSelect(index, it) {
const selectData = JSON.parse(JSON.stringify(this.selectData));
const active = index + 1;
selectData[index] = it;
this[tagMap[index]] = it;
for (let i = index + 1; i < 4; i++) {
this[tagMap[i]] = {
addrId: '',
addrLevel: i,
addrName: areaDefault[i]
};
selectData[i] = {
addrId: '',
addrName: '',
addrLevel: i
};
this.areaData[i] = [];
}
this.getAddrList(it.addrId, active);
this.$set(this, 'selectData', selectData);
if (index === 3) {
this.show = false;
this.submit();
}
},
async getAddrList(addrId = '', index = 0) {
const areaData = JSON.parse(JSON.stringify(this.areaData));
const res = await address.zoneList(addrId);
const addrList = res[0].addrList || [];
areaData[index] = addrList;
if (addrList && addrList.length) {
this.active = index;
} else {
this.show = false;
this.submit();
}
this.$set(this, 'areaData', areaData);
},
submit() {
const address = this.selectData.filter(item => item.addrId);
const addressName = address.map(item => item.addrName);
const addressValue = address.map(item => item.addrId);
this.pickerValShow = addressName.join(',');
this.$emit('input', addressValue);
this.$emit('finish', {
id: addressValue,
items: this.selectData
});
},
init() {
this.selectData = [];
this.areaData = [[], [], [], []];
this.pickerValShow = '';
this.selectData[0] = {
addrId: '',
addrName: '',
addrLevel: '1'
};
for (let i = 0; i < 4; i++) {
this[tagMap[i]] = {
addrId: '',
addrLevel: i + 1,
addrName: areaDefault[i]
};
}
this.getAddrList();
},
openPopup() {
this.show = true;
this.$refs.tabs && this.$refs.tabs.setLine();
if (this.value) {
this.active = this.addressValue.length - 1;
} else {
this.active = 0;
}
},
reset() {
this.init();
}
}
};
</script>
<style lang="less" scoped>
// 弹出框头部
.popup-head {
border-radius: 20px 20px 0 0;
.popup-title {
.text-size(16);
font-weight: @font-weight-bold;
color: @black;
text-align: center;
padding: 10px 0;
}
.popup-tab {
@{deep} .cr-tabs__item {
color: #000;
}
@{deep} .cr-tabs__item--active {
color: #ec1500;
}
}
}
.address-picker-wrap {
width: 100%;
&-txt {
width: 100%;
font-size: 15px;
color: #333333;
&.placeholder {
color: #b2b2b2;
opacity: 0.7;
}
}
@{deep} .cr-popup--close-top-right {
position: absolute !important;
}
@{deep} .cr-popup--close {
z-index: 999;
color: #333;
font-size: 18px;
padding: 10px;
top: 4px;
right: 4px;
}
.cr-tabs {
&__wrap {
border-bottom: 1px solid #eeeeee;
}
&__item {
flex: none;
width: 70px;
height: 40px;
font-size: 13px;
text-align: center;
line-height: 40px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
line-clamp: 1;
-webkit-box-orient: vertical;
}
}
}
.area-panel {
height: 300px;
overflow-x: scroll;
overflow-y: scroll;
&__item {
padding: 10px 15px;
font-size: 14px;
color: #333;
&.active {
color: #ee4155;
}
}
}
</style>
<template>
<view v-if="orderStatus == 11" class="prepayArea" :class="{ listPage: listPage }">
<span
v-if="
!!orderData &&
orderData.giftCardReturnInfo &&
orderData.giftCardReturnInfo.giftCardReturnAmt
"
class="giftCardReturnInfo"
>
<span class="content">{{ orderData.giftCardReturnInfo.giftCardReturnAmt }}元礼品卡</span>
</span>
<button class="prepayBtn" @click.stop="clickBtn">
付款
</button>
</view>
</template>
<script>
export default {
props: {
orderStatus: {
type: [Number, String],
default: ''
},
orderData: {
type: Object,
default() {
return {};
}
},
listPage: {
type: Boolean,
default: false
}
},
methods: {
clickBtn() {
this.$emit('clickBtn');
}
}
};
</script>
<style lang="less" scoped>
// 因待付款增加返礼品卡标识,无法使用cherry-ui button组件进行二次开发
.prepayArea {
display: inline-block;
position: relative;
margin-left: @padding-unit;
&.listPage {
margin-top: @padding-sm;
}
.prepayBtn {
display: block;
position: relative;
color: @red;
border: 1px solid @red;
background: @white;
width: 86px;
border-radius: 999px;
height: 30px;
z-index: 2;
font-size: 14px;
}
.giftCardReturnInfo {
max-width: 86px;
position: absolute;
right: 0.5px;
top: -11px;
display: inline-block;
// padding: 0 @padding-unit;
height: 25px;
background-image: linear-gradient(270deg, #ff5d00 50%, #fff 91%);
color: @white;
font-size: 8px;
// box-sizing: border-box;
border-top-left-radius: 7px;
border-top-right-radius: 7px;
border-bottom-left-radius: 7px;
border-bottom-right-radius: 0;
display: flex;
align-items: flex-start;
.content {
max-width: 86px;
position: relative;
padding: 0 @padding-unit + 2 0 @padding-unit;
display: inline-block;
box-sizing: border-box;
background-image: linear-gradient(270deg, #ff5d00 10%, #ff1900 91%);
border-top-left-radius: 7px;
border-top-right-radius: 7px;
border-bottom-left-radius: 7px;
border-bottom-right-radius: 0;
z-index: 3;
height: 16px;
line-height: 17px;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
</style>
<template>
<view class="list-wrap">
<view ref="scrollContent" class="content" @scroll="onScroll">
<slot />
</view>
</view>
</template>
<script>
export default {
props: {
loading: {
type: Boolean,
default: false
},
toTop: {
type: Number,
default: 0
},
beforeBottomHeight: {
type: Number,
default: 50
}
},
data() {
return {
activated: false
};
},
watch: {
toTop: {
handler(val) {
this.$nextTick(() => {
if (this.activated) this.$refs.scrollContent.scrollTop = val;
});
}
}
},
activated() {
this.activated = true;
},
methods: {
onScroll() {
const obj = this.$refs.scrollContent; // clientHeight 视口高度 scrollTop 滚动条离顶部的高度 scrollHeight 列表内容的高度
if (obj.clientHeight + (obj.scrollTop + this.beforeBottomHeight) >= obj.scrollHeight) {
this.$emit('toBottom');
}
this.activated = false;
this.$emit('scroll', obj.scrollTop);
}
}
};
</script>
<style lang="less" scoped>
.list-wrap {
width: 100%;
height: 100%;
position: relative;
}
.list-wrap {
width: 100%;
height: 100%;
position: relative;
}
.content {
width: 100%;
height: 100%;
overflow-y: scroll;
overflow-x: hidden;
}
.loading {
position: absolute;
bottom: -20px;
width: 100%;
height: 20px;
text-align: center;
.text-size(12);
color: @black;
}
::-webkit-scrollbar {
// 去除滚动条边框
width: 0 !important;
}
::-webkit-scrollbar {
width: 0 !important;
height: 0;
}
</style>
<template>
<view class="SearchPanel" @click="resetSearch">
<cr-search
ref="searchInput"
v-model.trim="keyWords"
shape="round"
left-icon="search"
placeholder="搜索你想要的宝贝"
@search="searchEnterEvent"
@clear="clearInputText"
/>
<cr-tag
v-if="isSearch"
size="medium"
color="#999"
shape="round"
closable
@close="resetSearch"
>{{ keyWords }}</cr-tag
>
</view>
</template>
<script>
const SEARCH_EVENT = 'enter';
const CLEAR_EVENT = 'clear';
export default {
props: {
isSearch: {
type: Boolean,
default: false
}
},
data() {
return {
keyWords: ''
};
},
watch: {
keyWords(val) {
if (val) this.$track.registeredEvents('H5_2B_CommodityListPageExposure');
}
},
methods: {
clearInputText() {
this.keyWords = '';
},
resetSearch() {
this.clearInputText();
this.$emit(CLEAR_EVENT);
},
searchEnterEvent() {
if (!this.keyWords) {
return this.$dialog({
message: '请输入内容',
showCancelButton: false
});
}
this.$refs.searchInput.$el.querySelector('input').blur();
this.$emit(SEARCH_EVENT, this.keyWords);
}
}
};
</script>
<style lang="less" scoped>
.SearchPanel {
@{deep} .cr-icon--cross {
position: absolute;
right: 5px;
top: 5px;
}
@{deep} .cr-search {
padding: @padding-sm @padding-sm + 4;
.cr-icon--search {
.text-size(16);
color: #999;
}
}
position: relative;
.cr-tag {
padding-left: 10px;
padding-right: 20px;
position: absolute;
top: @padding-sm + 3;
left: 45px;
max-width: 84%;
display: -webkit-box;
-webkit-line-clamp: 1;
box-sizing: border-box;
-webkit-box-orient: vertical;
word-break: break-all;
}
}
</style>
<template>
<view class="nav">
<view
v-for="(item, index) in filterItem"
:key="index"
class="nav-item"
:class="{ current: filterIndex === index }"
@click="tabClick(item, index)"
>
<span class="nav-item-title">{{ item.name }}</span>
<view v-if="Object.keys(item.select).length" class="nav-item-container">
<span
v-for="(selectItem, selectIndex) in item.select"
:key="selectIndex"
class="iconfont"
:class="computedActive(selectIndex, selectItem)"
/>
</view>
</view>
</view>
</template>
<script>
const CHANGE_TABEVT = 'change';
export default {
data() {
return {
rankType: 1,
filterIndex: 0,
filterItem: [
{ name: '综合', select: 1 },
{ name: '价格', select: { up: 3, down: 2 } },
{ name: '销量', select: { up: 5, down: 4 } }
]
};
},
methods: {
computedActive(selectIndex, selectItem) {
let className = `icon-sort-${selectIndex}-round`;
const rankType = this.rankType;
return rankType === selectItem ? `${className} active` : className;
},
tabClick({ select }, index) {
const rankType = this.rankType;
if (!index) {
if (rankType === select) return;
this.rankType = select;
} else {
this.rankType = rankType === select.down ? select.up : select.down;
}
this.filterIndex = index;
this.$track.registeredEvents('H5_2B_CommodityListPageSortBtnClick', {
buttons_name: name
});
this.$emit(CHANGE_TABEVT, this.rankType);
}
}
};
</script>
<style scoped lang="less">
.nav {
display: flex;
width: 100%;
height: 40px;
background: @white;
z-index: 10;
padding-top: 5px;
box-shadow: 0px 10px 12px -10px rgba(100, 101, 102, 0.08);
&-item {
.text-size(16);
flex: 1;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: @gray-4;
&-title {
line-height: 15px;
}
&.current {
color: @black;
font-weight: @font-weight-bold;
.nav-item-title {
font-weight: @font-weight-bold;
}
}
&-container {
display: flex;
flex-direction: column;
margin-left: @padding-unit / 2;
justify-content: center;
span {
.text-size(10);
color: @gray-4;
&.active {
color: @black;
}
&:nth-child(1) {
margin-bottom: -13px;
}
}
}
}
}
</style>
<template>
<view v-if="showSwiper">
<view ref="mySwiper" class="swiper-container swiper mySwiper">
<view class="swiper-wrapper">
<view v-for="(item, index) in secArr" ref="slide" :key="index" class="swiper-slide">
<view class="img">
<image :src="item.goodsImage" fit="contain" />
<view class="picNumber">{{ item.index }}/{{ totalCount }}</view>
</view>
<!-- {{ item }} -->
<view class="goodsInfo">
<view class="leftPart">
<view class="goodsName">
{{ item.goodsName }}
</view>
<p class="secStr">
{{ item.skuAttsStr }}
</p>
<view class="price">
<span>¥</span>
<span>{{ item.goodsSalePrice | formatNum }}</span>
<span>{{ item.goodsSalePrice | formatFloat }}</span>
</view>
</view>
<view class="rightPart" @click.stop="addShopCart(item)">
<view class="shopcartIcon">
<!-- {{ item }} -->
<svg-icon icon-class="shopcart" class="shopcart" />
<view v-if="skuShopCartMap[item.goodsId]" class="shopcartCount">
{{ skuShopCartMap[item.goodsId] }}
</view>
</view>
<view class="desc">
加入购物车
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import Swiper from 'swiper/swiper-bundle.js';
//引入css
import 'swiper/swiper-bundle.min.css';
export default {
filters: {
formatNum(val) {
let str = val + '';
return str.split('.')[0];
},
formatFloat(val) {
let str = val + '';
const float = str.split('.')[1];
return float ? '.' + str.split('.')[1] : '';
}
},
props: {
secArr: {
type: Array,
default() {
return {};
}
}
},
data() {
return {
list: [],
cacheList: [],
skuShopCartMap: {},
totalCount: 0,
currentIndex: 0,
showSwiper: true
};
},
watch: {
secArr: {
immediate: true,
handler(val) {
this.totalCount = val.length;
this.cacheList = val.map((item, index) => {
item.index = index + 1;
return item;
});
// this.list = val.slice(0, 3);
this.showSwiper = false;
this.$nextTick(() => {
this.refreshSwiper();
});
}
}
},
mounted() {
this.refreshSwiper();
},
methods: {
addShopCart(goods) {
const { goodsId: skuId, goodsType: skuSource } = goods;
this.$track.registeredEvents(
'APP_FeedCommodityCardCartBtnClick',
{
page_name: '搜索结果页'
},
async () => {
const [res, error] = await this.$store.dispatch('shopCart/good_add', {
type: 'ADD_CART',
goodInfo: { selected: true, skuId, skuSource, skuNum: 1 }
});
if (!error) {
this.$toast('购物车添加成功');
this.$store.dispatch('shopCart/saveCartCount', res?.count);
if (!this.skuShopCartMap[goods.goodsId]) {
// this.skuShopCartMap[goods.goodsId] = 1;
this.$set(this.skuShopCartMap, skuId, 1);
} else {
let currentCount = this.skuShopCartMap[goods.goodsId];
this.$set(this.skuShopCartMap, skuId, currentCount + 1);
}
}
}
);
},
refreshSwiper() {
if (!this.secArr.length) return;
const init = () => {
this.$nextTick(() => {
let totalOpacity = 1.33;
const opacityStep = 0.33;
// const index = this.$refs.mySwiper.swiper.activeIndex;
const slides = Array.from(document.getElementsByClassName('swiper-slide'));
const index = slides.findIndex(item => {
return item.className.indexOf('swiper-slide-active') > 0;
});
try {
for (let i = index; i < slides.length; i++) {
const surplus = totalOpacity - opacityStep;
slides[i].style.opacity = surplus;
slides[i].style.zIndex = 100;
totalOpacity = surplus;
}
if (index != 0) {
for (let i = index - 1; i >= 0; i--) {
slides[i].style.opacity = 0;
}
}
} catch (err) {
console.log(err);
}
});
};
this.showSwiper = true;
this.$nextTick(() => {
new Swiper('.swiper', {
effect: 'cards',
grabCursor: true,
loop: true,
loopedSlides: 10,
speed: 500,
cardsEffect: {
rotate: 0,
perSlideOffset: 10
},
on: {
init() {
init();
},
slideChange: () => {
init();
}
}
});
});
}
}
};
</script>
<style lang="less" scoped>
@opacityStep: 0.15;
@containerWidth: 315px;
@itemWidth: 295px;
.swiper {
width: @itemWidth;
height: 400px;
}
.swiper-slide {
display: flex;
// align-items: center;
// justify-content: center;
flex-direction: column;
border-radius: 12px;
font-size: 22px;
font-weight: bold;
color: #999;
background: @white;
.img {
position: relative;
width: @itemWidth;
height: @itemWidth;
.picNumber {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
bottom: 10px;
right: 10px;
padding: 2px @padding-x;
background: rgba(0, 0, 0, 0.4);
border-radius: 12px;
color: @white;
font-size: 10px;
}
}
.img {
width: 100%;
height: @itemWidth;
// border-radius: 12px 12px 0 0;
overflow: hidden;
img {
width: 100%;
height: 100%;
display: block;
}
}
.goodsInfo {
padding: @padding-xs @padding-sm;
box-sizing: border-box;
display: flex;
.leftPart {
width: calc(100% - 85px);
}
.rightPart {
font-size: 12px;
width: 85px;
padding-top: @padding-xs;
box-sizing: border-box;
// background: @gray-4;
display: flex;
flex-direction: column;
align-items: center;
.shopcartIcon {
position: relative;
.shopcartCount {
position: absolute;
top: -1px;
right: -1px;
width: 17px;
height: 17px;
border-radius: 50%;
background: @red;
color: @white;
font-size: 13px;
display: flex;
align-items: center;
justify-content: center;
}
}
.desc {
margin-top: @padding-unit;
.text-size(12);
}
}
}
.goodsName {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 100%;
.text-size(14);
color: @black;
word-break: break-all;
}
.secStr {
.text-size(12);
color: @gray-4;
margin-top: @padding-unit / 2;
}
.price {
color: @red;
margin-top: @padding-unit * 2;
span {
font-weight: bold;
&:nth-child(1) {
font-size: 12px;
}
&:nth-child(2) {
font-size: 18px;
}
&:nth-child(3) {
font-size: 12px;
}
}
}
}
.shopcart {
width: 50px;
height: 50px;
}
</style>
<template>
<view class="shopcart" @click.stop="goShopCart">
<span v-if="shopcartCount" class="count">{{ shopcartCount }}</span>
<svg-icon icon-class="shopcart" class="shopcart" />
</view>
</template>
<script>
import localStorage from '@/service/localStorage.service';
export default {
props: {
shopcartCount: {
type: [Number, String],
default: ''
}
},
created() {
// this.$store.dispatch('shopCart/queryCartCount');
},
methods: {
goShopCart() {
setTimeout(() => {
localStorage.get('vccToken')
? this.$router.push({ name: 'Cart' })
: this.$router.push({ name: 'Login', query: { backUrl: '/shopCart' } });
}, 500);
}
}
};
</script>
<style lang="less" scoped>
.shopcart {
position: fixed;
bottom: 126px;
right: 10px;
width: 42px;
height: 42px;
.count {
position: absolute;
right: -5px;
top: -5px;
z-index: 2;
background: #ff1616;
font-size: 14px;
color: #f8f8f8;
text-align: center;
width: 20px;
height: 20px;
border-radius: 50%;
text-align: center;
line-height: 20px;
}
}
</style>
<template>
<view class="uni-numbox">
<view class="uni-numbox-minus" @click="_calcValue('subtract')">
<span class="yticon" :class="canSubtract ? 'uni-numbox-disabled' : ''"> - </span>
</view>
<input class="uni-numbox-value" type="number" :disabled="disabled" :value="value" />
<view class="uni-numbox-plus" @click="_calcValue('add')">
<span class="yticon" :class="canAdd ? 'uni-numbox-disabled' : ''"> + </span>
</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
};
},
watch: {
value(val) {
this.inputValue = val;
}
},
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 });
} else {
this.$toast(`库存不足`);
}
}
}
}
};
</script>
<style lang="less" scoped>
.uni-numbox {
display: flex;
justify-content: flex-start;
align-items: center;
height: 24px;
background: #fff;
}
.uni-numbox-minus,
.uni-numbox-plus {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: #f2f3f5;
width: 24px;
height: 100%;
text-align: center;
position: relative;
}
.uni-numbox-minus .yticon,
.uni-numbox-plus .yticon {
.text-size(14);
color: #555;
}
.uni-numbox-minus {
border-right: none;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.uni-numbox-plus {
border-left: none;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.uni-numbox-value {
position: relative;
background-color: #f2f3f5;
width: 38px;
height: 24px;
text-align: center;
padding: 0;
.text-size(14);
margin: 0 2px;
}
.uni-numbox-disabled.yticon {
color: #d6d6d6;
}
</style>
<template> <template>
<popup ref="popup" background="transparent" class="pop" @change="change"> <cr-popup v-model="tipShow" round @close="handleClosePop">
<modal :title="typeInfo[type].title" type="warning" hide-cancel-btn hide-confirm-btn mkclick> <image class="wx" :src="typeInfo[type].url" alt="qr" />
<view class="content"> </cr-popup>
<view class="content__top">{{ typeInfo[type].top }}</view>
<image v-if="typeInfo[type].qr" :src="typeInfo[type].qr" class="content__qrcode" />
<template v-for="item in typeInfo[type].bottom">
<view :key="item.text" class="content__bottom">
<text v-if="item.tag" class="content__bottom--tag">{{ item.tag }}</text>
<tetx class="content__bottom__text">{{ item.text }}</tetx>
</view>
</template>
<template v-for="btn in typeInfo[type].btn">
<button v-if="!btn.type" :key="btn.text" class="content__btn" @click="action(btn)">
{{ btn.text }}
</button>
<view v-else :key="btn.text" class="content__text" @click="action(btn)">
{{ btn.text }}
</view>
</template>
</view>
</modal>
</popup>
</template> </template>
<script> <script>
import modal from "./uni-popup/uni-popup-dialog";
import popup from "./uni-popup/uni-popup";
import { downApp } from "../utils/index";
import { saTrackEvent } from "@/utils/sa";
import { getFaceUrl } from "@/api/face.api";
import saveImageMixin from "@/mixins/saveImage.mixin";
export default { export default {
options: { styleIsolation: "shared" }, components: {},
components: {
modal,
popup
},
mixins: [saveImageMixin],
props: { props: {
value: { value: {
type: Boolean, type: Boolean,
...@@ -43,206 +13,37 @@ export default { ...@@ -43,206 +13,37 @@ export default {
}, },
type: { type: {
type: String, type: String,
default: "gzh" default: 'wx'
},
scene: {
// 用于区分ka渠道活体场景,user -> 我的页面 pay -> 收银台
type: String,
default: "user"
} }
}, },
data() { data() {
return { return {
vccChannel: "", tipShow: false,
sonVccChannel: "",
typeInfo: { typeInfo: {
wx: { wx: {
url: "https://img.lkbang.net/xcx/downGzh.png", url: 'https://img.lkbang.net/xcx/downGzh.png',
qr: "https://img.lkbang.net/xcx/gzhQrcode.png", qr: 'https://img.lkbang.net/xcx/gzhQrcode.png',
top: "请关注【羊小咩Plus】公众号,获得更多信息", top: '请关注【羊小咩Plus】公众号,获得更多信息',
title: "关注微信", title: '关注微信'
bottom: [{ text: "下载保存图片" }, { text: "微信扫一扫识别二维码" }],
btn: [{ text: "保存图片", fn: this.saveEwm }]
},
gzh: {
url: "https://img.lkbang.net/xcx/downGzh.png",
qr: "https://img.lkbang.net/xcx/gzhQrcode.png",
top: "请关注【羊小咩Plus】公众号,获得更多信息",
title: "该功能正在开发中",
bottom: [{ text: "下载保存图片" }, { text: "微信扫一扫识别二维码" }],
btn: [{ text: "保存图片", fn: this.saveEwm }]
},
app: {
url: "https://img.lkbang.net/xcx/downApp.png",
qr: "https://img.lkbang.net/xcx/appQrcode.png",
top: "请在羊小咩APP中完成后续操作",
title: "该功能正在开发中",
bottom: [
{ text: "微信识别图中二维码下载羊小咩APP" },
{ text: "复制链接在浏览器打开前往应用市场下载", tag: "推荐" }
],
btn: [
{ text: "复制链接", fn: this.clipboard },
{ text: "保存图片", fn: this.saveEwm, type: "text" }
]
},
appToFace: {
url: "",
qr: "",
top: "完成后即可释放享花卡额度",
title: "请前往浏览器完成活体认证",
bottom: [
{ text: "复制链接在浏览器打开进行活体认证" }
// { text: "微信识别图中二维码下载羊小咩APP" },
// { text: "复制链接在浏览器打开前往应用市场下载", tag: "推荐" }
],
btn: [
{ text: "复制链接", fn: this.clipboard }
// { text: "保存图片", fn: this.saveEwm, type: "text" }
]
} }
} }
}; };
}, },
watch: { watch: {
value: { value(val) {
immediate: true, this.tipShow = val;
handler: function(val) {
val ? this.$refs.popup.open && this.$refs.popup.open() : null;
}
} }
}, },
methods: { methods: {
saveImage() { handleClosePop() {
uni.downloadFile({ this.$emit('update:value', false);
url: this.typeInfo[this.type].url,
success: function(res) {
if (res.statusCode === 200) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function() {
uni.showToast({
title: "保存成功",
icon: "none"
});
},
fail: function() {
uni.showToast({
title: "保存失败",
icon: "none"
});
}
});
}
},
fail: function(error) {
console.log(error);
}
});
},
change(val) {
if (val?.show === false) {
saTrackEvent("PD_YXMMACP_UserClickGuidePopupWindowBtn", {
buttons_name: "遮罩层"
});
}
this.$emit("change", val);
},
async clipboard() {
if (this.type === "appToFace") {
// 活体认证提示
const pages = getCurrentPages();
const page = pages[pages.length - 1];
const orderNo = Object.keys(page.options).length == 0 ? "" : page.options.orderNo;
const pagePath = page.route || "";
const from = pagePath.indexOf("pages/user/user") > -1 ? "user" : "pay";
const token = uni.getStorageSync("token") || "";
this.vccChannel = uni.getStorageSync("vccChannel") || "";
this.sonVccChannel = uni.getStorageSync("sonVccChannel") || "";
console.log(token, from, orderNo);
const [result] = await getFaceUrl(token, from, orderNo);
if (!result) return;
uni.setClipboardData({
data: result.faceUrl,
success: function() {
console.log("open vcc face ocr");
}
});
return;
}
uni.setClipboardData({
data: downApp,
success: function() {
console.log(downApp);
}
});
},
action(btn) {
saTrackEvent("PD_YXMMACP_UserClickGuidePopupWindowBtn", {
buttons_name: btn.text
});
if (this.type === "appToFace") {
const pages = getCurrentPages();
const page = pages[pages.length - 1];
const pagePath = page.route || "";
saTrackEvent("MINI_BodyConfirmationPopupWindowBtnClick", {
page_name: pagePath.indexOf("pages/user/user") > -1 ? "user" : "pay",
buttons_name: btn.text
});
}
btn.fn();
} }
} }
}; };
</script> </script>
<style lang="scss"> <style lang="less">
.pop { .wx {
text-align: center; width: 300px;
.uni-dialog-content { display: block;
padding: 0 0 48rpx 0;
}
.content {
&__top {
font-size: 24rpx;
color: #999999;
}
&__qrcode {
width: 300rpx;
height: 300rpx;
margin-top: 40rpx;
margin-bottom: 18rpx;
}
&__bottom {
font-size: 28rpx;
color: #333333;
margin: 16rpx;
display: flex;
align-items: flex-start;
justify-content: center;
&--tag {
min-width: 60rpx;
font-size: 20rpx;
color: #ffffff;
padding: 4rpx 8rpx;
border-radius: 8rpx;
margin-right: 8rpx;
@include primary-bg;
margin-top: 2rpx;
}
}
&__btn {
color: $white;
margin-top: 48rpx;
font-size: 32rpx;
border-radius: $uni-border-radius-xl;
width: 526rpx;
@include primary-bg;
}
&__text {
font-size: 32rpx;
margin-top: 36rpx;
color: #ec1500;
}
}
} }
</style> </style>
<!-- 悬浮按钮滚动到顶部 --> <!-- 悬浮按钮滚动到顶部 -->
<template> <template>
<view :animation="animationData" hover-class="bottom-btn-hover" class="to-top" @tap="tapTop"> <transition name="fade">
<i class="iconfont icon-back-top-line" /> <view v-if="scrollTop > 500" class="to-top" @click="handleTop">
<text>顶部</text> <!-- <i class="iconfont back-top-o" /> -->
<cr-icon type="back-top-o" size="20px" style="font-weight: bold" />
<span>顶部</span>
</view> </view>
</transition>
</template> </template>
<script> <script>
let animation = uni.createAnimation({
timingFunction: "ease"
});
export default { export default {
props: { props: {
// 页面滚动距离 // 页面滚动距离
...@@ -20,7 +20,7 @@ export default { ...@@ -20,7 +20,7 @@ export default {
}, },
data() { data() {
return { return {
animationData: {}, // animationData: {},
old: { old: {
scrollTop: 0 scrollTop: 0
} }
...@@ -31,50 +31,48 @@ export default { ...@@ -31,50 +31,48 @@ export default {
this.old.scrollTop = newVal; this.old.scrollTop = newVal;
if (newVal < 500) { if (newVal < 500) {
//淡出 //淡出
animation.opacity(0).step({ duration: 800 }); // animation.opacity(0).step({ duration: 800 });
this.animationData = animation.export(); // this.animationData = animation.export();
} else { } else {
//淡入 //淡入
animation.opacity(1).step({ duration: 800 }); //描述动画 // animation.opacity(1).step({ duration: 800 }); //描述动画
this.animationData = animation.export(); // this.animationData = animation.export();
} }
} }
}, },
created() { created() {
//默认不显示 //默认不显示
animation.opacity(0).step({ duration: 0 }); // animation.opacity(0).step({ duration: 0 });
// this.animationData = animation.export();
this.animationData = animation.export();
}, },
methods: { methods: {
//滚动到顶部 //滚动到顶部
tapTop() { handleTop() {
this.$emit("toTop"); this.$emit('toTop');
} }
} }
}; };
</script> </script>
<style scoped lang="scss"> <style scoped lang="less">
.to-top { .to-top {
position: fixed; position: fixed;
right: 20rpx; right: 10px;
justify-content: center; justify-content: center;
width: 80rpx; width: 40px;
height: 80rpx; height: 40px;
background: #fff; background: @white;
border-radius: 50rpx; border-radius: @border-radius-max;
border: 1rpx solid #ebebeb; border: 1px solid @gray-2;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
bottom: 218rpx; bottom: 69px;
font-size: 20rpx; .text-size(10);
color: #666666; color: @gray-5;
align-items: center; align-items: center;
z-index: 100;
.icon-top { .icon-top {
font-size: 36rpx; .text-size(18);
} }
} }
</style> </style>
<template>
<view class="treaty-block">
<cr-dialog v-model="showDialogSlot" confirm-button-text="我已阅读并同意">
<view slot="title" class="title">请阅读以下协议</view>
<view class="treaty-content">
<view class="treaty-register" @click="handleOpenTreaty('showRegister')">
《羊小咩注册协议》
</view>
<view class="treaty-rivacy" @click="handleOpenTreaty('showRivacy')">
《羊小咩用户隐私协议》
</view>
</view>
</cr-dialog>
<cr-dialog v-model="showRegister" confirm-button-text="已阅读">
<view slot="title">羊小咩注册协议</view>
<view class="content">
<treaty-register />
</view>
</cr-dialog>
<cr-dialog v-model="showRivacy" confirm-button-text="已阅读">
<view slot="title">羊小咩用户隐私协议</view>
<view class="content">
<treaty-rivacy />
</view>
</cr-dialog>
</view>
</template>
<script>
import treatyRegister from './treatyRegister';
import treatyRivacy from './treatyRivacy';
export default {
components: {
treatyRegister,
treatyRivacy
},
data() {
return {
showDialogSlot: true,
showRegister: false,
showRivacy: false
};
},
watch: {},
created() {},
methods: {
handleOpenTreaty(name) {
this[name] = true;
}
}
};
</script>
<style scoped lang="less">
.treaty-content {
color: @font-color-search;
overflow-y: scroll;
.treaty-register {
margin-top: 10px;
}
.treaty-rivacy {
margin-top: 10px;
}
}
::v-deep {
.cr-dialog--header {
padding: 10px 0 0;
}
.cr-dialog--message {
padding: 10px;
box-sizing: border-box;
margin-bottom: 10px;
}
.cr-hairline--top {
margin-bottom: 10px;
&:after {
content: '';
border: 0;
}
}
.cr-button {
border-radius: 30px;
width: 50%;
background: @red;
margin: 0 auto;
color: #fff;
display: block;
height: 40px;
line-height: 40px;
}
}
</style>
<template>
<view id="autoAgreement">
<p style="text-align: center;">
<b><span>羊小咩用户注册协议</span></b>
</p>
<p>
<span>为使用羊小咩软件产品(包括客户端</span><span>APP</span
><span>、小程序,运营方为北京量化派科技有限公司,以下简称</span><span></span
><span>本产品</span><span></span><span>)及相关服务,</span><span /><span>您(又称</span
><span></span><span>用户</span><span></span
><span>)应当阅读并遵守《羊小咩用户注册协议》(以下简称</span><span></span><span>本协议</span
><span></span><span>)。本协议是量子数科科技有限公司(以下简称</span><span></span
><span>羊小咩</span><span></span><span></span><span /><span
>与用户签署的协议,羊小咩同意按照本协议的规定及其不时发布的管理规则向您提供服务。请您务必审慎阅读并充分理解各条款的内容,特别是免除或者限制责任的条款以及开通或使用某项服务的单独协议,并选择接受或不接受。</span
>
</p>
<p>
<span
>除非您已经阅读并同意受本协议的约束,否则请您不要使用羊小咩的相关服务。您一旦注册、登录、使用羊小咩的相关服务或点击</span
><span></span><span>同意</span><span></span
><span
>本协议将视为对本协议所有条款的接受,并愿意受其约束。如您对本协议有任何疑问的,请您向客服咨询。</span
>
</p>
<p>
<span>请您理解,本产品目前仅对年满</span><span>18</span
><span
>周岁的成年人提供服务,如您是未成年人,请您不要使用本服务。如果您为未成年人的法定监护人,请您保证您的被监护人不要使用本服务。</span
>
</p>
<p>
<span
>请您理解,本产品目前仅对中华人民共和国境内(为本协议之目的,不包括香港、澳门特别行政区及台湾地区)用户提供服务,若您非中华人民共和国境内用户,请您不要使用本产品。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>1</span><span>、本协议的文本</span></p>
<p>
<span>1.1&nbsp;</span
><span
>本协议的内容包括以下全部条款。羊小咩已经发布的及将来可能发布的与用户有关的各项规则若与本协议不一致的以本协议为准。</span
>
</p>
<p>
<span>1.2&nbsp;</span
><span
>羊小咩可根据法律法规规定及本协议约定对本协议及相关规则进行调整。届时,羊小咩将通过(包括但不限于站内信、手机</span
><span>APP</span><span>、小程序等)方式进行公布。</span><span /><span
>您应根据本协议所载的公告方式及时查询相关信息,如您不同意该等调整,请您不要继续使用羊小咩提供的服务。如您继续使用羊小咩提供的服务,视为您同意羊小咩的上述调整。上述调整后的协议内容及相关规则为本协议不可分割的一部分,与本协议享有同等法律效力。</span
>
</p>
<p>
<span>1.3&nbsp;</span
><span
>您理解并同意,在您实名注册成为本产品的用户时,您已经阅读、理解并接受本协议的全部条款及各类规则,若您违反本协议而导致任何法律后果的发生,您将以自己的名义独立承担所有相应的法律责任,羊小咩不对此承担任何责任。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>2</span><span>、账号的注册和使用</span></p>
<p>
<span>2.1&nbsp;</span
><span
>您如果需要使用和享受本产品提供的相关服务,则您需要通过申请、注册、使用您享有使用权的羊小咩账号以成为本产品的用户,依据法律规定和本协议约定对</span
><span>&nbsp;</span
><span>您所提供的信息承担相应的法律责任。羊小咩平台用户,您必须是中国大陆公民,年龄在</span
><span>18</span
><span>周岁以上,且具有完全的民事权利能力及民事行为能力。如不具备上述资格,</span
><span /><span
>您应立即停止在羊小咩的注册程序、停止使用羊小咩服务,且羊小咩有权随时终止您的注册进程及终止向您提供羊小咩服务,您应对您的注册或使用给羊小咩平台带来的损失承担全额赔偿责任,且您的监护人(如您为限制民事行为能力的自然人)应承担连带责任。</span
>
</p>
<p>
<span>2.2&nbsp;</span
><span
>在注册时和使用羊小咩服务的期间,您应提供您自身的真实、完整、有效的身份资料和信息及其他相关信息(包括但不限于电子邮件地址、联系电话、联系地址、</span
><span>&nbsp;</span
><span
>邮政编码、个人身份信息、征信信息等),且不得以他人的身份资料进行实名注册。并保证自您注册之时起至您使用羊小咩服务的期间,您所提交的所有资料和信息</span
><span>&nbsp;</span
><span
>(包括但不限于电子邮件地址、联系电话、联系地址、邮政编码、邮寄地址、个人身份信息等)真实、准确、完整,且是最新的,若您提供的身份信息发生变化,</span
><span>&nbsp;</span
><span
>请您及时更新。若您违反上述保证,羊小咩有权终止为您提供所有服务,并有权对您的账号采取包括但不限于警告、限制或禁止使用账号全部或部分功能、删除账号及相关信息、封号直至注销的处理措施,由于您未提供真实的身份信息或未及时更新信息导致的任何损失,由您自行承担责任,羊小咩不对此承担任何责任。</span
>
</p>
<p>
<span>2.3&nbsp;</span
><span
>您充分理解并同意,为判断或核实您提供的相关实名注册信息是否真实或有效,羊小咩有权将您提供的实名注册信息提供给第三方进行比对、核验等处理。</span
>
</p>
<p>
<span>2.4&nbsp;</span
><span
>羊小咩有权审查您注册所提供的身份信息是否真实、有效,并应积极地采取技术与管理等合理措施保障您的账号安全、有效;您有义务妥善保管您的账号及密码,</span
><span>&nbsp;</span
><span
>并正确、安全地使用您的账号及密码,并定期更换密码。为了您的个人信息,账户及资金安全,羊小咩建议您每半年(</span
><span>180</span><span>天)时间之内,修改</span><span>1</span><span>次登录和交易密码,</span
><span /><span
>同时羊小咩会通过各种安全技术手段保证您的账户安全。通过您的用户名和密码编辑、发布的任何信息或作出的任何行为都将被视为您本人的行为。</span
><span>&nbsp;</span
><span
>由于您未尽上述义务导致账号密码遗失、账号被盗等情形而给您和他人的民事权利造成损害的,您应当承担由此产生的法律责任,羊小咩不对此承担任何责任。</span
>
</p>
<p>
<span>2.5&nbsp;</span><span>您对您登陆后所持有账号产生的行为依法享有权利和承担责任。</span>
</p>
<p>
<span>2.6&nbsp;</span
><span
>若您发现您的账号或密码被他人非法使用或有使用异常情况的,应及时通过本产品公布的客户服务方式通知羊小咩,并有权通知羊小咩采取措施暂停该账号的登录和使用,</span
><span>&nbsp;</span
><span
>若您没有提供您个人有效身份证件或者您提供的个人有效身份证件与所注册的身份信息不一致的,羊小咩有权拒绝您的上述请求。</span
>
</p>
<p>
<span>2.7&nbsp;</span
><span
>若羊小咩认为您的账号存在异常,羊小咩有权要求您提供充分证据证明自己系该账号所有人且与注册的身份信息一致。必要时,羊小咩将向您索取有关证件的原件、复印件、</span
><span>&nbsp;</span
><span
>影印件等,以核实您提供信息的真实性。一旦发现您提供的个人信息存在虚假、无效、不完整和</span
><span>/</span><span>或不准确等情形,羊小咩有权采取删除相关信息、要求您重新提供和</span
><span>/</span><span>或暂停提供相关服务等措施。</span>
</p>
<p>
<span>2.8&nbsp;</span
><span
>您应当妥善保管您的账号和密码,防止账号被第三人盗用,并且不得将账号出售、出租、转让、赠与、出借给第三人,否则,您应当对上述行为引起的一切后果承担全部责任。</span
>
</p>
<p>
<span>2.9&nbsp;</span
><span
>您充分理解并同意,若羊小咩依照法律法规或相关业务规则限制、冻结或终止您的账号,可能会导致您账号下的相关信息被删除,以及相关权益的丧失,该损失由您自行承担,羊小咩对此不承担任何责任。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>3</span><span>、羊小咩的服务内容</span></p>
<p>
<span>3.1&nbsp;</span
><span
>羊小咩为您提供商品展示、商品交易等服务,具体服务以羊小咩与您签订的具体协议和平台展示的服务内容信息为准。</span
>
</p>
<p>
<span>3.2&nbsp;</span
><span
>羊小咩可根据国家法律法规规章政策变化及维护交易秩序等原因,不定时的变更服务内容,变更后的服务内容将通过网站公告等方式告知您。一经羊小咩公布,则立即生效,羊小咩另有约定的除外。发生变更后的服务内容仍受到被协议的约束。</span
>
</p>
<p>
<span>3.3&nbsp;</span><span>羊小咩的商品由羊小咩或第三方商家提供,当您在羊小咩购买商品及</span
><span>/</span
><span
>或服务时,请您务必仔细确认所购买商品的品名、价格、数量、型号、规格、尺寸或服务的时间、内容、限制性要求等重要事项,并在下单时核实您的联系地址、电话、收货人等信息。如您填写的收货人非您本人,则您理解并同意,该收货人的行为和意思表示产生的法律后果均由您承担。</span
>
</p>
<p>
<span>您的购买行为应当基于真实的消费需求,不得存在对商品及</span><span>/</span
><span
>或服务实施恶意购买、恶意维权等扰乱正常交易秩序的行为。若羊小咩发现您存在上述行为,有权主动关闭交易订单和</span
><span>/</span><span>或向有关机关报告。</span>
</p>
<p>
<span
>您了解第三方提供的商品或服务中的信息由第三方服务提供商自行发布,且可能存在风险和瑕疵,请您审慎阅读并判断风险。羊小咩将尽可能保障您在羊小咩平台上的合法权益及良好体验。同时,羊小咩无法逐一审查商品及</span
><span>/</span><span>或服务的信息,无法逐一审查交易所涉及的商品及</span><span>/</span
><span>或服务的质量、安全以及合法性、真实性、准确性,对此您应谨慎判断。</span>
</p>
<p>
<span>3.4&nbsp;</span
><span>羊小咩就向您提供的服务是否收取服务费及服务费的具体标准和规则以羊小咩网站及</span
><span>APP</span><span>公示的相关规则为准。</span>
</p>
<p>
<span>3.5&nbsp;</span><span>羊小咩集成的由第三方提供的产品及服务、链接至第三方和</span
><span>/</span
><span
>或展示第三方的标记或内容,羊小咩提供该等集成、链接、展示的目的仅在于向您提供购买方便,羊小咩对第三方产品及服务的质量不作任何保证,亦不代表羊小咩对该等第三方、其产品及服务的任何推荐、支持或授权,您应当自行甄别并自担风险。您在使用上述第三方的任何产品和服务时,应当了解并接受该等第三方的条款和规则。一旦您选择接受该第三方提供的服务,则您还应当遵守您与该第三方对其服务作出的约定。羊小咩不保证通过第三方提供的服务内容或实现的结果的安全性、准确性、有效性及其他不确定风险,若您在使用第三方提供的服务过程中引发的任何争议、纠纷及损害,请您自行处理,羊小咩不对此承担任何责任,但是羊小咩会根据需要依法提供必要的协助。</span
>
</p>
<p>
<span>3.6</span
><span
>您可以通过参加羊小咩举行的各种活动获得奖励,奖励是指通过参与、点击羊小咩及其合作组织举办的各种活动及其设置的相应链接、页面才能获得的一种权利,奖励形式包括各类奖品和服务、积分、返现等。</span
>
</p>
<p><span>4</span><span>、用户使用规范</span></p>
<p><span>4.1&nbsp;</span><span>有关单位报告等必要处理措施或依有关单位合法指示行事。</span></p>
<p>
<span>4.2&nbsp;</span
><span
>在使用羊小咩平台提供的任何服务(包括但不限于站内信服务、群组服务、论坛服务或其他电子邮件转发服务)的过程中,您应当严格遵守以下义务:</span
>
</p>
<p>
<span></span><span>1</span
><span
>)必须遵循国家的相关法律法规,不得发布含有中国法律、法规、规章、条例以及任何具有法律效力之规范所限制或禁止的内容;</span
>
</p>
<p>
<span></span><span>2</span
><span>)不得传输损害国家社会公共利益和涉及国家安全的信息资料;</span>
</p>
<p>
<span></span><span>3</span
><span>)不得发布政治宣传、封建迷信、淫秽、色情、赌博、暴力、恐怖或者教唆犯罪的内容</span>
</p>
<p>
<span></span><span>4</span><span>)不得发布欺诈、虚假、不准确或存在误导性的信息;</span>
</p>
<p>
<span></span><span>5</span
><span>)不得利用平台从事窃取商业秘密、窃取个人信息等违法犯罪活动;</span>
</p>
<p>
<span></span><span>6</span><span>)不得利用在羊小咩注册的商户进行牟利性经营活动;</span>
</p>
<p>
<span></span><span>7</span
><span>)不得发布任何侵犯他人著作权、商标权等知识产权或合法权利的内容;</span>
</p>
<p>
<span></span><span>8</span
><span
>)您不得发送、公布或展示任何垃圾邮件、信息或其他可能违反中国法律法规及本协议或可能侵犯他人合法权益的内容。</span
>
</p>
<p>
<span
>羊小咩在发现您从事上述活动或发布该等内容时,有权不经您同意而删除该等内容,并有权不经通知而立即暂停或停止您对羊小咩的全部或部分功能的使用,追究法律责任等措施。</span
>
</p>
<p>
<span>4.3&nbsp;</span
><span
>您在注册时向羊小咩提交的用户名、密码及身份证号码是您在羊小咩的唯一识别信息。您注册成功后,不得将注册的用户名、密码及身份证号码转让或授权给第三方使用。您确认,使用您的用户名和密码登陆羊小咩后在羊小咩的一切行为均代表您本人并由您承担相应的法律后果。</span
>
</p>
<p>
<span>4.4&nbsp;</span
><span
>您知悉在您签署本协议后即授权平台及平台合作方以您或其关联人的名义向平台合作的电子签名认证机构申请用户数字证书,该数字证书由平台合作的电子签名认证机构保存。当您发起签章指令、您授权平台或平台合作的第三方代为发起签章指令后,平台合作的电子签名认证机构即在相关协议或文件上使用您或其关联人数字证书签章。您自行取得关联人的相关授权,如有纠纷由您与关联人自行解决,与平台无涉。</span
>
</p>
<p>
<span>4.5&nbsp;</span
><span
>您保证并承诺,严格遵守中国法律及其他监管机构的规范性文件,不在羊小咩从事危害国家安全、洗钱、套现、传销等任何违法活动或者其他有违社会公共利益或公共道德的行为。</span
>
</p>
<p>
<span>4.6</span
><span
>羊小咩严禁您通过以下行为获得利益,一经发现,羊小咩有权追回您账号及其关联账号(关联账户由羊小咩根据自身系统数据判定,判定依据包括但不限于您登记信息、交易信息、第三方反馈信息、设备终端信息、</span
><span>IP</span
><span
>地址等,下同)中已经给予的相关奖励,并视情节严重可中止您账号直至注销您账号,同时您必须承担由此给羊小咩带来的所有损失:</span
>
</p>
<p><span></span><span>1</span><span>)购买产品后恶意取消订单;</span></p>
<p><span></span><span>2</span><span>)劫持流量;</span></p>
<p><span></span><span>3</span><span>)自买自卖;</span></p>
<p><span></span><span>4</span><span>)劫持其他用户的正常访问链接使其变成推广链接;</span></p>
<p><span></span><span>5</span><span>)骗取其他用户点击其设置的非羊小咩设置的链接;</span></p>
<p><span></span><span>6</span><span>)违反购物所在网站用户协议及其规则;</span></p>
<p>
<span></span><span>7</span><span>)其他违反法律法规或者违反诚实信用、公平原则的行为。</span>
</p>
<p>
<span>4.7</span
><span
>羊小咩严禁各种针对奖励活动的作弊行为。对于查实的作弊行为,我们有权收回该账号及其关联账号全部的奖励,并列入羊小咩黑名单账户。作弊行为包括但不限于:使用相同的电脑或设备,相同的</span
><span>IP</span
><span
>地址在同一天内注册多个账号,以骗取奖励的行为;以注册送钱或注册送积分等利益诱导用户来注册羊小咩获取奖励的行为;获取返利后恶意取消交易或退款退货的行为等。</span
>
</p>
<p>
<span>4.8</span><span>您充分理解并同意,不在羊小咩的合作商城内进行任何形式的广告推广。</span>
</p>
<p><span>&nbsp;</span></p>
<p><span>5</span><span>、用户信息的保护</span></p>
<p>
<span>5.1&nbsp;</span
><span
>羊小咩重视保护用户的个人信息。羊小咩将按照本协议及《羊小咩隐私政策》的规定收集、使用、储存和分享您的个人信息。本协议对个人信息保护相关内容未做明确说明的,均以《羊小咩隐私政策》的内容为准。</span
>
</p>
<p>
<span>5.2&nbsp;</span
><span
>您在注册账号或使用本产品的过程中,为了向您提供服务,可能需要您填写或提供一些必要的信息,羊小咩也有可能通过其他合法方式同步用户的个人信息。</span
>
</p>
<p>
<span>5.3&nbsp;</span
><span
>您可以根据相关产品规则浏览、修改自己提交的信息,但出于安全性和身份识别(如号码申诉服务等)的考虑,您可能无法修改注册时提供的初始注册信息及其他验证信息。</span
>
</p>
<p>
<span>5.4&nbsp;</span
><span>羊小咩将尽可能采取各种安全措施保护用户的个人信息,并建立完善的管理制度。</span>
</p>
<p><span>5.5&nbsp;</span><span>羊小咩不会将您的个人信息转移或披露给任何第三方,除非:</span></p>
<p>
<span></span><span>1</span
><span>)根据法律法规、司法机关或政府主管部门、行业协会的要求;</span>
</p>
<p>
<span></span><span>2</span
><span
>)根据政府主管部门要求向中国人民银行金融信用信息基础数据库和中国人民银行批准设立的从事个人征信业务的机构(包括但不限于百行征信有限公司)报送您的基本信息和信用信息;</span
>
</p>
<p>
<span></span><span>3</span
><span>)依据《羊小咩隐私政策》或其他相关协议规则可以转移或披露给任何第三方的情形。</span>
</p>
<p><span>&nbsp;</span></p>
<p><span>6</span><span>、广告</span></p>
<p>
<span>6.1&nbsp;</span
><span
>您同意羊小咩可以自行或由第三方通过电话、短信、电子邮件或电子信息等多种方式向您发送、展示广告或其他信息(包括商业与非商业信息),广告或其他信息的具体发送及展示形式、频次及内容等以羊小咩实际提供为准。您如果不愿意接收此类的信息,您有权通过羊小咩提供的退订功能进行退订。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>7</span><span>、未成年人</span></p>
<p>
<span
>羊小咩非常重视对未成年人个人信息的保护。若您不具备完全民事行为能力,请您不要使用本产品,若您为限制民事行为能力人的法定监护人,请您确保您的被监护人不会使用本服务。</span
>
</p>
<p><span>羊小咩不对年龄</span><span>18</span><span>周岁以下个人及在校学生提供服务。</span></p>
<p><span>8</span><span>、知识产权声明</span></p>
<p>
<span>8.1&nbsp;</span
><span
>羊小咩的所有内容,包括但不限于文本、数据、图片、音频、视频、源代码和其他所有信息,均由羊小咩享有知识产权。未经羊小咩事先书面同意,您或其他任何人不得复制、改编、传播、公布、展示或以任何其他方式侵犯羊小咩的知识产权。</span
>
</p>
<p>
<span>8.2&nbsp;</span
><span
>羊小咩提供本产品时所依托的软件著作权、专利权、商标权及其他知识产权均归羊小咩所有。</span
>
</p>
<p><span>8.3&nbsp;</span><span>您不得从事下列行为:</span></p>
<p><span>8.3.1&nbsp;</span><span>删除本产品软件及其副本上关于著作权的信息。</span></p>
<p>
<span>8.3.2&nbsp;</span
><span>对软件进行反向工程、反向汇编、反向编译,或者以其他方式尝试发现软件的源代码。</span>
</p>
<p>
<span>8.3.3&nbsp;</span
><span
>对羊小咩拥有知识产权的内容进行使用、出租、出借、复制、修改、链接、转载、汇编、发表、出版、建立镜像站点等。</span
>
</p>
<p>
<span>8.3.4&nbsp;</span
><span
>对软件或者软件运行过程中释放到任何终端内存中的数据、软件运行过程中客户端与服务器端的交互数据,以及软件运行所必需的系统数据,进行复制、修改、增加、删除、挂接运行或创作任何衍生作品,形式包括但不限于使用插件、外挂或非经羊小咩授权的第三方工具</span
><span>/</span><span>服务接入软件和相关系统。</span>
</p>
<p>
<span>8.3.5&nbsp;</span
><span
>通过修改或伪造软件运行中的指令、数据等任何方式,增加、删减、变动软件的功能或运行效果,或者将用于上述用途的软件、方法进行运营或向公众传播,无论这些行为是否为商业目的。</span
>
</p>
<p>
<span>8.3.6&nbsp;</span
><span
>通过非羊小咩开发、授权的第三方软件、插件、外挂、系统、设备等任何方式,登录或使用羊小咩软件及服务,或制作、发布、传播非羊小咩开发、授权的用于登录或使用羊小咩软件及服务的第三方软件、插件、外挂、系统、设备等。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>9</span><span>、投诉处理</span></p>
<p>
<span>9.1&nbsp;</span
><span
>您通过本产品发送或传播的内容(包括但不限于网页、文字、图片、音频、视频、图表等)均由您自行承担责任。</span
><span>&nbsp;</span>
</p>
<p>
<span>9.2&nbsp;</span
><span>您发送或传播的内容应有合法来源,相关内容为您所有或您已获得必要的授权。</span>
</p>
<p>
<span>9.3&nbsp;</span
><span
>如果您发送或传播的内容违法违规或侵犯他人权利的,羊小咩有权进行独立判断并采取删除、屏蔽或断开链接等措施。</span
>
</p>
<p>
<span>9.4&nbsp;</span
><span
>如您被他人投诉或您投诉他人,羊小咩有权将争议中相关方的主体信息、联系方式、投诉相关内容等必要信息提供给相关当事方或相关部门,以便及时解决投诉纠纷,保护各方合法权益。</span
>
</p>
<p>
<span>9.5&nbsp;</span
><span>您保证对您在投诉处理程序中提供的信息、材料、证据等的真实性、合法性、有效性负责。</span>
</p>
<p><span>&nbsp;</span></p>
<p><span>10</span><span>、免责条款</span></p>
<p>
<span>10.1&nbsp;</span
><span
>您理解并同意,为了向您提供更完善的服务,羊小咩有权定期或不定期地对提供本产品或相关设备进行检修、维护、升级等,此类情况可能会造成相关服务在合理时间内中断或暂停的,若由此给您造成损失的,您同意放弃追究羊小咩的责任。</span
>
</p>
<p>
<span>10.2&nbsp;</span
><span
>您理解并同意,羊小咩会尽最大努力向您提供服务,确保服务的连贯性和安全性;但羊小咩不能保证其所提供的服务毫无瑕疵,也无法随时预见和防范法律、技术以及其他风险,包括但不限于不可抗力、病毒、木马、黑客攻击、系统不稳定、第三方服务瑕疵、政府行为等原因可能导致的服务中断、数据丢失以及其他的损失和风险。您同意,即使羊小咩提供的服务存在瑕疵,但上述瑕疵是当时行业技术水平所无法避免的,其将不被视为羊小咩违约,由此给您造成的数据或信息丢失等损失的,您同意放弃追究羊小咩的责任。</span
><span>&nbsp;</span>
</p>
<p>
<span>10.3&nbsp;</span
><span>羊小咩的部分服务可能涉及或链接到由第三方所有、控制或者运营的其他网站(</span
><span></span><span>第三方网站</span><span></span
><span
>)。羊小咩不能保证也没有义务保证第三方网站上的信息的真实性和有效性。您确认按照第三方网站的注册协议而非本注册协议使用第三方网站,第三方网站的内容、产品、广告和其他任何信息均由您自行判断并承担风险。</span
>
</p>
<p>
<span>10.4&nbsp;</span
><span
>如果由于羊小咩及相关第三方的设备、系统故障或缺陷、病毒、黑客攻击、网络故障、网络中断、地震、台风、水灾、海啸、雷电、火灾、瘟疫、流行病、战争、恐怖主义、敌对行为、暴动、罢工、交通中断、停止供应主要服务、电力中断、经济形势严重恶化、监管政策变更或其它类似事件,致使羊小咩未能履行本协议或履行本协议不符合规定,不构成羊小咩违约。</span
>
</p>
<p>
<span>10.5&nbsp;</span
><span
>在适用法律允许的最大范围内,羊小咩不就因用户使用本软件及相关服务引起的,或在任何方面与本软件及相关服务有关的任何意外的、非直接的、特殊的、或间接的损害或请求(包括但不限于因人身伤害、因未能履行包括诚信或合理谨慎在内的任何责任、因过失及因任何其他金钱上的损失或其他损失而造成的损害赔偿)承担任何责任。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>11</span><span>、通知</span></p>
<p>
<span
>本协议项下的通知如以羊小咩公示方式作出,一经在羊小咩平台公示即视为已经送达。采用站内信、邮件、手机短信息、绑定的微信号码等方式通知的,自信息发出即视为送达。您同意羊小咩出于向您提供服务之目的,可以向您的电子邮箱、绑定的微信号码、站内消息系统栏和手机发送有关通知或提醒。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>12</span><span>、违约责任</span></p>
<p>
<span
>如果您违反了您在协议中所作的陈述、保证、承诺或任何其他义务,致使羊小咩或羊小咩的股东、实际控制人、员工承受任何损失,您应向受损失的一方做出全额赔偿。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>13</span><span>、适用法律和管辖</span></p>
<p>
<span
>本协议的签订、效力、履行、终止及其解释适用中华人民共和国法律(为本条款的目的,不包括香港特别行政区、澳门特别行政区及台湾地区的法律)。</span
>
</p>
<p>
<span
>凡因本协议引起的或与本协议有关的任何争议(包括但不限于有关本协议的履行、解除、存在、有效性、终止或撤销或无效之后果的争议),均应提交北京仲裁委员会,根据申请仲裁时北京仲裁委员会现行有效的的仲裁规则进行仲裁。仲裁裁决是终局的,对各方具有约束力,各方特此不可撤销地放弃向可能对争议事项有管辖权的任何法院提起诉讼的权利。仲裁费用和胜诉方因办理案件所支出的合理费用由败诉方承担。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>14</span><span>、终止</span></p>
<p>
<span
>除非羊小咩终止本协议或者您申请终止本协议且经羊小咩同意,否则本协议始终有效。在您违反了本协议、相关规则,或在相关法律法规、政府部门的要求下,羊小咩有权通过邮件、手机短信息等方式告知终止本协议、关闭您的账户或者限制您使用羊小咩。如您为未成年人,羊小咩有权立即关闭您的账户。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>15</span><span>、注销账户</span></p>
<p>
<span
>如果您需要注销个人账户,在您账户无异常的情况下,需要拨打羊小咩客户服务电话通过人工方式完成账户注销。</span
>
</p>
<p><span>&nbsp;</span></p>
<p><span>16</span><span>、更新</span></p>
<p><span>16.1&nbsp;</span><span>您使用本产品即视为您已阅读本协议并接受本协议的约束。</span></p>
<p>
<span>16.2&nbsp;</span
><span>羊小咩有权在必要时修改本协议条款。您可以在相关服务页面查阅最新版本的协议条款。</span>
</p>
<p>
<span>16.3&nbsp;</span
><span
>本协议条款变更后,如果您继续使用羊小咩提供的软件或服务,即视为您已接受变更后的协议。若您不同意变更后的协议内容,您应立即停止使用羊小咩、注销您在羊小咩的注册账号,您将不再是羊小咩的用户,且无权继续访问羊小咩平台,如您通过本平台与合作方所达成的交易以及签署的协议未履行完毕的,相应后果将由您自行承担。</span
>
</p>
</view>
</template>
<style scoped lang="less">
span {
font-size: 10px;
color: rgb(44, 62, 80);
}
p {
text-align: left;
}
</style>
<template>
<view>
<p style="text-align: center">&nbsp;<b>羊小咩隐私政策</b></p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>羊小咩(包括客户端APP和小程序,运营方为北京量化派科技有限公司、量子数科科技有限公司,下简称“我们”)非常重视用户的隐私和个人信息保护。您在使用我们的产品与/或服务时,我们可能会收集和使用您的相关信息。我们希望通过《羊小咩隐私政策》(“本隐私政策”)向您说明我们在您使用我们的产品与/或服务时如何收集、使用、保存、共享和转让这些信息,以及我们为您提供的访问、更新和保护这些信息的方式。</span
>
</p>
<p style="text-align: center">
<span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>本政策将帮助您了解以下内容:</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>一、我们如何收集和使用您的个人信息</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>二、我们如何使用&nbsp;Cookie&nbsp;和同类技术</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>三、我们如何共享、转让、公开披露您的个人信息</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>四、我们如何保护和保存您的个人信息</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">五、您如何管理自己的个人信息</span>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">六、未成年人隐私权特别约定&nbsp;</span>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">七、本政策的适用及修订</span></p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>本隐私政策与您所使用的羊小咩服务(包括羊小咩网站、APP及小程序)以及该服务所包括的各种业务功能(以下统称“我们的产品与/或服务”)息息相关,希望您在使用我们的产品与/或服务前仔细阅读并确认您已经充分理解本政策所写明的内容,并让您可以按照本隐私政策的指引做出您认为适当的选择。本隐私政策中涉及的相关术语,我们尽量以简明扼要的表述,并提供进一步说明的链接,以便您更好地理解。您使用或在我们更新本隐私政策后(我们会及时提示您更新的情况)继续使用我们的产品与/或服务,即意味着您同意本隐私政策(含更新版本)内容,并且同意我们按照本隐私政策收集、使用、保存和共享您的相关信息。</span
></b
>
</p>
<p style="text-align: center">
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>如对本隐私政策或相关事宜有任何问题,您可随时通过访问在线客服系统或拨打我们的官方客服电话等多种方式与我们联系。</span
>
</p>
<p style="text-align: center">
<span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>一、我们如何收集和使用您的个人信息&nbsp;</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>个人信息是指以电子或者其他方式记录的能够单独或者与其他信息结合识别特定自然人身份或者反映特定自然人活动情况的各种信息。<b>本隐私政策</b>中涉及的个人信息包括:基本信息(包括个人姓名、生日、性别、住址、个人电话号码、电子邮箱);个人身份信息(包括身份证、军官证、护照、驾驶证等);面部特征;网络身份标识信息(包括系统账号、IP地址、邮箱地址及与前述有关的密码、口令、口令保护答案);个人财产信息(交易和消费记录、以及余额、优惠券、兑换码等虚拟财产信息);已安装的应用程序;个人上网记录(包括网站浏览记录、软件使用记录、点击记录);个人常用设备信息(包括硬件型号、设备MAC地址、操作系统类型、软件列表唯一设备识别码(如IMEI/androidID/IDFA/OPENUDID/GUID、SIM卡IMSI信息等在内的描述个人常用设备基本情况的信息);个人位置信息(包括行程信息、精准定位信息、住宿信息、经纬度等);</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">个人敏感信息</span></b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>是指一旦泄露、非法提供或滥用可能危害人身和财产安全,极易导致个人名誉、身心健康受到损害或歧视性待遇等的个人信息,<b>本隐私政策中涉及的个人敏感信息包括:</b>您的财产信息(包括交易记录及余额、优惠券等虚拟财产信息);面部识别特征;个人身份信息(包括身份证、军官证、护照、驾驶证、户口本);网络身份识别信息(包括账户名、账户昵称、邮箱地址及与前述有关的密码与密码保护问题和答案);其他信息(包括已安装的应用程序个人电话号码、手机号码、行程信息、网页浏览记录、住宿信息、精准定位信息)。</span
>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">您理解并同意:</span></p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们致力于打造多样的产品和服务以满足您的需求。因我们向您提供的产品和服务种类众多,且不同用户选择使用的具体产品/服务范围存在差异,相应的,基本/附加功能及收集使用的个人信息类型、范围等会有所区别,请以具体的产品/服务功能为准;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">2</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、为给您带来更好的产品和服务体验,我们在持续努力改进我们的技术,随之我们可能会不时推出新的或优化后的功能,可能需要收集、使用新的个人信息或变更个人信息使用目的或方式。对此,我们将通过更新本政策、弹窗、页面提示等方式另行向您说明对应信息的收集目的、范围及使用方式,并为您提供自主选择同意的方式,且在征得您明示同意后收集、使用。在此过程中,如果您有任何疑问、意见或建议的,您可通过羊小咩提供的各种联系方式与我们联系,我们会尽快为您作出解答。</span
>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们仅会出于以下目的,收集和使用您的个人信息:</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
><b>一)您须授权我们收集和使用您个人信息的情形</b></span
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们的产品与/或服务包括一些核心功能,这些功能包含了实现网络购物所必须的功能、改进我们的产品与/或服务所必须的功能及保障交易安全所必须的功能。我们可能会收集、保存和使用下列与您有关的信息才能实现上述这些功能。这些功能包括:</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)">、实现网络购物所必须的功能</span>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">(1)用户注册</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>您首先需要注册一个羊小咩账户成为羊小咩用户。<b
>当您注册时,您需要至少向我们提供您准备使用的羊小咩账户名、密码、您本人的手机号码、电子邮箱地址(用于验证邮箱),我们将通过发送短信验证码或邮件的方式来验证您的身份是否有效。</b
></span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>如果您已拥有羊小咩账户,我们可能会在羊小咩服务中显示您的上述个人信息,以及您在羊小咩上相关联的产品和服务中执行的操作(您可通过羊小咩账户在我们提供的手机羊小咩入口或其他产品/服务入口使用我们及/或关联公司提供的产品或服务),包括通过羊小咩账户集中展示您的个人资料、优惠权益、交易订单。我们会尊重您对羊小咩服务和羊小咩账户设置所做的选择。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"><b>2)信息展示和搜索</b></span>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>为了让您快速地找到您所需要的服务/产品,我们可能会收集您使用我们的产品与/或服务的设备信息(我们会通过百融云创科技股份有限公司的设备反欺诈SDK采集您的设备信息,可能采集的设备信息包括设备名称、设备型号、设备识别码、操作系统和应用程序版本、语言设置、分辨率、服务提供商网络ID(PLMN))、浏览器类型来为您提供信息展示的最优方式。我们也会为了不断改进和优化上述的功能来使用您的上述个人信息。</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>您也可以通过搜索来精准地找到您所需要的服务。我们会保留您的搜索内容以方便您重复输入或为您展示与您搜索内容相关联的商品。<b>请您注意,您的搜索关键词信息无法单独识别您的身份,不属于您的个人信息,我们有权以任何的目的对其进行使用;只有当您的搜索关键词信息与您的其他信息相互结合使用并可以识别您的身份时,则在结合使用期间,我们会将您的搜索关键词信息作为您的个人信息,与您的搜索历史记录一同按照本隐私政策对其进行处理与保护。</b>&nbsp;</span
>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">(3)网络购物</span></p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>当您在我们的产品及/或服务中订购具体商品及/或服务时,我们会通过系统为您生成购买该商品及/或服务的订单。需要注意的是,该订单会载明您所购买的商品及/或服务信息、订单编号、订单时间、订单金额,我们收集这些信息是为了帮助您展示订单内容,计算奖励金额及其他我们明确告知的目的。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>当您选择参加我们及我们的关联方或第三方举办的有关网络购物的营销奖励活动时,<b
>可能需要您提供姓名、微信号、支付宝号、联系方式等。这些信息是敏感个人信息,拒绝提供可能会影响您参加营销奖励活动,但不会影响其他功能。</b
></span
>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">(4)客服与售后功能</span></p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们的电话客服和售后功能会使用您的账号信息和订单信息。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>为保证您的账号安全,我们的呼叫中心客服和在线客服会使用您的账号信息与您核验您的身份。当您需要我们提供与您订单信息相关的客服与售后服务时,我们将会查询您的订单信息。您有可能会在与我们的客服人员沟通时,提供给出上述信息外的其他信息,如当您要求我们变更联系地址、联系人或联系电话。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">2</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、改进我们的产品与/或服务所必须的功能</span
></b
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们可能会收集您的订单信息、浏览信息、您的兴趣爱好(您可以在账户设置中选择)进行数据分析以形成用户画像,用来将您感兴趣的商品或服务信息展示给您;或在您搜索时向您展示您可能希望找到的商品。</span
></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们还可能为了提供服务及改进服务质量的合理需要而获得的您的其他信息,包括您与客服联系时您提供的相关信息,您参与问卷调查时向我们发送的问卷答复信息,以及您与我们的关联方、我们合作伙伴之间互动时我们获得的相关信息。对于从您的各种设备上收集到的信息,我们可能会将它们进行关联,以便我们能在这些设备上为您提供一致的服务。我们可能会将来自某项服务的信息与来自其他服务的信息结合起来,以便为您提供服务、个性化内容和建议。</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">3</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)">、保障交易安全所必须的功能</span></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>为提高您使用我们的产品与/或服务时系统的安全性,更准确地预防钓鱼网站欺诈和保护账户安全,我们可能会通过了解您的浏览信息、订单信息、您常用的软件信息、设备信息等手段来判断您的账号风险,并可能会记录一些我们认为有风险的链接(“URL”);我们也会收集您的设备信息对于羊小咩系统问题进行分析、统计流量并排查可能存在的风险、在您选择向我们发送异常信息时予以排查。</span
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>(二)您可选择是否授权我们收集和使用您的个人信息的情形</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、为使您使用羊小咩平台功能更便捷或更有乐趣,从而提升您在羊小咩的使用体验,我们的以下附加功能中可能会收集和使用您的个人信息。<b>如果您不提供这些个人信息,您依然可以使用羊小咩平台功能,但您可能无法使用这些可以为您所带来服务乐趣的附加功能或在使用某些功能时需要重复填写一些信息。</b>这些附加功能包括:</span
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>(1)基于位置信息的个性化推荐功能:我们会收集您的位置信息(我们仅收集您当时所处的地理位置,但不会将您各时段的位置信息进行结合以判断您的行踪轨迹)来判断您所处的地点,自动为您推荐您所在区域可以购买的商品或服务。</span
></b
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>(2)基于摄像头(相机)和图片上传的附加功能:</span
></b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>您可以使用这个附加功能完成视频拍摄、拍照、扫码以及人脸识别登录的功能。<b>当您使用人脸识别登录时我们会收集您的面部信息。</b>未来我们可能会将人脸识别技术应用于更多场景,但那时我们会再次与您确认您是否愿意我们使用您的面部信息来实现这些附加功能。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">2</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、上述附加功能可能需要您在您的设备中向我们开启您的地理位置(位置信息)、相机(摄像头)、相册(图片库)、麦克风的访问权限,以实现这些功能所涉及的信息的收集和使用。</span
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>(三)您充分知晓,以下情形中,我们收集、使用个人信息无需征得您的授权同意:</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">1</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、与国家安全、国防安全有关的;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">2</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、与公共安全、公共卫生、重大公共利益有关的;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">3</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、与犯罪侦查、起诉、审判和判决执行等有关的;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">4</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">5</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、所收集的个人信息是个人信息主体自行向社会公众公开的;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">6</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、从合法公开披露的信息中收集的您的个人信息的,如合法的新闻报道、政府信息公开等渠道;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">7</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、根据您的要求签订合同所必需的;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">8</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、用于维护所提供的产品与/或服务的安全稳定运行所必需的,例如发现、处置产品与/或服务的故障;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">9</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、为合法的新闻报道所必需的;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">10</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、学术研究机构基于公共利益开展统计或学术研究所必要,且对外提供学术研究或描述的结果时,对结果中所包含的个人信息进行去标识化处理的;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">11</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)">、法律法规规定的其他情形。</span></b
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>(四)我们从第三方获得您个人信息的情形</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们可能从第三方获取您授权共享的账户信息(头像、昵称),并在您同意本隐私政策后将您的第三方账户与您的羊小咩账户绑定,使您可以通过第三方账户直接登录并使用我们的产品与/或服务。我们会将依据与第三方的约定、对个人信息来源的合法性进行确认后,在符合相关法律和法规规定的前提下,使用您的这些个人信息。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">(五)您个人信息使用的规则</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们会根据本隐私政策的约定并为实现我们的产品与/或服务功能对所收集的个人信息进行使用。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">2</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、在收集您的个人信息后,我们将通过技术手段对数据进行去标识化处理,去标识化处理的信息将无法识别主体。<b
>请您了解并同意,在此情况下我们有权使用已经去标识化的信息;并在不透露您个人信息的前提下,我们有权对用户数据库进行分析并予以商业化的利用。</b
></span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">3</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、请您注意,您在使用我们的产品与/或服务时所提供的所有个人信息,除非您申请删除或通过系统设置拒绝我们收集,否则将在您使用我们的产品与/或服务期间持续授权我们使用。在您注销账号时,我们将停止使用并删除您的个人信息。</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">4</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们会对我们的产品与/或服务使用情况进行统计,并可能会与公众或第三方共享这些统计信息,以展示我们的产品与/或服务的整体使用趋势。但这些统计信息不包含您的任何身份识别信息。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">5</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、当我们展示您的个人信息时,我们会采用包括内容替换、匿名处理方式对您的信息进行脱敏,以保护您的信息安全。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">6</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、当我们要将您的个人信息用于本政策未载明的其它用途时,或基于特定目的收集而来的信息用于其他目的时,会通过您主动做出勾选的形式事先征求您的同意。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></b>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>二、我们如何使用&nbsp;Cookie&nbsp;和同类技术</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">(一)Cookies的使用</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、为实现您联机体验的个性化需求,使您获得更轻松的访问体验。我们会在您的计算机或移动设备上发送一个或多个名为Cookies的小数据文件,指定给您的Cookies&nbsp;是唯一的,它只能被将Cookies发布给您的域中的Web服务器读取。我们向您发送Cookies是为了简化您重复登录的步骤、存储您的服务偏好等数据进而为您提供服务的偏好设置、帮助您优化对广告的选择与互动、帮助判断您的登录状态以及账户或数据安全。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">2</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们不会将&nbsp;Cookies&nbsp;用于本隐私政策所述目的之外的任何用途。您可根据自己的偏好管理或删除Cookies。您可以清除计算机上保存的所有&nbsp;Cookies,大部分网络浏览器会自动接受Cookies,但您通常可根据自己的需要来修改浏览器的设置以拒绝&nbsp;Cookies;另外,您也可以清除软件内保存的所有Cookies。但如果您这么做,您可能需要在每一次访问羊小咩网站、APP及小程序时亲自更改用户设置,而且您之前所记录的相应信息也均会被删除,并且可能会对您所使用服务的安全性有一定影响。</span
>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>三、我们如何共享、转让、公开披露您的个人信息&nbsp;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">(一)共享</span></b>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">1</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们不会与羊小咩以外的任何公司、组织和个人共享您的个人信息,但以下情况除外:</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">(1)事先获得您明确的同意或授权;</span>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(2)根据适用的法律法规、法律程序的要求、强制性的行政或司法要求所必须的情况下进行提供;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(3)在法律法规允许的范围内,为维护羊小咩、羊小咩的关联方或合作伙伴、您或其他羊小咩用户或社会公众利益、财产或安全免遭损害而有必要提供;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(4)只有共享您的信息,才能实现我们的产品与/或服务的核心功能或提供您需要的服务;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(5)应您需求为您处理您与他人的纠纷或争议;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(6)符合与您签署的相关协议(包括在线签署的电子协议以及相应的平台规则)或其他的法律文件约定所提供;</span
>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">(7)基于学术研究而使用;</span></p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(8)基于符合法律法规的社会公共利益而使用。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">2</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们可能会将您的个人信息与我们的关联方共享。但我们只会共享必要的个人信息,且受本隐私政策中所声明目的的约束。我们的关联方如要改变个人信息的处理目的,将再次征求您的授权同意。</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">3</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们可能会向合作伙伴等第三方共享您的订单信息、账户信息、设备信息以及位置信息,以保障为您提供的服务顺利完成。但我们仅会出于合法、正当、必要、特定、明确的目的共享您的个人信息,并且只会共享提供服务所必要的个人信息。我们的合作伙伴无权将共享的个人信息用于任何其他用途。</span
></b
><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span
><span style="font-size: 11px; color: rgb(44, 62, 80)">我们的合作伙伴包括以下类型:</span>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(1)商品或技术服务的供应商。<b>我们可能会将您的个人信息共享给支持我们功能的第三方。</b>这些支持包括为我们的供货或提供基础设施技术服务、物流配送服务、支付服务、数据处理等。我们共享这些信息的目的是可以实现我们产品与/或服务的核心功能;或者我们需要将您的订单号和订单金额与第三方支付机构共享以实现其确认您的支付指令并完成支付等。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(2)第三方商家。<b
>我们必须将您的订单信息与交易有关的必要信息与第三方商家共享来实现您服务的需求,并促使其可以完成后续的售后服务。</b
></span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(3)委托我们进行推广的合作伙伴。有时我们会代表其他企业向使用我们产品与/或服务的用户群提供促销推广的服务。<b>我们可能会使用您的个人信息以及您的非个人信息集合形成的间接用户画像与委托我们进行推广的合作伙伴(“委托方”)共享,但我们仅会向这些委托方提供推广的覆盖面和有效性的信息,而不会提供您的个人身份信息,或者我们将这些信息进行汇总,以便它不会识别您个人。</b>比如我们可以告知该委托方有多少人看了他们的推广信息或在看到这些信息后购买了委托方的商品,或者向他们提供不能识别个人身份的统计信息,帮助他们了解其受众或顾客。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">4</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、对我们与之共享个人信息的公司、组织和个人,我们会与其签署严格的保密协定,要求他们按照我们的说明、本隐私政策以及其他任何相关的保密和安全措施来处理个人信息。在个人敏感数据使用上,我们要求第三方采用数据脱敏和加密技术,从而更好地保护用户数据。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">5</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、为了遵守法律、执行或适用我们的使用条件和其他协议,或者为了保护羊小咩、您或其他羊小咩客户的权利及其财产或安全,比如为防止欺诈等违法活动和减少信用风险,而与其他公司和组织交换信息。不过,这并不包括违反本隐私政策中所作的承诺而为获利目的出售、出租、共享或以其它方式披露的个人信息。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">(二)转让</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们不会将您的个人信息转让给任何公司、组织和个人,但以下情况除外:</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)">、事先获得您明确的同意或授权;</span>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">2</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、根据适用的法律法规、法律程序的要求、强制性的行政或司法要求所必须的情况进行提供;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">3</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、符合与您签署的相关协议(包括在线签署的电子协议以及相应的平台规则)或其他的法律文件约定所提供;</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">4</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、在涉及合并、收购、资产转让或类似的交易时,如涉及到个人信息转让,我们会要求新的持有您个人信息的公司、组织继续受本隐私政策的约束,否则,我们将要求该公司、组织重新向您征求授权同意。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">(三)公开披露</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们仅会在以下情况下,且采取符合业界标准的安全防护措施的前提下,才会公开披露您的个人信息:</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、根据您的需求,在您明确同意的披露方式下披露您所指定的个人信息;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">2</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、根据法律、法规的要求、强制性的行政执法或司法要求所必须提供您个人信息的情况下,我们可能会依据所要求的个人信息类型和披露方式公开披露您的个人信息。在符合法律法规的前提下,当我们收到上述披露信息的请求时,我们会要求必须出具与之相应的法律文件,如传票或调查函。我们坚信,对于要求我们提供的信息,应该在法律允许的范围内尽可能保持透明。我们对所有的请求都进行了慎重的审查,以确保其具备合法依据,且仅限于执法部门因特定调查目的且有合法权利获取的数据。在法律法规许可的前提下,我们披露的文件均在加密密钥的保护之下。</span
>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>四、我们如何保护和保存您的个人信息&nbsp;</span
></b
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>(一)我们保护您个人信息的技术与措施</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们非常重视个人信息安全,并采取一切合理可行的措施,保护您的个人信息:</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">1</span></b
><b><span style="font-size: 11px; color: rgb(44, 62, 80)">、数据安全技术措施</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们会采用符合业界标准的安全防护措施,包括建立合理的制度规范、安全技术来防止您的个人信息遭到未经授权的访问使用、修改,避免数据的损坏或丢失。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>羊小咩的网络服务采取了传输层安全协议等加密技术,通过https等方式提供浏览服务,确保用户数据在传输过程中的安全。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>羊小咩采取加密技术对用户个人信息进行加密保存,并通过隔离技术进行隔离。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>在个人信息使用时,例如个人信息展示、个人信息关联计算,我们会采用包括内容替换、SHA256在内多种数据脱敏技术增强个人信息在使用中安全性。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>羊小咩采用严格的数据访问权限控制和多重身份认证技术保护个人信息,避免数据被违规使用。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>羊小咩采用代码安全自动检查、数据访问日志分析技术进行个人信息安全审计。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">2</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、羊小咩为保护个人信息采取的其他安全措施</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>羊小咩通过建立数据分类分级制度、数据安全管理规范、数据安全开发规范来管理规范个人信息的存储和使用。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>羊小咩通过信息接触者保密协议、监控和审计机制来对数据进行全面安全控制。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>加强安全意识。我们还会举办安全和隐私保护培训课程,加强员工对于保护个人信息重要性的认识。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">3</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们仅允许有必要知晓这些信息的羊小咩及羊小咩关联方的员工、合作伙伴访问个人信息,并为此设置了严格的访问权限控制和监控机制。我们同时要求可能接触到您个人信息的所有人员履行相应的保密义务。如果未能履行这些义务,可能会被追究法律责任或被中止与羊小咩的合作关系。</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">4</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、我们会采取一切合理可行的措施,确保未收集无关的个人信息。</span
></b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>我们只会在达成本政策所述目的所需的期限内保留您的个人信息,除非需要延长保留期或受到法律的允许。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">5</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、互联网并非绝对安全的环境,而且电子邮件、即时通讯、社交软件等与其他用户的交流方式无法确定是否完全加密,我们建议您使用此类工具时请使用复杂密码,并注意保护您的个人信息安全。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">6</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、互联网环境并非百分之百安全,我们将尽力确保或担保您发送给我们的任何信息的安全性。如果我们的物理、技术、或管理防护设施遭到破坏,导致信息被非授权访问、公开披露、篡改、或毁坏,导致您的合法权益受损,我们将承担相应的法律责任。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">7</span></b
><b><span style="font-size: 11px; color: rgb(44, 62, 80)">、安全事件处置</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>在通过羊小咩网站及APP与第三方进行网上商品或服务的交易时,您不可避免的要向交易对方或潜在的交易对方披露自己的个人信息,如联络方式或者邮政地址等。请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>为应对个人信息泄露、损毁和丢失等可能出现的风险,羊小咩制定了多项制度,明确安全事件、安全漏洞的分类分级标准及相应的处理流程。羊小咩也为安全事件建立了专门的应急响应团队,按照安全事件处置规范要求,针对不同安全事件启动安全预案,进行止损、分析、定位、制定补救措施、联合相关部门进行溯源和打击。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>在不幸发生个人信息安全事件后,我们将按照法律法规的要求,及时向您告知:安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施等。我们同时将及时将事件相关情况以邮件、信函、电话、推送通知等方式告知您,难以逐一告知个人信息主体时,我们会采取合理、有效的方式发布公告。同时,我们还将按照监管部门要求,主动上报个人信息安全事件的处置情况。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">8</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、如果您对我们的个人信息保护有任何疑问,可通过本政策约定的联系方式联系我们。<b
>如您发现自己的个人信息泄密,尤其是您的账户及密码发生泄露,请您立即通过本政策的联系方式联络我们,以便我们采取相应措施。&nbsp;&nbsp;</b
></span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">(二)您个人信息的保存</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、您的个人信息将全被存储于中华人民共和国境内。如您使用跨境交易服务,且需要向境外传输您的个人信息完成交易的,我们会单独征得您的授权同意并要求接收方按照我们的说明、本隐私政策以及其他任何相关的保密和安全措施来处理这些个人信息。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">2</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、请您注意,当您成功申请注销账户后,我们将对您的个人信息进行删除或匿名化处理。</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">3</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、如果我们终止服务或运营,我们会至少提前三十日向您通知,并在终止服务或运营后对您的个人信息进行删除或匿名化处理。</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></b>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>五、您如何管理自己的个人信息&nbsp;</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>羊小咩非常重视您对个人信息的关注,并尽全力保护您对于您个人信息访问、更正以及撤回同意的权利,以使您拥有充分的能力保障您的隐私和安全。您的权利包括:</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">1</span></b
><b><span style="font-size: 11px; color: rgb(44, 62, 80)">、访问和更正您的个人信息</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>除法律法规规定外,您有权随时访问和更正您的个人信息,具体包括:</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(1)您的订单信息:您可以通过访问“我的订单”页面查看您的所有已经完成、待付款或待售后的订单。移动端具体路径为:移动端首页--“我的”进入我的羊小咩--我的订单/待收款/待收货/退换售后。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(2)您的浏览信息:您可以访问或清除您的搜索历史记录、查看和修改兴趣以及管理其他数据。移动端路径为:搜索历史记录:首页--“我的”进入我的羊小咩--浏览记录。&nbsp;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(3)对于您在使用我们的产品与/或服务过程中产生的其他个人信息需要访问或更正,请随时联系我们。我们会根据本隐私政策所列明的方式和期限响应您的请求。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(4)您无法访问和更正的个人信息:除上述列明的信息外,您的部分个人信息我们还无法为您提供访问和更正的服务,这些信息主要是为了提升您的用户体验和保证交易安全所收集的您的设备信息、您使用附加功能时产生的个人信息。上述信息我们会在您的授权范围内进行使用,您无法访问和更正,但您可联系我们进行删除或做匿名化处理。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">2</span></b
><b><span style="font-size: 11px; color: rgb(44, 62, 80)">、删除您的个人信息</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>您在我们的产品与/或服务页面中可以申请清除或申请删除的信息,包括订单信息、浏览信息、收货地址信息;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>在以下情形中,您可以向我们提出删除个人信息的请求</span
></b
><span style="font-size: 11px; color: rgb(44, 62, 80)"></span>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(1)如果我们处理个人信息的行为违反法律法规;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(2)如果我们收集、使用您的个人信息,却未征得您的同意;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(3)如果我们处理个人信息的行为违反了与您的约定;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">(4)如果您注销了羊小咩账户;</span>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">(5)如果我们终止服务及运营。</span>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>若我们决定响应您的删除请求,我们还将同时通知从我们获得您的个人信息的实体,要求其及时删除,除非法律法规另有规定,或这些实体获得您的独立授权。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">3</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、改变您授权同意的范围或撤回您的授权</span
></b
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>您可以通过申请删除信息、关闭设备功能、在羊小咩网站及APP或软件中进行隐私设置等方式改变您授权我们继续收集个人信息的范围或撤回您的授权。您也可以通过注销账户的方式,撤回我们继续收集您个人信息的全部授权。</span
></b
>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>请您理解,每个业务功能需要一些基本的个人信息才能得以完成,当您撤回同意或授权后,我们无法继续为您提供撤回同意或授权所对应的服务,也不再处理您相应的个人信息。但您撤回同意或授权的决定,不会影响此前基于您的授权而开展的个人信息处理。</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">4</span></b
><b><span style="font-size: 11px; color: rgb(44, 62, 80)">、注销账户</span></b>
</p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>您可以在我们的产品中直接申请注销账户。您注销账户后,我们将停止为您提供产品与/或服务,并依据您的要求,除法律法规另有规定外,我们将删除您的个人信息。</span
></b
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">5</span></b
><b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、如果您不想接受我们给您发送的促销信息,您随时可通过以下方式取消:</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(1)您可以随时回复“TD”来取消我们给您发送的手机促销短信。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(2)我们会与第三方的平台或媒体(“平台”)合作基于您的个人信息向您推荐个性化的商品。这些个人信息包括诸如在本网站的服务情况、访问本网站关联公司网站的情况及您在您的账户设置中填写的兴趣爱好。平台仅向我们提供了展示商品的窗口,窗口内容的链接是羊小咩站内的个性化商品展示信息,由羊小咩进行管理,因此我们不会向广告商提供您的任何的个人信息。如您不愿意接受羊小咩在单个平台上的推荐服务,请联系平台进行关闭。您知晓并理解平台是自主经营的实体,羊小咩无法对其进行管理。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(3)为了保护您的隐私,我们不会以任何方式和途径向您推送涉及宗教信仰、性、疾病等相关敏感内容的促销或商品信息给您。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">6</span></b
><b><span style="font-size: 11px; color: rgb(44, 62, 80)">、响应您的请求</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>如果您无法通过上述方式访问、更正您的个人信息,或您需要访问、更正您在使用我们产品与/或服务时所产生的其他个人信息,或您认为羊小咩存在任何违反法律法规或与您关于个人信息的收集或使用的约定,您均可以与我们联系。为了保障安全,我们可能需要您提供书面请求,或以其他方式证明您的身份,我们将在收到您反馈并验证您的身份后的30天内答复您的请求。对于您合理的请求,我们原则上不收取费用,但对多次重复、超出合理限度的请求,我们将视情况收取一定成本费用。对于那些无端重复、需要过多技术手段(例如,需要开发新系统或从根本上改变现行惯例)、给他人合法权益带来风险或者非常不切实际(例如,涉及备份磁带上存放的信息)的请求,我们可能会予以拒绝。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>在以下情形中,按照法律法规要求,我们将无法响应您的请求:</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">(1)与国家安全、国防安全有关的;</span>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(2)与公共安全、公共卫生、重大公共利益有关的;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(3)与犯罪侦查、起诉和审判等有关的;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(4)有充分证据表明您存在主观恶意或滥用权利的;</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)"
>(5)响应您的请求将导致您或其他个人、组织的合法权益受到严重损害的。</span
>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></b>
</p>
<p>
<b><span style="font-size: 11px; color: rgb(44, 62, 80)">六、未成年人隐私权特别约定</span></b>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、羊小咩非常重视对未成年人个人信息的保护。若您是18周岁以下的未成年人,在使用我们的产品与/或服务前,应事先取得您家长或法定监护人的书面同意。羊小咩根据国家相关法律法规的规定保护未成年人的个人信息。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">2</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、对于经父母或法定监护人同意而收集未成年人个人信息的情况,我们只会在受到法律允许、父母或监护人明确同意或者保护未成年人所必要的情况下使用或公开披露此信息。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">3</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、如果我们发现自己在未事先获得可证实的父母或法定监护人同意的情况下收集了未成年人的个人信息,则会设法尽快删除相关数据。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">4</span
><span style="font-size: 11px; color: rgb(44, 62, 80)">、羊小咩不对在校学生提供服务。</span>
</p>
<p><span style="font-size: 11px; color: rgb(44, 62, 80)">&nbsp;</span></p>
<p>
<b
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>七、本政策的适用及修订&nbsp;</span
></b
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">1</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、羊小咩网站及APP所有服务均适用本政策。</span
>
</p>
<p>
<span style="font-size: 11px; color: rgb(44, 62, 80)">2</span
><span style="font-size: 11px; color: rgb(44, 62, 80)"
>、基于业务功能、使用规则、联络方式、保存地域变更或法律法规及监管要求,我们可能会适时对本政策进行修订。如本政策发生变更,我们将在羊小咩官方网站发布公告或以推送通知或发送邮件或信函或电话或以其他适当的方式来通知您。为了您能及时接收到通知,建议您在电子邮箱地址更新时及时通知我们。若您在本政策修订后继续使用羊小咩网站及APP服务,这表示您已充分阅读、理解并接受修订后的本政策并愿意受修订后的本政策约束。</span
>&nbsp;
</p>
<p>&nbsp;</p>
<p style="text-align: justify">&nbsp;</p>
<p style="text-align: justify">&nbsp;</p>
</view>
</template>
<style scoped lang="less">
// span {
// font-size: 10px;
// color: rgb(44, 62, 80);
// }
p {
text-align: left;
}
</style>
.vjs-custom-skin {
width: 100%;
// 去掉蓝色边框
video:focus,
button:focus {
outline: none;
}
.video-js {
&.vjs-fluid {
height: 100%;
}
.vjs-big-play-button {
display: none !important;
}
// 播放按钮居中、圆形
// .vjs-big-play-button {
// width: 1.6em;
// height: 1.6em;
// top: 50%;
// left: 50%;
// margin-left: -0.8em;
// margin-top: -0.8em;
// border-radius: 50%;
// }
// &.vjs-playing.vjs-user-active {
// .vjs-big-play-button .vjs-icon-placeholder:before {
// content: '\f103';
// }
// }
// &.vjs-has-started.vjs-playing.vjs-user-active {
// .vjs-big-play-button {
// display: block;
// }
// }
.vjs-play-control {
position: fixed;
top: 50%;
left: 50vw;
width: 40px;/*no*/
height: 40px;/*no*/
border-radius: 20px;/*no*/
margin-left: -20px;/*no*/
margin-top: -20px;/*no*/
background-color: rgba(115, 133, 159, 0.5);
border: 2px solid #fff;/*no*/
}
.vjs-play-control .vjs-icon-placeholder:before {
font-size: 26px; /*no*/
line-height: 36px;/*no*/
}
.vjs-error-display.vjs-modal-dialog {
outline: none;
&::before {
display: none;
}
}
}
// 暂停时显示播放按钮
.vjs-paused {
.vjs-big-play-button {
display: block;
}
}
.video-js.vjs-playing .vjs-tech {
pointer-events: auto;
}
}
.vjs-custom-skin {
width: 100%;
// 去掉蓝色边框
video:focus,
button:focus {
outline: none;
}
.video-js {
&.vjs-fluid {
height: 100%;
}
.vjs-big-play-button {
display: none !important;
}
// 播放按钮居中、圆形
// .vjs-big-play-button {
// width: 1.6em;
// height: 1.6em;
// top: 50%;
// left: 50%;
// margin-left: -0.8em;
// margin-top: -0.8em;
// border-radius: 50%;
// }
// &.vjs-playing.vjs-user-active {
// .vjs-big-play-button .vjs-icon-placeholder:before {
// content: '\f103';
// }
// }
// &.vjs-has-started.vjs-playing.vjs-user-active {
// .vjs-big-play-button {
// display: block;
// }
// }
.vjs-play-control {
position: fixed;
top: 50%;
left: 50vw;
width: 40px;/*no*/
height: 40px;/*no*/
border-radius: 20px;/*no*/
margin-left: -20px;/*no*/
margin-top: -20px;/*no*/
background-color: rgba(115, 133, 159, 0.5);
border: 2px solid #fff;/*no*/
}
.vjs-play-control .vjs-icon-placeholder:before {
font-size: 26px; /*no*/
line-height: 36px;/*no*/
}
.vjs-error-display.vjs-modal-dialog {
outline: none;
&::before {
display: none;
}
}
}
// 暂停时显示播放按钮
.vjs-paused {
.vjs-big-play-button {
display: block;
}
}
.video-js.vjs-playing .vjs-tech {
pointer-events: auto;
}
}
import Video from './video.vue';
Video.install = function(Vue) {
Vue.component(Video.name, Video);
};
export default Video;
<template>
<!-- FIXME: 通过元素绑定 -->
<view>
<video ref="videoPlayer" class="video-js" />
</view>
</template>
<script>
import videojs from 'video.js';
import 'video.js/dist/video-js.css';
export default {
name,
props: {
sources: {
type: Array,
required: true
},
options: {
type: Object
},
defaultOptions: {
type: Object,
default: () => {
return {
autoplay: true,
muted: true, // 自动播放必须静音
controls: true,
fluid: true,
loop: false,
preload: 'auto',
playsinline: true, // 内联播放
techOrder: ['html5'],
language: 'zh-CN',
notSupportedMessage: '此视频暂无法播放,请稍后再试',
controlBar: {
fullscreenToggle: false,
pictureInPictureToggle: false,
remainingTimeDisplay: false,
volumePanel: {
inline: false
}
},
userActions: {
// 禁止双击全屏
doubleClick: false
}
};
}
},
playsinline: {
type: Boolean,
default: true
}
},
data() {
return {
player: null
};
},
mounted() {
this.init();
},
beforeDestroy() {
if (this.player) {
this.player.dispose();
}
},
methods: {
init() {
const options = Object.assign({}, this.defaultOptions, this.options);
options.sources = this.sources;
if (options.playsinline) {
this.$refs.videoPlayer.setAttribute('playsinline', options.playsinline);
this.$refs.videoPlayer.setAttribute('webkit-playsinline', options.playsinline);
this.$refs.videoPlayer.setAttribute('x5-playsinline', options.playsinline);
this.$refs.videoPlayer.setAttribute('x5-video-player-type', 'h5');
this.$refs.videoPlayer.setAttribute('x5-video-player-fullscreen', false);
}
this.player = videojs(this.$refs.videoPlayer, options, function onPlayerReady() {
this.play();
});
this.player.on('play', () => {
console.log('play');
});
this.player.on('pause', () => {
console.log('pause');
});
this.player.on('ended', () => {
console.log('ended');
});
this.player.on('timeupdate', () => {
console.log('timeupdate');
});
},
play() {
if (this.player) {
this.player.play();
}
},
pause() {
if (this.player) {
this.player.pause();
}
},
onTouchstart(event) {
this.touchStartTime = new Date();
this.touchStart(event);
},
onTouchmove(event) {
this.touchMove(event);
},
onTouchend(event) {
console.log(10, event);
const { offsetX = 0, offsetY = 0 } = this;
const deltaTime = new Date() - this.touchStartTime;
const TAP_TIME = 250;
const TAP_OFFSET = 10;
if (offsetX < TAP_OFFSET && offsetY < TAP_OFFSET && deltaTime < TAP_TIME) {
if (
event &&
event.path &&
event.path[1] &&
event.path[1].className === 'vjs-big-play-button'
) {
console.log('点击的是播放按钮', this.player.paused());
// // 单击切换播放状态
if (this.player.paused()) {
this.player.play();
} else {
this.player.pause();
}
}
}
}
}
};
</script>
export const SHOULD_BILL = 0;
export const AWAIT_BILL = 1;
export const HISTORY_BILL = 2;
export const SHOULD_ALSO = 1;
export const PAY_BACK = 2;
export const OVERDUE = 3;
export const PAY_COMPLETE = 0;
// MAX会员颜色
export const MAXCOLOR = '#4330B7';
// 活动价签通用颜色
export const ACTIVECOLOR = '#ED7D08';
// 价签颜色判断
export function colorJudgment(info) {
if (info.priceFontColor) {
return info.priceFontColor;
}
if (info.discountType === 9) {
return MAXCOLOR;
} else {
return ACTIVECOLOR;
}
}
/**
* 优惠券
*/
export const DISCOUNT = 1; export const DISCOUNT = 1;
/**
* 运费券
*/
export const FREIGHT = 2; export const FREIGHT = 2;
/**
* 现金券
*/
export const CASH = 3; export const CASH = 3;
/**
* 活动优惠
*/
export const REDUCTION = 4; export const REDUCTION = 4;
export const HAS_DISCOUNT = 2; /**
* 礼品卡
*/
export const GIFT = 20; export const GIFT = 20;
/**
* 是否有折扣
*/
export const HAS_DISCOUNT = 2;
/**
* 不可用的折扣
* @type {number}
*/
export const INVALID_DISCOUNT = 1;
export const COMB_COUPON = 9; // 组合优惠券
export const COMB_ACTIVITY = 10; // 组合活动
/**
* 1.优惠券
* 2.运费优惠
* 3.现金券
* 4.活动优惠
* 20.礼品卡
*/
export const TITLE_LIST = { export const TITLE_LIST = {
[DISCOUNT]: "优惠券", [DISCOUNT]: '优惠券',
[FREIGHT]: "运费券", [FREIGHT]: '运费优惠',
[CASH]: "现金券", [CASH]: '现金券',
[REDUCTION]: "活动优惠", [REDUCTION]: '活动优惠',
[GIFT]: "礼品卡" [GIFT]: '礼品卡'
}; };
export const SHIP_BUS = -1; // 商家配送 export const GIFT_USE = 2;
export const SHIP_USE = 101; // 用户自提
export const defaultCoupon = {
[DISCOUNT]: 'defaultUseCoupon',
[COMB_COUPON]: 'defaultUseCoupon',
[FREIGHT]: 'defaultUseFreightFeeCoupon',
[CASH]: 'defaultUseCashCoupon',
[REDUCTION]: 'defaultUseActivityCoupon',
[GIFT]: 'defaultUseGiftCard'
};
/**
* 商家配送
*/
export const SHIP_BUS = -1;
/**
* 用户自提
*/
export const SHIP_USE = 101;
// NO_SERVICE(0,"未发起售后","","未发起售后",""),
// AUDITING(10, "商家审核中","申请中","平台处理中","平台处理中"),
// AUDIT_PASS(20, "商家已同意您的申请","申请中","商家已同意您的申请","待填物流单号"),
// /**
// * 售后失败-售后申请被拒绝
// */
// AUDIT_REFUSE(30, "商家拒绝了您的售后申请","售后失败","退款失败","售后失败"),
// POSTING(40,"商家待核验商品","商品待验收","平台处理中","核验商品"),
// /**
// * 售后失败-回寄商品不符合售后要求
// */
// UN_ACCEPT(50,"商家拒绝了您的售后申请","售后失败","退款失败","退款失败"),
// REFUNDING(60, "商家退款中","退款中","退款中","退款中"),
// REFUND_FINISH(70,"商家退款成功","售后成功","退款成功","退款成功"),
// CANCEL(90,"买家主动取消售后申请","用户取消","售后取消","售后取消"),
export const REFUND_TYPE = {
NO_SERVICE: 0,
AUDITING: 10,
AUDIT_PASS: 20,
AUDIT_REFUSE: 30,
POSTING: 40,
UN_ACCEPT: 50,
REFUNDING: 60,
REFUND_FINISH: 70,
CANCEL: 90
};
/*
* @Description: 根据图片来源匹配压缩
* @Date: 2021-04-26 17:47:15
* @LastEditors: gzw
* @LastEditTime: 2023-05-08 19:54:55
*/
import localStorage from '@/service/localStorage.service';
const CAN_USE_WEBP = 'checkWebp';
// url协议替换
const replaceProtocol = (str = '') => {
return str.replace('http://', 'https://');
};
// 通过url检测cdn类型, 已处理的会返回false
const getCdnType = function(url, checkProceed = true) {
const aliReg = new RegExp('img.lkbang.net');
const qiniuReg = new RegExp('img.mumcooking.com|kdspstatic|appsync');
const jdReg = new RegExp('360buyimg');
const hadProceed = new RegExp('imageMogr2|x-oss-process|.dpg|.webp|_jfs'); // 已经处理过的不再处理
let cdnType = false;
if (checkProceed && hadProceed.test(url)) {
cdnType = false;
} else {
if (aliReg.test(url)) cdnType = 'ali';
if (qiniuReg.test(url)) cdnType = 'qiniu';
if (jdReg.test(url)) cdnType = 'jd';
}
return cdnType;
};
// 检测webp是否支持
const canUseWebp = function() {
return localStorage.get(CAN_USE_WEBP);
};
// webp支持检测
export const checkWebp = function() {
return new Promise(resolve => {
const image = new Image();
image.onload = () => {
const state = image.width > 0 && image.height > 0;
localStorage.set(CAN_USE_WEBP, state);
resolve(state);
};
image.onerror = () => {
localStorage.set(CAN_USE_WEBP, false);
resolve(false);
};
image.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
});
};
/**
*
* 数组join拼接 [url,基础压缩,格式转换,尺寸压缩].join('')
* 京东的特殊
*
*/
export const imgMogr = function(url, option = {}) {
const cdnType = getCdnType(url);
url = replaceProtocol(url);
if (!cdnType) return url;
let { w, h, f } = option;
if (w) {
w = w * 2;
}
if (h) {
h = h * 2;
}
if (canUseWebp()) f = 'webp';
const sizeBoth = w && h;
const sizeMaybe = w || h;
return {
ali() {
return [
url,
'?x-oss-process=image/quality,q_70/interlace,1',
f ? `/format,${f}` : '',
sizeMaybe
? `/resize,${w ? 'w_' + w : ''}${sizeBoth ? ',' : ''}${h ? 'h_' + h : ''},m_fixed`
: ''
].join('');
},
qiniu() {
return [
url,
'?imageMogr2/quality/70/interlace/1',
f ? `/format/${f}` : '',
sizeMaybe
? `/thumbnail/${w || ''}${sizeBoth ? 'x' : ''}${h || ''}${sizeBoth ? '!' : ''}`
: ''
].join('');
},
jd() {
return [
w && h ? url.replace('jfs', `s${w}x${h}_jfs`) : url,
'!q70.dpg',
f === 'webp' ? '.webp' : ''
].join('');
}
}[cdnType]();
};
// 商品图片压缩polyfill
export function imageMogr4Operation(url, png = false) {
return imgMogr(url, {
format: png ? 'png' : 'jpg'
});
}
// 商品图片压缩polyfill
export function Img2Thumb(url, level = 1) {
const levelSize = {
0: {
width: 220,
height: 200
},
1: {
width: 360,
height: 360
}
};
return imgMogr(url, {
...levelSize[level]
});
}
// 指令中通用逻辑提取
const handleTagType = function(el, binding, vnode, reset) {
if (
vnode.tag.toLowerCase().indexOf('crimage') > -1 &&
vnode.child.imgSrc &&
getCdnType(vnode.child.imgSrc)
) {
const imgSrc = vnode.child.imgSrc;
if (reset) vnode.child.imgSrc = '';
vnode.child.imgSrc = imgMogr(imgSrc, binding.value);
}
};
// 图片处理指令
export const imgMogrDirective = {
bind(el, binding, vnode) {
if (el.tagName.toLowerCase() === 'img' && el.src && getCdnType(el.src)) {
const imgSrc = el.src;
el.src = '';
el.src = imgMogr(imgSrc, binding.value);
}
handleTagType.call(this, el, binding, vnode, true);
},
update(_, binding, vnode) {
if (vnode.tag.toLowerCase() === 'img' && getCdnType(vnode.elm.src) && vnode.elm.src) {
vnode.elm.src = imgMogr(vnode.elm.src, binding.value);
}
handleTagType.call(this, _, binding, vnode);
}
};
export const imgMogrVue = {
install(Vue) {
// polyfill
Vue.filter('imageMogr4Operation', imageMogr4Operation);
// polyfill
Vue.filter('Img2Thumb', Img2Thumb);
Vue.filter('imogr', imgMogr);
Vue.directive('imogr', imgMogrDirective);
Vue.prototype.$imogr = imgMogr;
}
};
import { getUserInfo } from '@/service/userInfo.service';
import { smTrackEvent } from '@/service/shumei.service';
import localStorage from '@/service/localStorage.service';
import {
jverificationInit,
isJverificationInitSuccess,
getJverificationToken,
jverificationLogin
} from '@/service/Jverify.service';
import { oneKeyLogin } from '@/api/user.api';
export default {
data() {
return {
operater: '', // 运营商标识,CM 代表中国移动,CU 代表中国联通,CT 代表中国电信
DOMObserver: null, // 用于监听运营商一键登录弹窗
jverificationLoopMaxTime: 10000, // 最大允许极光轮询时间,当累计轮询时间达到最大允许极光轮询时间,终止轮询,避免过度消耗手机内存
jverificationLoopSingelTime: 200, // 单次轮询时间
jverificationLoopCurrentTime: 0, // 累计轮询时间
jverificationLoopTimer: null // 存储极光sdk初始化windows.JVerificationInterface的轮询计时器
};
},
destroyed() {
this.DOMObserver = null;
},
methods: {
saUploadOneKeyLoginEvent(loginSuccess, failCode, failMessage) {
this.$track.registeredEvents('H5_LoginEvent', {
le_is_login_success: loginSuccess,
le_channel_code: localStorage.get('vccChannel') || '',
le_login_type: '一键登录',
le_failure_code: failCode || '',
le_failure_message: failMessage || ''
});
},
createObserver() {
// 开始监听运营商一键登录弹窗展示情况
this.DOMObserver = null;
const _that = this;
this.DOMObserver = new MutationObserver(function(mutations) {
// 用户注册协议和隐私协议
const fillHtmlContent = `<span>、</span><a id="agreement-1" href="${_that.$config.privacyRreaty.url}" class="link">《${_that.$config.privacyRreaty.label}》</a><span>和</span><a href="${_that.$config.registerRreaty.url}" class="link">《${_that.$config.registerRreaty.label}》</a>`;
mutations.forEach(function(mutation) {
if (mutation.addedNodes && mutation.addedNodes[0] && mutation.addedNodes[0].id) {
const id = mutation.addedNodes[0].id;
if (id == 'YDRZLayer') {
// 中国移动弹窗, 增加注册、登录协议
// eslint-disable-next-line no-undef
const originAgreement = $('#YDRZ_Agreement')
.find('p')
.find('a');
if (
// eslint-disable-next-line no-undef
$('#YDRZ_Agreement')
.html()
.indexOf('agreement-1') == -1
) {
originAgreement.after(fillHtmlContent);
}
}
if (id == 'authxwLoginBox') {
// 中国移动弹窗, 增加注册、登录协议
if (
// eslint-disable-next-line no-undef
$('.xw-agreeement-txt')
.html()
.indexOf('agreement-1') == -1
) {
// eslint-disable-next-line no-undef
$('.xw-agreeement-txt').append(fillHtmlContent);
}
}
}
});
});
this.DOMObserver.observe(document.body, { childList: true });
},
async jVerify(manual) {
if (manual) {
this.$store.dispatch('change_loading', true);
}
this.createObserver();
// 极光认证开始
this.jverificationLoopTimer = null;
clearInterval(this.jverificationLoopTimer);
try {
this.jverificationLoopTimer = setInterval(async () => {
if (window.JVerificationInterface) {
clearInterval(this.jverificationLoopTimer);
this.jverificationLoopTimer = null;
await jverificationInit();
// 判断极光sdk是否初始化成功,如初始化成功,则不进行后续操作
const JverificationInitSuccess = isJverificationInitSuccess();
if (!JverificationInitSuccess) {
this.$store.dispatch('change_loading', false);
return console.log('极光sdk初始化失败');
}
// 判断当前网络环境是否可用,如不可用,不进行后续操作
const verifyEnable = window.JVerificationInterface.checkVerifyEnable();
if (!verifyEnable) {
this.$store.dispatch('change_loading', false);
return console.log('当前网络环境不支持认证');
}
// 获取网络通信商token
const tokenResult = await getJverificationToken();
if (tokenResult.code !== 0 && tokenResult.operater != 'CT') {
console.log(tokenResult.message || '获取运营商token失败');
this.$store.dispatch('change_loading', false);
return;
}
if (tokenResult.operater) {
this.operater = tokenResult.operater;
}
// 当运营商为中国联通时,设置logo及应用名
if (tokenResult?.operater === 'CU') {
window.JVerificationInterface.setCustomUIWithConfig({
logo: 'https://img.lkbang.net/auth-logo.1c5fddec.png',
appName: '羊小咩商城'
});
}
// 中国电信因隐私协议无法修改的问题,禁止调起一键登录
if (tokenResult?.operater === 'CT') {
this.$store.dispatch('change_loading', false);
return;
}
// 调起认证登录弹窗
this.$store.dispatch('change_loading', false);
const { operater, content, message, code } = await jverificationLogin();
if (content && content[this.operater] && code !== 0 && manual) {
if (content[this.operater].indexOf('105025') > -1) {
// 中国移动输入超过3次错误中间四位,进行24小时封禁
this.$toast('输入错误次数过多,请24小时后再操作');
} else {
this.$toast('请稍后重试');
}
return this.$store.dispatch('change_loading', false);
}
if (operater && content && message === 'success') {
// 认证成功,调kdsp接口进行登录
const [res, err] = await oneKeyLogin({
operator: 'operatorWeb', // 用于区分H5终端类型
verifyToken: content
});
if (err) return;
// 上报数美风控
const phoneNo = res.phoneNo || '';
if (phoneNo) {
smTrackEvent({
eventId: 'login',
phone: phoneNo,
type: 'phoneOneLogin'
});
}
this.$toast.success('登录成功');
this.CHANGE_TOKEN(res.token);
this.$track.run('loginSa', res.uuid);
// 上报神策登录事件
// this.saUploadLoginEvent(true, '一键登录');
this.saUploadOneKeyLoginEvent(true);
await getUserInfo();
setTimeout(() => {
if (this.backUrl) {
location.replace(this.backUrl);
return;
}
this.$router.go(-1);
}, 1000);
return;
}
this.saUploadOneKeyLoginEvent(false);
} else {
// 当轮询时间达到上限的时候,不再轮询,终止调起一键登录(短时间且多次轮询会严重导致低端机型内存消耗)
this.jverificationLoopCurrentTime += this.jverificationLoopSingelTime;
if (this.jverificationLoopCurrentTime >= this.jverificationLoopMaxTime) {
clearInterval(this.jverificationLoopTimer);
}
}
}, this.jverificationLoopSingelTime);
} catch (err) {
this.$store.dispatch('change_loading', false);
}
// 极光认证结束
}
}
};
import localStorageService from '@/service/localStorage.service';
import { isApp } from '@/service/validation.service';
export default {
data() {
return {
refreshKey: null,
visibilityChange: null,
visibilityHidden: null
};
},
mounted() {
this.refreshKey && localStorageService.remove(this.refreshKey);
if (isApp) {
this.pageVisibilityChange();
}
},
beforeDestroy() {
this.removePageVisibility();
},
methods: {
getEvent() {
let hidden = 'hidden';
let visibilityChange = 'visibilitychange';
if (typeof document.hidden !== 'undefined') {
hidden = 'hidden';
visibilityChange = 'visibilitychange';
} else if (typeof document.webkitHidden !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
}
return { hidden, visibilityChange };
},
removePageVisibility() {
window.removeEventListener(this.visibilityChange, this.handleVisibilityChange, false);
},
pageVisibilityChange() {
const { visibilityChange, hidden } = this.getEvent();
this.visibilityChange = visibilityChange;
this.visibilityHidden = hidden;
window.addEventListener(visibilityChange, this.handleVisibilityChange, false);
},
handleVisibilityChange() {
const state = document[this.visibilityHidden];
if (!state) {
if (this.refreshKey) {
if (localStorageService.get(this.refreshKey)) {
this.refreshChange && this.refreshChange();
return;
}
}
this.refreshChange && this.refreshChange();
}
}
}
};
/*
* @Description: autoSaveForm mixins
* @LastEditors: gzw
* @Date: 2019-08-14 15:53:37
* @LastEditTime: 2020-12-15 19:17:44
*/
import localStorage from '@/service/localStorage.service';
export default {
data() {
return {
autoSaveTimer: null
};
},
methods: {
autoSaveHandler(key, saveKey, interval = 1000) {
if (this.autoSaveTimer) {
clearTimeout(this.autoSaveTimer);
}
const val = this[key];
this.autoSaveTimer = setTimeout(() => {
localStorage.set(saveKey, val);
}, interval);
},
clearSaveHandler(key) {
localStorage.remove(key);
},
hasAutoSaveData(key) {
return !!localStorage.get(key);
},
getSaveParams(key) {
return localStorage.get(key);
},
getSaveInfoHandler(key, target) {
this[target] = localStorage.get(key);
this[target + 'Cache'] = JSON.parse(JSON.stringify(localStorage.get(key)));
this.$forceUpdate();
}
}
};
import { getTokenFromApp } from '@/service/yxmLogin.service';
import { maxMember } from '@/api/member.api';
import { isApp } from '@/service/validation.service';
export default {
methods: {
// 加购
async mxAddShopCart(goods) {
if (goods.status === 2) return;
if (goods.status === 1) {
this.$toast('来晚了已经卖完了~');
return;
}
try {
await getTokenFromApp();
const { skuNo, goodsId, skuSource } = goods;
const params = [{ skuId: skuNo || goodsId, skuNum: 1, skuSource, type: 1 }];
const [res, err] = await maxMember.addShopCart({
shopCartBaseList: params,
selected: true
});
if (res) {
this.$toast.success('添加成功');
} else if (err.response.businessCode === '401') {
await getTokenFromApp(true);
}
if (isApp) {
this.editor?.updateShopCartCount();
this.nativeBridge.run({
event: 'shopCarAddGoodsNotification',
data: {
count: res.count
}
});
}
} catch (error) {
console.log(error);
}
}
}
};
import Clipboard from 'clipboard';
export default {
methods: {
setClipboardData(
options = {
data: '',
success: () => {
return;
},
fail: () => {
return;
}
}
) {
const fakeEl = document.createElement('button');
const clipboard = new Clipboard(fakeEl, {
text() {
return options.data || '';
},
action() {
return 'copy';
},
container: document.body
});
clipboard.on('success', e => {
clipboard.destroy();
if (options.success) {
options.success(e);
}
});
clipboard.on('error', e => {
clipboard.destroy();
if (options.fail) {
options.fail(e);
}
});
document.body.appendChild(fakeEl);
fakeEl.click();
document.body.removeChild(fakeEl);
}
}
};
import store from '@/store';
export default {
data() {
return {
prevRoute: ''
};
},
// ! 注意:组件名称需要与route中的name一致,route中只支持驼峰
beforeRouteEnter(to, from, next) {
store.commit('ADD_KEEP_ALIVE', to.name);
next(vm => {
if (!vm.prevRoute) vm.prevRoute = from.name;
});
},
beforeRouteLeave(to, from, next) {
// this.prevRoute === to.name && store.commit('DEL_KEEP_ALIVE', from.name);
next();
}
};
import { locationHrefPatch } from '@/service/utils.service';
import { mapGetters } from 'vuex';
import { mapActions as ShopCartMapActions } from '@/views/shopCart/shopCartModules.js';
export default {
data() {
return {
iframeLink: ''
};
},
computed: {
...mapGetters(['vccToken'])
},
created() {
window.addEventListener('message', event => {
console.log('parent', event);
// 来源页面地址
if (event.data.event && this.iframeLink.indexOf(event.origin) > -1) {
this[event.data.event](event.data.data);
}
});
},
beforeDestroy() {
window.removeEventListener('message', this.postMsgBack);
},
methods: {
...ShopCartMapActions(['queryCartCount']),
postMsgBack(event) {
console.log('parent', event);
// 来源页面地址
if (this.iframeLink === event.data.sourceUrl) {
this[event.event](event.data);
}
},
run(data) {
this.$refs.memberCenterIframe.contentWindow.postMessage(data, '*');
},
closeBrowser() {
this.$router.back();
},
getToken() {
if (!this.vccToken) {
this.$router.replace({ name: 'Login', query: { backUrl: location.href } });
return;
}
this.run({
event: 'getTokenSuccess',
data: {
token: this.vccToken
}
});
},
openNewUrl(data) {
locationHrefPatch(data.newUrl, this.$router);
},
shopCarAddGoodsNotification(data) {
// this.queryCartCount();
this.$store.dispatch('shopCart/saveCartCount', data.count);
},
getShuMeiId() {}
}
};
/*
* @Description: 页面跳转时保存当前浏览位置和数据,返回时加载原有数据
* @Date: 2020-11-19 11:49:00
* @LastEditors: gzw
* @LastEditTime: 2020-11-19 14:46:51
*/
export default {
data() {
return {
cacheKey: '',
saveKeys: [],
loadCache: false
};
},
methods: {
setListCache() {
const val = {};
if (!this.saveKeys || !this.saveKeys.length) return;
this.saveKeys.forEach(item => {
val[item] = this[item];
});
val.scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
sessionStorage.setItem(this.cacheKey, JSON.stringify(val));
},
clearListCache() {
sessionStorage.removeItem(this.cacheKey);
},
hasListCache() {
return !!sessionStorage.getItem(this.cacheKey);
},
getListCache() {
this.loadCache = true;
const listCache = JSON.parse(sessionStorage.getItem(this.cacheKey));
this.saveKeys.forEach(item => {
this[item] = listCache[item];
});
document.documentElement.scrollTop = listCache.scrollTop;
document.body.scrollTop = listCache.scrollTop;
this.clearListCache();
this.$nextTick(() => {
this.loadCache = false;
});
}
}
};
<template>
<view class="home">这里是test 页面</view>
</template>
<script></script>
<template>
<view class="home">这里是test 页面</view>
</template>
<script></script>
<template>
<view class="home-skeleton ">
<view class="group ">
<view class="group_1 ">
<view class="circle_26 skeleton-animate-into_1" />
<view class="ellipse_279_26 skeleton-animate-into_2" />
<view class="circle_26 skeleton-animate-into_3" />
</view>
<view class="group_2">
<view class="rectangle_32_14 skeleton-animate-into_1" />
<view class="rectangle_56_10 skeleton-animate-into_2" />
<view class="rectangle_56_10 skeleton-animate-into_3" />
<view class="rectangle_56_10 skeleton-animate-into_4" />
<view class="rectangle_56_10" />
<view class="rectangle_56_10" />
</view>
<view class="group_3 " />
<view class="group_4">
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
</view>
<view class="group_5">
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
</view>
<view class="group_4">
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
</view>
<view class="group_5">
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
</view>
<view class="group_6">
<view class="progress" />
</view>
<view class="group_7 ">
<view class="square_50_50 skeleton-animate-into_1 " />
</view>
<view class="group_8 ">
<view class="left" />
<view class="right">
<view class="rectangle_172_82" />
<view class="rectangle_172_82" />
<view class="rectangle_172_82" />
</view>
</view>
<view class="group_4">
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
<view class="square_48_48" />
</view>
<view class="group_5">
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
<view class="rectangle_32_9" />
</view>
</view>
</view>
</template>
<script>
export default {
name: 'HomeSkeleton'
};
</script>
<style lang="less" scoped>
.home-skeleton {
background-color: rgba(246, 246, 246, 1);
height: 100%;
width: 100%;
z-index: 99999;
position: fixed;
top: 0;
left: 0;
right: 0;
.group {
background-color: rgb(177, 177, 177);
padding: 30px 13px;
box-shadow: 0 0 15px 10px rgb(177, 177, 177);
height: 100px;
}
.group_1 {
display: flex;
justify-content: space-around;
.circle_26 {
background-color: rgba(255, 255, 255, 1);
border-radius: 13px;
width: 26px;
height: 26px;
}
.ellipse_279_26 {
background-color: rgba(247, 248, 250, 1);
border-radius: 15px;
height: 26px;
margin: 0 15px;
flex: 1;
}
}
.group_2 {
display: flex;
justify-content: flex-start;
align-items: center;
margin-top: 13px;
width: 100%;
.rectangle_32_14 {
background-color: rgba(247, 248, 250, 1);
border-radius: 15px;
height: 14px;
width: 32px;
margin: 0 32px 0 16px;
flex-shrink: 0;
position: relative;
&:after {
content: '';
position: absolute;
top: 20px;
height: 8px;
width: 50px;
left: -1px;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACcAAAAHCAMAAAC80aQxAAAAclBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9eWEHEAAAAJXRSTlMA+/SCG+bGaFrTtzkxFA7gyrymbCEE78zBq6qOfHBjS0E2KyoIwsQIPQAAAHZJREFUGNN9zlcOhDAMBFDHTk/osL3v+v5X3CAEQgh4P/4YeTRg8GQk7MgeHglAcVLeYgdrYuNFykUHJt0e6qsNs+L8bckfeEB9b1MJHonCHXWlnUKe6Lscf21d8CpVL8dnTzqXiifoLmRb2PBrPzG8wlfmi+APX4sOXNJyhqwAAAAASUVORK5CYII=');
background-repeat: no-repeat;
}
}
.rectangle_56_10 {
background-color: rgba(247, 248, 250, 1);
border-radius: 15px;
height: 10px;
width: 56px;
margin-right: 32px;
flex-shrink: 0;
}
}
.group_3 {
width: 100%;
height: 110px;
border-radius: 10px;
background: #ededed;
margin-top: 23px;
}
.group_4 {
display: flex;
justify-content: space-between;
margin: 15px;
}
.group_5 {
display: flex;
justify-content: space-between;
margin: 10px 22px;
}
.group_6 {
margin: 21px auto 16px auto;
width: 36px;
height: 4px;
background: #d8d8d8;
border-radius: 25px;
position: relative;
.progress {
position: absolute;
left: 0;
width: 18px;
height: 4px;
background: #a3a3a3;
border-radius: 25px;
}
}
.group_7 {
width: 100%;
height: 72px;
border-radius: 10px;
background: #ededed;
display: flex;
justify-content: flex-end;
align-items: center;
.square_50_50 {
background: #fff;
border-radius: 12px;
flex-shrink: 0;
width: 50px;
height: 50px;
margin-right: 16px;
}
}
.rectangle {
width: 100%;
height: 110px;
border-radius: 10px;
}
.square_48_48 {
width: 48px;
height: 48px;
background: #ededed;
border-radius: 12px;
flex-shrink: 0;
}
.rectangle_32_9 {
background-color: #ededed;
border-radius: 15px;
height: 9px;
width: 32px;
flex-shrink: 0;
}
.group_8 {
margin-top: 12px;
height: 262px;
display: flex;
justify-content: space-between;
.left {
height: 100%;
width: 171px;
background: #ededed;
border-radius: 10px;
margin-right: 8px;
flex-shrink: 0;
}
.right {
height: 100%;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.rectangle_172_82 {
background: #ededed;
height: 82px;
width: 100%;
border-radius: 10px;
}
}
}
}
.skeleton-animate-into {
animation: into 1s ease-in-out infinite;
}
.skeleton-animate-into_1 {
animation: into 1s ease-in-out infinite;
}
.skeleton-animate-into_2 {
animation: into 1.2s ease-in-out infinite;
}
.skeleton-animate-into_3 {
animation: into 1.4s ease-in-out infinite;
}
.skeleton-animate-into_4 {
animation: into 1.6s ease-in-out infinite;
}
</style>
<template>
<view class="home">
<view class="home-header">
<image
v-if="brandInfo.brandImageUrl"
:src="brandInfo.brandImageUrl | Img2Thumb"
class="brand-img"
@click="homePageLogoClick(brandInfo)"
/>
<view class="home-header-search" @click="handleToSearch">
<view class="home-header-search-wrapper">
<i class="iconfont icon-search" />
<span>搜索商品</span>
</view>
<view class="item-center">
<span class="item-center-btn">搜索</span>
</view>
</view>
</view>
<view v-if="tabList.length" class="home-tab">
<cr-tabs v-model="pageTabIndex" :swipe-threshold="3">
<cr-tab v-for="(tab, i) in tabList" :key="i" :title="tab.name" />
</cr-tabs>
</view>
<cr-swipe
:show-indicators="false"
class="home-swipe"
:initial-swipe="pageTabIndex"
@change="onPageSwitch"
>
<cr-swipe-item>
<MainInfo
:active="pageTabIndex"
:top="activeTop"
@changeTop="scrollTop = $event"
@onLoadSkeleton="onLoadSkeleton"
/>
</cr-swipe-item>
<cr-swipe-item v-for="(tab, i) in categoryList" :key="tab.id">
<CategoryInfo
:id="tab.id"
:before-active="beforeTabIndex"
:active="pageTabIndex"
:tab-name="tab.name"
:rear-category-ids="tab.rearCategoryIds"
:label-ids="tab.labelIds"
:index="i + 1"
:top="activeTop"
@changeTop="scrollTop = $event"
/>
</cr-swipe-item>
</cr-swipe>
<LoginPopup />
<loginGuide v-if="!hasLogin" />
<transition name="fade">
<Skeleton v-if="skeletonStatus" />
</transition>
</view>
</template>
<script>
import { getTopTab } from '@/api/home.api.js';
import LoginPopup from '@/components/loginPopup.vue';
import MainInfo from './components/Main.vue';
import CategoryInfo from './components/Category.vue';
import loginGuide from '@/components/loginGuide.vue';
import historyRecordMixins from '@/mixins/historyRecord.mixins';
import mxBll from './mixin/mxBll';
import { Img2Thumb } from '@/filters/img2Thumb.filter';
import Skeleton from './components/Skeleton.vue';
import { mapGetters as homeMapGetters } from 'vuex';
export default {
name: 'Home',
components: {
LoginPopup,
MainInfo,
CategoryInfo,
loginGuide,
Skeleton
},
filters: {
Img2Thumb
},
mixins: [historyRecordMixins, mxBll],
data() {
return {
brandInfo: {}, // 品牌形象信息
pageTabIndex: 0,
beforeTabIndex: 0,
tabList: [],
scrollTop: 0,
activeTop: 0,
timer: null,
skeletonStatus: true
};
},
computed: {
...homeMapGetters(['hasLogin']),
specialCol() {
return this.$refs.specialCol;
},
// 专题纵向宽度固定宽度
scrollColWidth() {
return this.specialCol[0].offsetWidth;
},
categoryList() {
return this.tabList.slice(1);
}
},
watch: {
pageTabIndex() {
this.tabExposureClick();
this.onPageSwitch(this.pageTabIndex);
}
},
activated() {
const currnetScrollTop = this.scrollTop;
console.log('currnetScrollTop :>> ', currnetScrollTop);
this.activeTop = 0;
this.$nextTick(() => {
this.activeTop = currnetScrollTop;
});
const timer = setTimeout(() => {
clearTimeout(timer);
this.onLoadSkeleton(false);
}, 2000);
},
mounted() {
this.getTopTabData();
this.$track.registeredEvents('H5_2BSelectionPageExposure');
},
beforeDestroy() {
clearTimeout(this.timer);
},
methods: {
onLoadSkeleton(e) {
this.skeletonStatus = e;
},
homePageLogoClick(item) {
this.$track.registeredEvents('H5_HomePageLogoClick');
this.mxHandleToDetails({ item, urlKey: 'brandImageActivityUrl' });
},
// 获取顶部信息
async getTopTabData() {
const [data] = await getTopTab();
if (data) {
this.brandInfo = data || {};
this.tabList = data.topTabList || [];
this.tabExposureClick();
}
},
handleToSearch() {
this.$store.commit('DEL_KEEP_ALIVE', 'search');
this.$track.registeredEvents('H5_UserClickSearchTrigger', { page_name: 'home' });
setTimeout(() => {
this.$router.push({ name: 'search' });
}, 200);
},
// 导航点击埋点
tabExposureClick() {
const params = {
navigation_name: this.tabList[this.pageTabIndex]?.name,
position_number: this.pageTabIndex
};
this.$track.registeredEvents('H5_HomePageTopTapClick', params);
},
// 页面滑动
onPageSwitch(index) {
this.beforeTabIndex = index;
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.pageTabIndex = index;
clearTimeout(this.timer);
}, 300);
}
}
};
</script>
<style lang="less" src="./style/index.less" scoped></style>
import { mapState } from 'vuex';
import { locationHrefPatch } from '@/service/utils.service';
import { sStorage } from '@/service/sessionStorage.service';
import localStorage from '@/service/localStorage.service';
export default {
methods: {
mxHandleToDetails({ item, area, index, urlKey }) {
const jumpUrl = this.formatUrl(
item[urlKey] || item.jumpUrl || item.coverJumpUrl || item.floorJumpUrl
);
locationHrefPatch(jumpUrl, this.$router);
console.log('DEBUG: toDetails ====>', item, area, index);
},
formatUrl(url) {
if (url && url.indexOf('://quantum-h5') > -1) {
// 量子积木url增加数美ID键,feat: 量子积木领券数美埋点; PM: 崔倩倩
const shumeiKey = sStorage.getItem('shumeiKey');
if (shumeiKey) url = this.addParamToURL(url, 'shumeiKey', shumeiKey);
}
return url
?.replace(/\{vccToken\}/g, localStorage.get('vccToken'))
?.replace(/\{token\}/g, localStorage.get('vccToken'))
?.replace(/\{registerFrom\}/g, localStorage.get('vccChannel') || '')
?.replace(/\{tenantId\}/g, localStorage.get('tenantId') || '560761')
?.replace(/\{appChannel\}/g, localStorage.get('appChannel') || '')
?.replace(/\{phone\}/g, this.userInfo.phoneNumber);
},
addParamToURL(url, key, value) {
let newUrl = url.indexOf('?') < 0 ? url + '?' : url + '&';
return newUrl + key + '=' + value;
}
},
computed: {
...mapState({
userInfo: state => {
return (state && state.pay.userInfo) || {};
},
smDeviceId: state => state.pay.smDeviceId
})
}
};
// 首页埋点
export const TRACK_EVENT_MAP = {
// banner点击
Banner: {
name: 'H5_2BSelectionPageBannerClick',
trackKey: 'bname',
itemKey: 'bname'
},
// 新banner曝光
newBannerExposure: {
name: 'H5_HomePageBannerExposure',
trackKey: 'new_banner_exposure',
itemKey: 'bname'
},
// 新banner点击
newBannerClick: {
name: 'H5_HomePageBannerClick',
trackKey: 'bname',
itemKey: 'bname'
},
KingKongPosition: {
name: 'H5_2BSelectionPageKingKongZoneClick',
trackKey: 'kingkong_title',
itemKey: 'name'
},
// 横向运营区点击
OperationPromotion_across: {
name: 'H5_2BSelectionPageHorizontalZoneClick',
trackKey: 'horizontal_title',
itemKey: 'bname'
},
// 竖向运营区点击
OperationPromotion_vertical: {
name: 'H5_2BSelectionPageVerticalZoneClick',
trackKey: 'vertical_title',
itemKey: 'bname'
},
// 首页瓷片区曝光
HomePagePorcelainAreaExposure: {
name: 'H5_HomePagePorcelainAreaExposure',
trackKey: 'porcelain_area_title',
itemKey: 'assembly_name'
},
// 首页瓷片区点击
HomePagePorcelainAreaClick: {
name: 'H5_HomePagePorcelainAreaClick',
trackKey: 'porcelain_area_title',
itemKey: 'assembly_name'
},
// 搜索
UserClickSearchTrigger: {
name: 'H5_UserClickSearchTrigger',
trackKey: 'search_trigger_title',
itemKey: 'search'
},
// 商品专题more
HomePageCommoditySpecialMoreBtnClick: {
name: 'H5_2B_HomePageCommoditySpecialMoreBtnClick',
trackKey: 'more_title',
itemKey: 'assembly_name'
},
// 商品专题卡片
HomePageCommoditySpecialCommodityCardClick: {
name: 'H5_HomePageCommoditySpecialCommodityCardClick',
trackKey: 'card-title',
itemKey: 'assembly_name'
},
// 首页通栏点击
HomePageExtensionBannerClick: {
name: 'H5_HomePageExtensionBannerClick',
trackKey: 'extension-banner-click-title',
itemKey: 'assembly_name'
},
// 首页通栏曝光
HomePageExtensionBannerExposure: {
name: 'H5_HomePageExtensionBannerExposure',
trackKey: 'extension-banner-title',
itemKey: 'assembly_name'
},
// H5_首页商品专题商品卡曝光-横向
CrosswiseHomePageCommoditySpecialCommodityCardExposure: {
name: 'H5_HomePageCommoditySpecialCommodityCardExposure',
trackKey: 'crosswise-homePage-title',
itemKey: 'assembly_name'
},
// H5_首页商品专题商品卡曝光-纵向
LengthwaysHomePageCommoditySpecialCommodityCardExposure: {
name: 'H5_HomePageCommoditySpecialCommodityCardExposure',
trackKey: 'lengthways-HomePage-title',
itemKey: 'assembly_name'
},
// 首页导航点击
HomePageTabClick: {
name: 'H5_HomePageTopTapClick',
trackKey: 'KKD_name',
itemKey: 'assembly_name'
},
// 频道页面金刚区点击
CategoryKingKongClick: {
name: 'H5_SelectionPageKingKongZoneClick',
trackKey: 'KKD_name',
itemKey: 'name'
},
// 频道页面品牌区点击
CategoryBrandClick: {
name: 'H5_SelectionPageBrandClick',
trackKey: 'brand',
itemKey: 'name'
}
};
// 频道页面曝光
export const TRACK_EXPOSURE_MAP = {
4: 'H5_SelectionPageKingKongZoneExposure',
113: 'H5_SelectionPageBrandExposure'
};
.category-box {
height: 100%;
&-wrapper {
padding: 12px 12px 0 12px;
}
&--card {
padding-top: 12px;
&:first-child {
padding-top: 0;
}
}
&--vajra {
display: flex;
flex-wrap: wrap;
padding: 16px 0 0 0;
justify-content: space-between;
box-sizing: border-box;
border-radius: 8px;
background-color: #fff;
.vajra--item {
width: 66px;
height: 64px;
margin-bottom: 16px;
&--imgwrapper {
width: 48px;
height: 48px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
}
&--img {
width: 100%;
height: 100%;
}
&--txt {
display: block;
height: 16px;
line-height: 16px;
font-size: 10px;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
&--activity {
display: flex;
justify-content: space-between;
&--item {
width: 172px;
height: 72px;
img {
display: block;
width: 100%;
height: 100%;
}
}
}
&--brands {
background-color: #fff;
padding-bottom: 18px;
border-radius: 8px;
overflow: hidden;
&--title {
height: 37px;
display: flex;
align-items: center;
padding-left: 11px;
&__img {
height: 14px !important;
}
}
&--body {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
&--item {
width: 64px;
height: 92px;
margin: 0 4px;
&__img {
display: block;
width: 64px !important;
height: 64px !important;
}
&--name {
margin-top: 6px;
height: 16px;
line-height: 16px;
.text-size(11);
color: @gray-4;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
\ No newline at end of file
.category-box {
height: 100%;
&-wrapper {
padding: 12px 12px 0 12px;
}
&--card {
padding-top: 12px;
&:first-child {
padding-top: 0;
}
}
&--vajra {
display: flex;
flex-wrap: wrap;
padding: 16px 0 0 0;
justify-content: space-between;
box-sizing: border-box;
border-radius: 8px;
background-color: #fff;
.vajra--item {
width: 66px;
height: 64px;
margin-bottom: 16px;
&--imgwrapper {
width: 48px;
height: 48px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
}
&--img {
width: 100%;
height: 100%;
}
&--txt {
display: block;
height: 16px;
line-height: 16px;
font-size: 10px;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
&--activity {
display: flex;
justify-content: space-between;
&--item {
width: 172px;
height: 72px;
img {
display: block;
width: 100%;
height: 100%;
}
}
}
&--brands {
background-color: #fff;
padding-bottom: 18px;
border-radius: 8px;
overflow: hidden;
&--title {
height: 37px;
display: flex;
align-items: center;
padding-left: 11px;
&__img {
height: 14px !important;
}
}
&--body {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
&--item {
width: 64px;
height: 92px;
margin: 0 4px;
&__img {
display: block;
width: 64px !important;
height: 64px !important;
}
&--name {
margin-top: 6px;
height: 16px;
line-height: 16px;
@include text-size(11);
color: $gray-4;
text-align: center;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
}
\ No newline at end of file
@lritem-width: 172px;
@border-radius: 8px;
.home {
height: 100%;
width: 100%;
overflow: hidden;
&-header {
display: flex;
align-items: center;
box-sizing: border-box;
padding: @padding-sm @padding-sm 4px @padding-sm;
background: @white;
.brand-img {
margin-right: 8px;
max-height: 28px;
}
&-search-wrapper {
height: 100%;
display: flex;
align-items: center;
}
&-search {
display: flex;
align-items: center;
justify-content:space-between;
box-sizing: border-box;
padding: 0 @padding-sm - 2;
width: 100%;
height: 30px;
border-radius: @border-radius-lg + 222;
background-color: @grey-border;
color: #c8c9cc;
.text-size(12);
text-align: center;
color: @gray-4;
.iconfont {
margin-right: @padding-unit;
.text-size(16);
color: @black;
}
.item-center {
display: flex;
align-items: center;
border-left: 1px solid #DCDEE0;
padding-left: 8px;
&-btn {
color: #333;
.text-size(12);
}
span:last-child{
color: #666;
}
}
}
}
&-tab {
color: #666;
background-color: #fff;
// padding-bottom: 6px;
// height: 50px;
overflow: hidden;
/deep/ .cr-tabs__nav {
background-color: transparent;
.cr-tabs__item {
color: #666;
font-size: 14px;
padding: 0 14px;
flex: none !important;
}
.cr-tabs__item--active {
color: #ec1500;
font-size: 16px;
padding: 0 20px;
}
}
/deep/ .cr-tabs__content {
display: none;
}
/deep/ .cr-tabs__line {
bottom: 20px;
height: 8px;
background-color: transparent;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE4AAAAOCAYAAACB8ipxAAAAAXNSR0IArs4c6QAAAsxJREFUWEfll01PU0EUhp9zW2kJ0lKgxaBiTKCJLg2KG0jUuDAajG5Y6D/ApWz8G/oD3LDQmIg10cTEhWhMhA26MSkkAqIRKC23Kv2i95jbFlNLtRQKIk4yuZPJmfeceebrXFGQpQBDwCBKPcprEYbjDTw+Ok2S/7AoOKMBzqkygHIWYb8ID7LKzcAi32wkEvEzCNwpwycu8MRSQs5VnvqWWd7LDBUcS22cUYsBgStAy7r5CsOtC1zPgwvwBuVUBSirKC8QQg4HId8XpvcCRHtnRVrpNQwGVLkK+CtxaFmkQSBt77hxoLsaEArvBEIijBppxv+V3fjxEPXuJD0G9Cn0IZwGGqqYeybhwnt4joQN7gZwu4rBpaYKTKKMIYxhMBZrZKJritQWNGsydMHPAeCEDQroRehGqdu0ePFRtUUWAwyJcgto2rTorwMzwFuU9wgzqswaBjOaZTbtYrb9Mys18kPUhzfroAsIYhA0IKhKEHJ9nhr5SYlw17IY8kf4mrvj1oQnO3H54lxEuQZcAOpr5HSdjEJEYEZgXiGBkEJzL3hShZQoSbuqYC9AI+BF8KJ4JQ/Dq3ZffqFrtdilcWYEnqlw38jwqDmGWWzwE1xxZ+EuOI/QL3AJaNsuiLtMdxV4LnDPkWakyST2u/jKgis2VjCiAXpU6QcuA8d22WS3Go4p8AplZJ+Lh55PLG1EsCK4UpEFP52GfZSFnkIa01l85Dfi9C/bzAMv7WrBqH8xlyFY1cZUNbhSB8tefFkXJzWfC67V3XK0VxSmBCZEC6AihKuFVM5+y+DKiUZ9dKiT45bSIcIRCl/Nt9sBZy2CL2jY99IHgbAlOShhyRIWZbI5ypyAnS7VvGwLuD9Faf/axHwcxEnHKngMwa0WbkNwqeAWC7eutfM513fARDDVyr1spgpmnYEpCUxPHPuOytacTAXBHQe30xPcLn8/APIH7Q/QCEdaAAAAAElFTkSuQmCC');
background-size: 35px 7px;
background-repeat: no-repeat;
background-position: bottom center;
}
}
&-swipe {
// height: calc(100% - (44px + 30px + @padding-sm + 4px));
// tab:44px + search(input: 30px + paddingtop: @padding-sm + paddingbottom: 4px)
// height: calc(100% - (78px + @padding-sm));
height: calc(100% - (30px + @padding-sm));
}
}
$lritem-width: 172px;
$border-radius: 8px;
.home {
height: 100%;
width: 100%;
overflow: hidden;
&-header {
display: flex;
align-items: center;
box-sizing: border-box;
padding: $padding-sm $padding-sm 4px $padding-sm;
background: $white;
.brand-img {
margin-right: 8px;
max-height: 28px;
}
&-search-wrapper {
height: 100%;
display: flex;
align-items: center;
}
&-search {
display: flex;
align-items: center;
justify-content:space-between;
box-sizing: border-box;
padding: 0 $padding-sm - 2;
width: 100%;
height: 30px;
border-radius: $border-radius-lg + 222;
background-color: $grey-border;
color: #c8c9cc;
@include text-size(12);
text-align: center;
color: $gray-4;
.iconfont {
margin-right: $padding-unit;
@include text-size(16);
color: $black;
}
.item-center {
display: flex;
align-items: center;
border-left: 1px solid #DCDEE0;
padding-left: 8px;
&-btn {
color: #333;
@include text-size(12);
}
span:last-child{
color: #666;
}
}
}
}
&-tab {
color: #666;
background-color: #fff;
// padding-bottom: 6px;
// height: 50px;
overflow: hidden;
/deep/ .cr-tabs__nav {
background-color: transparent;
.cr-tabs__item {
color: #666;
font-size: 14px;
padding: 0 14px;
flex: none !important;
}
.cr-tabs__item--active {
color: #ec1500;
font-size: 16px;
padding: 0 20px;
}
}
/deep/ .cr-tabs__content {
display: none;
}
/deep/ .cr-tabs__line {
bottom: 20px;
height: 8px;
background-color: transparent;
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE4AAAAOCAYAAACB8ipxAAAAAXNSR0IArs4c6QAAAsxJREFUWEfll01PU0EUhp9zW2kJ0lKgxaBiTKCJLg2KG0jUuDAajG5Y6D/ApWz8G/oD3LDQmIg10cTEhWhMhA26MSkkAqIRKC23Kv2i95jbFlNLtRQKIk4yuZPJmfeceebrXFGQpQBDwCBKPcprEYbjDTw+Ok2S/7AoOKMBzqkygHIWYb8ID7LKzcAi32wkEvEzCNwpwycu8MRSQs5VnvqWWd7LDBUcS22cUYsBgStAy7r5CsOtC1zPgwvwBuVUBSirKC8QQg4HId8XpvcCRHtnRVrpNQwGVLkK+CtxaFmkQSBt77hxoLsaEArvBEIijBppxv+V3fjxEPXuJD0G9Cn0IZwGGqqYeybhwnt4joQN7gZwu4rBpaYKTKKMIYxhMBZrZKJritQWNGsydMHPAeCEDQroRehGqdu0ePFRtUUWAwyJcgto2rTorwMzwFuU9wgzqswaBjOaZTbtYrb9Mys18kPUhzfroAsIYhA0IKhKEHJ9nhr5SYlw17IY8kf4mrvj1oQnO3H54lxEuQZcAOpr5HSdjEJEYEZgXiGBkEJzL3hShZQoSbuqYC9AI+BF8KJ4JQ/Dq3ZffqFrtdilcWYEnqlw38jwqDmGWWzwE1xxZ+EuOI/QL3AJaNsuiLtMdxV4LnDPkWakyST2u/jKgis2VjCiAXpU6QcuA8d22WS3Go4p8AplZJ+Lh55PLG1EsCK4UpEFP52GfZSFnkIa01l85Dfi9C/bzAMv7WrBqH8xlyFY1cZUNbhSB8tefFkXJzWfC67V3XK0VxSmBCZEC6AihKuFVM5+y+DKiUZ9dKiT45bSIcIRCl/Nt9sBZy2CL2jY99IHgbAlOShhyRIWZbI5ypyAnS7VvGwLuD9Faf/axHwcxEnHKngMwa0WbkNwqeAWC7eutfM513fARDDVyr1spgpmnYEpCUxPHPuOytacTAXBHQe30xPcLn8/APIH7Q/QCEdaAAAAAElFTkSuQmCC');
background-size: 35px 7px;
background-repeat: no-repeat;
background-position: bottom center;
}
}
&-swipe {
// height: calc(100% - (44px + 30px + $padding-sm + 4px));
// tab:44px + search(input: 30px + paddingtop: $padding-sm + paddingbottom: 4px)
// height: calc(100% - (78px + $padding-sm));
height: calc(100% - (30px + $padding-sm));
}
}
@lritem-width: 172px;
@border-radius: 8px;
.main-box {
height: 100%;
width: 100%;
overflow: hidden;
.main-box-container {
height: 100%;
.content{
.goods-card {
margin: 0 @padding-sm;
@{deep} .home-list-container {
padding-top: 12px;
}
}
}
}
&-bn {
box-sizing: border-box;
position: relative;
&-swiper {
height: 100%;
position: relative;
background-image: linear-gradient(@white, @gray-1);
.hb-swiper-item {
display: flex;
justify-content: center;
.hbs-item-img {
width: calc(100% - @padding-sm * 2) !important;
height: 100%;
border-radius: @border-radius-md;
}
}
.main-box-bn-dots {
display: flex;
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
.hb-dots-item {
width: 6px;
height: 6px;
border-radius: @border-radius-max;
background: rgba(255, 255, 255, 0.5);
margin-right: @padding-xs;
}
.hb-dots-item_selected {
height: 6px;
width: 6px;
border-radius: @border-radius-sm;
background: @white;
}
}
}
}
&-container {
height: calc(100% - 46px);
&-body {
padding: @padding-sm;
}
}
&-nav {
// background: @white;
border-radius: @border-radius-md;
display: flex;
align-items: center;
flex-wrap: wrap;
align-content: flex-start;
padding: @padding-sm/2 @padding-sm;
// margin-bottom: @padding-sm;
max-height: 180px;
.my-nav-swipe {
max-height: 180px;
width: 100%;
&-item {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-content: flex-start;
flex-direction: column;
flex-wrap: wrap;
max-height: 180px;
}
.custom-indicator {
position: relative;
right: 0;
left: 0;
bottom:0px;
text-align: center;
font-size: 12px;
background: #e5e5e5;
max-width: 36px;
margin: 0 auto;
height:4px;
border-radius: 25px;
&-in{
position: absolute;
left: 0;
top:0;
background:linear-gradient(to right, rgba(255, 75, 0, 1), rgba(255, 119, 5, 1));
width: 0px;
min-height:4px;
position: relative;
border-radius: 25px;
}
}
}
.hn-item {
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: @padding-sm;
width: 20%;
text-align: center;
.text-size(12);
line-height: 16px !important;
color: @gray-5;
white-space: nowrap;
&-imgbox {
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content:center;
img {
display: block;
max-width: 100%;
max-height: 100%;
border-radius: @gray-1;
}
}
&-title {
display: block;
width: 100%;
height: 16px;
line-height: 16px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: @font-color-dark;
.text-size(10);
}
}
}
&-welfare {
font-size: 0;
display: flex;
align-content: flex-start;
padding: @padding-sm/2 @padding-sm ;
box-sizing: border-box;
&-item {
flex: 1;
img {
height: 130px;
width: 100%;
display: block;
}
}
}
&-tonglans {
margin: @padding-sm/2 @padding-sm ;
img {
border-radius: @border-radius-md;
display: block;
width: 100%;
}
}
&-find {
display: flex;
justify-content: space-between;
padding: @padding-sm/2 @padding-sm 0 @padding-sm;
box-sizing: border-box;
&-item {
width: @lritem-width;
height: 145px;
img {
display: block;
width: 100%;
height: 100%;
}
}
}
&-chip {
display: flex;
justify-content: space-between;
padding: @padding-sm/2 @padding-sm;
&-left {
width: @lritem-width;
border-radius: @border-radius;
overflow: hidden;
position: relative;
z-index: 1;
.my-swipes {
height: 260px;
width: @lritem-width;
border-radius: @border-radius;
overflow: hidden;
img {
height: 260px;
width: @lritem-width;
display: block;
}
}
}
&-right {
display: flex;
justify-content: space-between;
flex-direction: column;
img {
width: @lritem-width;
height: 82px;
display: block;
border-radius: @border-radius;
}
}
}
&-special-row{
display: flex;
flex-direction: column;
padding: @padding-sm/2 @padding-sm;
img {
width: 100%;
display: block;
}
.special-row-con {
background: #fff;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
overflow: hidden;
padding: 0 16px;
.content{
display: flex;
overflow-x: scroll;
overflow-y: hidden;
&::-webkit-scrollbar {
display: none;
width: 0px;
}
&-wrapper {
display: flex;
flex-flow: row nowrap;
height: 110px;
&::-webkit-scrollbar {
width: 0 !important;
display: none;
}
}
&-wrapper-rushpurchase {
overflow-x: scroll;
overflow-y: hidden;
display: flex;
flex-flow: row nowrap;
height: 120px;
&::-webkit-scrollbar {
width: 0 !important;
display: none;
}
}
&-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-bottom: 6px;
width: 25%;
flex-shrink: 0;
.special-row-img {
width: 76px;
height: 76px;
border-radius: @border-radius;
}
.special-row-money {
margin: 5px auto 0 auto;
display: flex;
align-items: flex-start;
span {
&:nth-child(1) {
.text-size(10);
color: @red-light;
font-weight: bold;
}
&:nth-child(2) {
.text-size(14);
line-height: 16px;
color: @red-light;
font-weight: bold;
}
}
}
.special-row-saleprice {
margin: 0 auto;
display: flex;
align-items: flex-start;
.text-size(12);
color: #999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-indent: -1px;
}
}
}
.rushpurchase-content {
height: 116px;
}
.progress {
margin:0 auto 10px auto;
width:36px;
}
}
}
&-special-wrapper {
border-radius: @border-radius;
overflow: hidden;
position: relative;
.purchase-count-start {
position:absolute;
left: 90px;
top: 14px;
display: flex;
flex-flow: row nowrap;
align-items: center;
background: #FEE8E2;
border-radius: 25px;
color: #FF1515;
padding: 0 10px 0 3px;
height: 20px;
line-height: 20px;
img {
width: 16px;
height: 15px;
box-sizing: border-box;
margin-right: 2px;
}
.purchase-text {
.text-size(12);
margin-right: 6px;
}
}
.purchase-count-end {
position:absolute;
left: 90px;
top: 14px;
display: flex;
flex-flow: row nowrap;
align-items: center;
background: linear-gradient(to right,#F58C00,#EC1500);
border-radius: 25px;
color: #FFFFFF;
padding: 0 10px 0 3px;
height: 20px;
line-height: 20px;
img {
width: 16px;
height: 15px;
box-sizing: border-box;
margin-right: 2px;
}
.purchase-text {
font-size: #fff;
.text-size(12);
margin-right: 6px;
}
}
}
&-special-column {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: @padding-sm/2 @padding-sm;
.content {
width: @lritem-width;
display: flex;
flex-direction: column;
flex-shrink: 0;
border-radius: @border-radius;
overflow: hidden;
.special-cover-img {
width: @lritem-width;
height: 58px;
display: block;
}
.my-swipe {
background: #fff;
height: 220px;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
overflow: hidden;
&-item{
display: flex;
flex-flow: row wrap;
justify-content: space-between;
align-content: flex-start;
padding: 0 @padding-xs;
box-sizing: border-box;
&-con {
display: flex;
flex-direction: column;
position: relative;
img {
width: 76px;
height: 76px;
border-radius: 5px;
display: block;
}
}
&-money{
margin: 5px auto;
display: flex;
align-items: flex-start;
user-select: none;
span {
&:nth-child(1) {
.text-size(10);
color: @red-light;
font-weight: bold;
}
&:nth-child(2) {
.text-size(14);
line-height: 16px;
color: @red-light;
font-weight: bold;
}
}
}
}
.custom-indicator {
position: relative;
right: 0;
left: 0;
bottom: 12px;
text-align: center;
font-size: 12px;
background: #e5e5e5;
max-width: 36px;
margin: 0 auto;
height:4px;
border-radius: 25px;
&-in{
position: absolute;
left: 0;
top:0;
background:linear-gradient(to right, rgba(255, 75, 0, 1), rgba(255, 119, 5, 1));
width: 0px;
min-height:4px;
position: relative;
border-radius: 25px;
}
}
}
}
}
}
$lritem-width: 172px;
$border-radius: 8px;
.main-box {
height: 100%;
width: 100%;
overflow: hidden;
.main-box-container {
height: 100%;
.content{
.goods-card {
margin: 0 $padding-sm;
#{$deep} .home-list-container {
padding-top: 12px;
}
}
}
}
&-bn {
box-sizing: border-box;
position: relative;
&-swiper {
height: 100%;
position: relative;
background-image: linear-gradient($white, $gray-1);
.hb-swiper-item {
display: flex;
justify-content: center;
.hbs-item-img {
width: calc(100% - $padding-sm * 2) !important;
height: 100%;
border-radius: $border-radius-md;
}
}
.main-box-bn-dots {
display: flex;
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
.hb-dots-item {
width: 6px;
height: 6px;
border-radius: $border-radius-max;
background: rgba(255, 255, 255, 0.5);
margin-right: $padding-xs;
}
.hb-dots-item_selected {
height: 6px;
width: 6px;
border-radius: $border-radius-sm;
background: $white;
}
}
}
}
&-container {
height: calc(100% - 46px);
&-body {
padding: $padding-sm;
}
}
&-nav {
// background: $white;
border-radius: $border-radius-md;
display: flex;
align-items: center;
flex-wrap: wrap;
align-content: flex-start;
padding: $padding-sm/2 $padding-sm;
// margin-bottom: $padding-sm;
max-height: 180px;
.my-nav-swipe {
max-height: 180px;
width: 100%;
&-item {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-content: flex-start;
flex-direction: column;
flex-wrap: wrap;
max-height: 180px;
}
.custom-indicator {
position: relative;
right: 0;
left: 0;
bottom:0px;
text-align: center;
font-size: 12px;
background: #e5e5e5;
max-width: 36px;
margin: 0 auto;
height:4px;
border-radius: 25px;
&-in{
position: absolute;
left: 0;
top:0;
background:linear-gradient(to right, rgba(255, 75, 0, 1), rgba(255, 119, 5, 1));
width: 0px;
min-height:4px;
position: relative;
border-radius: 25px;
}
}
}
.hn-item {
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: $padding-sm;
width: 20%;
text-align: center;
@mixin text-size(12),
line-height: 16px !important,
color: $gray-5,
white-space: nowrap,
&-imgbox {
width: 48px,
height: 48px,
display: flex,
align-items: center,
justify-content:center,
img {
display: block,
max-width: 100%,
max-height: 100%,
border-radius: $gray-1,
}
}
&-title {
display: block,
width: 100%,
height: 16px,
line-height: 16px,
text-align: center,
overflow: hidden,
text-overflow: ellipsis,
white-space: nowrap,
color: $font-color-dark,
.text-size(10),
}
}
}
&-welfare {
font-size: 0,
display: flex,
align-content: flex-start,
padding: $padding-sm/2 $padding-sm ,
box-sizing: border-box,
&-item {
flex: 1,
img {
height: 130px,
width: 100%,
display: block,
}
}
}
&-tonglans {
margin: $padding-sm/2 $padding-sm ,
img {
border-radius: $border-radius-md,
display: block,
width: 100%,
}
}
&-find {
display: flex,
justify-content: space-between,
padding: $padding-sm/2 $padding-sm 0 $padding-sm,
box-sizing: border-box,
&-item {
width: $lritem-width,
height: 145px,
img {
display: block,
width: 100%,
height: 100%,
}
}
}
&-chip {
display: flex,
justify-content: space-between,
padding: $padding-sm/2 $padding-sm,
&-left {
width: $lritem-width,
border-radius: $border-radius,
overflow: hidden,
position: relative,
z-index: 1,
.my-swipes {
height: 260px,
width: $lritem-width,
border-radius: $border-radius,
overflow: hidden,
img {
height: 260px,
width: $lritem-width,
display: block,
}
}
}
&-right {
display: flex,
justify-content: space-between,
flex-direction: column,
img {
width: $lritem-width,
height: 82px,
display: block,
border-radius: $border-radius,
}
}
}
&-special-row{
display: flex,
flex-direction: column,
padding: $padding-sm/2 $padding-sm,
img {
width: 100%,
display: block,
}
.special-row-con {
background: #fff,
border-bottom-left-radius: 8px,
border-bottom-right-radius: 8px,
overflow: hidden,
padding: 0 16px,
.content{
display: flex,
overflow-x: scroll,
overflow-y: hidden,
&::-webkit-scrollbar {
display: none,
width: 0px,
}
&-wrapper {
display: flex,
flex-flow: row nowrap,
height: 110px,
&::-webkit-scrollbar {
width: 0 !important,
display: none,
}
}
&-wrapper-rushpurchase {
overflow-x: scroll,
overflow-y: hidden,
display: flex,
flex-flow: row nowrap,
height: 120px,
&::-webkit-scrollbar {
width: 0 !important,
display: none,
}
}
&-item {
display: flex,
flex-direction: column,
justify-content: center,
align-items: center,
margin-bottom: 6px,
width: 25%,
flex-shrink: 0,
.special-row-img {
width: 76px,
height: 76px,
border-radius: $border-radius,
}
.special-row-money {
margin: 5px auto 0 auto,
display: flex,
align-items: flex-start,
span {
&:nth-child(1) {
@mixin text-size(10),
color: $red-light,
font-weight: bold,
}
&:nth-child(2) {
@include text-size(14);
line-height: 16px;
color: $red-light;
font-weight: bold;
}
}
}
.special-row-saleprice {
margin: 0 auto;
display: flex;
align-items: flex-start;
@include text-size(12);
color: #999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-indent: -1px;
}
}
}
.rushpurchase-content {
height: 116px;
}
.progress {
margin:0 auto 10px auto;
width:36px;
}
}
}
&-special-wrapper {
border-radius: $border-radius;
overflow: hidden;
position: relative;
.purchase-count-start {
position:absolute;
left: 90px;
top: 14px;
display: flex;
flex-flow: row nowrap;
align-items: center;
background: #FEE8E2;
border-radius: 25px;
color: #FF1515;
padding: 0 10px 0 3px;
height: 20px;
line-height: 20px;
img {
width: 16px;
height: 15px;
box-sizing: border-box;
margin-right: 2px;
}
.purchase-text {
@include text-size(12);
margin-right: 6px;
}
}
.purchase-count-end {
position:absolute;
left: 90px;
top: 14px;
display: flex;
flex-flow: row nowrap;
align-items: center;
background: linear-gradient(to right,#F58C00,#EC1500);
border-radius: 25px;
color: #FFFFFF;
padding: 0 10px 0 3px;
height: 20px;
line-height: 20px;
img {
width: 16px;
height: 15px;
box-sizing: border-box;
margin-right: 2px;
}
.purchase-text {
font-size: #fff;
@mixin text-size(12),
margin-right: 6px,
}
}
}
&-special-column {
display: flex,
flex-flow: row nowrap,
justify-content: space-between,
padding: $padding-sm/2 $padding-sm,
.content {
width: $lritem-width,
display: flex,
flex-direction: column,
flex-shrink: 0,
border-radius: $border-radius,
overflow: hidden,
.special-cover-img {
width: $lritem-width,
height: 58px,
display: block,
}
.my-swipe {
background: #fff,
height: 220px,
border-bottom-left-radius: 8px,
border-bottom-right-radius: 8px,
overflow: hidden,
&-item{
display: flex,
flex-flow: row wrap,
justify-content: space-between,
align-content: flex-start,
padding: 0 $padding-xs,
box-sizing: border-box,
&-con {
display: flex,
flex-direction: column,
position: relative,
img {
width: 76px,
height: 76px,
border-radius: 5px,
display: block,
}
}
&-money{
margin: 5px auto,
display: flex,
align-items: flex-start,
user-select: none,
span {
&:nth-child(1) {
@mixin text-size(10),
color: $red-light,
font-weight: bold,
}
&:nth-child(2) {
@include text-size(14);
line-height: 16px;
color: $red-light;
font-weight: bold;
}
}
}
}
.custom-indicator {
position: relative;
right: 0;
left: 0;
bottom: 12px;
text-align: center;
font-size: 12px;
background: #e5e5e5;
max-width: 36px;
margin: 0 auto;
height:4px;
border-radius: 25px;
&-in{
position: absolute;
left: 0;
top:0;
background:linear-gradient(to right, rgba(255, 75, 0, 1), rgba(255, 119, 5, 1));
width: 0px;
min-height:4px;
position: relative;
border-radius: 25px;
}
}
}
}
}
}
<template>
<view class="empty">
<image class="empty-image" src="https://img.lkbang.net/xcx/empty.png" />
<text class="empty-text">购物车空空如也~</text>
</view>
</template>
<style lang="scss">
.empty {
text-align: center;
width: 710rpx;
height: 422rpx;
margin: auto;
background-color: $white;
text-align: center;
margin-top: 20rpx;
border-radius: $uni-border-radius-lg;
padding-top: 24rpx;
&-image {
display: block;
margin: auto;
width: 260rpx;
height: 240rpx;
margin-bottom: 82rpx;
}
&-text {
font-size: $uni-font-size-lg;
color: $font-color-base;
}
}
</style>
<template>
<view v-if="!manageCartState && activityInfo.length" class="activity">
<view
:class="['activity-list', { init: end }]"
:style="{ transform: 'translateY(' + -lampY + 'rpx)' }"
>
<view
v-for="item in activityInfo"
:key="item.activityDesc"
class="activity-list-detail"
@click="goSpecialList(item)"
>
<view class="activity-list-name">
<image src="https://img.lkbang.net/xcx/couponicon.png" class="activity-list-icon" />
<text>{{ item.activityDesc }}</text>
</view>
<text style="color: #333"
>查看更多商品<text class="iconfont icon-arrow" style="color: #c8c9cc"
/></text>
</view>
</view>
</view>
</template>
<script>
import { mapState } from "../shopCartModules.js";
export default {
props: {
isActivity: {
type: Boolean,
default: true
}
},
data() {
return {
setInterval: null,
lampY: 0,
height: 0,
end: false,
boxHeight: 76
};
},
computed: {
...mapState(["activityInfo", "manageCartState"])
},
watch: {
activityInfo: {
deep: true,
immediate: true,
handler(value) {
clearInterval(this.setInterval);
if (!this.activityInfo.length) return;
this.$nextTick(() => {
this.height = value.length * 76;
this.setInterval = setInterval(this.marquee, 3000);
});
}
},
isActivity(v) {
if (v) {
if (this.activityInfo.length) {
clearInterval(this.setInterval);
this.setInterval = setInterval(this.marquee, 3000);
}
} else {
clearInterval(this.setInterval);
}
}
},
methods: {
marquee() {
if (this.lampY + this.boxHeight >= this.height) {
this.end = true;
this.lampY = 0;
} else {
this.end = false;
this.lampY += this.boxHeight;
}
},
goSpecialList(item) {
// 跳转活动专题并带参数activity
uni.navigateTo({
url: `/pages/activityProduct/index?activityId=${item.activityId}&activityDesc=${item.activityDesc}&activityLimitAmt=${item.activityLimitAmt}`
});
}
}
};
</script>
<style lang="scss">
.activity {
position: fixed;
z-index: 2;
left: 0;
width: 100vw;
height: 76rpx;
overflow: hidden;
margin: auto;
font-size: 28rpx;
padding: 0 30rpx 0 20rpx;
color: $font-color-base;
background-color: #f7f8fa;
&-list {
transition-timing-function: ease;
transition-duration: 0.3s;
transition-property: all;
&-icon {
width: 44rpx;
height: 36rpx;
margin-right: 8rpx;
}
&-name {
display: flex;
// align-items: center;
align-content: center;
color: #333;
font-weight: bold;
}
&-detail {
display: flex;
align-items: center;
align-content: center;
justify-content: space-between;
padding: 0 8rpx;
width: 100%;
height: 76rpx;
background: #ffffff;
background-image: url("https://img.lkbang.net/xcx/rectangle.png");
background-repeat: no-repeat;
background-size: auto 100%;
background-position: -5% 0;
}
}
.init {
transition-duration: 0s;
}
}
</style>
<template>
<view class="good-del">
<uni-popup ref="popup" type="dialog">
<uni-popup-dialog
mode="base"
message="成功消息"
:duration="2000"
:before-close="true"
type="info"
cancel-txt="再想想"
confirm-txt="删除"
content="确定要删除这些商品吗?"
:show-title="false"
@cancel="close"
@confirm="confirm"
>
确定要删除这些商品吗?
</uni-popup-dialog>
</uni-popup>
</view>
</template>
<script>
import uniPopupDialog from "@/components/uni-popup/uni-popup-dialog.vue";
import { mapActions } from "../shopCartModules";
export default {
name: "GoodDel",
components: {
uniPopupDialog
},
props: {
show: {
type: Boolean,
default() {
return false;
}
}
},
watch: {
show: function(val) {
if (val) {
this.$refs?.popup?.open();
} else {
this.$refs?.popup?.close();
}
}
},
methods: {
...mapActions({
delCartGood: "del_cart_good"
}),
close() {
this.$emit("close");
},
confirm() {
this.$emit("close");
this.delCartGood();
}
}
};
</script>
<style lang="scss">
.uni-dialog-button-text {
color: #333;
}
</style>
<template>
<view class="footer-disCounts">
<uniPopup
ref="uniPopup"
class="discounts-popup"
title="金额明细"
type="bottom"
closeable
@change="closeDisCountsDialog"
>
<view class="discounts-detail">
<view class="detail-list">
<text>商品金额</text>
<text>优惠金额</text>
<!-- <text>运费金额</text> -->
</view>
<view class="detail-list list-right">
<text class="list-right-order-amount">{{ calcFeeInfo.totalSkuFee }}</text>
<text
:class="[
'list-right-coupon-amount',
{ 'list-right-coupon-amount_val': calcFeeInfo.totalCouponFee }
]"
>{{ calcFeeInfo.totalCouponFee || 0 }}</text
>
<!-- <text :class="{ 'list-right-freight-amount': calcFeeInfo.totalFreightFee }">{{
calcFeeInfo.totalFreightFee || "免运费"
}}</text> -->
</view>
</view>
</uniPopup>
</view>
</template>
<script>
import uniPopup from "@/components/uni-popup/uni-popup.vue";
import { mapState } from "../shopCartModules";
export default {
components: {
uniPopup
},
props: {
value: {
type: Boolean,
default: false
}
},
computed: {
...mapState(["calcFeeInfo"])
},
watch: {
value: function(val) {
if (val) {
this.$refs?.uniPopup?.open();
} else {
this.$refs?.uniPopup?.close();
}
}
},
methods: {
closeDisCountsDialog(obj) {
this.$emit("close", obj);
}
}
};
</script>
<style lang="scss" scoped>
.footer-disCounts {
.discounts-detail {
// height: 486rpx;
height: 346rpx;
width: 750rpx;
background-color: $white;
display: flex;
box-sizing: border-box;
justify-content: space-between;
padding: 0 $padding-lg;
border-top: 1rpx solid #f2f3f5;
.detail-list {
display: flex;
width: 50%;
justify-content: flex-start;
flex-direction: column;
flex-shrink: none;
font-size: $uni-font-size-base;
color: $font-color-dark;
line-height: 100rpx;
}
.list-right {
align-items: flex-end;
font-size: $uni-font-size-base;
&-order-amount::before,
&-freight-amount::before,
&-coupon-amount::before {
content: "¥";
}
&-coupon-amount_val {
color: $font-color-search;
&::before {
content: "-¥";
}
}
}
}
}
</style>
<template>
<view class="good">
<view class="good-radio-box" @click="changeSelectStatus">
<radio class="good-radio" :checked="value.selected" color="#EC1500" />
<view class="good-radio-cover" />
</view>
<image :src="value.skuImg" lazy-load class="good-img" @click="goDetail" />
<view class="good-info" @click="goDetail">
<view class="good-title-wrap">
<good-title :value="value" />
<good-tag :value="value.tagList" />
</view>
<view class="good-footer" @click.stop="() => {}">
<text class="good-footer-price">{{ value.salePrice }}</text>
<good-num
ref="goodNum"
:value="count"
:min="1"
:item="value"
:max="maxNum.num"
disabled-input
:class="['good-footer-num']"
@change="changeGoodNum"
@click.native.stop="stopPropagation"
@onClickInputBox="clickInputBox"
/>
<!-- :can-add="value.canAdd" -->
</view>
</view>
</view>
</template>
<script>
import GoodTitle from "./goodTitle.vue";
import GoodTag from "./goodTag.vue";
import GoodNum from "./goodNum.vue";
import { mapActions } from "../shopCartModules";
import { debounce } from "@/utils";
export default {
name: "GoodItem",
components: {
GoodTag,
GoodTitle,
GoodNum
},
props: {
value: {
type: Object,
default() {
return {};
}
},
index: {
type: Number
}
},
data() {
return {
count: this.value?.count ?? 0,
canAdd: this.value.canAdd ?? true
};
},
computed: {
maxNum() {
const v = this.value;
let num = 99999999;
let type = 1; // 1库存,2普通限购,3,每日限购,4活动限购
if (v) {
// 库存
if (v.stock && v.stock > 0) {
num = Math.min(v.stock + 1, num);
}
// 活动限购数量
if (v.activityCanBuyCount) {
num = Math.min(v.activityCanBuyCount, num);
type = 4;
}
// 每日限购
else if (v.commonLimitCount !== undefined) {
num = Math.min(v.commonLimitCount, num);
type = 3;
}
// 普通限购
else if (v.limitCount) {
num = Math.min(v.limitCount, num);
type = 2;
}
}
return {
num,
type
};
}
},
watch: {
value: function(val) {
this.count = val.count;
}
},
methods: {
...mapActions({
selectCartGood: "select_cart_good",
changeCartGoodNum: "change_cart_good_num"
}),
changeSelectStatus() {
const goodInfo = { ...this.value, selected: !this.value.selected };
this.selectCartGood({ index: this.index, goodInfo });
},
changeGoodNum: debounce(async function(count, type) {
const goodInfo = { ...this.value, count, skuNum: Math.abs(count - this.value.count) };
if (!type) return; // 页面初始化的时候
const result = await this.changeCartGoodNum({ index: this.index, goodInfo, type });
if (result && !result.canAdd) {
this.$refs.goodNum && (this.$refs.goodNum.inputValue = this.value.count);
}
}, 500),
clickInputBox() {
this.$emit("openEditNumDialog", this.index, this.value);
},
goDetail() {
debounce(
uni.navigateTo({
url: `/pages/product/goodDetail?skuNo=${this.value.skuId}&count=${
this.value.count
}&receiverId=&goodsName=${encodeURIComponent(this.value.skuName)}&goodsImage=${
this.value.skuImg
}`
}),
300
);
},
stopPropagation(e) {
e.stopPropagation();
}
}
};
</script>
<style lang="scss">
.good {
display: flex;
width: 704rpx;
background: $white;
align-items: center;
padding: $padding-md;
border-radius: $border-radius-base;
// margin-top: 20px;
&-radio {
transform: scale(0.7);
}
&-radio-box {
position: relative;
}
&_radio--cover {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
}
&-img {
width: 200rpx;
height: 200rpx;
flex-shrink: 0;
margin: 0 $margin-md;
border-radius: $border-radius-md;
}
&-info {
flex: 1;
width: 400rpx;
display: flex;
min-height: 200rpx;
flex-direction: column;
justify-content: space-between;
}
&-footer {
display: flex;
align-items: center;
margin-top: $margin-base;
justify-content: space-between;
&-price {
font-weight: bold;
font-size: $line-height-md;
color: $font-color-red;
&::before {
content: "¥";
font-size: $font-sm;
}
}
}
}
</style>
<template>
<uni-popup ref="popupLimit" type="center" :mask-click="false">
<view class="limit-box">
<view class="limit-box-title">以下商品已限制售卖数量,现需按照限购数量购买,请确认:</view>
<scroll-view scroll-y="true" class="limit-box-list">
<view v-for="(item, i) in list" :key="i" class="LBL-item">
<image class="LBL-item-img" :src="item.skuImg" />
<view class="LBL-item-proinfo">
<view class="LBL-item-proinfo-name">
{{ item.skuName }}
</view>
<view class="LBL-item-proinfo-nums">
<text class="LBL-IPN-limit">限购{{ item.commonLimitCount }}</text>
<text class="LBL-IPN-count">x{{ item.count }}</text>
</view>
</view>
</view>
</scroll-view>
<view class="limit-box-btns">
<view class="limit-box-btns-btn" @click="onCancle">取消</view>
<view class="limit-box-btns-btn" @click="onBuy">继续购买</view>
</view>
</view>
</uni-popup>
</template>
<script>
export default {
name: "GoodLimitPopup",
props: {
list: {
type: Array,
default: () => []
},
value: {
type: Boolean,
default: false
}
},
watch: {
value(v) {
if (v) {
this.$refs.popupLimit.open();
} else {
this.$refs.popupLimit.close();
}
}
},
methods: {
onCancle() {
this.$emit("input", false);
},
onBuy() {
this.$emit("continueBuy");
}
}
};
</script>
<style lang="scss" scoped>
@import "@/style/var.scss";
.limit-box {
position: fixed;
z-index: 1112;
left: 50%;
top: 50%;
width: 622rpx;
transform: translate(-50%, -50%);
background-color: #ffffff;
border-radius: 32rpx;
padding-top: 48rpx;
box-sizing: border-box;
font-size: 32rpx;
&-title {
color: #000;
text-align: center;
line-height: 40rpx;
padding: 0 48rpx;
}
&-list {
margin-top: 20rpx;
padding: 10rpx 48rpx 20rpx 48rpx;
max-height: 476rpx;
overflow-x: hidden;
overflow-y: auto;
.LBL-item {
height: 112rpx;
display: flex;
justify-content: space-between;
margin-bottom: 24rpx;
&-img {
display: block;
width: 112rpx;
height: 112rpx;
border-radius: 10rpx;
overflow: hidden;
}
&-proinfo {
padding-left: 16rpx;
width: 400rpx;
&-name {
font-size: 24rpx;
color: #999;
line-height: 32rpx;
@include mx_multline_overwrite();
}
&-nums {
padding-top: 20rpx;
display: flex;
justify-content: space-between;
font-size: 24rpx;
.LBL-IPN-limit {
color: #ec1500;
}
}
}
&:last-child {
margin: 0;
}
}
}
&-btns {
display: flex;
height: 96rpx;
&-btn {
flex: 1;
color: #333333;
display: flex;
align-items: center;
justify-content: center;
&:nth-child(2) {
color: #ec1500;
border-left: 1rpx solid #ebedf0;
}
}
}
}
</style>
<template>
<view class="uni-numbox">
<view class="uni-numbox__minus" @click="_calcValue('minus')">
<text
class="uni-numbox--text"
:class="{ 'uni-numbox--disabled': inputValue <= min || disabled }"
>-</text
>
</view>
<view v-if="disabled || disabledInput" class="uni-numbox__value">{{ inputValue }}</view>
<input
v-else
v-model="inputValue"
:disabled="disabled || disabledInput"
class="uni-numbox__value"
type="number"
@blur="_onBlur"
@click="_onClickInputBox"
/>
<view class="uni-numbox__plus" @click="_calcValue('plus')">
<text
class="uni-numbox--text"
:class="{ 'uni-numbox--disabled': inputValue >= max || disabled || !canAdd }"
>+</text
>
</view>
</view>
</template>
<script>
/**
* NumberBox 数字输入框
* @description 带加减按钮的数字输入框
* @tutorial https://ext.dcloud.net.cn/plugin?id=31
* @property {Number} value 输入框当前值
* @property {Number} min 最小值
* @property {Number} max 最大值
* @property {Number} step 每次点击改变的间隔大小
* @property {Boolean} disabled = [true|false] 是否为禁用状态
* @event {Function} change 输入框值改变时触发的事件,参数为输入框当前的 value
*/
export default {
name: "UniNumberBox",
props: {
value: {
type: [Number, String],
default: 1
},
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 100
},
item: {
type: Object,
default: () => ({})
},
step: {
type: Number,
default: 1
},
disabled: {
type: Boolean,
default: false
},
disabledInput: {
type: Boolean,
default: false
},
canAdd: {
type: Boolean,
default: true
},
showMaxToast: {
type: Boolean,
default: false
}
},
data() {
return {
inputValue: 0,
changeType: null
};
},
watch: {
value(val) {
this.inputValue = +val;
},
inputValue(newVal, oldVal) {
if (+newVal !== +oldVal) {
this.$emit("change", +newVal || 1, this.changeType);
}
}
},
created() {
this.inputValue = +this.value;
},
methods: {
_calcValue(type) {
if (this.disabled) {
return;
}
const scale = this._getDecimalScale();
let value = this.inputValue * scale;
let step = this.step * scale;
if (type === "minus") {
this.changeType = "REDUCE_NUM";
value -= step;
if (value < this.min * scale) {
return;
}
if (value > this.max * scale) {
value = this.max * scale;
}
} else if (type === "plus") {
if (!this.canAdd) {
return;
}
this.changeType = "ADD_NUM";
value += step;
if (this.item.commonLimitCount !== undefined && value > this.item.commonLimitCount) {
let title = "";
if (this.item.commonLimitCount > 0) {
title = `您当前购买的商品限购${this.item.commonLimitCount}件`;
} else {
title = "今日已用完限购数量";
}
uni.showToast({
title,
duration: 2000,
icon: "none"
});
return;
}
if (value > this.max * scale) {
return;
}
if (value < this.min * scale) {
value = this.min * scale;
}
}
this.inputValue = String(value / 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) {
if (this.showMaxToast) {
uni.showToast({ icon: "none", title: `您当前购买的商品限购${this.max}件` });
}
value = this.max;
} else if (value < this.min) {
value = this.min;
}
this.inputValue = value;
},
_onClickInputBox() {
this.$emit("onClickInputBox");
}
}
};
</script>
<style lang="scss" scoped>
$box-height: 48px;
/* #ifdef APP-NVUE */
$box-line-height: 48px;
/* #endif */
$box-line-height: 48px;
$box-width: 48px;
$input-width: 89px;
$uni-box: 191px;
.uni-numbox {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
height: $box-height;
width: $uni-box;
align-items: center;
/* #ifdef MP-ALIPAY */
width: 96px;
height: 24px;
/* #endif */
}
.uni-numbox__value {
background-color: #f8f8f8;
width: $input-width;
height: $box-height;
text-align: center;
font-size: $uni-font-size-lg;
border-width: 4rpx;
border-style: solid;
border-top-width: 0;
border-bottom-width: 0;
border-color: $white;
line-height: $box-line-height;
position: relative;
z-index: 1;
color: #333;
/* #ifdef MP-ALIPAY */
font-size: 14px;
height: 24px;
line-height: 24px;
width: 45px;
/* #endif */
}
.uni-numbox__minus {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
width: 40px;
flex-direction: row;
align-items: center;
justify-content: center;
width: $box-width;
height: $box-height;
// line-height: $box-line-height;
// text-align: center;
font-size: 20px;
color: $uni-text-color;
border-radius: 8px 0 0 8px;
background-color: $uni-bg-color-grey;
/* #ifdef MP-ALIPAY */
height: 24px;
line-height: 24px;
width: 24px;
/* #endif */
}
.uni-numbox__plus {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
width: 40px;
align-items: center;
justify-content: center;
width: $box-width;
height: $box-height;
border-radius: 0px 4px 4px 0px;
background-color: $uni-bg-color-grey;
/* #ifdef MP-ALIPAY */
height: 24px;
line-height: 24px;
width: 24px;
/* #endif */
}
.uni-numbox--text {
font-size: 40rpx;
color: $uni-text-color;
}
.uni-numbox--disabled {
color: $uni-text-color-disable;
}
</style>
<template>
<view class="good">
<uni-popup ref="popup" type="dialog">
<uni-popup-dialog
message="成功消息"
title="修改购买数量"
:duration="2000"
:before-close="true"
type="info"
@cancel="close"
@confirm="confirm"
>
<uni-number-box
:value="goodCount"
:min="1"
:max="max"
:common-limit-count="max"
show-max-toast
:class="['num']"
@change="changeGoodNum"
/>
</uni-popup-dialog>
</uni-popup>
</view>
</template>
<script>
import uniNumberBox from "./goodNum.vue";
import uniPopupDialog from "@/components/uni-popup/uni-popup-dialog.vue";
import { mapActions } from "../shopCartModules";
import { throtte } from "@/utils";
export default {
name: "GoodNum",
components: {
uniNumberBox,
uniPopupDialog
},
props: {
show: {
type: Boolean,
default() {
return false;
}
},
value: {
type: Object,
default() {
return {};
}
},
index: {
type: Number
}
},
data() {
return {
goodCount: this.value?.count
};
},
computed: {
max() {
let max = 999999999;
let v = this.value;
if (v) {
if (v.activityCanBuyCount) {
max = v.activityCanBuyCount;
} else if (v.commonLimitCount !== undefined) {
max = v.commonLimitCount;
} else if (v.limitCount) {
max = v.limitCount;
}
}
return max;
}
},
watch: {
show: function(val) {
if (val) {
this.goodCount = this?.value?.count;
this.$refs?.popup?.open();
} else {
this.$refs?.popup?.close();
}
}
},
mounted() {
this.$refs.popup.duration = 0; //解决输入框上移问题
},
methods: {
...mapActions({
changeCartGoodNum: "change_cart_good_num"
}),
close() {
this.$emit("close");
},
confirm: throtte(function() {
this.changeCartGoodNum({
index: this.index,
goodInfo: { ...this.value, count: this.goodCount, skuNum: this.goodCount },
type: "EDIT_NUM"
});
this.$emit("close");
}, 2000),
changeGoodNum(count) {
this.goodCount = count;
}
}
};
</script>
<style lang="scss"></style>
<template>
<view class="tagList">
<template v-for="tag in value">
<text
v-if="tag.type === 2"
:key="tag.name"
:text="tag.name"
inverted
type="error"
size="small"
class="tagList-tag"
>{{ tag.name }}</text
>
<image
v-else
:key="tag.name"
:src="tag.icon"
lazy-load
mode="heightFix"
class="tagList-image"
/>
</template>
</view>
</template>
<script>
export default {
props: {
value: {
type: Array,
default() {
return [];
}
}
}
};
</script>
<style lang="scss">
.tagList {
display: flex;
flex-wrap: wrap;
&-tag {
height: 32rpx;
display: flex;
font-size: $uni-font-size-tiny;
justify-content: center;
align-items: center;
margin-top: 8rpx;
border-radius: $uni-border-radius-base;
color: $font-color-search;
padding: 0 $padding-sm;
margin-right: $padding-sm;
border: 1rpx solid $font-color-search;
/* #ifdef MP-ALIPAY */
border-width: 1px;
/* #endif */
::v-deep .uni-tag {
width: 10rpx;
}
}
&-image {
width: auto;
height: 32rpx;
margin-top: 8rpx;
margin-right: $padding-sm;
}
}
</style>
<template>
<view class="good-title">
<view class="good-title-title"
><image v-if="value.goodsTypeImage" :src="value.goodsTypeImage" class="title-tag" />{{
value.skuName
}}</view
>
<view v-if="value.skuAttr" class="good-title-sku">{{ value.skuAttr }}</view>
<img
v-if="value.goods.userBenefitsLabelImgUrl"
:src="value.goods.userBenefitsLabelImgUrl"
class="memberImg"
/>
</view>
</template>
<script>
export default {
name: "GoodTitle",
props: {
value: {
type: Object,
default() {
return {};
}
}
}
// watch: {
// value: {
// deep: true,
// immediate: true,
// handler: function(val) {
// console.log(val);
// }
// }
// }
};
</script>
<style lang="scss">
.good-title {
width: 100%;
font-size: $uni-font-size-md;
color: $font-color-dark;
&-title {
/* #ifdef MP-ALIPAY */
line-height: 36rpx;
/* #endif */
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
.title-tag {
width: 52rpx;
height: 26rpx;
vertical-align: middle;
box-sizing: border-box;
margin-top: -6rpx;
margin-right: $margin-sm;
}
}
&-sku {
margin-top: 4rpx;
max-width: 100%;
display: inline-block;
overflow: hidden;
white-space: nowrap;
color: $text-color-n1;
text-overflow: ellipsis;
padding: 0 $padding-sm;
background-color: #f2f3f5;
border-radius: 4rpx;
font-size: $uni-font-size-sm;
}
}
.memberImg {
width: 132.68rpx;
height: 28rpx;
}
</style>
<template>
<view :class="['manage', { right: manageCartState }]">
<text v-if="!manageCartState">{{ cartTotal }}件商品</text>
<text style="display: flex;align-items: center" @click="openManageCartState">
<text
v-if="!manageCartState"
size="26"
class="iconfont icon-edit"
style="margin-right: 4px;"
/>
<text v-if="!manageCartState">管理购物车</text>
</text>
<text v-if="manageCartState" @click="closeManageCartState">完成</text>
</view>
</template>
<script>
import { mapState, mapActions, mapGetters } from "../shopCartModules.js";
export default {
computed: {
...mapState(["manageCartState"]),
...mapGetters(["cartTotal"])
},
// watch: {
// manageCartState: {
// deep: true,
// immediate: true,
// handler() {
// // console.log(val, "watch");
// }
// }
// },
// created() {
// console.log("this.manageCartState :>> ", this.manageCartState);
// },
methods: {
...mapActions({
openManageCartState: "open_manage_cart_state",
closeManageCartState: "close_manage_cart_state"
})
}
};
</script>
<style lang="scss">
.manage {
width: 100vw;
height: 82rpx;
position: fixed;
top: 0;
left: 0;
z-index: 1;
display: flex;
font-size: 28rpx;
color: $font-color-dark;
justify-content: space-between;
align-items: center;
padding: 0 20rpx;
box-sizing: border-box;
background-color: $uni-bg-color-grey;
}
.right {
justify-content: flex-end;
}
</style>
<template>
<view class="footer-wrap">
<view :class="['footer', { between: manageCartState }]">
<view class="footer-check" @click="allSelect">
<radio color="#EC1500" class="footer-allS" :checked="isSelectedAll" />
<view class="footer-check-label">全选</view>
</view>
<view v-if="!manageCartState" class="footer-detail">
<text class="footer-total"
>合计:<text class="footer-total-num">{{ calcFeeInfo.totalPayFee || "0.00" }}</text></text
>
<view v-if="calcFeeInfo.totalSkuFee" class="footer-discounts" @click="openDisCountsDialog">
<template v-if="calcFeeInfo.totalCouponFee">
已优惠:
<text class="footer-total-discounts">{{ calcFeeInfo.totalCouponFee }}</text> </template
><text class="footer-total-discounts-detail">
优惠明细
<text
:class="[
'iconfont',
{ 'icon-arrow-down': showDisCountsDislog },
{ 'icon-arrow-up': !showDisCountsDislog }
]"/></text
></view>
</view>
<button
v-if="!manageCartState"
class="footer-button-settle"
type="default"
@click="orderSettle"
>
结算{{ selectedNumText }}
</button>
<view v-if="manageCartState">
<button class="footer-button-del" type="default" @click="delGoods">
删除
</button>
</view>
</view>
<good-discounts v-model="showDisCountsDislog" @close="closeDisCountsDialog" />
<good-del-dialog :show="showGoodDelDialog" @close="showGoodDelDialog = false" />
<GoodLimitPopup v-model="isShowLimit" :list="limitGoods" @continueBuy="onContinueBuy" />
</view>
</template>
<script>
import { throtte } from "@/utils";
import { saTrackEvent } from "@/utils/sa";
import { orderConfirm, beforeConfirmCheck } from "@/api/shopCart.api";
import { mapActions, mapState, mapGetters } from "../shopCartModules";
import goodDiscounts from "./goodDiscounts.vue";
import GoodDelDialog from "./goodDelConfirm";
import GoodLimitPopup from "./goodLimitPopup.vue";
export default {
components: {
GoodDelDialog,
goodDiscounts,
GoodLimitPopup
},
data() {
return {
isFree: false,
isShowLimit: false,
limitGoods: [],
showGoodDelDialog: false,
showDisCountsDislog: false
};
},
computed: {
...mapState(["manageCartState", "calcFeeInfo"]),
...mapGetters(["isSelectedAll", "selectedList"]),
selectedNumText: function() {
return this.selectedList.length ? `(${this.selectedList.length})` : "";
}
},
methods: {
...mapActions({
selectAllCartGood: "select_all_cart_good",
delCartGood: "del_cart_good"
}),
openDisCountsDialog() {
this.showDisCountsDislog = !this.showDisCountsDislog;
},
closeDisCountsDialog({ show }) {
this.showDisCountsDislog = show;
},
allSelect() {
saTrackEvent("MINI_ShoppingCartPageSelectAllBtnClick", { check_or_not: !this.isSelectedAll });
this.$nextTick(() => {
this.selectAllCartGood(!this.isSelectedAll);
});
},
delGoods() {
if (!this.selectedList.length) {
uni.showToast({
title: "您还没有选择要删除的商品哦!",
icon: "none"
});
return;
}
this.showGoodDelDialog = true;
},
orderSettle: throtte(function() {
if (!this.selectedList.length) {
uni.showToast({
title: "您还没有选择商品哦",
icon: "none"
});
return;
}
let sku_nos = [];
let pros = [];
this.selectedList.forEach(item => {
sku_nos.push(item.skuId);
if (
typeof item.product.commonLimitCount === "number" &&
item.product.commonLimitCount < item.skuNum
) {
pros.push(item.product);
}
});
sku_nos = JSON.stringify(sku_nos);
saTrackEvent("MINI_ShoppingCartPageBalanceBtnClick", { sku_nos });
if (pros.length > 0) {
this.limitGoods = pros;
this.isShowLimit = true;
} else {
this.onSettle();
}
}, 2000),
// 继续购买
onContinueBuy() {
this.selectedList.forEach(item => {
if (
typeof item.product.commonLimitCount === "number" &&
item.product.commonLimitCount < item.skuNum
) {
item.skuNum = item.product.commonLimitCount;
}
});
this.onSettle();
},
async checkActivityForNewUserBreakOff() {
try {
let haveNewUserProduct = false;
const arr = this.selectedList;
for (let i = 0; i < arr.length; i++) {
if (arr[i].product && arr[i].product.activityType && arr[i].product.activityType == 8) {
haveNewUserProduct = true;
break;
} else {
continue;
}
}
if (haveNewUserProduct) {
const [res, err] = await beforeConfirmCheck();
if (res) {
return false;
}
if (err) {
return true;
}
} else {
return false;
}
} catch (e) {
return false;
}
},
async onSettle() {
// 检查新人专享商品允许下单情况
if (await this.checkActivityForNewUserBreakOff()) {
return;
}
const [data] = await orderConfirm({ selectedSkuList: this.selectedList });
if (data) {
const that = this;
setTimeout(() => {
uni.navigateTo({
url: `/pages/order/createOrder`,
success: function(res) {
res.eventChannel.emit("onDetailConfirmInfo", {
addrReceiverId: data.addrReceiverInfo?.addrReceiverId,
selectedSkuList: that.selectedList,
defaultUseCoupon: true,
defaultUseFreightFeeCoupon: true,
defaultUseCashCoupon: true,
defaultUseActivityCoupon: true,
defaultUseGiftCard: true,
couponActivityUseIdList: []
});
}
});
}, 200);
}
}
}
};
</script>
<style lang="scss" scoped>
.footer-wrap {
height: 120rpx;
width: 100vw;
position: fixed;
left: 0;
bottom: 0;
z-index: 1;
.footer {
width: 100%;
height: 100%;
display: flex;
position: relative;
z-index: 98;
align-items: center;
color: $text-color-n1;
background-color: $white;
font-size: $uni-font-size-sm;
padding: $padding-md 24rpx;
border-top: 1rpx solid $border-color-gray;
&-allS {
transform: scale(0.7);
}
.iconfont {
font-size: $uni-font-size-base;
vertical-align: bottom;
}
&-detail {
flex: 1;
text-align: right;
padding-right: $padding-md;
}
&-total {
color: $font-color-dark;
&-num {
font-size: $uni-font-size-lg;
font-weight: bold;
color: $font-color-search;
&::before {
content: "¥";
font-size: $uni-font-size-base;
}
}
&-discounts {
color: $font-color-search;
display: inline-block;
&::before {
content: "¥";
}
}
&-discounts-detail {
padding-left: $margin-md;
color: $font-color-search;
}
}
&-button-settle {
width: 260rpx;
background: $background-primary !important;
border-radius: $uni-border-radius-xl;
font-size: $line-height-md;
color: $white;
border: none;
}
&-button-del {
width: 174rpx;
background: $white !important;
border-radius: $uni-border-radius-xl;
font-size: $line-height-md;
color: $font-color-search;
border: 2rpx solid;
}
}
.between {
justify-content: space-between;
}
.footer-check {
position: relative;
height: 42rpx;
display: flex;
align-items: center;
&-label {
position: absolute;
z-index: 1;
left: 0;
top: 0;
padding-left: 50rpx;
width: 100rpx;
height: 42rpx;
box-sizing: border-box;
display: flex;
align-items: center;
}
}
}
</style>
<template>
<view class="shopping">
<GoodsManage v-if="cartCount && cartList.length" class="shopping-manage" />
<scroll-view
:key="cartList.length"
class="shopping-list"
:class="{ haveSettle: validCount }"
scroll-y
>
<template v-if="cartCount">
<template v-if="cartList.length">
<view class="shopping-good-wrap">
<GoodActivity class="shopping-good-activity" :is-activity="isActivity" />
<view v-if="hasActivity && !manageCartState" class="divider" />
<view
class="shopping-goods"
:class="hasActivity && !manageCartState ? 'hasActivity' : 'noHasActivity'"
>
<view
v-for="(goodInfo, goodIndex) in cartList"
:key="goodIndex"
class="shopping-good-swipe"
>
<uni-swipe-action-item
:right-options="options"
:swipeaction="swipeaction"
auto-close
@closeOther="closeOther"
@click="delGood([goodInfo])"
>
<Goods
:key="goodIndex"
:value="goodInfo"
:index="goodIndex"
@openEditNumDialog="openEditNumDialog"
@change="changeGoodSelectStatus"
/>
</uni-swipe-action-item>
</view>
</view>
</view>
</template>
<DisabledGoods />
</template>
<Empty v-else />
<LikeGoodList :goods-list.sync="goodsList" title="猜你喜欢" />
</scroll-view>
<GoodsSettle v-if="cartList.length" class="shopping-settle" />
<edit-goodNum-dialog
:show="editNumDialog"
:value="editGoodInfo"
:index="editGoodIndex"
@close="closeEditNumDialog"
/>
<login-popup ref="login-popup" type="center" title="用户授权登录" @change="loginChange" />
</view>
</template>
<script>
import GoodsSettle from "./components/goodsSettle.vue";
import Goods from "./components/goodItem.vue";
import GoodsManage from "./components/goodsMange.vue";
import Empty from "./components/empty.vue";
import { mapState, mapActions } from "./shopCartModules.js";
import { saTrackEvent } from "@/utils/sa.js";
import GoodActivity from "./components/goodActivity";
import DisabledGoods from "@/components/disabledGoods";
import { shopCartLike } from "@/api/home.api.js";
import LikeGoodList from "../product/components/goodsCard.vue";
import uniSwipeActionItem from "@/components/uni-swipe-action-item/index";
import editGoodNumDialog from "./components/goodNumEdit";
import { getCartCountVal } from "../../mixins/common.js";
import loginPopup from "@/components/loginPopup";
export default {
components: {
Empty,
Goods,
GoodsSettle,
GoodsManage,
GoodActivity,
DisabledGoods,
LikeGoodList,
editGoodNumDialog,
uniSwipeActionItem,
loginPopup
},
data() {
return {
show: false,
hasActivity: false,
editNumDialog: false,
goodsList: [],
options: [
{
text: "删除",
style: {
backgroundColor: "#F43530"
}
}
],
editGoodInfo: {},
swipeaction: {
children: []
},
isActivity: true,
editGoodIndex: 0
};
},
async onShow() {
this.isActivity = true;
const token = uni.getStorageSync("token") || "";
if (this.$refs["login-popup"]) {
if (!token) {
this.$refs["login-popup"].open();
} else {
this.$refs["login-popup"].close();
}
}
this.initMethods();
},
onLoad() {
uni.$on("cartUpdate", () => {
getCartCountVal();
});
uni.$on("login", isLogin => {
isLogin && this.initMethods();
});
this.loadData();
},
onHide() {
this.isActivity = false;
},
onUnload() {
uni.$off("cartUpdate");
},
onTabItemTap() {
saTrackEvent("MINI_BottomTabsClick", { tab_name: "购物车" });
},
computed: {
...mapState({
cartList: state => state.cartList,
cartCount: state => state.cartCount
}),
...mapState(["activityInfo", "manageCartState"]),
validCount() {
return this.cartList.length;
}
},
watch: {
activityInfo: {
deep: true,
immediate: true,
handler(val) {
if (val.length) {
this.hasActivity = true;
} else {
this.hasActivity = false;
}
}
}
},
methods: {
...mapActions({
delGood: "del_cart_good",
queryList: "query_cart_list",
closeManageCartState: "close_manage_cart_state"
}),
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;
},
initMethods() {
const token = uni.getStorageSync("token") || "";
getCartCountVal();
this.closeManageCartState();
token && this.queryList({ pageNo: 1, pageSize: 1000 });
uni.$emit("updateInvalid");
},
changeGoodSelectStatus() {
// console.log("obj--index", obj, index);
// this.$set(this.goodInfo, index, obj);
},
async loadData() {
// 商品详情没有无限流 只有20条数据
const [res] = await shopCartLike({ pageNo: 1, pageSize: 20, pageType: 3 });
this.goodsList = this.goodsList.concat((res && res.goodsList) || []);
},
closeEditNumDialog() {
this.editNumDialog = false;
},
openEditNumDialog(index, goodInfo) {
this.editGoodIndex = index;
this.editGoodInfo = goodInfo;
this.editNumDialog = true;
},
loginChange({ show }) {
const token = uni.getStorageSync("token") || "";
if (!show && !token) {
this.loginModal();
}
},
loginModal() {
const vm = this;
uni.showModal({
title: "温馨提示",
content: "购物车需要您授权才能使用",
cancelText: "不授权",
confirmText: "重新授权",
confirmColor: "#ec1500",
success: function(res) {
if (res.confirm) {
vm.$refs["login-popup"].open();
} else {
uni.switchTab({
url: "/pages/index/index"
});
}
}
});
}
}
};
</script>
<style lang="scss">
.shopping {
height: 100vh;
padding: 0 12rpx 0 20rpx;
// padding-top: 82rpx;
overflow: auto;
box-sizing: border-box;
&-good-wrap {
padding-top: 82rpx;
}
&-good-activity {
position: fixed;
z-index: 2;
}
// &-manage {
// width: 710rpx;
// height: 82rpx;
// position: fixed;
// top: 0;
// z-index: 2;
// }
&-list {
// margin-top: -20px;
/* height: calc(100vh - 82rpx); */
height: 100vh;
&.haveSettle {
height: calc(100vh - 82rpx - 25rpx);
}
}
&-goods {
// max-height: 1200rpx;
overflow: auto;
padding: 0 0rpx 22rpx 0rpx;
background-color: $uni-bg-color-grey;
}
&-good-swipe {
margin-bottom: $margin-base;
}
// .shopping-settle {
// position: fixed;
// bottom: 0;
// left: 0;
// width: 100%;
// z-index: 3;
// height: 114rpx;
// }
.hasActivity {
margin-top: 50px;
}
.noHasActivity {
margin-top: 0px;
}
.divider {
height: 8px;
width: 100%;
background-color: #f7f8fa;
z-index: 2;
position: fixed;
margin-right: 10rpx;
top: 150rpx;
}
}
</style>
import { createNamespacedHelpers } from "vuex";
const { mapState, mapActions, mapGetters, mapMutations } = createNamespacedHelpers("shopCart");
export { mapState, mapActions, mapGetters, mapMutations };
<template>
<view class="home">这里是test 页面</view>
</template>
<script></script>
export const jverificationInit = function() {
return new Promise(resolve => {
console.log(window.JVerificationInterface);
window.JVerificationInterface.init({
appkey: '1f70875fc3941d8f1964eb63', // 极光官网中创建应用后分配的 appkey,必填
debugMode: true, // 设置是否开启 debug 模式。true 则会打印更多的日志信息。设置 false 则只会输出 w、e 级别的日志
fail: function(data) {
resolve(data);
},
success: function(data) {
resolve(data);
}
});
});
};
export const isJverificationInitSuccess = function() {
// 是否成功初始化
var succ = window.JVerificationInterface.isInitSuccess();
return succ;
};
// 获取运营商token
export const getJverificationToken = function() {
return new Promise(resolve => {
window.JVerificationInterface.getToken({
success: function(data) {
console.log(data, 'getTokenSuccess');
resolve(data);
},
fail: function(data) {
console.log(data, 'getTokenFailed');
resolve(data);
}
});
});
};
// 认证登录
export const jverificationLogin = function() {
return new Promise(resolve => {
window.JVerificationInterface.loginAuth({
type: 'dialog', //可填全屏:full,弹窗:dialog,不填默认全屏
fail: function(data) {
console.log('JVerificationInterface loginAuth fail:' + JSON.stringify(data));
resolve(data);
},
success: function(data) {
var token = data.content;
console.log('JVerificationInterface loginAuth success:' + token);
resolve(data);
}
});
});
};
import Vue from 'vue';
// import store from '../store';
import {
Button,
Image,
Icon,
Cell,
CellGroup,
Radio,
RadioGroup,
Dialog,
Popup,
Overlay,
Divider,
Loading,
Toast,
NavBar,
Field,
Checkbox,
List,
Form,
Sticky,
Tab,
Tabs,
Empty,
Swipe,
SwipeItem,
Search,
Tabbar,
TabbarItem,
BackTop,
Stepper,
CouponList,
Switch,
Collapse,
CollapseItem,
Uploader,
IndexList,
IndexListItem,
Tag,
ActionSheet,
Steps,
Step,
Notify,
CountDown,
PwdField,
AuthcodeField,
Skeleton,
Card,
Progress,
GoodsAction,
NoticeBar,
SwipeCell,
Grid,
GridItem,
ImagePreview,
DropdownMenu,
DropdownItem,
Rate,
PullRefresh,
Col,
Row
} from '@qg/cherry-ui';
import DialogFn from '@qg/cherry-ui/src/dialog/func';
// import "@qg/cherry-ui/dist/cherry.css";
Vue.use(NavBar);
Vue.use(Button);
Vue.use(Image);
Vue.use(Cell);
Vue.use(CellGroup);
Vue.use(Radio);
Vue.use(RadioGroup);
Vue.use(Popup);
Vue.use(Divider);
Vue.use(Toast);
Vue.use(Field);
Vue.use(Dialog);
Vue.use(Checkbox);
Vue.use(Form);
Vue.use(Icon);
Vue.use(Sticky);
Vue.use(Overlay);
Vue.use(Loading);
Vue.use(List);
Vue.use(Tab);
Vue.use(Tabs);
Vue.use(Empty);
Vue.use(Swipe);
Vue.use(SwipeItem);
Vue.use(Search);
Vue.use(Tabbar);
Vue.use(TabbarItem);
Vue.use(Stepper);
Vue.use(BackTop);
Vue.use(CouponList);
Vue.use(Switch);
Vue.use(Collapse);
Vue.use(CollapseItem);
Vue.use(Uploader);
Vue.use(IndexList);
Vue.use(IndexListItem);
Vue.use(Tag);
Vue.use(ActionSheet);
Vue.use(Steps);
Vue.use(Step);
Vue.use(Notify);
Vue.use(CountDown);
Vue.use(PwdField);
Vue.use(AuthcodeField);
Vue.use(Skeleton);
Vue.use(Card);
Vue.use(Progress);
Vue.use(GoodsAction);
Vue.use(NoticeBar);
Vue.use(SwipeCell);
Vue.use(Grid);
Vue.use(GridItem);
Vue.use(ImagePreview);
Vue.use(DropdownMenu);
Vue.use(DropdownItem);
Vue.use(Rate);
Vue.use(PullRefresh);
Vue.use(Col);
Vue.use(Row);
// const _proto = Vue.prototype;
// const proto = Object.create(_proto);
// proto.$notify = option => {
// option.customClass = store.state.pay.header ? 'has-header' : '';
// return _proto.$notify(option);
// };
// Vue.prototype = proto;
Vue.prototype.$dialog = DialogFn;
// tslint:disable
import Bridge from '@qg/js-bridge';
import { isApp } from './validation.service';
// RGB转HEX
export function rgbToHex(r, g, b) {
const hex = ((r << 16) | (g << 8) | b).toString(16);
return '#' + new Array(Math.abs(hex.length - 7)).join('0') + hex;
}
// HEX转RGB
export function hexToRgb(hex) {
var rgb = [];
for (let i = 1; i < 7; i += 2) {
rgb.push(parseInt('0x' + hex.slice(i, i + 2)));
}
return rgb;
}
// 计算RGB渐变色色值
export function gradient(startColor, endColor, step) {
// 将 hex 转换为rgb
let sColor = hexToRgb(startColor);
let eColor = hexToRgb(endColor);
// 计算R\G\B每一步的差值
let rStep = (eColor[0] - sColor[0]) / step;
let gStep = (eColor[1] - sColor[1]) / step;
let bStep = (eColor[2] - sColor[2]) / step;
let gradientColorArr = [];
for (let i = 0; i < step; i++) {
// 计算每一步的hex值
gradientColorArr.push(
rgbToHex(
parseInt(rStep * i + sColor[0]),
parseInt(gStep * i + sColor[1]),
parseInt(bStep * i + sColor[2])
)
);
}
return gradientColorArr;
}
export function colorToRgb(color) {
// 16进制颜色值的正则
let reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
// 把颜色值变成小写
color = color.toLowerCase();
if (reg.test(color)) {
// 如果只有三位的值,需变成六位,如:#fff => #ffffff
if (color.length === 4) {
let colorNew = '#';
for (let i = 1; i < 4; i += 1) {
colorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1));
}
color = colorNew;
}
// 处理六位的颜色值,转为RGB
let colorChange = [];
for (let i = 1; i < 7; i += 2) {
colorChange.push(parseInt('0x' + color.slice(i, i + 2)));
}
return 'RGB(' + colorChange.join(',') + ')';
} else {
return color;
}
}
// RGB TO RGBA
export function rgbToRgba(rgb, opacity) {
return rgb.replace(')', `, ${opacity})`);
}
// 判断色值
export function isColor(color) {
var re1 = /^#([0-9a-f]{6}|[0-9a-f]{3})$/i;
var re2 = /^rgb\(([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\\,([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\\,([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\)$/i;
var re3 = /^rgba\(([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\\,([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\\,([0-9]|[0-9][0-9]|25[0-5]|2[0-4][0-9]|[0-1][0-9][0-9])\\,(1|1.0|0.[0-9])\)$/i;
return re2.test(color) || re1.test(color) || re3.test(color);
}
export function setAppTitleColor(bgcolor = '#fff') {
if (!isApp) return;
let jsBridge = new Bridge();
const isGradient = Array.isArray(bgcolor);
let rgbColor = isGradient ? bgcolor[0] : bgcolor;
if (rgbColor.toLocaleLowerCase().indexOf('rgb') === -1) rgbColor = hexToRgb(rgbColor);
const isDarkContent = 0.213 * rgbColor[0] + 0.715 * rgbColor[1] + 0.072 * rgbColor[2] <= 255 / 2;
const colors = isGradient
? [bgcolor[0].substr(1), bgcolor[1].substr(1)]
: [bgcolor.substr(1), bgcolor.substr(1)];
changeColor();
function changeColor() {
if (!jsBridge) return;
try {
const jbInstance = jsBridge.run({
event: 'resetNavigationBarColor',
data: {
isDarkContent,
colors
}
});
if (!jbInstance) {
changeColor();
} else {
jsBridge = null;
}
} catch (error) {
jsBridge = null;
}
}
}
//压缩图片
function compressImg(file) {
let fileSize = parseFloat(parseInt(file['size']) / 1024 / 1024).toFixed(2);
let read = new FileReader();
read.readAsDataURL(file);
return new Promise(function(resolve) {
read.onload = function(e) {
let img = new Image();
img.src = e.target.result;
img.onload = function() {
//默认按比例压缩
let w = this.width,
h = this.height;
//生成canvas
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 创建属性节点
canvas.setAttribute('width', w);
canvas.setAttribute('height', h);
ctx.drawImage(this, 0, 0, w, h);
let ratio = fileSize < 1 ? 0.95 : 0.85;
canvas.toBlob(
blob => {
resolve(blob);
},
'image/jpeg',
ratio
);
};
};
});
}
//结尾处将该方法暴露出来供外部调用
export default {
compressImg
};
import { isDef } from "./utils.service";
import cookies from "js-cookie";
const option = {
domain: "",
expires: 1
};
const Cookies = {
get(key) {
let result = cookies.get(key);
result = isDef(result) ? result : "";
try {
return JSON.parse(result);
} catch (e) {
return result;
}
},
set(key, value) {
return cookies.set(key, value, option);
},
clear() {
return Object.keys(cookies.get()).forEach(function(cookie) {
Cookies.remove(cookie, option);
});
},
remove(key) {
return cookies.remove(key, option);
}
};
export default Cookies;
/*
* @Description: 数据加密,aes加密数据主体,rsa加密aes密钥,aes密钥前端自己存储
* @Date: 2020-12-08 11:08:28
* @LastEditors: gzw
* @LastEditTime: 2021-11-18 17:17:27
*/
import { cipher as AES, util as UTIL, pki as PKI, md as SHA1 } from 'node-forge';
import uuidv1 from 'uuid/v1';
import { parseTime } from './utils.service';
import { APP_ID, PUBLIC_KEY, PRIVATE_KEY } from '@/config/encrypt.config';
/**
* @description: 数据加密
* @param {String} data 数据源
* @return {String} 加密后的数据base64
*/
export function encryption(data = '') {
if (!data) return null;
const key = generateRandomStr(16);
const iv = key; // 后台约定iv与key一致
const plaintext = typeof data === 'object' ? JSON.stringify(data) : data;
const body = encryptDataByAes(plaintext, key, iv); // AES加密数据
const encryptKey = encryptDataByPb(key); // RSA公钥加密AES密钥
const signData = generateSign(plaintext);
return {
appId: APP_ID,
body,
encryptKey,
...signData
};
}
/**
* @description: AES加密数据,默认CBC, Pki#cs7
* @param {String} txt 数据源
* @param {String} key 密钥,16位字符串
* @param {String} iv 初始化向量
* @return {String} 加密后的数据base64
*/
function encryptDataByAes(txt, key, iv) {
const cipher = AES.createCipher('AES-CBC', key);
cipher.start({ iv });
cipher.update(UTIL.createBuffer(txt, 'utf8'));
cipher.finish();
const ciphertext = cipher.output.getBytes();
return buffer2Base64(ciphertext);
}
/**
* @description: 使用RSA公钥加密数据
* @param {String} txt 数据源
* @return {String} 加密后的数据base64
*/
function encryptDataByPb(txt) {
const publicKey = PKI.publicKeyFromPem(PUBLIC_KEY);
const pbData = publicKey.encrypt(txt);
return buffer2Base64(pbData);
}
/**
* @description: RSA私钥+SHA1生成签名
* 签名组成结构nonce+appid+timestamp+body
* @param {String} txt 数据源
* @return {Object} 生成的sign数据,时间戳、Nonce
*/
function generateSign(txt) {
const timestamp = parseTime('');
const nonce = generateNonce();
const privateKey = PKI.privateKeyFromPem(PRIVATE_KEY);
const md = SHA1.sha1.create();
md.update(nonce + APP_ID + timestamp + txt, 'utf8');
let sign = privateKey.sign(md);
sign = buffer2Base64(sign);
return {
timestamp,
nonce,
sign
};
}
/**
* @description: buffer转base64
* @param {Buffer} buf buffer源数据
* @return {String} base64 字符串
*/
function buffer2Base64(buf) {
return UTIL.encode64(buf);
}
/**
* @description: 生成nonce(uuid)
* 规则:以当前时间的uuid作为name,以随机生成的uuid作为namespace,生成最终的uuid
* @return {String} 生成的uuid
*/
function generateNonce() {
return uuidv1();
}
/**
* @description: 生成随机字符串
* @param {Number} n 位数
* @return {String} 生成的字符串
*/
function generateRandomStr(n) {
const len = n || 32;
const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789';
const maxPos = chars.length;
let pwd = '';
for (let i = 0; i < len; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
import CryptoJS from 'crypto-js';
import pay from '@/api/pay.api';
/**
* @description: 数据加密
* @message {String} message 数据源
* @return {String} 加密后的数据16进制
*/
export async function encryptByDESModeEBC(message) {
console.log(message);
const [{ payPwdSalt }] = await pay.desSalt();
var keyHex = CryptoJS.enc.Utf8.parse(payPwdSalt);
var encrypted = CryptoJS.DES.encrypt(message, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.ciphertext.toString().toLocaleUpperCase();
}
import { util as UTIL, pki as PKI, md as SHA1 } from 'node-forge';
const PRIVATE_KEY = `
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNVDPPQWzRINwz
9uXuop/y4zOQt7i2RPB79ITp40G3ceFiMp0SHo7Usc5WDkN6lEF2CvI20+cztT/7
scf40snP5vm75NHU3t0lOZjSllZjAsBfJHgHrXJIBgWt484CoHGimFyd2xGUs44z
IFHus6ilMAY3aqfUHtuMnggTdHYYMZPYX28fY5h0mixAJylqR7oadxgk6oUMWDtn
tBYZZd1eMy6P7TYo5ecbfFfGuJ9xOMHlbybJl88b+E/YIvf5K8csS1W5262AW8v/
yyEj0Fr/QtGsycW5klEoOdDCy+8IFYBl4R9IohHPcVd84Ya4xb2tED1gTFP6+61D
Sf6X/Ky9AgMBAAECggEBAJ3GoRUWKf68qFiJ1P89GXkzGrGOazIr4Trulp9+kEXd
DRo+2DFPJ+PKSUoZJcLwXyjMmniE9fjmwqauYoIRvx+xVZ8K4i4Xnoj3LDZNbU4h
lB7H0C/eGJ29eum2zdt43DjbqPdnmafRHWit4idxCBr+vxggLZwypfP0jzIb4I8P
UTggJqs2mt574FDaov2vf1BYoc8MXQWDCHrMJQOaZbZJhzIisu/gOzbMcq2m8gT4
3wtPEe3Hs0froQ2mwpLpURu6JwgYwTfWoV/hkBuvBeTJ8qHLhjiql69v3PIuMQPi
4Rz7TbQTcQhHRnHHqrIn7/iEoVtHoAesvfXoqqmHaUUCgYEA5rHwf1l164UeZe99
yj3d8Dntu6mH/xbRrHT+gSJJBZ5Jd0/RWRo6CA/gxnBXUotDHGLNZSKBt5/sENtl
vRmk9LMm4RPELDs8b9LdlbOYOOFEWbcHDGUInMSIZBNlisyp6J8bLVP6jTWsLQBw
kAJPzq7A2iiQdzXxKbOmq3AgqPcCgYEA49n3J7cZNIMRqFlmf8W4Dd1YKt0RivJW
hkGTnrd6+4YbdJZM1R55oW2WuxuoSwsQiHeiuzUi7WE+NPIoAfxBCnUj7uvEca0H
r2PKE8BMimQQ1+MQDyTR7eI39mg5pUPS56Tf06vc7LeeckPM4uC4wB26aUCVlQEf
xmP7l4HofusCgYACHK7u+4qw1U8p779fEqHtiRo8FZlBJJxWz9tko0O34XMavIhW
IH9Xg42zQ2QJRW0f3Wez/VTisXwfy2JrEMkJ1HoOpXeuT/yFqZCNxk8mdimCCMLv
wh0KEmKNSAAt/SGxF4PQLmykzlD9OHvPVbYVVlQ9qxFnhf7nOtXTy/sAkQKBgQCa
RHVGen2iRCusY/s1/1RCbt7HBq5d+P4EIFomV+v4aDAmm6yhjuSjG2O2g19Kj889
1mJjhfKD7hcEGgBkd7pBrlYJ6a8zmAdgBJxJCyXHfUC6Ko4w8qj/+u4Q8zg0YNtm
4wZ4diA6VYf9rVIHOkdcK8SOhp/AJuawl/k790TGyQKBgC9vau2PNLh2SaTEk5yj
fU7YAa1tVA/I6mSCtn5txDxImmAdrr+0CUgkxseRD6C9R7+LhTAI7ut9Dfyas2rt
qaWaTzv8WpQKzz5bTnJ0jIDzixKTwh/HsbSLKLNFSq1ll6p5McXdl1x0mRJP0/Vi
hSPWLmUrK0i/WulMr0sOaDT/
-----END PRIVATE KEY-----`;
/**
* @description: 数据加密
* @param {String} data 数据源
* @return {String} 加密后的数据base64
*/
export function encryption(data = '') {
if (!data) return null;
const plaintext = typeof data === 'object' ? JSON.stringify(data) : data;
const signData = generateSign(plaintext);
return signData;
}
/**
* @description: RSA私钥+SHA1生成签名
* 签名组成结构nonce+appid+timestamp+body
* @param {String} txt 数据源
* @return {Object} 生成的sign数据,时间戳、Nonce
*/
function generateSign(txt) {
const privateKey = PKI.privateKeyFromPem(PRIVATE_KEY);
const md = SHA1.sha1.create();
md.update(txt, 'utf8');
let signData = privateKey.sign(md);
signData = buffer2Base64(signData);
return {
signData
};
}
/**
* @description: buffer转base64
* @param {Buffer} buf buffer源数据
* @return {String} base64 字符串
*/
function buffer2Base64(buf) {
return UTIL.encode64(buf);
}
/* eslint-disable prettier/prettier */
import HttpRequest from '@qg/ui-request';
import { Toast } from '@qg/cherry-ui';
import allCfg from '@/config';
import store from '@/store';
import router from '@/router';
import localStorage from './localStorage.service';
import { getVccChannel, getUid, getTc } from './userInfo.service';
import { getPublicConfig } from '@/customize';
import { isApp, isWxMp, isAndroid } from './validation.service';
import wx from 'weixin-js-sdk';
const http = new HttpRequest(
{
tob: {
response(res) {
const { data, config } = res;
const returnRawData = config.rawData;
if (returnRawData) return [data, null];
if (data.businessCode === '401' || data.businessCode === '0401') {
if (isApp) {
// 羊小咩打开礼品卡禁止弹出请重新打开APP弹窗
// TODO 目前只对小程序token失效做了处理,app后续按需添加,具体实现方式可参考
// http://git.quantgroup.cn/ui/quantum-block-h5/blob/master/app/web/component/layout/activity/index.ts#L47
return;
}
if (isWxMp) {
wx.miniProgram.navigateTo({
url: `/pages/webview/middleWay?event=getToken&clear=true`
});
return;
}
const publicConfig = getPublicConfig();
publicConfig.signOutFn();
return;
}
const success =
(data.code === '0000' && data.businessCode === '0000') || data.business_code === 0;
if (success) {
return [data.data, null];
}
const msg = data.msg || '服务异常';
const hasNoAlert = typeof data?.noAlert !== 'undefined'; // 查看接口返回数据是否存在noAlert
if (!config.hideToast || (hasNoAlert && !data.noAlert)) {
Toast(msg);
}
let error = new Error(msg);
error.response = data;
console.error(error);
return [null, error];
},
request(cfg) {
const publicConfig = getPublicConfig();
if (!cfg.hideVccChannel) {
cfg.headers['vccChannel'] = getVccChannel() || publicConfig.vccChannel || '';
cfg.headers['sonVccChannel'] = getVccChannel('sonVccChannel') || '';
}
cfg.headers['qg-tenant-id'] = store?.getters?.tenantId || 560761;
if (publicConfig.flw) {
cfg.headers['uid'] = getUid();
cfg.headers['tc'] = getTc();
}
cfg.headers['version'] = allCfg.VERSION;
cfg.headers['X-Auth-Token'] = localStorage.get('vccToken') || '';
let terminal =''
if (isApp) {
terminal = isAndroid ? 'ANDROID' : 'IOS';
} else if (isWxMp) {
terminal = 'MINI-APP';
} else {
terminal = 'H5';
}
cfg.headers['x-user-terminal'] = terminal;
// cfg.headers['x-user-terminal'] = 'IOS';
// cfg.headers['appchannel'] = 'AppStore';
// cfg.headers['vccChannel'] = '214'
cfg.headers = { ...cfg.headers, ...cfg.customHeader };
return cfg;
}
},
promotion: {
// 地推工具专用
response(res) {
const { data, config } = res;
const returnRawData = config.rawData;
if (returnRawData) return [data, null];
if (data.businessCode === '401' || data.businessCode === '0401') {
router.push({ name: 'PromotionLogin' });
}
const success =
(data.code === '0000' && data.businessCode === '0000') || data.business_code === 0;
if (success) {
return [data.data, null];
}
const msg = data.msg || '服务异常';
if (!config.hideToast || !data.noAlert) {
Toast(msg);
}
let error = new Error(msg);
error.response = data;
return [null, error];
},
request(cfg) {
if (!cfg.hideVccChannel) {
cfg.headers['vccChannel'] = getVccChannel() || '';
cfg.headers['sonVccChannel'] = getVccChannel('sonVccChannel') || '';
}
cfg.headers['qg-tenant-id'] = '560867';
cfg.headers['version'] = allCfg.VERSION;
cfg.headers['group-push-auth-token'] = localStorage.get('promotionToken') || '';
cfg.headers['x-user-terminal'] = allCfg.TERMINAL; //H5 MINI-APP
cfg.headers = { ...cfg.headers, ...cfg.customHeader };
return cfg;
}
}
},
{
strategy: 'tob'
},
() => {},
// eslint-disable-next-line space-before-function-paren
function(loadingState) {
store.dispatch('change_loading', loadingState);
}
).getInstance();
export default http;
/* eslint-disable prettier/prettier */
/* eslint-disable space-before-function-paren */
/**
* Created by jialiu on 17/1/11.
*/
import store from '../store';
import { isWechat, isApp, isWxMp } from './validation.service';
import Cookies from './cookieStorage.service';
import localStorage from './localStorage.service';
import { sStorage } from './sessionStorage.service';
import { shouDemo } from '@/config/channel.config';
import { QG_TENANT_ID } from '@/store/type';
import { loadScript } from './utils.service';
//formXcxPage:标识是从小程序跳转过来的;
const localStorageParams = [
'creditToken',
'vccToken',
'vccChannel',
'sonVccChannel',
'formXcxPage',
'orderInfo',
'uuid',
'demoPhone',
'tenantId',
'token'
];
const cookiesParams = ['h', 'returnUrl', 'source', 'uid', 'agreed', 'tc'];
const sessionParams = [
'adv_utm_campaign',
'adv_utm_content',
'adv_utm_medium',
'adv_utm_source',
'adv_utm_term',
'vccToken'
];
export default {
// token校验,整个流程都是登陆后的
init: router => {
router.beforeEach(async (to, from, next) => {
try {
const queryParamsKeys = Object.keys(to.query);
if (queryParamsKeys.length) {
for (let i = 0; i < queryParamsKeys.length; i++) {
if (queryParamsKeys[i].toLowerCase() === 'offlinepath') {
if (to.query[queryParamsKeys[i]] && to.path != to.query[queryParamsKeys[i]]) {
const { offlinePath, ...otherQuery } = to.query;
router.replace({
path: offlinePath,
query: otherQuery
});
return false;
}
}
}
}
} catch (err) {
console.log(err);
}
// 所有自定义路由字段在此处理
const { meta } = to;
if (meta.cdn) {
if (Array.isArray(meta.cdn)) {
for (let i = 0; i < meta.cdn.length; i++) {
await loadScript(meta.cdn[i].url, meta.cdn[i].globalName);
}
} else {
await loadScript(meta.cdn.url, meta.cdn.globalName);
}
}
if (meta.cdns) {
for (let i = 0; i < meta.cdns.length; i++) {
await loadScript(meta.cdns[i]);
}
}
meta?.has?.header && store.commit('CHANGE_HEADER', meta.has.header); // 改变header
localStorageParams.forEach(item => {
if (isApp || isWxMp) {
localStorage.remove(item);
}
to.query[item] && localStorage.set(item, to.query[item]);
if (to.query['token']) {
localStorage.set('vccToken', to.query['token']);
}
});
cookiesParams.forEach(item => {
to.query[item] && Cookies.set(item, to.query[item]);
});
sessionParams.forEach(item => {
to.query[item] && sStorage.setItem(item, to.query[item]);
});
(isWechat || isApp || Cookies.get('h') === '0') && store.commit('CHANGE_HEADER', false); // 改变header
document.body.className = store.state.pay.header ? 'has-header' : '';
document.body.className = store.state.pay.tabBar ? 'has-tab-bar' : '';
store.commit('CHANGE_TITLE', meta?.title); // 改变title
const HOME = 0;
const MEMBER = 1;
const CART = 2;
const USER = 3;
switch (to.name) {
case 'Home':
store.commit('CHANGE_TABBAR', true);
store.commit('CHANGE_ROUTE_IDX', HOME);
break;
case 'Member':
store.commit('CHANGE_TABBAR', true);
store.commit('CHANGE_ROUTE_IDX', MEMBER);
break;
case 'Cart':
store.commit('CHANGE_TABBAR', true);
store.commit('CHANGE_ROUTE_IDX', CART);
break;
case 'User':
store.commit('CHANGE_TABBAR', true);
store.commit('CHANGE_ROUTE_IDX', USER);
break;
default:
store.commit('CHANGE_TABBAR', false);
break;
}
store.commit(QG_TENANT_ID, localStorage.get('tenantId'));
// 针对安硕渠道的相关配置
if (to.query['demoPhone'] || localStorage.get('demoPhone')) {
store.commit('CHANGE_TABBAR', false);
}
if (to.query['demoPhone'] && !localStorage.get('vccToken')) {
shouDemo(next);
} else {
next();
}
});
}
};
/* eslint-disable */
/* initGeetest 1.0.0
* 用于加载id对应的验证码库,并支持宕机模式
* 暴露 initGeetest 进行验证码的初始化
* 一般不需要用户进行修改
*/
(function(global, factory) {
"use strict";
if (typeof module === "object" && typeof module.exports === "object") {
// CommonJS
module.exports = global.document
? factory(global, true)
: function(w) {
if (!w.document) {
throw new Error("Geetest requires a window with a document");
}
return factory(w);
};
} else {
factory(global);
}
})(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
"use strict";
if (typeof window === "undefined") {
throw new Error("Geetest requires browser environment");
}
var document = window.document;
var Math = window.Math;
var head = document.getElementsByTagName("head")[0];
function _Object(obj) {
this._obj = obj;
}
_Object.prototype = {
_each: function(process) {
var _obj = this._obj;
for (var k in _obj) {
if (_obj.hasOwnProperty(k)) {
process(k, _obj[k]);
}
}
return this;
}
};
function Config(config) {
var self = this;
new _Object(config)._each(function(key, value) {
self[key] = value;
});
}
Config.prototype = {
api_server: "api.geetest.com",
protocol: "http://",
type_path: "/gettype.php",
fallback_config: {
slide: {
static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
type: "slide",
slide: "/static/js/geetest.0.0.0.js"
},
fullpage: {
static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
type: "fullpage",
fullpage: "/static/js/fullpage.0.0.0.js"
}
},
_get_fallback_config: function() {
var self = this;
if (isString(self.type)) {
return self.fallback_config[self.type];
} else if (self.new_captcha) {
return self.fallback_config.fullpage;
} else {
return self.fallback_config.slide;
}
},
_extend: function(obj) {
var self = this;
new _Object(obj)._each(function(key, value) {
self[key] = value;
});
}
};
var isNumber = function(value) {
return typeof value === "number";
};
var isString = function(value) {
return typeof value === "string";
};
var isBoolean = function(value) {
return typeof value === "boolean";
};
var isObject = function(value) {
return typeof value === "object" && value !== null;
};
var isFunction = function(value) {
return typeof value === "function";
};
var callbacks = {};
var status = {};
var random = function() {
return parseInt(Math.random() * 10000) + new Date().valueOf();
};
var loadScript = function(url, cb) {
var script = document.createElement("script");
script.charset = "UTF-8";
script.async = true;
script.onerror = function() {
cb(true);
};
var loaded = false;
script.onload = script.onreadystatechange = function() {
if (
!loaded &&
(!script.readyState || "loaded" === script.readyState || "complete" === script.readyState)
) {
loaded = true;
setTimeout(function() {
cb(false);
}, 0);
}
};
script.src = url;
head.appendChild(script);
};
var normalizeDomain = function(domain) {
return domain.replace(/^https?:\/\/|\/$/g, "");
};
var normalizePath = function(path) {
path = path.replace(/\/+/g, "/");
if (path.indexOf("/") !== 0) {
path = "/" + path;
}
return path;
};
var normalizeQuery = function(query) {
if (!query) {
return "";
}
var q = "?";
new _Object(query)._each(function(key, value) {
if (isString(value) || isNumber(value) || isBoolean(value)) {
q = q + encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
}
});
if (q === "?") {
q = "";
}
return q.replace(/&$/, "");
};
var makeURL = function(protocol, domain, path, query) {
domain = normalizeDomain(domain);
var url = normalizePath(path) + normalizeQuery(query);
if (domain) {
url = protocol + domain + url;
}
return url;
};
var load = function(protocol, domains, path, query, cb) {
var tryRequest = function(at) {
var url = makeURL(protocol, domains[at], path, query);
loadScript(url, function(err) {
if (err) {
if (at >= domains.length - 1) {
cb(true);
} else {
tryRequest(at + 1);
}
} else {
cb(false);
}
});
};
tryRequest(0);
};
var jsonp = function(domains, path, config, callback) {
if (isObject(config.getLib)) {
config._extend(config.getLib);
callback(config);
return;
}
if (config.offline) {
callback(config._get_fallback_config());
return;
}
var cb = "geetest_" + random();
window[cb] = function(data) {
if (data.status === "success") {
callback(data.data);
} else if (!data.status) {
callback(data);
} else {
callback(config._get_fallback_config());
}
window[cb] = undefined;
try {
delete window[cb];
} catch (e) {}
};
load(
config.protocol,
domains,
path,
{
gt: config.gt,
callback: cb
},
function(err) {
if (err) {
callback(config._get_fallback_config());
}
}
);
};
var throwError = function(errorType, config) {
var errors = {
networkError: "网络错误"
};
if (typeof config.onError === "function") {
config.onError(errors[errorType]);
} else {
throw new Error(errors[errorType]);
}
};
var detect = function() {
return !!window.Geetest;
};
if (detect()) {
status.slide = "loaded";
}
var initGeetest = function(userConfig, callback) {
var config = new Config(userConfig);
if (userConfig.https) {
config.protocol = "https://";
} else if (!userConfig.protocol) {
config.protocol = window.location.protocol + "//";
}
jsonp([config.api_server || config.apiserver], config.type_path, config, function(newConfig) {
var type = newConfig.type;
var init = function() {
config._extend(newConfig);
callback(new window.Geetest(config));
};
callbacks[type] = callbacks[type] || [];
var s = status[type] || "init";
if (s === "init") {
status[type] = "loading";
callbacks[type].push(init);
load(
config.protocol,
newConfig.static_servers || newConfig.domains,
newConfig[type] || newConfig.path,
null,
function(err) {
if (err) {
status[type] = "fail";
throwError("networkError", config);
} else {
status[type] = "loaded";
var cbs = callbacks[type];
for (var i = 0, len = cbs.length; i < len; i = i + 1) {
var cb = cbs[i];
if (isFunction(cb)) {
cb();
}
}
callbacks[type] = [];
}
}
);
} else if (s === "loaded") {
init();
} else if (s === "fail") {
throwError("networkError", config);
} else if (s === "loading") {
callbacks[type].push(init);
}
});
};
window.initGeetest = initGeetest;
return initGeetest;
});
import { isDef } from './utils.service';
export default {
get(key) {
let result = window.localStorage.getItem(key);
result = isDef(result) ? result : '';
try {
return JSON.parse(result);
} catch (e) {
return result;
}
},
set(key, value) {
let toString = Object.prototype.toString;
if (toString.call(value) === '[object Array]' || toString.call(value) === '[object Object]') {
value = JSON.stringify(value);
}
return window.localStorage.setItem(key, value);
},
remove(key) {
console.log('remove', key);
return window.localStorage.removeItem(key);
},
clear() {
console.log('clear');
return window.localStorage.clear();
}
};
/*
* @Description: h5 与 mp 交互
* @Date: 2021-04-29 15:19:37
* @LastEditors: gzw
* @LastEditTime: 2021-06-07 19:30:02
*/
import qs from 'qs';
import commonCfg from '../config/common.setting';
const { MP_URL_MAP } = commonCfg;
class Mp {
constructor() {
this.callbackQueue = {};
this.wx = require('weixin-js-sdk');
}
// 小程序中postMessage在特定时机(小程序后退、组件销毁、分享)触发; 如果需要立即触发,需要navigateTo跳转
run(data, callback, immediate = false) {
const { wx } = this;
console.log(data.event);
if (immediate) {
const url = `${MP_URL_MAP.middleWay}${qs.stringify(data, {
encode: true,
addQueryPrefix: true
})}`;
if (callback) this.callbackQueue[data.event] = callback;
wx.miniProgram.navigateTo({
url,
success: () => {
this.bindListener();
}
});
} else {
wx.miniProgram.postMessage({ data });
}
}
getToken(data, callback = () => {}) {
this.run({ event: 'getToken', ...data }, callback, true);
}
closeBrowser() {
const { wx } = this;
wx.miniProgram.navigateBack();
}
openNewUrl(data = {}) {
const { wx } = this;
const { newUrl } = data;
console.log(newUrl);
if (/(https|http):\/\//gi.test(newUrl)) {
// window.location.href = newUrl;
wx.miniProgram.navigateTo({
url: `${MP_URL_MAP['webview']}?url=${encodeURIComponent(JSON.stringify(newUrl))}`
});
} else if (/xyqb:\/\//gi.test(newUrl)) {
let urlTag = '';
if (/goodsdetail|goodsDetail/gi.test(newUrl)) {
urlTag = 'goodDetail';
} else if (/goodsList/gi.test(newUrl)) {
urlTag = 'landPage';
} else if (/discover|homepage/gi.test(newUrl)) {
urlTag = 'home';
} else {
urlTag = 'home';
}
if (urlTag) {
const url = `${MP_URL_MAP[urlTag]}?${newUrl.split('?')[1]}`;
wx.miniProgram[urlTag === 'home' ? 'reLaunch' : 'navigateTo']({ url });
}
} else {
wx.miniProgram[data.type || 'navigateTo']({
url: newUrl
});
}
}
getHashData(that, currentHref) {
const hashArr = decodeURIComponent(currentHref).split('#/');
const lastHashStr = hashArr[hashArr.length - 1];
const hashData = qs.parse(lastHashStr);
this.callbackQueue[hashData.event](hashData.data);
this.unBindListener();
}
// TODO hashchange使用非匿名函数,获取location是异步的
bindListener() {
window.addEventListener(
'hashchange',
() => {
this.getHashData(this, window.location.href);
},
false
);
}
// TODO
unBindListener() {
window.removeEventListener(
'hashchange',
() => {
this.getHashData(this, window.location.href);
},
false
);
}
}
export default Mp;
/* eslint-disable space-before-function-paren */
/* eslint-disable prettier/prettier */
/*
* @Description: 支付微信h5, jsapi, 第三方收银台,跳转)
* @Date: 2020-07-28 15:03:52
* @LastEditors: guang.wu
* @LastEditTime: 2023-01-30 15:43:12
*/
import cookies from '@/service/cookieStorage.service';
import localStorage from '@/service/localStorage.service';
import { queryStringify } from './utils.service';
import TMDConfig from '@/customize/tmd-config';
import { CHANNEL_TIANMEIDAI } from '@/customize/utils/config-type';
/**
* payByWeixinJsapi
* @description: 微信通过jsapi支付
* 可以在微信浏览器调起支付
* @param {type}
* @return:
*/
function payByWeixinJsapi(info = {}, callback) {
function onBridgeReady() {
// eslint-disable-next-line no-undef
WeixinJSBridge.invoke('getBrandWCPayRequest', info, function(res) {
if (res.err_msg == 'get_brand_wcpay_request:ok') {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
callback('ok');
} else if (res.err_msg == 'get_brand_wcpay_request:cancel') {
// 支付取消
callback('cancel');
} else {
// 支付失败
callback('fail');
}
});
}
if (typeof WeixinJSBridge == 'undefined') {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
}
/**
* payByWeixinH5
* @description: 微信通过H5支付
* 可以在浏览器调起微信支付
* 在羊小咩(信用钱包)app中调起微信支付,会先唤起微信,原来的页面会自动跳转到redirect_url设定的地址
* @param {type}
* @return:
*/
function payByWeixinH5(info) {
if (!info.url) return;
if (!info.params) {
info.params = {};
}
const vccToken = localStorage.get('vccToken');
const orderNo = cookies.get('orderNo')?.orderNo;
info.params.isWxH5 = 1;
info.params.vccToken = vccToken;
info.params.orderNo = orderNo;
info.params.isWx = true;
const currentPath = window.location.origin + '/payWaiting?' + queryStringify(info.params);
localStorage.set('inPay', true);
const config = new TMDConfig();
if (localStorage.get('vccChannel') === config.channelId.id) {
window.location.replace(`${info.url}&redirect_uri=${currentPath}`);
} else {
const nextPage = document.createElement('a');
nextPage.setAttribute('href', `${info.url}&redirect_url=${currentPath}`);
nextPage.click();
}
}
/**
* payByALIH5
* @description: 支付宝支付
* @param {type}
* @return:
*/
export function payByALIH5(info) {
if (!info.url) return;
const aliWrap = document.createElement('div');
aliWrap.id = 'ALIWEB_WRAP';
aliWrap.setAttribute('id', 'ALIWEB_WRAP');
// 判断 只有天美贷才执行
if (localStorage.get('vccChannel') === CHANNEL_TIANMEIDAI) {
info.url = info.url.replace(
'<form ',
"<iframe src='' style='height: 1px; width: 1px;opacity: 0;' frameborder='0' name='frameName'></iframe><form target='frameName'"
);
}
aliWrap.innerHTML = info.url;
document.body.appendChild(aliWrap);
document.forms[0].submit();
setTimeout(() => {
const ALIWEB_WRAP = document.getElementById('ALIWEB_WRAP');
if (ALIWEB_WRAP != null) ALIWEB_WRAP.parentNode.removeChild(ALIWEB_WRAP);
}, 5000);
}
/**
* payByThirdPartyCashier
* @description: 第三方收银台
* @param {type}
* @return:
*/
function payByThirdPartyCashier(info) {
if (!info.url) return;
if (info.params) {
info.params.third = 1;
} else {
info.params = {
third: 1
};
}
const currentPath = encodeURIComponent(
window.location.origin + '/payWaiting?' + queryStringify(info.params)
);
const nextPage = document.createElement('a');
nextPage.setAttribute('href', `${info.url}&redirect_uri=${currentPath}`);
nextPage.click();
// window.location.href = `${info.url}&redirect_uri=${currentPath}`;
}
/**
* @description: 支付方式判断, 返回promise
* NATIVE=原生扫码支付.,APP=ap支付,,JSAPI=公众号支付/小程序支付,,MWEB=H5支付.,MICROPAY=刷卡支付,默认JSAPI
* @param {String} type 支付方式,THIRD -> 第三方,MWEB -> H5支付, JSAPI -> jsapi支付,默认支付方式,THIRD
* @param {Object/String} payInfo 支付信息
* @return {Promise} 回调
*/
export function payByWay(type = 'THIRD', payInfo, isXc = true) {
return new Promise((resolve, reject) => {
if (!isXc) {
localStorage.set('payByThirdPartyCashierUrl', payInfo.url);
// payByThirdPartyCashier(payInfo);
reject();
return;
}
if (type === 'JSAPI' && !payInfo.url) {
payByWeixinJsapi(payInfo, function(e) {
if (e === 'ok') {
resolve();
} else {
reject();
}
});
} else {
if (payInfo.url.indexOf('tenpay') > -1) {
payByWeixinH5(payInfo);
reject();
} else if (type === 'ALIWEB') {
const config = new TMDConfig();
if (localStorage.get('vccChannel') === config.channelId.id) {
localStorage.set('payByThirdPartyCashierUrl', payInfo.url);
}
payByALIH5(payInfo);
resolve();
} else {
payByThirdPartyCashier(payInfo);
reject();
}
// resolve();
}
});
}
import UiTrack from '@qg/ui-track-web/src/index.js';
import router from '@/router';
import config from '@/config';
import { getVccChannel, getTenantId } from '@/service/userInfo.service';
const uiTrack = new UiTrack({
globalVars: {
platformType: 'H5',
parent_channel_id: getVccChannel('vccChannel'),
son_channel_id: getVccChannel('sonVccChannel'),
tenant_id: getTenantId()
},
useUweb: false,
batch: false,
appTrack: false,
shenceHost: config.shenceHost,
showLog: config.test,
router: router // router实例
});
export default uiTrack;
class Store {
constructor(store) {
// 检测是否支持localstorage
if (!store) {
console.log("不支持localStorage");
return;
}
this._store = store;
}
/**
* @function 设置值
* @param {string} _k 必须参数,属性
* @param {any} _v 非必须参数,属性值
*/
setItem(_k, _v) {
if (!this._store) return;
const kType = this.getType(_k);
if (kType === "string") {
this._store.setItem(_k, this.filterValue(_v));
} else {
console.log("key只能为字符串!");
}
}
/**
* @function 获取值
* @param {string} _k 必须参数,属性
*/
getItem(_k) {
if (!this._store) return;
let res;
const kType = this.getType(_k);
if (kType === "string") {
res = this._store.getItem(_k);
} else {
console.log("key只能为字符串!");
}
return res;
}
/**
* @function 移除值
* @param {string} _k 必须参数,属性
*/
removeItem(_k) {
if (!this._store) return;
let res;
const kType = this.getType(_k);
if (kType === "string") {
res = this._store.removeItem(_k);
} else {
console.log("key只能为字符串!", res);
}
}
/**
* @function 移除所有
*/
clear() {
if (!this._store) return;
this._store.clear();
}
/**
* @function 判断类型
* @param {any} para 必须参数,判断的值
*/
getType(para) {
const type = typeof para;
if (type === "number" && isNaN(para)) return "NaN";
if (type !== "object") return type;
return Object.prototype.toString
.call(para)
.replace(/[\[\]]/g, '') // eslint-disable-line
.split(" ")[1]
.toLowerCase();
}
/**
* @function 过滤值
* @param {any} val 必须参数,过滤的值
*/
filterValue(val) {
const vType = this.getType(val);
const nullVal = ["null", "undefined", "NaN"];
const stringVal = ["boolean", "number", "string"];
if (nullVal.indexOf(vType) >= 0) return "";
if (stringVal.indexOf(vType) >= 0) return val;
return JSON.stringify(val);
}
}
class SessionStorage extends Store {
constructor(store) { // eslint-disable-line
super(store);
}
}
const sStorage = new SessionStorage({});
export { sStorage };
import { encryption } from '@/service/encrypt';
import store from '@/store';
import { smEvent } from '@/api/user.api';
import { uploadSMIDToKdsp } from '@/api/user.api';
import { sStorage } from '@/service/sessionStorage.service';
window.SMSdk;
window._smReadyFuncs = [];
const APP_ID =
process.env === 'production' && (!process.env.QG_ENV || process.env.QG_ENV !== 'test')
? 'YXM'
: 'YXM_TEST';
console.log(APP_ID);
export function shuMeiInit() {
window._smConf = {
organization: 'YGXboTJhF42EIELHANew',
appId: APP_ID,
publicKey:
'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6Zl01PHYV2rG/WyfiBfhLDAfm2i1Wx1eiw9lkHiYNnD27c9rdy8OWZ/6DR7xmn7gDT4zyeDteBMVH226E/4gstNEOpt2ld3eOCLto+cdYYB8W0LtSE6mFHSFJk4YYxIGtTOoj/hEUWG9vwDFP6pli/c6iIVS+JZD5zyViFAzQXwIDAQAB'
};
(function() {
window.SMSdk = {
onBoxDataReady: function() {
// console.log('sm box id =', boxData);
},
ready: function(fn) {
fn && window._smReadyFuncs.push(fn);
}
};
})();
const url = 'https://misc.lkbang.net/common/shumei/fp.min.js';
const sm = document.createElement('script');
const s = document.getElementsByTagName('script')[0];
sm.src = url;
s.parentNode.insertBefore(sm, s);
}
export async function getSmDeviceId() {
return new Promise(resolve => {
let smDeviceId = '';
let smDeviceIdReady = false;
window.SMSdk.ready(async function() {
if (window.SMSdk.getDeviceId) {
smDeviceId = window.SMSdk.getDeviceId();
}
if (!smDeviceIdReady) {
smDeviceIdReady = true;
}
store.commit('SET_SM_DEVICEID', smDeviceId);
// 执行业务逻辑
const [shumeiKey] = await uploadSMIDToKdsp({
shumeiDeviceId: smDeviceId
});
if (shumeiKey) sStorage.setItem('shumeiKey', shumeiKey);
resolve(shumeiKey);
});
});
}
export function dealSmDeviceId() {
return new Promise(resolve => {
let smDeviceId = '';
let smDeviceIdReady = false;
window.SMSdk.ready(function() {
if (window.SMSdk.getDeviceId) {
smDeviceId = window.SMSdk.getDeviceId();
}
if (!smDeviceIdReady) {
smDeviceIdReady = true;
// 执行业务逻辑
resolve(smDeviceId);
}
});
});
}
// 上报数美
export function smTrackEvent(data) {
// data.appId = 'YXM_H5';
let smDeviceId = '';
let smDeviceIdReady = false;
window.SMSdk.ready(async function() {
if (window.SMSdk.getDeviceId) {
smDeviceId = window.SMSdk.getDeviceId();
}
if (!smDeviceIdReady) {
smDeviceIdReady = true;
}
if (!data || !smDeviceId) return false;
data.shumeiDeviceId = smDeviceId;
await smEvent(encryption(data));
return true;
});
}
import localStorage from './localStorage.service';
export const basicOptions = {
// 职业选项
jobs: [
{
value: 'WORKER',
name: '工人'
},
{
value: 'TEACHER',
name: '教师'
},
{
value: 'WHITE_COLLAR',
name: '白领'
},
{
value: 'CAREER_BUILDER',
name: '创业者'
},
{
value: 'SELF_EMPLOYER',
name: '个体户'
},
{
value: 'EMPLOYEE',
name: '公司职员'
},
{
value: 'BISUNESS_ENTITY',
name: '企业法人'
},
{
value: 'ONLINE_STORE_OWNER',
name: '网店店主'
},
{
value: 'UNEMPLOYED',
name: '暂无职业'
},
{
value: 'OTHER',
name: '其他'
}
],
// 学历选项
educationList: [
{
value: 'MASTER',
name: '硕士及以上'
},
{
value: 'UNDER_GRADUATE',
name: '本科'
},
{
value: 'JUNIOR_COLLEGE',
name: '大专'
},
{
value: 'TECHNICAL_SECONDARY_SCHOOL',
name: '中专'
},
{
value: 'TECHNICAL_SCHOOL',
name: '技校'
},
{
value: 'HIGH_SCHOOL',
name: '高中'
},
{
value: 'MIDDLE_SCHOOL',
name: '初中'
},
{
value: 'PRIMARY_SCHOOL',
name: '小学'
},
{
value: 'OTHER',
name: '其他'
}
],
// 月收入选项
incomeRangeList: [
{
value: 'BELOW_1000',
name: '小于1000元'
},
{
value: 'BELOW_3000',
name: '1000至3000元'
},
{
value: 'BELOW_5000',
name: '3000至5000元'
},
{
value: 'BELOW_8000',
name: '5000至8000元'
},
{
value: 'BELOW_10000',
name: '8000至10000元'
},
{
value: 'BELOW_15000',
name: '10000至15000元'
},
{
value: 'BELOW_20000',
name: '15000至20000元'
},
{
value: 'ABOVE_20000',
name: '大于20000元'
}
],
emailList: [
{
value: 1,
name: 'qq.com'
},
{
value: 2,
name: '163.com'
},
{
value: 3,
name: '126.com'
},
{
value: 4,
name: 'icloud.com'
},
{
value: 5,
name: '139.com'
},
{
value: 6,
name: '189.com'
},
{
value: 7,
name: 'gmail.com'
}
]
};
export const relation = [
{
value: 'PARENT',
name: '父母'
},
{
value: 'CHILDREN',
name: '子女'
},
{
value: 'BROTHER',
name: '兄弟姐妹'
},
{
value: 'COLLEAGUE',
name: '同事'
},
{
value: 'CLASSMATE',
name: '同学'
},
{
value: 'FRIEND',
name: '朋友'
},
{
value: 'SPOUSE',
name: '夫妻'
},
{
value: 'SELF',
name: '本人'
},
{
value: 'OTHER',
name: '其他'
}
];
// 消费额度申请合同列表
export const authList = [
{
id: 328,
contractTemplateName: '客户非学生承诺函'
},
{
id: 9,
contractTemplateName: '个人信息查询及使用综合授权书'
}
];
export const qoutaList = [
{
id: 281,
contractTemplateName: '上海银行直销银行电子账户服务协议'
},
{
id: 414,
contractTemplateName: '享花卡消费贷款服务协议'
},
{
id: 413,
contractTemplateName: '享花卡服务协议'
},
{
id: 412,
contractTemplateName: '委托扣款授权书'
}
];
export const xyqbDownLink =
'https://activity.q-gp.com/activity/59a4d7f7f70cff7a37fed830?from=singlemessage&isappinstalled=0';
export const toUseUrl = 'xyqb://mall/goodsList?title=品牌尖货&labelId=58&categoryId=';
export function wxsdk() {
if (+localStorage.get('vccChannel') !== 159913) return; // 是否是小程序
var oHead = document.getElementsByTagName('head').item(0);
var oScript = document.createElement('script');
oScript.type = 'text/javascript';
oScript.src = 'https://res.wx.qq.com/open/js/jweixin-1.4.0.js';
oHead.appendChild(oScript);
}
import Vue from 'vue';
import SvgIcon from '@/components/SvgIcon'; // svg component
// register globally
Vue.component('svg-icon', SvgIcon);
const req = require.context('../assets/svg', false, /\.svg$/);
const requireAll = requireContext => requireContext.keys().map(requireContext);
requireAll(req);
import user from '@/api/user.api';
import store from '@/store';
import { getQueryString, parseSearch } from './utils.service';
import localStorage from './localStorage.service';
import cookie from './cookieStorage.service';
// eslint-disable-next-line space-before-function-paren
export const getUserInfo = async () => {
const [data] = await user.getUserInfo();
const { userInfo } = data || {};
store.commit('CHANGE_LOGIN', userInfo);
return userInfo;
};
export const getToKen = () => {
const vccToken = getQueryString('vccToken');
const oldToken = localStorage.get('vccToken') || '';
store.commit('CHANGE_TOKEN', vccToken || oldToken || '');
};
export function getVccChannel(channelKey = 'vccChannel') {
if (channelKey === 'sonVccChannel') {
return localStorage.get(channelKey) || parseSearch(window.location.href)[channelKey] || '';
}
return localStorage.get(channelKey) || parseSearch(window.location.href)[channelKey] || '';
}
export function getTenantId() {
return localStorage.get('tenantId') || parseSearch(window.location.href)['tenantId'] || '';
}
export function getUid() {
// 返利网会员标识
return cookie.get('uid') || '';
}
export function getTc() {
// 返利网订单附加跟踪信息
return cookie.get('tc') || '';
}
/* eslint-disable prettier/prettier */
import { isAndroid, isIOS } from './validation.service';
import Cookies from './cookieStorage.service';
import 'dingtalk-jsapi/entry/mobile'; // 只引入移动端(支持小程序)
import ddSetTitle from 'dingtalk-jsapi/api/biz/navigation/setTitle'; // 按需引入方法
import localStorage from './localStorage.service';
import Vue from 'vue';
export const EventBus = new Vue();
/**
* 替换邮箱字符
* @param {String} email 输入字符串
* @return: {Function} new_email 邮箱
*/
export function regEmail(email) {
if (String(email).indexOf('@') > 0) {
const str = email.split('@');
let _s = '';
if (str[0].length > 3) {
for (var i = 0; i < str[0].length - 3; i++) {
_s += '*';
}
}
var new_email = str[0].substr(0, 3) + _s + '@' + str[1];
}
return new_email;
}
/**
* 替换手机字符
* @param {String} mobile 输入字符串
* @return: {Function} new_email 邮箱
*/
export function regMobile(mobile) {
if (mobile.length > 7) {
var new_mobile = mobile.substr(0, 3) + '****' + mobile.substr(7);
}
return new_mobile;
}
/**
* 去除两侧空格
* @param {String} s 输入字符串
* @return: {Function} new_email 邮箱
*/
export function stringTrim(s) {
s = stringTrimLeft(s);
return stringTrimRight(s);
}
/**
* 去除左侧空格
* @param {String} s 输入字符串
* @return: {Function} new_email 邮箱
*/
export function stringTrimLeft(s) {
return s.replace(/^[\s\n\t]+/g, '');
}
/**
* 去除右侧空格
* @param {String} s 输入字符串
* @return: {Function} new_email 邮箱
*/
export function stringTrimRight(s) {
return s.replace(/[\s\n\t]+$/g, '');
}
/**
* 只能输入中文、英文、数字
* @param {String} str 输入字符串
* @return: {String} new_stremail 中文、英文、数字
*/
export function filterSc(str) {
// eslint-disable-next-line
return str.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g, '');
}
/**
* 字符长度(中文)
* @param {String} str 输入字符串
* @return: {Number} len 长度
*/
export function strLen(str) {
var len = 0;
for (var i = 0; i < str.length; i++) {
var c = str.charCodeAt(i);
//单字节加1
if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f)) {
len++;
} else {
len += 2;
}
}
return len;
}
/**
* 替换emoji表情
* @param {String} name 输入字符串
* @return: {String} str 字符串
*/
export function filterEmoji(name) {
// eslint-disable-next-line
let str = name.replace(
// eslint-disable-next-line
/[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/gi,
''
);
return str;
}
/**
* hash路由获取url参数
* @param {String} searchString 输入字符串
* @return: {String} str 字符串
*/
export function parseSearch(searchString) {
if (!searchString) {
return {};
}
if (!searchString.includes('?')) {
return {};
}
return searchString
.split('?')[1]
.split('#')[0]
.split('&')
.reduce((result, next) => {
const pair = next.split('=');
try {
result[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
} catch (e) {
// eslint-disable-next-line
// result[decodeURIComponent(pair[0])] = window.$URL.decode(pair[1]);
}
return result;
}, {});
}
/**
* 时间转换
* @param {String} time 需要转换的时间
* @param {String} cFormat 格式 {y}-{m}-{d} {h}:{i}:{s}
* @return: {String} timeStr 转换完成的时间
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return '-';
}
if (time == null) {
return '-';
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}';
let date;
if (time == '') {
date = new Date();
} else if (typeof time === 'object') {
date = time;
} else if (!isNaN(time) && ('' + time).length === 10) {
time = parseInt(time) * 1000;
} else {
if (String(time).indexOf('T') > -1) {
time = time.replace(/T/g, ' ').replace(/\..*/g, '');
}
if (
(String(time).indexOf('-') > -1 || String(time).indexOf('.') > -1) &&
String(time).indexOf('T') == -1
) {
time = time.replace(/-|\./g, '/');
}
date = new Date(time);
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
};
const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key];
if (key === 'a') {
return ['', '', '', '', '', '', ''][value];
}
if (result.length > 0 && value < 10) {
value = '0' + value;
}
return value || 0;
});
return timeStr;
}
//返回拨打标签
export function regPhone(data) {
const regExp = new RegExp(/((0\d{2,3}-\d{7,8})|(1[358674]\d{9}))/, 'g'); //匹配电话,以便能直接拨打
const newData = data.replace(regExp, "<a class='tel' href='tel:$1'>$1</a>");
return newData;
}
export function formatPhone(phone) {
const reg = /^(\d{3})(\d{4})(\d{4})$/;
const matches = reg.exec(phone);
const newPhone = matches[1] + ' ' + matches[2] + ' ' + matches[3];
return newPhone;
}
export function formatMaskPhone(phone) {
const reg = /(\d{3})\d{4}(\d{4})/;
return phone.replace(reg, '$1****$2') || '';
}
/**
* @description: 移动端监听软键盘弹起或收起,IOS,android
* @param {Boolean} off 是否销毁
* @return {Function} callback 软键盘弹起或收取回调, true => 弹起, false => 隐藏
*/
export function onKeyboardStateChange(
callback = () => {
return;
},
off = false
) {
if (isIOS) {
let isReset = true; //是否归位
const focusinHandler = () => {
isReset = false; //聚焦时键盘弹出,焦点在输入框之间切换时,会先触发上一个输入框的失焦事件,再触发下一个输入框的聚焦事件
callback(true);
};
const focusoutHandler = () => {
isReset = true;
setTimeout(() => {
//当焦点在弹出层的输入框之间切换时先不归位
if (isReset) {
// window.scroll(0, 0); // 【暂时取掉】确定延时后没有聚焦下一元素,是由收起键盘引起的失焦,则强制让页面归位
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
callback(false);
}
}, 30);
};
if (off) {
document.body.removeEventListener('focusin', focusinHandler);
document.body.removeEventListener('focusout', focusoutHandler);
} else {
document.body.addEventListener('focusin', focusinHandler);
document.body.addEventListener('focusout', focusoutHandler);
}
}
if (isAndroid) {
const originHeight = document.documentElement.clientHeight || document.body.clientHeight;
const resizeHandler = () => {
const resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
const activeElement = document.activeElement;
if (resizeHeight < originHeight) {
// 键盘弹起后逻辑
if (
activeElement &&
(activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA')
) {
setTimeout(() => {
activeElement.scrollIntoView({ block: 'center' }); //焦点元素滚到可视区域的问题
}, 0);
callback(true);
}
} else {
// 键盘收起后逻辑
callback(false);
}
};
if (off) {
window.removeEventListener('resize', resizeHandler);
} else {
window.addEventListener('resize', resizeHandler);
}
}
}
export function getParameterByName(name, url) {
if (!url) url = window.location.href;
// eslint-disable-next-line no-useless-escape
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
// 清除键盘
export function clearKeyboard() {
var input = document.getElementsByTagName('input');
for (let i = 0; i < input.length; i++) {
input[i].blur();
}
var textarea = document.getElementsByTagName('textarea');
for (let i = 0; i < textarea.length; i++) {
textarea[i].blur();
}
}
export function idNoFormat(value) {
// eslint-disable-next-line prettier/prettier
// eslint-disable-next-line space-before-function-paren
return value.replace(/(\d{6})(\d{0,8})?(\d{0,4})?/, function(res, $1, $2, $3) {
if (res.length <= 6) {
return $1;
}
if (res.length <= 14) {
return $1 + ' ' + $2;
}
return $1 + ' ' + $2 + ' ' + $3;
});
}
export function dateFormat(value) {
return value.replace(/(\d{4})(\d{2})(\d{2})/, '$1.$2.$3');
}
export function getQueryString(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
export const getMonthAdd0 = m => {
return m < 10 ? '0' + m : m;
};
export const isPhone = str => {
if (str) {
const reg = new RegExp('^1[3456789]\\d{9}$');
return reg.test(str);
}
return false;
};
export function throttle(fn, wait) {
let flag = true;
return function() {
if (flag) {
fn.apply(this, arguments);
flag = false;
setTimeout(() => {
flag = true;
}, wait);
}
};
}
export function getType(n) {
const str = Object.prototype.toString.call(n);
return str.slice(8, str.length - 1);
}
// 深拷贝
export function deepCopy(d) {
let obj = {};
let _type = getType(d);
if (_type === 'Date') {
return new Date(d);
} else if (_type === 'RegExp') {
return new RegExp(d.source, d.flags);
} else if (_type === 'Function') {
return function() {
return d.apply(this, arguments);
};
} else if (_type === 'NodeList') {
return d.cloneNode(true);
} else if (_type === 'Object') {
for (let o in d) {
obj[o] = deepCopy(d[o]);
}
} else if (_type === 'Array') {
obj = [];
for (let i in d) {
obj[i] = deepCopy(d[i]);
}
} else {
return d;
}
return obj;
}
// 链接跳转,增加参数,app跳转
const localStorageParams = ['vccToken', 'vccChannel', 'sonVccChannel', 'tenantId'];
const cookiesParams = ['h'];
let navTimer = null;
export function locationHrefPatchDelay(url = '', from = '') {
if (navTimer) clearTimeout(navTimer);
navTimer = setTimeout(() => {
locationHrefPatch(url, from);
}, 300);
}
const H5_URL_MAP = {
home: '/',
goodDetail: 'goodDetail',
landPage: 'search',
shopCart: 'shopCart',
cashier: 'pay',
activityGoodsList: 'activityProduct'
};
export function locationHrefPatch(url = '', router) {
if (!url) return;
let params = parseSearch(url);
localStorageParams.forEach(item => {
const itemVal = localStorage.get(item);
if (itemVal) params[item] = itemVal;
});
cookiesParams.forEach(item => {
const itemVal = Cookies.get(item);
if (itemVal) params[item] = itemVal;
});
params.fromHost = /(https|http):\/\//gi.test(url) ? window.location.origin : '';
let paramsStr = '';
Object.keys(params).forEach(item => {
paramsStr += `&${item}=${params[item]}`;
});
const targetUrl = `${url.split('?')[0]}?${paramsStr.slice(1)}`;
if (/(https|http):\/\//gi.test(targetUrl)) {
window.location.href = targetUrl;
} else if (/xyqb:\/\//gi.test(targetUrl)) {
let urlTag = '';
if (/goodsdetail|goodsDetail/gi.test(targetUrl)) {
urlTag = 'goodDetail';
} else if (/goodsList|search/g.test(targetUrl)) {
urlTag = 'landPage';
} else if (/activityGoodsList/gi.test(targetUrl)) {
urlTag = 'activityGoodsList';
} else if (/shopCart|shoppingCart/gi.test(targetUrl)) {
urlTag = 'shopCart';
} else if (/cashier/gi.test(targetUrl)) {
urlTag = 'cashier';
} else if (/discover|homepage/g.test(targetUrl)) {
urlTag = 'home';
} else {
urlTag = 'home';
}
if (urlTag) {
const url = `${H5_URL_MAP[urlTag]}?${targetUrl.split('?')[1]}`;
console.log(url);
if (router) {
router.push({ path: url });
} else {
window.location.href = window.location.origin + '/' + url;
}
}
} else {
window.location.href = window.location.origin + '/' + targetUrl;
}
}
export function loadScript(url, globalName) {
return new Promise((resolve, reject) => {
if (window[globalName] || process.env.NODE_ENV === 'development') {
resolve();
}
const head = document.getElementsByTagName('head')[0];
const script = document.createElement('script');
// script.charset = 'UTF-8';
script.async = true;
script.onerror = function() {
// eslint-disable-next-line
reject();
};
let loaded = false;
script.onload = script.onreadystatechange = function() {
if (
!loaded &&
(!script.readyState || script.readyState === 'loaded' || script.readyState === 'complete')
) {
loaded = true;
setTimeout(function() {
// eslint-disable-next-line
resolve();
}, 0);
}
};
script.src = url;
head.appendChild(script);
});
}
function cleanArray(actual) {
const newArray = [];
for (let i = 0; i < actual.length; i++) {
if (actual[i]) {
newArray.push(actual[i]);
}
}
return newArray;
}
export function queryStringify(json) {
if (!json) return '';
return cleanArray(
Object.keys(json).map(key => {
if (json[key] === undefined) return '';
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]);
})
).join('&');
}
export const clearLoginInfo = () => {
localStorage.remove('userInfo');
localStorage.remove('historyArr');
// localStorage.remove('vccChannel');
localStorage.remove('vccToken');
localStorage.remove('orderData');
localStorage.remove('token');
localStorage.remove('uuid');
localStorage.remove('userPhoneNo');
};
export const replaceFavicon = icon => {
const link = document.querySelector("link[rel*='icon']") || document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'icon';
link.href = icon;
document.getElementsByTagName('head')[0].appendChild(link);
};
export const changeDocumentTitle = title => {
// 钉钉浏览器内部,使用钉钉提供的JSAPI中的接口dd.biz.navigation.setTitle设置导航栏标题
if (window.navigator.userAgent.includes('DingTalk')) {
ddSetTitle({
title,
onSuccess: result => {
console.log(result);
},
onFail: err => {
console.log(err);
}
});
return;
}
document.title = title;
if (isIOS) {
const hackIframe = document.createElement('iframe');
hackIframe.style.display = 'none';
hackIframe.src = '/fixIosTitle.html?r=' + Math.random();
document.body.appendChild(hackIframe);
setTimeout(() => {
document.body.removeChild(hackIframe);
}, 300);
}
};
// 格式化输出价格
export const formatPrice = v => {
return ${v || '0.00'}`;
};
// 判断是否为0
export const checkEqualZero = v => Number(v) === 0;
export function isDef(val) {
return val !== undefined && val !== null && val !== 'null' && val !== 'undefined';
}
export function debounce(fn, interval, immediate) {
let flag = true;
const time = interval || 1000;
let timer = null;
return function() {
if (!immediate) {
timer && clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, time);
} else {
if (flag) {
fn.apply(this, arguments);
flag = false;
return;
}
timer && clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, time);
}
};
}
export function throtte(fn, interval, immediate) {
let time = 0;
let flag = true;
return function() {
if (immediate) {
if (flag) {
fn.apply(this, arguments);
flag = false;
time = Date.now();
return;
}
if (Date.now() - time > interval) {
fn.apply(this, arguments);
time = Date.now();
}
} else {
if (Date.now() - time > interval) {
time = Date.now();
fn.apply(this, arguments);
}
}
};
}
// 0是相等, 1是v1>v2, -1是v1<v2, -2 不存在
export function compareVersion(v1, v2) {
if (!v1 || !v2) return -2;
const v1Arr = v1.split('.');
const v2Arr = v2.split('.');
const len = Math.max(v1Arr.length, v2Arr.length);
while (v1Arr.length < len) {
v1Arr.push('0');
}
while (v2Arr.length < len) {
v2Arr.push('0');
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1Arr[i]);
const num2 = parseInt(v2Arr[i]);
if (num1 > num2) {
return 1;
} else if (num1 < num2) {
return -1;
}
}
return 0;
}
export const getServiceHeaders = () => ({
'living-service': JSON.stringify({ citycode: localStorage.get('citycode') || 1 })
});
export const cleanUndefinedOrNull = (params = {}) => {
return Object.keys(params).reduce((origin, key) => {
const item = params[key];
if (!(item === null || item === undefined)) {
origin[key] = item;
}
return origin;
}, {});
};
/**
* 将数组切割n的二维数组
* @param {*} array
* @param {*} n
* @returns
*/
export const getNewArray = (list, n) => {
const arr = [];
let index = 0;
while (list.length > index) {
arr.push(list.slice(index, index + n));
index += n;
}
return arr;
};
/**
*
* @param {*} arr old arr
* @returns new arr
*/
export const exportNewArr = arr => {
const odd = [];
const even = [];
arr.forEach(function(item, index) {
if ((index + 1) % 2 === 0) even.push(item);
else odd.push(item);
});
return odd.concat(even);
};
export const pick = (obj, arr) =>
arr.reduce((iter, val) => (val in obj && (iter[val] = obj[val]), iter), {});
export const sub = (arg1, arg2) => {
arg1 = arg1 || "";
arg2 = arg2 || "";
let r1, r2;
try {
r1 = arg1.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = arg2.toString().split(".")[1].length;
} catch (e) {
r2 = 0;
}
const c = Math.abs(r1 - r2);
const m = Math.pow(10, Math.max(r1, r2));
if (c > 0) {
const cm = Math.pow(10, c);
if (r1 > r2) {
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", "")) * cm;
} else {
arg1 = Number(arg1.toString().replace(".", "")) * cm;
arg2 = Number(arg2.toString().replace(".", ""));
}
} else {
arg1 = Number(arg1.toString().replace(".", ""));
arg2 = Number(arg2.toString().replace(".", ""));
}
return (arg1 - arg2) / m;
};
/*eslint-disable*/
import { stringTrim } from './utils.service';
// 判断输入内容是否为空
export function isNull(str) {
return str === undefined || str.length === 0 || str === null;
}
// 判断输入内容去掉空格是否为空
export function isTrimNull(str) {
if (str === undefined || str.length === 0 || str === null) {
return true;
}
return stringTrim(str).length === 0;
}
// 判断日期类型是否为YYYY-MM-DD格式的类型
export function isDate(str) {
if (!isNull(str)) {
const reg = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/;
const r = str.match(reg);
return r !== null;
}
}
// 判断日期类型是否为YYYY-MM-DD hh:mm:ss格式的类型
export function isDateTime(str) {
if (!isNull(str)) {
const reg = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/;
const r = str.match(reg);
return r !== null;
}
return false;
}
// 判断日期类型是否为hh:mm:ss格式的类型
export function isTime(str) {
if (!isNull(str)) {
const reg = /^((20|21|22|23|[0-1]\d)\:[0-5][0-9])(\:[0-5][0-9])?$/;
return reg.test(str);
}
return false;
}
// 校验是否合法日期
export function isValidDate(date) {
return date instanceof Date && !isNaN(date.getTime());
}
// 判断输入的字符是否为英文字母
export function isLetter(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z]+$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为整数
export function isInteger(str) {
if (!isNull(str)) {
const reg = /^[-+]?\d*$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为身份证号
export function isIdNo(str) {
if (!isNull(str)) {
const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为中文姓名最少两个中文字符
export function isChineseName(str) {
if (!isNull(str)) {
const reg = /^[\u0391-\uFFE5\·]{2,}$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否以数字开头
export function isStartWithInteger(str) {
if (!isNull(str)) {
const reg = /^[0-9].*$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为双精度
export function isDouble(str) {
if (!isNull(str)) {
const reg = /^[-\+]?\d+(\.\d+)?$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为:a-z,A-Z,0-9,_,并以字母开头
export function isProgramVar(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z][a-zA-Z0-9_]*$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为:a-z,A-Z,0-9,_,并以大写字母开头
export function isProgramClassName(str) {
if (!isNull(str)) {
const reg = /^[A-Z][a-zA-Z0-9_]*$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为中文
export function isChinese(str) {
if (!isNull(str)) {
const reg = /^[\u0391-\uFFE5]+$/;
return reg.test(str);
}
return false;
}
// 判断输入的EMAIL格式是否正确
export function isEmail(str) {
if (!isNull(str)) {
const reg = /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/g;
return reg.test(str);
}
return false;
}
// 判断输入的邮编(只能为六位)是否正确
export function isZIP(str) {
if (!isNull(str)) {
const reg = /^\d{6}$/;
return reg.test(str);
}
}
// 判断字符串的长度是否满足条件
export function isLengthValidate(str, len) {
if (str) {
if (str.length <= len) {
return true;
} else {
return false;
}
} else {
return true;
}
}
// 判断输入的字符是否为:a-z,A-Z,0-9,_,汉字
export function isProgramName(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z0-9_\u4e00-\u9fa5]+$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否为:a-z,A-Z,0-9,_,汉字
export function isProgramCode(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z0-9_\u4e00-\u9fa5]+$/;
return reg.test(str);
}
return false;
}
// 判断输入的字符是否以http://或者https://开头,且必须是个网址
export function isProgramWeb(str) {
if (!isNull(str)) {
let reg = /^((https|http)?:\/\/)[^\s]+/;
return reg.test(str);
}
return false;
}
export function isValueTypeMatched(type, value) {
switch (type) {
case 'Integer':
if (!/^\-?\d+$/.test(value)) {
return false;
}
break;
case 'Double':
if (!/^\-?\d+\.\d+$/.test(value)) {
return false;
}
break;
case 'Long':
if (!/^\-?\d+$/.test(value)) {
return false;
}
break;
case 'Boolean':
if (value !== 'true' && value !== 'false') {
return false;
}
break;
default:
return true;
}
return true;
}
export function isProperties(str) {
if (!isNull(str)) {
let reg = /^[a-zA-Z\u4e00-\u9fa5][a-zA-Z_0-9\u4e00-\u9fa5]*\s*=\s*[a-zA-Z_0-9\u4e00-\u9fa5]+/;
return reg.test(str);
}
return false;
}
// 拒绝码以大写字母开头,包含数字、大写字母、下划线,且为四段式
export function isUppercase(str) {
const reg = /^[A-Z]([A-Z0-9]*_){1}([A-Z0-9]+_){2}[A-Z0-9]+$/;
return reg.test(str);
}
//判断用户名
export function isUserName(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z\d_]{4,20}$/;
return reg.test(str);
}
return false;
}
//判断密码
export function isPassword(str) {
if (!isNull(str)) {
const reg = /^[a-zA-Z\d]{6,14}$/;
return reg.test(str);
}
return false;
}
//判断手机号
export function isPhone(str) {
if (!isNull(str)) {
const reg = /^1[3456789]\d{9}$/;
return reg.test(str);
}
return false;
}
// 判断税号
export function isTax(str) {
if (!isNull(str)) {
const reg = /^[A-Z0-9]{15}$|^[A-Z0-9]{17}$|^[A-Z0-9]{18}$|^[A-Z0-9]{20}$/;
return reg.test(str);
}
return false;
}
// 判断银行号
export function isBankNumber(str) {
if (!isNull(str)) {
const reg = /^[0-9]{16}$|^[0-9]{17}$|^[0-9]{19}$/;
return reg.test(str);
}
return false;
}
// 判断中文地址不能少于5个汉字,且必须有一位数字
export function isChnAddress(str) {
const isNum = /[0-9]\d*/;
const isChinese_var = /[\u4e00-\u9fa5]/g;
if (!isNull(str)) {
return isNum.test(str) && str.match(isChinese_var).length >= 5;
}
return false;
}
const ua = uni.getSystemInfoSync().ua||''
// 判断微信环境
export const isWechat = true
// 是否信用钱包
export const isXYQB = ua.indexOf("xyqb") > -1;
// 判断微信小程序环境
export const isWxMp = uni.getSystemInfoSync().platform === 'mp-weixin'
// 判断羊小咩(信用钱包)环境
export const isApp = false
// 判断真享生活
export const isVcc = ua.match(/VCC/i) == 'vcc';
// 判断IOS环境
export const isIOS = /iphone|ipad|ipod/.test(ua);
// 判读Android环境
export const isAndroid = /android/.test(ua);
// 判断
export const appVersion = ua.match(/xyqb\/([\d|.]+)/) ? ua.match(/xyqb\/([\d|.]+)/)[1] : '8.8.00';
export const isQQ = ua.match(/QQ/i) == 'qq';
export const isWeiBo = ua.match(/Weibo/i) == 'weibo';
export const isDingTalk = ua.match(/DingTalk/i) == 'dingtalk';
// 判读非微信浏览器和appwebview和小程序webview
export const isH5Normal = !isWechat && !isWxMp && !isApp;
/* eslint-disable prettier/prettier */
import { isApp, isWxMp, isH5Normal } from './validation.service';
import Bridge from '@qg/js-bridge';
import MpBridge from '@/service/mp';
import commonCfg from '@/config/common.setting';
import qs from 'qs';
import localStorage from '@/service/localStorage.service'
function getTokenFromNative(resolve = () => {}, reject = () => {}) {
const nativeBridge = new Bridge();
window.xyqbNativeEvent = function(res) {
const json = typeof res === 'string' ? JSON.parse(res) : res;
console.log(json, 'res');
if (json.event === 'getTokenSuccess'||json.event === 'loginAndLogoutNotification') {
const appData = json.data || {};
if (appData && appData.token) {
localStorage.set('vccToken', appData.token);
resolve(appData.token);
} else {
reject();
}
} else {
reject();
}
}
nativeBridge.getToken();
}
function getTokenFromWxMp(resolve = () => {}, reject = () => {}, clearToken) {
const mpBridge = new MpBridge();
mpBridge.getToken(res => {
if (res && res.vccToken) {
localStorage.set('vccToken', res.vccToken);
resolve(res.vccToken);
} else {
reject();
}
}, clearToken);
}
// 获取token从app
export function getTokenFromApp(clearToken = false) {
if (clearToken) {
localStorage.remove('vccToken');
}
return new Promise((resolve, reject) => {
if (localStorage.get('vccToken')) {
resolve(localStorage.get('vccToken'));
return;
}
if (isApp) {
console.log('is app');
getTokenFromNative(resolve, reject);
} else if (isWxMp) {
console.log('is wxmp');
getTokenFromWxMp(resolve, reject, clearToken);
} else {
// h5暂不做处理
console.log('not app or wxmp');
reject();
}
});
}
// 自动跳转对应平台页面
export function jumpTargetPlatformPage(schemeName = '', data = {}, exit = false) {
if (!schemeName || isH5Normal) return;
const query = qs.stringify(data, { encode: true, addQueryPrefix: true });
if (isApp && commonCfg.APP_URL_MAP[schemeName]) {
console.log('isApp goto ' + commonCfg.APP_URL_MAP[schemeName] + query);
const nativeBridge = new Bridge();
nativeBridge.openNewUrl({
data: {
newUrl: commonCfg.APP_URL_MAP[schemeName] + query
}
});
} else if (isWxMp && commonCfg.MP_URL_MAP[schemeName]) {
console.log('isWxMp goto ' + commonCfg.APP_URL_MAP[schemeName] + query);
const mpBridge = new MpBridge();
mpBridge.openNewUrl(commonCfg.MP_URL_MAP[schemeName] + query);
}
if (exit) {
window.history.back();
}
}
<svg width="12" height="13" viewBox="0 0 12 13" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="87.672%" y1="63.857%" x2="13.893%" y2="63.857%" id="b"><stop stop-color="#FF5D00" offset="0%"/><stop stop-color="#FF1900" offset="100%"/></linearGradient><circle id="a" cx="6" cy="6" r="6"/></defs><g fill="none" fill-rule="evenodd"><g transform="translate(0 .5)"><use fill="#FFF" xlink:href="#a"/><use fill="url(#b)" xlink:href="#a"/></g><path d="M7.883 6.762l-3.2 2.963a.422.422 0 0 1-.566 0 .35.35 0 0 1 0-.523L7.037 6.5l-2.92-2.702a.35.35 0 0 1 0-.523.422.422 0 0 1 .565 0l3.2 2.963a.351.351 0 0 1 0 .525z" fill="#FFF"/></g></svg>
\ No newline at end of file
<svg width="8px" height="13px" viewBox="0 0 8 13" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-3" transform="translate(-0.000000, 0.000000)" fill="#DCDEE0">
<polygon id="三角形" transform="translate(4.000000, 2.000000) scale(1, -1) rotate(-180.000000) translate(-4.000000, -2.000000) " points="4 0 8 4 0 4"></polygon>
<polygon id="三角形备份-2" transform="translate(4.000000, 11.000000) rotate(-180.000000) translate(-4.000000, -11.000000) " points="4 9 8 13 0 13"></polygon>
</g>
</g>
</svg>
\ No newline at end of file
<svg width="30" height="30" viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><circle fill="#FFF3F3" cx="15" cy="15" r="15"/><path d="M22.815 10.484a.39.39 0 0 0-.303-.153H10.097L9.57 7.562a.382.382 0 0 0-.38-.308H7.46a.386.386 0 0 0 0 .773H8.87l.497 2.767v.007l1.559 8.102c.035.181.208.309.393.309h9.263a.387.387 0 0 0 0-.773h-8.945l-.238-1.218 9.66.05c.178 0 .334-.15.375-.323l1.451-6.136a.38.38 0 0 0-.07-.328zm-2.06 5.963l-9.502-.02-.703-3.69-.306-1.618h11.78l-1.27 5.328zm-8.262 3.56c-.744 0-1.35.606-1.35 1.35 0 .745.606 1.35 1.35 1.35.745 0 1.35-.605 1.35-1.35 0-.744-.605-1.35-1.35-1.35zm0 1.931a.58.58 0 0 1-.579-.579.58.58 0 0 1 .58-.579.58.58 0 0 1 .578.579.58.58 0 0 1-.579.579zm6.561-1.93c-.744 0-1.35.605-1.35 1.35 0 .744.606 1.35 1.35 1.35a1.35 1.35 0 0 0 0-2.7zm0 1.93a.58.58 0 0 1-.579-.579.58.58 0 0 1 .58-.579.58.58 0 0 1 0 1.158z" fill="#EC1500" fill-rule="nonzero"/></g></svg>
\ No newline at end of file
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="运营活动" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="首页弹出框备份-2" transform="translate(-6.000000, -658.000000)">
<g id="关闭" transform="translate(6.000000, 658.000000)">
<circle id="椭圆形" fill-opacity="0.850648253" fill="#232323" cx="9" cy="9" r="9"></circle>
<path d="M9.72196431,9 L12.8504763,12.128512 C13.0498412,12.3278769 13.0498412,12.6511114 12.8504763,12.8504763 C12.6511114,13.0498412 12.3278769,13.0498412 12.128512,12.8504763 L9,9.72196431 L5.87148801,12.8504763 C5.67212307,13.0498412 5.34888864,13.0498412 5.1495237,12.8504763 C4.95015877,12.6511114 4.95015877,12.3278769 5.1495237,12.128512 L8.27803569,9 L5.1495237,5.87148801 C4.95015877,5.67212307 4.95015877,5.34888864 5.1495237,5.1495237 C5.34888864,4.95015877 5.67212307,4.95015877 5.87148801,5.1495237 L9,8.27803569 L12.128512,5.1495237 C12.3278769,4.95015877 12.6511114,4.95015877 12.8504763,5.1495237 C13.0498412,5.34888864 13.0498412,5.67212307 12.8504763,5.87148801 L9.72196431,9 Z" id="cross" fill="#FFFFFF"></path>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<svg width="10px" height="10px" viewBox="0 0 10 10" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="筛选" fill="#DCDEE0" fill-rule="nonzero">
<path d="M4.16729388,10 C4.08402756,10 4.00074799,9.95833554 3.95911509,9.95833554 C3.83421561,9.87500661 3.75093631,9.70833603 3.75093631,9.58334213 L3.75093631,5.95833564 L0.0870203228,0.666670115 C0.00375400285,0.54167686 -0.0378790273,0.375005107 0.0453871628,0.208335304 C0.128666728,0.0833420491 0.253565949,0 0.420111834,0 L9.5798953,0 C9.74644118,0 9.87134118,0.0833289235 9.95460698,0.208335304 C10.0378865,0.33332856 9.99624014,0.5 9.91297382,0.625005913 L6.24907083,5.95833564 L6.24907083,8.74999311 C6.24907083,8.91666421 6.16579126,9.04165812 5.99925914,9.12499952 L4.33383924,9.95832774 C4.29220608,10 4.25057292,10 4.16729336,10 L4.16729388,10 Z" id="路径"></path>
</g>
</g>
</svg>
\ No newline at end of file
<svg width="10px" height="10px" viewBox="0 0 10 10" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="筛选" fill="#EC1500" fill-rule="nonzero">
<path d="M4.16729388,10 C4.08402756,10 4.00074799,9.95833554 3.95911509,9.95833554 C3.83421561,9.87500661 3.75093631,9.70833603 3.75093631,9.58334213 L3.75093631,5.95833564 L0.0870203228,0.666670115 C0.00375400285,0.54167686 -0.0378790273,0.375005107 0.0453871628,0.208335304 C0.128666728,0.0833420491 0.253565949,0 0.420111834,0 L9.5798953,0 C9.74644118,0 9.87134118,0.0833289235 9.95460698,0.208335304 C10.0378865,0.33332856 9.99624014,0.5 9.91297382,0.625005913 L6.24907083,5.95833564 L6.24907083,8.74999311 C6.24907083,8.91666421 6.16579126,9.04165812 5.99925914,9.12499952 L4.33383924,9.95832774 C4.29220608,10 4.25057292,10 4.16729336,10 L4.16729388,10 Z" id="路径"></path>
</g>
</g>
</svg>
\ No newline at end of file
import Vue from 'vue';
import SvgIcon from '@/components/SvgIcon'; // svg component
// register globally
Vue.component('svg-icon', SvgIcon);
const req = require.context('./', false, /\.svg$/);
const requireAll = requireContext => requireContext.keys().map(requireContext);
requireAll(req);
<svg width="12px" height="13px" viewBox="0 0 12 13" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient x1="87.672023%" y1="63.8571372%" x2="13.892539%" y2="63.8571372%" id="linearGradient-pez1im_683-1">
<stop stop-color="#FF5D00" offset="0%"></stop>
<stop stop-color="#FF1900" offset="100%"></stop>
</linearGradient>
<circle id="path-pez1im_683-2" cx="6" cy="6" r="6"></circle>
</defs>
<g id="电商页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="商品详情页-海报分享" transform="translate(-339.000000, -530.000000)">
<g id="编组-4" transform="translate(8.000000, 515.000000)">
<g id="编组-2备份-4" transform="translate(301.000000, 12.000000)">
<g id="编组-24" transform="translate(30.000000, 3.500000)">
<g id="椭圆形">
<use fill="#FFFFFF" xlink:href="#path-pez1im_683-2"></use>
<use fill="url(#linearGradient-pez1im_683-1)" xlink:href="#path-pez1im_683-2"></use>
</g>
<path d="M4.1169816,5.73768175 L7.31772547,2.77494937 C7.47370094,2.63057243 7.72658715,2.63057243 7.88256262,2.77494937 C8.03853809,2.9193263 8.03853809,3.15340756 7.88256262,3.29778449 L4.96349217,5.99978906 L7.8830184,8.70221551 C8.03899387,8.84659244 8.03899387,9.0806737 7.8830184,9.22505063 C7.72704292,9.36942757 7.47415672,9.36942757 7.31818124,9.22505063 L4.11743738,6.26231825 C4.06262355,6.21158046 4.02707273,6.14976416 4.0107849,6.08465591 C3.9799153,5.96400854 4.0153142,5.83178903 4.1169816,5.73768175 Z" id="Path" fill="#FFFFFF" transform="translate(6.000000, 6.000000) rotate(-180.000000) translate(-6.000000, -6.000000) "></path>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="14px" viewBox="0 0 16 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>shijian</title>
<defs>
<polygon id="path-1" points="0 0 16 0 16 14 0 14"></polygon>
<pattern id="pattern-3" width="100%" height="100%" patternUnits="objectBoundingBox">
<use xlink:href="#image-4"></use>
</pattern>
<image id="image-4" width="14" height="14" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAADqADAAQAAAABAAAADgAAAAC98Dn6AAAA6klEQVQoFV2Ryw0CMQxEd/ldoAMKoVN6ow+4AEuYZ/JQwNLIsePx2MncWjtN0/TqWOLFM+dzgDeHr9pNDutAazkALrExtjl+gbiiopuFc2KA2Uhiqar4X0gzcpIclbGrwT9RFS4luqP+h4iC3SU/kkMJfw9Uq3VQBAQYfhvsCGK34BrQoAjxWJP4CT/joc5LH4NLcOgxkzjNPO4IQRKK+wBFjJha7quBigSSyFGIKiOyH8ajkCsBFSvoF2OOvSDzMBgx5BdFI4mkXXOsQpQgux/51djdBnoKfUm8fwuxXtVCfS3PbbeR9FV9A+FBV/EffopMAAAAAElFTkSuQmCC"></image>
</defs>
<g id="---0417基础页面" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="商品详情页-海报分享" transform="translate(-243.000000, -467.000000)">
<g id="编组-2" transform="translate(8.000000, 427.000000)">
<g id="编组-15" transform="translate(233.000000, 37.910256)">
<g id="编组" transform="translate(2.000000, 0.089744)">
<g id="shijian" transform="translate(0.000000, 2.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Clip-2"></g>
<circle id="椭圆形" fill="url(#pattern-3)" mask="url(#mask-2)" cx="9" cy="7" r="7"></circle>
<path d="M6.07089281,9.41172227 L8.12773946,7.38217496 L8.12773946,3.28015278 L9.44296831,3.28015278 L9.44296831,7.89539759 C9.35150947,7.98558984 7.00168188,10.3295089 7.00168188,10.3295089 L6.07089281,9.41172227 Z M8.90326347,0 L8.90326347,1.23080905 C12.1279105,1.23080905 14.7517237,3.81874257 14.7517237,6.99997109 C14.7517237,10.1810261 12.1279105,12.7689789 8.90326347,12.7689789 C5.94402299,12.7689789 3.49243767,10.5887514 3.10883821,7.77153022 L3.99893982,8.63752232 L4.88140032,7.76707747 L2.44324068,5.36226564 L-0.00117254916,7.76730879 L0.881287948,8.63773436 L1.84254375,7.68960736 C2.19491431,11.226516 5.2269701,14 8.90355661,14 C12.8162554,14 16,10.8598293 16,7.00018312 C15.9996873,3.14040201 12.8161773,0 8.90326347,0 Z" id="Fill-1" fill="#FFFFFF" mask="url(#mask-2)"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<svg width="26px" height="26px" viewBox="0 0 26 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="搜索词样式优化" transform="translate(-332.000000, -487.000000)">
<g id="编组备份-14" transform="translate(12.000000, 401.000000)">
<g id="一键加购" transform="translate(321.000000, 87.000000)">
<rect id="加购" stroke="#C8C9CC" stroke-width="0.5" fill="#FFFFFF" x="0" y="0" width="24" height="24" rx="12"></rect>
<path d="M17.381072,8.07995938 L7.77489146,8.07995938 L7.63837546,7.3 C7.50196607,6.54597969 6.8197059,6 6.02826278,6 L5.04585078,6 C4.74561366,6 4.5,6.234 4.5,6.52004063 C4.5,6.806 4.74561366,7.03997969 5.04585078,7.03997969 L6.02826278,7.03997969 C6.30116685,7.03997969 6.51946878,7.222 6.57409224,7.48202031 L7.85674135,14.5019797 L7.85674135,14.5540203 C7.96586034,15.022 8.40250685,15.3600203 8.92102458,15.3600203 L16.4258864,15.3600203 C16.9444255,15.3600203 17.4083837,14.9959797 17.4902549,14.5019797 L18.472667,9.30197969 C18.472667,9.25 18.5,9.172 18.5,9.12004063 C18.472667,8.54802031 17.981461,8.07995938 17.381072,8.07995938 Z M16.4258864,14.3200406 L8.92102458,14.3200406 L7.99317207,9.12004063 L17.4083837,9.12004063 L16.4258864,14.3200406 Z M8.59356102,15.8799594 C7.69302023,15.8799594 6.95611529,16.5820203 6.95611529,17.4399797 C6.95611529,18.2980203 7.69302023,19 8.59356102,19 C9.4941018,19 10.2310067,18.2980203 10.2310067,17.4399797 C10.2310067,16.5820203 9.4941018,15.8799594 8.59356102,15.8799594 Z M8.59356102,17.9600203 C8.29340918,17.9600203 8.04771024,17.7260203 8.04771024,17.4399797 C8.04771024,17.1540203 8.29340918,16.9200406 8.59356102,16.9200406 C8.89371285,16.9200406 9.13941179,17.1540203 9.13941179,17.4399797 C9.13941179,17.7260203 8.89371285,17.9600203 8.59356102,17.9600203 Z M16.5077577,15.8799594 C15.6072169,15.8799594 14.8703119,16.5820203 14.8703119,17.4399797 C14.8703119,18.2980203 15.6072169,19 16.5077577,19 C17.4083837,19 18.1452034,18.2980203 18.1452034,17.4399797 C18.1452034,16.5820203 17.4083837,15.8799594 16.5077577,15.8799594 Z M16.5077577,17.9600203 C16.2076058,17.9600203 15.9620135,17.7260203 15.9620135,17.4399797 C15.9620135,17.1540203 16.2076058,16.9200406 16.5077577,16.9200406 C16.8079948,16.9200406 17.0536084,17.1540203 17.0536084,17.4399797 C17.0536084,17.7260203 16.8079948,17.9600203 16.5077577,17.9600203 Z" id="Fill-1" fill="#666666"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1600935447036" class="icon" viewBox="0 0 1150 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13605" xmlns:xlink="http://www.w3.org/1999/xlink" width="898.4375" height="800"><defs><style type="text/css"></style></defs><path d="M815.338057 760.110324c-3.569371 0-6.456076-2.720914-6.456076-6.075734s2.886705-6.075733 6.456076-6.075733h226.0992c3.559619 0 6.446324 2.720914 6.446324 6.075733s-2.886705 6.075733-6.436571 6.075734H815.328305z m-804.015543 0c-3.559619 0-6.446324-2.720914-6.446324-6.075734s2.886705-6.075733 6.446324-6.075733h257.589638c3.559619 0 6.436571 2.720914 6.436572 6.075733s-2.876952 6.075733-6.436572 6.075734H11.312762z m286.573715 0c-3.559619 0-6.446324-2.720914-6.446324-6.075734s2.886705-6.075733 6.436571-6.075733h33.83101c3.559619 0 6.446324 2.720914 6.446324 6.075733s-2.886705 6.075733-6.446324 6.075734h-33.821257z m787.504761 0c-3.559619 0-6.436571-2.720914-6.436571-6.075734s2.876952-6.075733 6.436571-6.075733h50.25402c3.559619 0 6.436571 2.720914 6.436571 6.075733s-2.876952 6.075733-6.436571 6.075734h-50.244267z" fill="#666666" p-id="13606"></path><path d="M256.585143 713.56221a30.086095 30.086095 0 1 1 0-60.172191 30.086095 30.086095 0 1 1 0 60.172191z m0-12.892648a17.193448 17.193448 0 1 0 0-34.386895 17.193448 17.193448 0 0 0 0 34.386895z m55.881143-640.487619a30.086095 30.086095 0 1 1 0-60.181943 30.086095 30.086095 0 1 1 0 60.17219z m0-12.892648a17.193448 17.193448 0 1 0 0-34.396647 17.193448 17.193448 0 1 0 0 34.396647z" fill="#999999" p-id="13607"></path><path d="M174.723657 455.387429a7.528838 7.528838 0 0 0 7.3728-7.3728v-13.165715h13.692343a7.528838 7.528838 0 0 0 7.3728-7.3728 7.528838 7.528838 0 0 0-7.3728-7.3728h-13.692343v-13.165714a7.528838 7.528838 0 0 0-7.3728-7.3728 7.528838 7.528838 0 0 0-7.3728 7.3728v13.165714h-13.692343a7.528838 7.528838 0 0 0-7.3728 7.3728c0 3.6864 3.159771 7.3728 7.3728 7.3728h13.692343v13.165715c0 4.213029 3.159771 7.3728 7.3728 7.3728z" fill="#D1E7FF" p-id="13608"></path><path d="M1008.620495 479.534324c0.692419-0.029257 0.897219 0.195048 0.877715 0.877714-0.029257 3.637638 0 7.285029 0 10.922667 0 3.676648-0.029257 7.353295 0 11.02019 0 0.57539-0.126781 0.838705-0.546134 0.906972l-0.37059 0.019504c-1.755429-0.03901-3.510857-0.03901-5.256534 0-0.565638 0-0.741181-0.195048-0.741181-0.750933v-22.206171c0-0.585143 0.175543-0.809448 0.780191-0.789943 1.755429 0.019505 3.510857 0.029257 5.256533 0z m21.767315-10.990934l18.178438 18.217448c0.03901 0.03901 0.068267 0.097524 0.195047 0.321829-1.531124 1.501867-3.052495 3.03299-4.612876 4.486095-0.126781 0.117029-0.672914-0.03901-0.877714-0.234057-2.555124-2.506362-5.090743-5.061486-7.626362-7.587353l-9.908419-9.918171-0.682667-0.721676c0.117029-0.175543 0.214552-0.360838 0.331581-0.487619 1.355581-1.355581 2.691657-2.681905 4.017981-4.027734 0.331581-0.341333 0.585143-0.44861 0.984991-0.048762z m-42.383848 0.175543c1.170286 1.26781 2.408838 2.4576 3.64739 3.657143 0.341333 0.341333 0.44861 0.594895 0.058515 1.004495l-17.905372 17.885867c-0.078019 0.078019-0.195048 0.126781-0.390095 0.273067-1.531124-1.521371-3.023238-2.993981-4.46659-4.5056-0.107276-0.107276-0.068267-0.44861 0-0.643657 0.03901-0.146286 0.224305-0.253562 0.341333-0.370591 5.753905-5.763657 11.537067-11.517562 17.290971-17.300724 0.555886-0.585143 0.897219-0.565638 1.423848 0z m-7.5776-22.89859c0.594895 0 0.887467 0.117029 0.965486 0.565638l0.019504 0.399848a97.123962 97.123962 0 0 0 0 5.168761c0 0.594895-0.2048 0.78019-0.789942 0.780191-7.41181-0.019505-14.823619-0.019505-22.206172 0-0.643657 0-0.770438-0.263314-0.770438-0.828952 0.03901-1.755429 0.03901-3.501105 0-5.246781 0-0.643657 0.2048-0.838705 0.848457-0.838705l5.500343 0.019505h5.510095c3.637638 0 7.285029 0.019505 10.922667-0.019505z m78.682209 0c0.702171 0 0.955733 0.185295 0.936229 0.926476a116.736 116.736 0 0 0 0 5.237029c0 0.565638-0.195048 0.750933-0.750933 0.750933h-22.196419c-0.682667 0-0.8192-0.263314-0.809448-0.877714 0.029257-1.706667 0.03901-3.44259 0-5.168762-0.029257-0.682667 0.214552-0.867962 0.877714-0.867962l5.510096 0.019505h5.510095c3.64739 0 7.285029 0.019505 10.922666-0.019505z m-85.586895-33.704229l0.721676 0.682667 17.534781 17.505524c0.585143 0.585143 0.526629 0.897219-0.019504 1.4336-1.39459 1.345829-2.750171 2.759924-4.183772 4.242285-0.390095-0.351086-0.643657-0.565638-0.877714-0.809447-5.783162-5.77341-11.546819-11.566324-17.359238-17.320229-0.633905-0.633905-0.585143-0.975238 0.029257-1.560381 1.414095-1.336076 2.750171-2.750171 4.154514-4.174019z m70.090362 0c1.511619 1.531124 2.993981 3.003733 4.447086 4.5056 0.107276 0.117029 0.068267 0.44861 0.009752 0.643657-0.048762 0.146286-0.224305 0.253562-0.331581 0.370591-5.783162 5.77341-11.556571 11.527314-17.300724 17.310476-0.565638 0.57539-0.887467 0.565638-1.4336-0.009752-1.170286-1.26781-2.408838-2.4576-3.637638-3.666896-0.331581-0.331581-0.458362-0.585143-0.068266-0.98499l17.915123-17.895619c0.087771-0.078019 0.185295-0.126781 0.390096-0.273067z m-34.98179-11.234743c0.702171-0.029257 0.877714 0.224305 0.877714 0.877715-0.029257 3.676648-0.019505 7.353295-0.019505 11.02019v0.009753c0 3.618133-0.019505 7.236267 0.019505 10.8544 0 0.633905-0.146286 0.916724-0.604648 0.994742l-0.4096 0.019505a101.015162 101.015162 0 0 0-5.090743-0.009752c-0.565638 0-0.8192-0.126781-0.8192-0.750934v-22.225676c0-0.604648 0.195048-0.809448 0.780191-0.78019 1.765181 0.019505 3.52061 0.029257 5.266286 0z" fill="#52CC90" p-id="13609"></path><path d="M890.63619 235.129905a13.390019 13.390019 0 0 1-8.97219 3.462095c-3.540114 0-7.12899-1.414095-9.752381-4.174019-66.540495-69.992838-160.797257-110.162895-258.769676-110.162895s-188.884114 38.180571-256.195048 107.539504a13.507048 13.507048 0 0 1-18.724571 0.507124 12.65859 12.65859 0 0 1-0.585143-18.217447c72.313905-74.556952 170.159543-115.614476 275.446248-115.614477s206.652952 43.17379 278.196419 118.432915c5.002971 5.198019 4.681143 13.409524-0.643658 18.2272z m-277.494247-24.254172c79.306362 0 155.140876 32.914286 208.0768 90.277791 4.934705 5.383314 4.486095 13.653333-1.024 18.471009-2.574629 2.243048-5.77341 3.335314-8.981943 3.335315-3.72541 0-7.382552-1.462857-10.07421-4.359315-47.806171-51.843657-116.3264-81.607924-187.92838-81.607923-70.256152 0-137.820648 28.808533-185.490286 78.97478a13.789867 13.789867 0 0 1-19.056153 0.780191 12.804876 12.804876 0 0 1-0.770438-18.490514c52.682362-55.559314 127.561143-87.381333 205.24861-87.381334z m0.068267 125.942248c48.313295 0 93.671619 22.528 124.411123 61.732571a14.316495 14.316495 0 0 1-1.80419 19.436496 12.648838 12.648838 0 0 1-18.47101-1.930972c-25.736533-32.846019-63.712305-51.707124-104.135923-51.707124-39.136305 0-76.283124 17.837105-101.883124 48.956953a12.746362 12.746362 0 0 1-18.549029 1.404343 14.238476 14.238476 0 0 1-1.345828-19.436496c30.671238-37.156571 74.99581-58.455771 121.777981-58.455771z m1.287314 98.108952a56.046933 56.046933 0 0 1 56.07619 56.076191 56.046933 56.046933 0 0 1-56.07619 56.07619 56.046933 56.046933 0 0 1-56.076191-56.07619 56.134705 56.134705 0 0 1 56.076191-56.076191z m0 84.114286a28.067352 28.067352 0 0 0 28.038095-28.038095 28.028343 28.028343 0 0 0-28.038095-28.038095 28.028343 28.028343 0 0 0-28.038095 28.038095 28.067352 28.067352 0 0 0 28.038095 28.038095zM616.272457 565.062705c6.524343 0 11.6736 5.15901 11.6736 11.332266l0.341333 61.810591h35.108572a132.047238 132.047238 0 0 0 75.12259 80.115809v17.408a24.478476 24.478476 0 0 1-24.380952 24.380953H419.498667a24.478476 24.478476 0 0 1-24.380953-24.380953v-73.142857a24.478476 24.478476 0 0 1 24.380953-24.380952H603.574857v-61.810591c0-6.173257 5.149257-11.332267 11.332267-11.332266h1.365333zM505.699962 687.318552c-6.875429 0-12.366019 5.49059-12.366019 12.014934s5.49059 12.014933 12.366019 12.014933c6.865676 0 12.356267-5.49059 12.356267-12.014933 0-6.865676-5.49059-12.014933-12.356267-12.014934z m48.761905 0c-6.875429 0-12.366019 5.49059-12.366019 12.014934 0.341333 6.524343 5.841676 12.014933 12.366019 12.014933 6.865676 0 12.356267-5.49059 12.356266-12.014933 0-6.865676-5.49059-12.014933-12.356266-12.014934z m-97.874896 0c-6.865676 0-12.356267 5.49059-12.356266 12.014934s5.49059 12.014933 12.356266 12.014933c6.875429 0 12.366019-5.49059 12.366019-12.014933 0-6.865676-5.49059-12.014933-12.366019-12.014934z" fill="#999999" p-id="13610"></path><path d="M788.284952 493.987352c-56.554057 0-102.4 45.855695-102.4 102.4s45.845943 102.4 102.4 102.4c56.534552 0 102.4-45.855695 102.4-102.4s-45.865448-102.4-102.4-102.4z m49.893181 137.840153a10.24 10.24 0 0 1-14.492038 14.482285l-35.401143-35.440152-35.440152 35.410895a10.259505 10.259505 0 0 1-14.482286 0 10.24 10.24 0 0 1 0-14.482285l35.4304-35.410896-35.410895-35.440152a10.24 10.24 0 0 1 14.482286-14.482286l35.410895 35.440153 35.440152-35.440153a10.24 10.24 0 0 1 14.482286 14.482286l-35.4304 35.440152 35.401143 35.440153z" fill="#FC5A5A" p-id="13611"></path></svg>
\ No newline at end of file
@font-face {
font-family: 'iconfont'; /* Project id 2314957 */
src: url('data:application/x-font-woff2;charset=utf-8;base64,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')
format('woff2'),
url('//at.alicdn.com/t/font_2314957_9tncsytx5v8.woff?t=1639991676072') format('woff'),
url('//at.alicdn.com/t/font_2314957_9tncsytx5v8.ttf?t=1639991676072') format('truetype');
}
.iconfont {
font-family: 'iconfont' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-qrcode:before {
content: '\e629';
}
.icon-edit:before {
content: '\e643';
}
.icon-cart:before {
content: '\e642';
}
.icon-photo-line-bold:before {
content: '\e6b9';
}
.icon-qq:before {
content: '\e6ba';
}
.icon-download-line-bold:before {
content: '\e6bb';
}
.icon-weixin:before {
content: '\e6bc';
}
.icon-mini-apps-o:before {
content: '\e6bd';
}
.icon-qrcode-bold:before {
content: '\e6be';
}
.icon-weibo:before {
content: '\e6c1';
}
.icon-qzone:before {
content: '\e6c2';
}
.icon-moments:before {
content: '\e6c3';
}
.icon-link:before {
content: '\e6c4';
}
.icon-back-top:before {
content: '\e6b6';
}
.icon-fenxiang:before {
content: '\e6b7';
}
.icon-gouwuche:before {
content: '\e6b8';
}
.icon-order-line:before {
content: '\e6b5';
}
.icon-location:before {
content: '\e602';
}
.icon-sort-down-round:before {
content: '\e74d';
}
.icon-sort-up-round:before {
content: '\e641';
}
.icon-share-line:before {
content: '\e63e';
}
.icon-yuan:before {
content: '\e63f';
}
.icon-setting-line:before {
content: '\e640';
}
.icon-arrow:before {
content: '\e612';
}
.icon-arrow-left:before {
content: '\e613';
}
.icon-minus:before {
content: '\e614';
}
.icon-close-plane:before {
content: '\e615';
}
.icon-photo-plane:before {
content: '\e616';
}
.icon-arrow-up:before {
content: '\e617';
}
.icon-trash:before {
content: '\e618';
}
.icon-tianjia:before {
content: '\e619';
}
.icon-sort-up:before {
content: '\e61a';
}
.icon-setting-plane:before {
content: '\e61b';
}
.icon-plus:before {
content: '\e61c';
}
.icon-back-top-line:before {
content: '\e61d';
}
.icon-location-plane:before {
content: '\e61e';
}
.icon-arrow-down:before {
content: '\e61f';
}
.icon-cart-card:before {
content: '\e620';
}
.icon-sort-down:before {
content: '\e621';
}
.icon-info-plane:before {
content: '\e622';
}
.icon-info-line:before {
content: '\e623';
}
.icon-search:before {
content: '\e624';
}
.icon-home-plane:before {
content: '\e625';
}
.icon-user-plane:before {
content: '\e626';
}
.icon-location-line:before {
content: '\e627';
}
.icon-weinxin:before {
content: '\e628';
}
.icon-camera-line:before {
content: '\e62a';
}
.icon-warning-line:before {
content: '\e62b';
}
.icon-cart-line:before {
content: '\e62c';
}
.icon-found-plane:before {
content: '\e62d';
}
.icon-success:before {
content: '\e62e';
}
.icon-warning-plane:before {
content: '\e62f';
}
.icon-home:before {
content: '\e630';
}
.icon-loading:before {
content: '\e631';
}
.icon-checked:before {
content: '\e632';
}
.icon-fail:before {
content: '\e633';
}
.icon-volume:before {
content: '\e634';
}
.icon-close-line:before {
content: '\e635';
}
.icon-user:before {
content: '\e636';
}
.icon-photo-line:before {
content: '\e637';
}
.icon-circle:before {
content: '\e638';
}
.icon-close:before {
content: '\e639';
}
.icon-found-line:before {
content: '\e63a';
}
.icon-home-line:before {
content: '\e63b';
}
.icon-customer:before {
content: '\e63c';
}
.icon-cart-plane:before {
content: '\e63d';
}
@font-face { @font-face {
font-family: "iconfont"; /* Project id 2314957 */ font-family: 'iconfont'; /* Project id 2314957 */
src: src: url('data:application/x-font-woff2;charset=utf-8;base64,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')
url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), format('woff2'),
url('//at.alicdn.com/t/font_2314957_i2934lpwxv.woff?t=1646303283345') format('woff'), url('//at.alicdn.com/t/font_2314957_9tncsytx5v8.woff?t=1639991676072') format('woff'),
url('//at.alicdn.com/t/font_2314957_i2934lpwxv.ttf?t=1646303283345') format('truetype'); url('//at.alicdn.com/t/font_2314957_9tncsytx5v8.ttf?t=1639991676072') format('truetype');
} }
.iconfont { .iconfont {
font-family: "iconfont" !important; font-family: 'iconfont' !important;
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-saoyisao:before {
content: "\e644";
}
.icon-qrcode:before { .icon-qrcode:before {
content: "\e629"; content: '\e629';
} }
.icon-edit:before { .icon-edit:before {
content: "\e643"; content: '\e643';
} }
.icon-cart:before { .icon-cart:before {
content: "\e642"; content: '\e642';
} }
.icon-photo-line-bold:before { .icon-photo-line-bold:before {
content: "\e6b9"; content: '\e6b9';
} }
.icon-qq:before { .icon-qq:before {
content: "\e6ba"; content: '\e6ba';
} }
.icon-download-line-bold:before { .icon-download-line-bold:before {
content: "\e6bb"; content: '\e6bb';
} }
.icon-weixin:before { .icon-weixin:before {
content: "\e6bc"; content: '\e6bc';
} }
.icon-mini-apps-o:before { .icon-mini-apps-o:before {
content: "\e6bd"; content: '\e6bd';
} }
.icon-qrcode-bold:before { .icon-qrcode-bold:before {
content: "\e6be"; content: '\e6be';
} }
.icon-weibo:before { .icon-weibo:before {
content: "\e6c1"; content: '\e6c1';
} }
.icon-qzone:before { .icon-qzone:before {
content: "\e6c2"; content: '\e6c2';
} }
.icon-moments:before { .icon-moments:before {
content: "\e6c3"; content: '\e6c3';
} }
.icon-link:before { .icon-link:before {
content: "\e6c4"; content: '\e6c4';
} }
.icon-back-top:before { .icon-back-top:before {
content: "\e6b6"; content: '\e6b6';
} }
.icon-fenxiang:before { .icon-fenxiang:before {
content: "\e6b7"; content: '\e6b7';
} }
.icon-gouwuche:before { .icon-gouwuche:before {
content: "\e6b8"; content: '\e6b8';
} }
.icon-order-line:before { .icon-order-line:before {
content: "\e6b5"; content: '\e6b5';
} }
.icon-location:before { .icon-location:before {
content: "\e602"; content: '\e602';
} }
.icon-sort-down-round:before { .icon-sort-down-round:before {
content: "\e74d"; content: '\e74d';
} }
.icon-sort-up-round:before { .icon-sort-up-round:before {
content: "\e641"; content: '\e641';
} }
.icon-share-line:before { .icon-share-line:before {
content: "\e63e"; content: '\e63e';
} }
.icon-yuan:before { .icon-yuan:before {
content: "\e63f"; content: '\e63f';
} }
.icon-setting-line:before { .icon-setting-line:before {
content: "\e640"; content: '\e640';
} }
.icon-arrow:before { .icon-arrow:before {
content: "\e612"; content: '\e612';
} }
.icon-arrow-left:before { .icon-arrow-left:before {
content: "\e613"; content: '\e613';
} }
.icon-minus:before { .icon-minus:before {
content: "\e614"; content: '\e614';
} }
.icon-close-plane:before { .icon-close-plane:before {
content: "\e615"; content: '\e615';
} }
.icon-photo-plane:before { .icon-photo-plane:before {
content: "\e616"; content: '\e616';
} }
.icon-arrow-up:before { .icon-arrow-up:before {
content: "\e617"; content: '\e617';
} }
.icon-trash:before { .icon-trash:before {
content: "\e618"; content: '\e618';
} }
.icon-tianjia:before { .icon-tianjia:before {
content: "\e619"; content: '\e619';
} }
.icon-sort-up:before { .icon-sort-up:before {
content: "\e61a"; content: '\e61a';
} }
.icon-setting-plane:before { .icon-setting-plane:before {
content: "\e61b"; content: '\e61b';
} }
.icon-plus:before { .icon-plus:before {
content: "\e61c"; content: '\e61c';
} }
.icon-back-top-line:before { .icon-back-top-line:before {
content: "\e61d"; content: '\e61d';
} }
.icon-location-plane:before { .icon-location-plane:before {
content: "\e61e"; content: '\e61e';
} }
.icon-arrow-down:before { .icon-arrow-down:before {
content: "\e61f"; content: '\e61f';
} }
.icon-cart-card:before { .icon-cart-card:before {
content: "\e620"; content: '\e620';
} }
.icon-sort-down:before { .icon-sort-down:before {
content: "\e621"; content: '\e621';
} }
.icon-info-plane:before { .icon-info-plane:before {
content: "\e622"; content: '\e622';
} }
.icon-info-line:before { .icon-info-line:before {
content: "\e623"; content: '\e623';
} }
.icon-search:before { .icon-search:before {
content: "\e624"; content: '\e624';
} }
.icon-home-plane:before { .icon-home-plane:before {
content: "\e625"; content: '\e625';
} }
.icon-user-plane:before { .icon-user-plane:before {
content: "\e626"; content: '\e626';
} }
.icon-location-line:before { .icon-location-line:before {
content: "\e627"; content: '\e627';
} }
.icon-weinxin:before { .icon-weinxin:before {
content: "\e628"; content: '\e628';
} }
.icon-camera-line:before { .icon-camera-line:before {
content: "\e62a"; content: '\e62a';
} }
.icon-warning-line:before { .icon-warning-line:before {
content: "\e62b"; content: '\e62b';
} }
.icon-cart-line:before { .icon-cart-line:before {
content: "\e62c"; content: '\e62c';
} }
.icon-found-plane:before { .icon-found-plane:before {
content: "\e62d"; content: '\e62d';
} }
.icon-success:before { .icon-success:before {
content: "\e62e"; content: '\e62e';
} }
.icon-warning-plane:before { .icon-warning-plane:before {
content: "\e62f"; content: '\e62f';
} }
.icon-home:before { .icon-home:before {
content: "\e630"; content: '\e630';
} }
.icon-loading:before { .icon-loading:before {
content: "\e631"; content: '\e631';
} }
.icon-checked:before { .icon-checked:before {
content: "\e632"; content: '\e632';
} }
.icon-fail:before { .icon-fail:before {
content: "\e633"; content: '\e633';
} }
.icon-volume:before { .icon-volume:before {
content: "\e634"; content: '\e634';
} }
.icon-close-line:before { .icon-close-line:before {
content: "\e635"; content: '\e635';
} }
.icon-user:before { .icon-user:before {
content: "\e636"; content: '\e636';
} }
.icon-photo-line:before { .icon-photo-line:before {
content: "\e637"; content: '\e637';
} }
.icon-circle:before { .icon-circle:before {
content: "\e638"; content: '\e638';
} }
.icon-close:before { .icon-close:before {
content: "\e639"; content: '\e639';
} }
.icon-found-line:before { .icon-found-line:before {
content: "\e63a"; content: '\e63a';
} }
.icon-home-line:before { .icon-home-line:before {
content: "\e63b"; content: '\e63b';
} }
.icon-customer:before { .icon-customer:before {
content: "\e63c"; content: '\e63c';
} }
.icon-cart-plane:before { .icon-cart-plane:before {
content: "\e63d"; content: '\e63d';
} }
// @font-face {
// font-family: 'iconfont'; /* project id 2032151 */
// src: url('//at.alicdn.com/t/font_2032151_38j664if0q9.eot');
// src: url('//at.alicdn.com/t/font_2032151_38j664if0q9.eot?#iefix') format('embedded-opentype'),
// url('//at.alicdn.com/t/font_2032151_38j664if0q9.woff2') format('woff2'),
// url('//at.alicdn.com/t/font_2032151_38j664if0q9.woff') format('woff'),
// url('//at.alicdn.com/t/font_2032151_38j664if0q9.ttf') format('truetype'),
// url('//at.alicdn.com/t/font_2032151_38j664if0q9.svg#iconfont') format('svg');
// }
@font-face {
font-family: 'din';
src: url('./DIN.ttf') format('truetype');
}
\ No newline at end of file
// @font-face {
// font-family: 'iconfont'; /* project id 2032151 */
// src: url('//at.alicdn.com/t/font_2032151_38j664if0q9.eot');
// src: url('//at.alicdn.com/t/font_2032151_38j664if0q9.eot?#iefix') format('embedded-opentype'),
// url('//at.alicdn.com/t/font_2032151_38j664if0q9.woff2') format('woff2'),
// url('//at.alicdn.com/t/font_2032151_38j664if0q9.woff') format('woff'),
// url('//at.alicdn.com/t/font_2032151_38j664if0q9.ttf') format('truetype'),
// url('//at.alicdn.com/t/font_2032151_38j664if0q9.svg#iconfont') format('svg');
// }
@font-face {
font-family: 'din';
src: url('./DIN.ttf') format('truetype');
}
\ No newline at end of file
@import 'reset.less';
@import 'var.less';
@import 'mixins.less';
@import 'iconfont.less';
@import 'icon.less';
html,
body,
#app {
height: 100%;
}
html {
font-size: 37.5px;
font-size: 10vw;
}
body {
font-family: @font-family;
background-color: @background-color;
}
button {
border: 0;
}
button:focus {
outline: 0;
}
.tel {
color: #5371e0;
font-size: 12px;
}
.page {
background-size: contain;
background-color: @background-color;
height: 100%;
padding: 0 @page-padding;
&__ios-fix-bottom {
&::after {
content: '';
display: block;
padding-bottom: @ios-bottom-height;
}
}
&__nopad {
padding: 0;
}
}
a {
color: @red;
.text-size(14);
}
textarea::-webkit-input-placeholder,
input::-webkit-input-placeholder {
color: @gray-3;
}
input,
textarea {
outline: none !important;
}
input {
-webkit-appearance: none;
}
strong {
font-weight: @font-weight-bold;
}
.cr-nav-bar {
&__title {
font-weight: 400 !important;
}
&__left {
color: @gray-4 !important;
}
}
.cr-cell-group::after,
.cr-cell-group_content::after {
display: none !important;
}
.cr-picker {
&--toolbar {
&-title {
font-size: 16px;
color: #333;
}
&-cancel {
color: #999999 !important;
}
&-confirm {
color: @red !important;
}
&::after {
display: none;
}
}
}
.has-header {
.app {
height: calc(100% - @nav-bar-height);
min-height: calc(100% - @nav-bar-height);
}
}
.has-tab-bar {
.app {
height: calc(100% - @tab-bar-height - constant(safe-area-inset-bottom));
height: calc(100% - @tab-bar-height - env(safe-area-inset-bottom));
min-height: calc(100% - @tab-bar-height - constant(safe-area-inset-bottom));
min-height: calc(100% - @tab-bar-height - env(safe-area-inset-bottom));
}
}
.cr-dialog--confirm,
.cr-dialog--confirm:active {
color: @red;
}
.cr-cell:last-child::after {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
bottom: 0;
left: 0.426667rem;
right: 0;
border-bottom: 0.026667rem solid #f2f3f5;
transform: scaleY(0.5);
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.cr-dialog--header {
padding: @padding-xl;
&--isolated {
padding-bottom: 0;
}
}
.cr-dialog-invoice {
.cr-dialog--header > div {
color: @black;
font-weight: bold;
}
.cr-dialog--close {
top: 12px;
right: 12px;
z-index: 1;
.cr-icon {
color: #c8c9cc;
}
}
.cr-dialog--message {
color: @black;
}
.cr-button::before,
.cr-button::after {
border-color: #ebedf0;
}
.cr-hairline--top::after {
border-color: #ebedf0;
}
}
.cr-toast {
left: 0;
max-width: 85vw;
right: 0;
margin: auto;
}
@import 'reset.scss';
@import 'var.scss';
@import 'mixins.scss';
@import 'iconfont.scss';
@import 'icon.scss';
html,
body,
#app {
height: 100%;
}
html {
font-size: 37.5px;
font-size: 10vw;
}
body {
font-family: $font-family;
background-color: $background-color;
}
button {
border: 0;
}
button:focus {
outline: 0;
}
.tel {
color: #5371e0;
font-size: 12px;
}
.page {
background-size: contain;
background-color: $background-color;
height: 100%;
padding: 0 $page-padding;
&__ios-fix-bottom {
&::after {
content: '';
display: block;
padding-bottom: $ios-bottom-height;
}
}
&__nopad {
padding: 0;
}
}
a {
color: $red;
@include text-size(14);
}
textarea::-webkit-input-placeholder,
input::-webkit-input-placeholder {
color: $gray-3;
}
input,
textarea {
outline: none !important;
}
input {
-webkit-appearance: none;
}
strong {
font-weight: $font-weight-bold;
}
.cr-nav-bar {
&__title {
font-weight: 400 !important;
}
&__left {
color: $gray-4 !important;
}
}
.cr-cell-group::after,
.cr-cell-group_content::after {
display: none !important;
}
.cr-picker {
&--toolbar {
&-title {
font-size: 16px;
color: #333;
}
&-cancel {
color: #999999 !important;
}
&-confirm {
color: $red !important;
}
&::after {
display: none;
}
}
}
.has-header {
.app {
height: calc(100% - $nav-bar-height);
min-height: calc(100% - $nav-bar-height);
}
}
.has-tab-bar {
.app {
height: calc(100% - $tab-bar-height - constant(safe-area-inset-bottom));
height: calc(100% - $tab-bar-height - env(safe-area-inset-bottom));
min-height: calc(100% - $tab-bar-height - constant(safe-area-inset-bottom));
min-height: calc(100% - $tab-bar-height - env(safe-area-inset-bottom));
}
}
.cr-dialog--confirm,
.cr-dialog--confirm:active {
color: $red;
}
.cr-cell:last-child::after {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
bottom: 0;
left: 0.426667rem;
right: 0;
border-bottom: 0.026667rem solid #f2f3f5;
transform: scaleY(0.5);
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.cr-dialog--header {
padding: $padding-xl;
&--isolated {
padding-bottom: 0;
}
}
.cr-dialog-invoice {
.cr-dialog--header > div {
color: $black;
font-weight: bold;
}
.cr-dialog--close {
top: 12px;
right: 12px;
z-index: 1;
.cr-icon {
color: #c8c9cc;
}
}
.cr-dialog--message {
color: $black;
}
.cr-button::before,
.cr-button::after {
border-color: #ebedf0;
}
.cr-hairline--top::after {
border-color: #ebedf0;
}
}
.cr-toast {
left: 0;
max-width: 85vw;
right: 0;
margin: auto;
}
.iphonex-fix-padding {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.iphonex-fix-margin {
margin-bottom: constant(safe-area-inset-bottom);
margin-bottom: env(safe-area-inset-bottom);
}
.countdown-mixin(@txtColor, @bgColor, @colonColor, @txtSize, @txtWeight) {
.cr-count-down {
font-size: 10px;
span {
box-sizing: border-box;
display: inline-block;
text-align: center;
height: @txtSize;
line-height: @txtSize+1;
font-weight: @txtWeight;
}
}
.block {
background-color: @bgColor;
color: @txtColor;
border-radius: 3.2px;
width: @txtSize;
}
.colon {
color: @colonColor;
width: 12px;
margin: 0 2px;
}
}
.through-line-mixin(@color) {
position: relative;
&:after {
content: ' ';
display: block;
position: absolute;
top: 0;
bottom: 0;
left: -5%;
margin: auto;
width: 110%;
height: 1px;
background-color: @color;
}
}
.border-divider-y(@left: 0; @right: inherit; @color: @grey-border) {
position: relative;
&::after {
content: '';
position: absolute;
width: 1px;
height: 100%;
background-color: @color;
top: 0;
left: @left;
right: @right;
transform: scaleX(0.5);
}
}
// 边框1像素问题
.mx_order_one(@color: @black, @type: solid, @bRadius: @border-radius-md) {
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 1px @type @color;
border-radius: @bRadius;
transform: scale(1, 1);
transform-origin: top left;
}
@media screen and (-webkit-min-device-pixel-ratio: 2) {
&::after {
transform: scale(0.5, 0.5);
width: 200%;
height: 200%;
border-radius: calc(@bRadius * 2);
}
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
&::after {
transform: scale(0.33, 0.33);
width: 300%;
height: 300%;
border-radius: calc(@bRadius * 3);
}
}
}
// 多行...
.mx_multline_overwrite(@line: 2) {
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: @line;
-webkit-box-orient: vertical;
}
.title-mixin {
color: #999;
font-size: 14px;
line-height: 18px;
}
.iphonex-fix-padding {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
.iphonex-fix-margin {
margin-bottom: constant(safe-area-inset-bottom);
margin-bottom: env(safe-area-inset-bottom);
}
@mixin countdown-mixin($txtColor, $bgColor, $colonColor, $txtSize, $txtWeight) {
.cr-count-down {
font-size: 10px;
span {
box-sizing: border-box;
display: inline-block;
text-align: center;
height: $txtSize;
line-height: $txtSize+1;
font-weight: $txtWeight;
}
}
.block {
background-color: $bgColor;
color: $txtColor;
border-radius: 3.2px;
width: $txtSize;
}
.colon {
color: $colonColor;
width: 12px;
margin: 0 2px;
}
}
@mixin through-line-mixin($color) {
position: relative;
&:after {
content: ' ';
display: block;
position: absolute;
top: 0;
bottom: 0;
left: -5%;
margin: auto;
width: 110%;
height: 1px;
background-color: $color;
}
}
@mixin border-divider-y($left: 0, $right: inherit, $color: $grey-border) {
position: relative;
&::after {
content: '';
position: absolute;
width: 1px;
height: 100%;
background-color: $color;
top: 0;
left: $left;
right: $right;
transform: scaleX(0.5);
}
}
// 边框1像素问题
@mixin mx_order_one($color: $black, $type: solid, $bRadius: $border-radius-md) {
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 1px $type $color;
border-radius: $bRadius;
transform: scale(1, 1);
transform-origin: top left;
}
@media screen and (-webkit-min-device-pixel-ratio: 2) {
&::after {
transform: scale(0.5, 0.5);
width: 200%;
height: 200%;
border-radius: calc($bRadius * 2);
}
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
&::after {
transform: scale(0.33, 0.33);
width: 300%;
height: 300%;
border-radius: calc($bRadius * 3);
}
}
}
// 多行...
@mixin mx_multline_overwrite($line: 2) {
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: $line;
-webkit-box-orient: vertical;
}
.title-mixin {
color: #999;
font-size: 14px;
line-height: 18px;
}
/* 中国移动认证css覆写 */
#YDRZ_Modal{
min-height: 0 !important;
padding-bottom: 20px;
border-radius: 16px !important;
#YDRZ_Closebtn + div{
display: none;
}
#YDRZ_Closebtn{
filter: grayscale(1);
opacity: .4;
}
#YDRZ_InputPhone{
width: 80% !important;
padding: 24px 0 18px !important;
}
.ydrz-input-val{
border-radius: 0px !important;
height: 24px !important;
width: 22px !important;
border: 0 !important;
border-bottom: 1px solid #DCDCDC !important;
}
#YDRZ_Agreement input:checked{
border: 1px solid #ec1500 !important;
background: #ec1500;
}
#YDRZ_Agreement input:checked::after{
border: 1px solid #fff;
border-top: none;
border-right: none;
}
#YDRZ_Agreement a {
font-size: 12px;
color: #ec1500 !important;
}
#YDRZ_Closebtn{
top: 16px !important;
right: 16px !important
}
}
/**
中国联通授权弹窗样式覆写
**/
#authxwLoginBox{
.xw-app-logo {
border-radius: 12px !important;
}
.xw-inputbox{
// border: 0 !important;
// border-bottom: 1px solid #dcdcdc !important;
background: transparent !important;
border-radius: 0 !important;
// padding: 0 !important;
// margin: 0 0.05em !important
}
.xw-agreement{
align-items: center !important;
a{
font-size: 12px !important;
}
}
.xw-agreeement-policy{
font-size: 12px;
color: #ec1500 !important;
}
.xw-img-back{
width: 0.15em !important;
}
.xw-back-area{
margin: 0.15em 0.06em 0 auto !important
}
.xw-btn{
border-radius: 0.2em !important;
background: linear-gradient(90deg,#ff1900,#ff5d00) !important;
&.disable {
background: #ccc !important;
}
span {
color:#fff !important;
font-weight: bold;
}
}
}
\ No newline at end of file
/* 中国移动认证css覆写 */
#YDRZ_Modal{
min-height: 0 !important;
padding-bottom: 20px;
border-radius: 16px !important;
#YDRZ_Closebtn + div{
display: none;
}
#YDRZ_Closebtn{
filter: grayscale(1);
opacity: .4;
}
#YDRZ_InputPhone{
width: 80% !important;
padding: 24px 0 18px !important;
}
.ydrz-input-val{
border-radius: 0px !important;
height: 24px !important;
width: 22px !important;
border: 0 !important;
border-bottom: 1px solid #DCDCDC !important;
}
#YDRZ_Agreement input:checked{
border: 1px solid #ec1500 !important;
background: #ec1500;
}
#YDRZ_Agreement input:checked::after{
border: 1px solid #fff;
border-top: none;
border-right: none;
}
#YDRZ_Agreement a {
font-size: 12px;
color: #ec1500 !important;
}
#YDRZ_Closebtn{
top: 16px !important;
right: 16px !important
}
}
/**
中国联通授权弹窗样式覆写
**/
#authxwLoginBox{
.xw-app-logo {
border-radius: 12px !important;
}
.xw-inputbox{
// border: 0 !important;
// border-bottom: 1px solid #dcdcdc !important;
background: transparent !important;
border-radius: 0 !important;
// padding: 0 !important;
// margin: 0 0.05em !important
}
.xw-agreement{
align-items: center !important;
a{
font-size: 12px !important;
}
}
.xw-agreeement-policy{
font-size: 12px;
color: #ec1500 !important;
}
.xw-img-back{
width: 0.15em !important;
}
.xw-back-area{
margin: 0.15em 0.06em 0 auto !important
}
.xw-btn{
border-radius: 0.2em !important;
background: linear-gradient(90deg,#ff1900,#ff5d00) !important;
&.disable {
background: #ccc !important;
}
span {
color:#fff !important;
font-weight: bold;
}
}
}
\ No newline at end of file
/**
* Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/)
* http://cssreset.com
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video,
input {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font-weight: normal;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* custom */
a {
color: #7e8c8d;
text-decoration: none;
}
li {
list-style: none;
}
body {
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important;
-moz-text-size-adjust: 100% !important;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
/**
* Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/)
* http://cssreset.com
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video,
input {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font-weight: normal;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* custom */
a {
color: #7e8c8d;
text-decoration: none;
}
li {
list-style: none;
}
body {
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important;
-moz-text-size-adjust: 100% !important;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
// 覆盖cherry-ui样式
@import "./var.less";
@import "./mixins.less";
@button-border-width: 1px;
@button-default-height: 37px;
@button-default-line-height: 37px;
@button-default-font-size: 16px;
@button-default-color: @gray-4;
@button-default-border-color: @gray-4;
@button-primary-color: @white;
@button-primary-background-color: @gradient-red;
@button-danger-background-color: @red;
@button-danger-border-color: @red;
@button-large-height: 48px;
@button-large-line-height: 48px;
@image-placeholder-text-color: @gray-4;
@field-error-message-color: @red-dark;
@field-error-message-font-size: 12px;
@field-error-placeholder-color: @red-dark;
@index-list-bar-font-size: 11px;
@checkbox-icon-border: @border-width-base solid @gray-2;
@checkbox-label-color: @text-color;
@checkbox-checked-color: @white;
@checkbox-checked-border-color: @red;
@checkbox-checked-background-color: @red;
@cell-group-title-background: @gray-1;
@cell-group-title-color: @orange;
@cell-group-title-padding: @padding-xs @padding-lg @padding-xs;
@cell-group-title-font-size: 12px;
@cell-border-color: @grey-border;
@cell-right-icon-color: @gray-3;
@cell-icon-size: 16px;
@field-label-width: 75px;
@dialog-border-radius: @border-radius-lg;
@dialog-has-title-message-text-color: @text-grey;
@navbar-default-height: @nav-bar-height;
@picker-toolbar-padding: @padding-unit - 2 @padding-md;
@picker-font-size: 14px;
@empty-description-color: @gray-4;
@tabs-nav-background-color: @background-color;
@list-text-color: @gray-4;
@index-list-title-color: @gray-5;
@back-top-txt-color: @gray-5;
@coupon-list-date-color: @gray-5;
\ No newline at end of file
// 覆盖cherry-ui样式
@import "./var.scss";
@import "./mixins.scss";
$button-border-width: 1px;
$button-default-height: 37px;
$button-default-line-height: 37px;
$button-default-font-size: 16px;
$button-default-color: $gray-4;
$button-default-border-color: $gray-4;
$button-primary-color: $white;
$button-primary-background-color: $gradient-red;
$button-danger-background-color: $red;
$button-danger-border-color: $red;
$button-large-height: 48px;
$button-large-line-height: 48px;
$image-placeholder-text-color: $gray-4;
$field-error-message-color: $red-dark;
$field-error-message-font-size: 12px;
$field-error-placeholder-color: $red-dark;
$index-list-bar-font-size: 11px;
$checkbox-icon-border: $border-width-base solid $gray-2;
$checkbox-label-color: $text-color;
$checkbox-checked-color: $white;
$checkbox-checked-border-color: $red;
$checkbox-checked-background-color: $red;
$cell-group-title-background: $gray-1;
$cell-group-title-color: $orange;
$cell-group-title-padding: $padding-xs $padding-lg $padding-xs;
$cell-group-title-font-size: 12px;
$cell-border-color: $grey-border;
$cell-right-icon-color: $gray-3;
$cell-icon-size: 16px;
$field-label-width: 75px;
$dialog-border-radius: $border-radius-lg;
$dialog-has-title-message-text-color: $text-grey;
$navbar-default-height: $nav-bar-height;
$picker-toolbar-padding: $padding-unit - 2 $padding-md;
$picker-font-size: 14px;
$empty-description-color: $gray-4;
$tabs-nav-background-color: $background-color;
$list-text-color: $gray-4;
$index-list-title-color: $gray-5;
$back-top-txt-color: $gray-5;
$coupon-list-date-color: $gray-5;
\ No newline at end of file
// page Colors
@page-color-base: #f7f8fa;
// Color Palette
@black: #333333;
@white: #fff;
@gray-1: #f7f8fa;
@gray-2: #dcdcdc;
@gray-3: #c8c9cc;
@gray-4: #999999;
@gray-5: #666666;
@gray-6: #f8f8f8;
@gray-7: #d8d8d8;
// @gray-8 不要用
@red: #ec1500;
@red-light: #ec3333;
@red-dark: #ee0a24;
@orange: #faab0c;
@red-btn: #ff5d00;
@grey-border: #f2f3f5;
// Gradient Colors
@gradient-red: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
@gradient-pink: linear-gradient(180deg, #fff7f0 0%, #ffe4dc 100%);
@primary-bg: {
background-image: linear-gradient(269deg, #ff4b00 12%, #ff7705 86%);
background-image: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
};
@cherry-color-error: #dd524d;
@text-color-red: #e81800;
@text-color-light: #ff5a4b;
// Component Colors
@text-color: @black;
@text-grey: @gray-4;
@active-opacity: 0.8;
@disabled-opacity: 0.7;
@background-color: @gray-1;
@line-height-sm: 16px;
@line-height-md: 22px;
@line-height-lg: 24px;
// Border
@border-width-base: 1px;
@border-radius-sm: 6px;
@border-radius-md: 8px;
@border-radius-lg: 16px;
@border-radius-lx: 20px;
@border-radius-max: 999px;
// Padding
@padding-unit: 4px;
@padding-x: @padding-unit + 2;
@padding-xs: @padding-unit * 2;
@padding-sm: @padding-unit * 3;
@padding-md: @padding-unit * 4;
@padding-lg: @padding-unit * 5;
@padding-xl: @padding-unit * 8;
@padding-sd: @padding-xs + 4;
@font-color-disabled: #c0c4cc;
@font-color-dark: #333333;
@font-color-light: #909399;
@font-color-red: #f23e33;
// Font
@font-size-list: 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 52, 40;
// .generate-text(15);
// .generate-text(@n, @i: 1) when (@i =< @n) {
// @font: extract(@font-size-list, @i);
// .text-size(@{font} {
// font-size: @font + 0px;
// line-height: @font + 6px;
// }
// .generate-text(@n, @i + 1);
// }
.text-size(@f) {
font-size: @f + 0px;
line-height: @f + 6px;
}
@font-weight-bold: 600;
@font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial,
Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
@font-din: 'din';
@deep: ~'>>>';
// 页面内边距
@page-padding: @padding-sm;
@page-padding-lg: @padding-lg;
// ios底部防遮挡高度
@ios-bottom-height: 60px;
// 页面顶部header高度
@nav-bar-height: 48px;
@tab-bar-height: 56px;
/* 页面左右间距 */
@page-row-spacing: 15px;
/* 行为相关颜色 */
@color-primary: #fa436a;
// 灰色
// 主要操作按钮背景色
@background-primary: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
@background-coupon: linear-gradient(270deg, #f76b1c 0%, #ffc049 100%);
/*文字颜色*/
@font-color-dark: #333333;
@font-color-base: #606266;
@font-color-light: #909399;
@font-color-disabled: #c0c4cc;
@font-color-spec: #4399fc;
@font-color-search: #ec1500;
@font-color-red: #f23e33;
// @font-color-red: #EC3333;
@font-color-red: #f23e33;
// 边框
@border-sm: 2px;
@border-md: 4px;
@border-gray: #999;
@border-red: #ec1500;
/* 边框颜色 */
@border-color-dark: #dcdfe6;
@border-color-base: #e4e7ed;
@border-color-light: #ebeef5;
@border-color-search: #ec1500;
@border-color-line: #F2f2f5;
// page Colors
$page-color-base: #f7f8fa;
// Color Palette // Color Palette
$black: #333333; $black: #333333;
$white: #fff; $white: #fff;
...@@ -6,19 +9,28 @@ $gray-2: #dcdcdc; ...@@ -6,19 +9,28 @@ $gray-2: #dcdcdc;
$gray-3: #c8c9cc; $gray-3: #c8c9cc;
$gray-4: #999999; $gray-4: #999999;
$gray-5: #666666; $gray-5: #666666;
$gray-6: #D8D8D8; $gray-6: #f8f8f8;
$gray-7: #d8d8d8;
// $gray-8 不要用
$red: #ec1500; $red: #ec1500;
$red-light: #ec3333; $red-light: #ec3333;
$red-dark: #ee0a24; $red-dark: #ee0a24;
$orange: #faab0c; $orange: #faab0c;
$pink: #FFECE6; $red-btn: #ff5d00;
$grey-border: #f2f3f5; $grey-border: #f2f3f5;
// Gradient Colors // Gradient Colors
$gradient-red: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%); $gradient-red: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
$gradient-red-reverse: linear-gradient(270deg, #FF4B00 0%, #FF7705 100%);;
$gradient-pink: linear-gradient(180deg, #fff7f0 0%, #ffe4dc 100%); $gradient-pink: linear-gradient(180deg, #fff7f0 0%, #ffe4dc 100%);
$primary-bg: {
background-image: linear-gradient(269deg, #ff4b00 12%, #ff7705 86%);
background-image: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
};
$cherry-color-error: #dd524d;
$text-color-red: #e81800;
$text-color-light: #ff5a4b;
// Component Colors // Component Colors
$text-color: $black; $text-color: $black;
$text-grey: $gray-4; $text-grey: $gray-4;
...@@ -26,55 +38,100 @@ $active-opacity: 0.8; ...@@ -26,55 +38,100 @@ $active-opacity: 0.8;
$disabled-opacity: 0.7; $disabled-opacity: 0.7;
$background-color: $gray-1; $background-color: $gray-1;
$line-height-sm: 32rpx; $line-height-sm: 16px;
$line-height-md: 44rpx; $line-height-md: 22px;
$line-height-lg: 48rpx; $line-height-lg: 24px;
// Border // Border
$border-width-base: 1rpx; $border-width-base: 1px;
$border-radius-sm: 12rpx; $border-radius-sm: 6px;
$border-radius-md: 16rpx; $border-radius-md: 8px;
$border-radius-lg: 32rpx; $border-radius-lg: 16px;
$border-radius-lx: 40rpx; $border-radius-lx: 20px;
$border-radius-max: 999rpx; $border-radius-max: 999px;
// Padding // Padding
$padding-unit: 8rpx; $padding-unit: 4px;
$padding-x: $padding-unit + 2;
$padding-xs: $padding-unit * 2; $padding-xs: $padding-unit * 2;
$padding-sm: $padding-unit * 3; $padding-sm: $padding-unit * 3;
$padding-md: $padding-unit * 4; $padding-md: $padding-unit * 4;
$padding-lg: $padding-unit * 5; $padding-lg: $padding-unit * 5;
$padding-xl: $padding-unit * 8; $padding-xl: $padding-unit * 8;
$padding-sd: $padding-xs + 4;
$font-color-disabled: #c0c4cc;
$font-color-dark: #333333;
$font-color-light: #909399;
$font-color-red: #f23e33;
// Font // Font
$font-size-list: 10, 11, 12, 13, 14, 16, 17, 18, 20, 26, 28, 30, 52; $font-size-list: 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28, 30, 52, 40;
// .generate-text(15);
// .generate-text($n, $i: 1) when ($i =< $n) {
// $font: extract($font-size-list, $i);
// .text-size(#{$font} {
// font-size: $font + 0px;
// line-height: $font + 6px;
// }
// .generate-text($n, $i + 1);
// }
@mixin text-size($f) { @mixin text-size($f) {
$font: $f; font-size: $f + 0px;
font-size: #{$font}rpx; line-height: $f + 6px;
line-height: #{($font + 12)}rpx; }
};
$font-weight-bold: 600; $font-weight-bold: 600;
$font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; $font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial,
Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
$font-din: 'din';
$deep: '>>>';
// 页面内边距 // 页面内边距
$page-padding: $padding-sm; $page-padding: $padding-sm;
$page-padding-lg: $padding-lg; $page-padding-lg: $padding-lg;
// ios底部防遮挡高度 // ios底部防遮挡高度
$ios-bottom-height: 120rpx; $ios-bottom-height: 60px;
// 页面顶部header高度 // 页面顶部header高度
$nav-bar-height: 96rpx; $nav-bar-height: 48px;
// 多行... $tab-bar-height: 56px;
@mixin mx_multline_overwrite($line: 2) {
display: -webkit-box; /* 页面左右间距 */
overflow: hidden; $page-row-spacing: 15px;
text-overflow: ellipsis;
word-wrap: break-word; /* 行为相关颜色 */
white-space: normal !important; $color-primary: #fa436a;
-webkit-line-clamp: $line;
-webkit-box-orient: vertical; // 灰色
} // 主要操作按钮背景色
$background-primary: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
$background-coupon: linear-gradient(270deg, #f76b1c 0%, #ffc049 100%);
/*文字颜色*/
$font-color-dark: #333333;
$font-color-base: #606266;
$font-color-light: #909399;
$font-color-disabled: #c0c4cc;
$font-color-spec: #4399fc;
$font-color-search: #ec1500;
$font-color-red: #f23e33;
// $font-color-red: #EC3333;
$font-color-red: #f23e33;
// 边框
$border-sm: 2px;
$border-md: 4px;
$border-gray: #999;
$border-red: #ec1500;
/* 边框颜色 */
$border-color-dark: #dcdfe6;
$border-color-base: #e4e7ed;
$border-color-light: #ebeef5;
$border-color-search: #ec1500;
$border-color-line: #F2f2f5;
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
*/ */
/* 颜色变量 */ /* 颜色变量 */
/* 行为相关颜色 */ /* 行为相关颜色 */
$uni-color-primary: #007aff; $uni-color-primary: #007aff;
$uni-color-success: #4cd964; $uni-color-success: #4cd964;
......
...@@ -9,7 +9,7 @@ const basePath = "./base"; // 基础文件夹路径 ...@@ -9,7 +9,7 @@ const basePath = "./base"; // 基础文件夹路径
const map = { const map = {
// 替换规则 // 替换规则
"\\.txt$": "_text", "\\.txt$": "_text",
"\\.js$": "_js", "\\.js$": "_js"
}; };
/** /**
...@@ -27,7 +27,7 @@ function copyDir(srcDir, destDir, options = {}) { ...@@ -27,7 +27,7 @@ function copyDir(srcDir, destDir, options = {}) {
const excludeDirs = exclude ? exclude.split(",") : []; const excludeDirs = exclude ? exclude.split(",") : [];
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 创建目标文件夹 // 创建目标文件夹
fs.mkdir(destDir, { recursive: true }, (err) => { fs.mkdir(destDir, { recursive: true }, err => {
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
...@@ -38,7 +38,7 @@ function copyDir(srcDir, destDir, options = {}) { ...@@ -38,7 +38,7 @@ function copyDir(srcDir, destDir, options = {}) {
} else { } else {
// 处理每个文件 // 处理每个文件
Promise.all( Promise.all(
files.map((file) => { files.map(file => {
const srcPath = path.join(srcDir, file.name); const srcPath = path.join(srcDir, file.name);
const destPath = path.join(destDir, `${prefix}${file.name}${suffix}`); const destPath = path.join(destDir, `${prefix}${file.name}${suffix}`);
...@@ -46,6 +46,15 @@ function copyDir(srcDir, destDir, options = {}) { ...@@ -46,6 +46,15 @@ function copyDir(srcDir, destDir, options = {}) {
if (excludeDirs.includes(file.name)) { if (excludeDirs.includes(file.name)) {
return Promise.resolve(); return Promise.resolve();
} }
if (excludeDirs?.length > 0) {
const filters = excludeDirs.filter(dir => {
return new RegExp(dir, "g").test(srcPath);
});
if (filters.length > 0) {
return Promise.resolve();
}
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 复制文件或递归复制子文件夹 // 复制文件或递归复制子文件夹
...@@ -108,13 +117,13 @@ async function readDir(dirPath, options) { ...@@ -108,13 +117,13 @@ async function readDir(dirPath, options) {
reject(err); reject(err);
} else { } else {
if (options && options.extensions) { if (options && options.extensions) {
files = files.filter((file) => { files = files.filter(file => {
const extension = path.extname(file).toLowerCase(); const extension = path.extname(file).toLowerCase();
return options.extensions.includes(extension); return options.extensions.includes(extension);
}); });
} }
if (options && options.exclude) { if (options && options.exclude) {
files = files.filter((file) => !options.exclude.test(file)); files = files.filter(file => !options.exclude.test(file));
} }
resolve(files); resolve(files);
} }
...@@ -145,7 +154,7 @@ async function readFile(filePath) { ...@@ -145,7 +154,7 @@ async function readFile(filePath) {
} }
async function writeFile(filePath, content) { async function writeFile(filePath, content) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fs.writeFile(filePath, content, "utf8", (err) => { fs.writeFile(filePath, content, "utf8", err => {
if (err) { if (err) {
reject(err); reject(err);
} else { } else {
...@@ -161,7 +170,7 @@ const copyTempToSrc = async (tempPath, srcPath) => { ...@@ -161,7 +170,7 @@ const copyTempToSrc = async (tempPath, srcPath) => {
}; };
// 删除目录 // 删除目录
const deleteFolder = async (folderPath) => { const deleteFolder = async folderPath => {
const files = await util.promisify(fs.readdir)(folderPath); const files = await util.promisify(fs.readdir)(folderPath);
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
const file = files[i]; const file = files[i];
...@@ -231,21 +240,31 @@ const traverseDirectory = async (dir, mapping, options) => { ...@@ -231,21 +240,31 @@ const traverseDirectory = async (dir, mapping, options) => {
// await copyDir(`${sourcePath}`, `${tempPath}`); // await copyDir(`${sourcePath}`, `${tempPath}`);
await copyDir(`${sourcePath}/views/home/`, `${tempPath}/pages/home`); await copyDir(`${sourcePath}/views/home/`, `${tempPath}/pages/home`);
await copyDir(`${sourcePath}/views/test/`, `${tempPath}/pages/test`);
await copyDir(`${sourcePath}/components/`, `${tempPath}/components`); await copyDir(`${sourcePath}/components/`, `${tempPath}/components`);
await copyDir(`${sourcePath}/style/`, `${tempPath}/style`);
await copyDir(`${sourcePath}/assets/`, `${tempPath}/static`);
await copyDir(`${sourcePath}/filters/`, `${tempPath}/filters`);
await copyDir(`${sourcePath}/mixins/`, `${tempPath}/mixins`);
await copyDir(`${sourcePath}/service/`, `${tempPath}/service`);
await copyDir(`${sourcePath}/constants/`, `${tempPath}/constants`);
// 标签操作 // 标签操作
const mapping = { const mapping = {
"<div": "<view", "<div": "<view",
"</div": "</view", "</div": "</view",
"@/assets/": "@/static/",
"@/views/": "@/pages/",
"<img": "<image"
}; };
const options = { const options = {
extensions: [".vue"], extensions: [".vue"]
}; };
await traverseDirectory(tempPath, mapping, options); await traverseDirectory(tempPath, mapping, options);
await copyDir(tempPath, "./src"); await copyDir(tempPath, "./src");
await copyDir(basePath, "./src");
// 删除并重新创建 temp 目录 // 删除并重新创建 temp 目录
// await deleteFolder(tempPath).finally(() => { // await deleteFolder(tempPath).finally(() => {
......
// const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") const path = require("path");
// .BundleAnalyzerPlugin; const resolve = dir => path.join(__dirname, dir);
// const plugins = [
// new BundleAnalyzerPlugin({
// analyzerMode: "static"
// // analyzerHost: "192.168.24.158",
// // analyzerPort: 8889,
// // reportFilename: "report.html",
// // defaultSizes: "parsed",
// // generateStatsFile: false,
// // statsFilename: "stats.json",
// // statsOptions: null,
// // logLevel: "info"
// })
// ];
module.exports = { module.exports = {
css: {
loaderOptions: {
less: {
// 若使用 less-loader@5,请移除 lessOptions 这一级,直接配置选项。
modifyVars: {
// 直接覆盖变量
hack: `true; @import "${resolve("./src/style/theme.less")}";`
}
}
}
},
configureWebpack: () => { configureWebpack: () => {
return { return {
optimization: { optimization: {
minimize: true, minimize: true,
usedExports: true, usedExports: true
}, }
}; };
}, }
}; };
This source diff could not be displayed because it is too large. You can view the blob instead.
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