Commit 7900ec19 authored by FE-安焕焕's avatar FE-安焕焕 👣

Merge branch 'pay' into 'master'

Pay

See merge request !4
parents 6aa1b0ca 8a43632a
......@@ -1159,9 +1159,9 @@
}
},
"@qg/ui-request": {
"version": "0.0.8",
"resolved": "http://npmprivate.quantgroups.com/@qg%2fui-request/-/ui-request-0.0.8.tgz",
"integrity": "sha512-BeS7fWiTM5uI/FzGpZ5phuU0ZQXWsjX5LDiMq6FhMz5IXQthd3gMn+Q1DyYF6YyQI6rG9eDq18CMvWMdkbtt/Q==",
"version": "0.0.15",
"resolved": "http://npmprivate.quantgroups.com/@qg%2fui-request/-/ui-request-0.0.15.tgz",
"integrity": "sha512-ZYR/7NMFDY0NBU0B71D3/ENdI29YTKhmk0BE68IFlt63rPwKXeUWzUtmfsA1Wgx/iMkNE8qfJMKt7lPLreYYWA==",
"requires": {
"axios": "^0.19.2"
}
......@@ -3973,9 +3973,9 @@
}
},
"crypto-js": {
"version": "3.1.9-1",
"resolved": "http://npmprivate.quantgroups.com/crypto-js/-/crypto-js-3.1.9-1.tgz",
"integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
"version": "3.3.0",
"resolved": "http://npmprivate.quantgroups.com/crypto-js/-/crypto-js-3.3.0.tgz",
"integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q=="
},
"css": {
"version": "2.2.4",
......
......@@ -19,10 +19,11 @@ export default {
},
// 订单详情查询接口
orderDetail(data) {
return http.get(`${talosHost}/api/kdsp/order-info/virtual-recharge/detail`, data);
return http.get(`${talosHost}/api/kdsp/order-info/virtual-recharge/detail`, { params: data });
},
// 订单创建
orderCreate(data) {
return http.post(`${talosHost}/api/kdsp/order-info/e/vmSubmit`, { data: encryption(data) });
console.log(data);
return http.post(`${talosHost}/api/kdsp/order-info/e/vmSubmit`, encryption(data));
}
};
import request from '@/service/httpDecorator';
import config from '@/config';
import { encryption } from '@/service/encrypt';
import { saDeviceId } from '@/service/sa.service';
const { talosHost } = config;
const queryPayInfo = function(data) {
return request.post(`${talosHost}/open/checkout`, data);
};
const prepay = function(data) {
console.log('prepay-param', data);
return request.post(`${talosHost}/open/checkout/prepay`, data);
const prepay = async function(data) {
const scDeviceId = await saDeviceId();
return request.post(`${talosHost}/open/checkout/prepay`, data, {
customHeader: {
scDeviceId
}
});
};
const pay = function(data) {
return request.post(
`${talosHost}/open/checkout/pay`,
{ data: encryption(data) },
{
needScDeviceId: true
const pay = async function(data) {
const scDeviceId = await saDeviceId();
return request.post(`${talosHost}/open/checkout/pay`, data, {
customHeader: {
scDeviceId
}
);
});
};
const queryPayStatus = function(data) {
......@@ -52,6 +55,11 @@ const getGoodsList = function(data) {
});
};
// KA流程节点
const kaGetNextUrl = function() {
return request.get(`${talosHost}/api/kdsp/ka/process/get-next-url`);
};
export {
pay,
prepay,
......@@ -62,5 +70,6 @@ export {
ocrFaceId,
queryPayInfo,
getGoodsList,
kaGetNextUrl,
queryPayStatus
};
export default {
101: `<p>充值类商品售出<strong>后无法进行退换</strong>,非充值用户请谨慎购买。</p>`,
102: `<p>充值类商品售出<strong>后无法进行退换</strong>,非充值用户请谨慎购买。</p>`
1: {
title: '温馨提示',
content: `<p>充值类商品售出后无法进行退换,非充值用户请谨慎购买。</p>`
},
2: {
title: '温馨提示',
content: `<p>充值类商品售出后无法进行退换,非充值用户请谨慎购买。</p>`
},
401: {
title: '使用方法',
content: `<p>1. 进入猫眼APP,登陆后打开“我的”,点击“优惠券”;</p>
<p>2. 进入“优惠券”,在页面上方白框中输入13位优惠券密码,点击“添加”即可;</p>
<p>3. 返回,选定场次并完成选座;</p>
<p>4. 核对购票信息、结算金额,点击“确认支付”完成选座购票;</p>
<p>5. 用户到影城“取票机”取票即可使用。</p>`
},
301: {
title: '使用方法',
content: `<p>1. 进入饿了么APP-选择我的-点击会员,使用兑换码兑换会员,输入兑换码即可兑换;</p>
<p>2. 饿了么月度会员含4个5元的红包总计20元,全品类通用(早餐及帮买帮送等特殊订单除外),红包仅限购买会员时选择的城市使用;</p>
<p>3. 每完成1笔在线订单(实际支付金额大于等于20元),即可获得1个奖励金,奖励金可累计并兑换各种无门槛红包及高额商家红包。</p>`
}
};
......@@ -26,9 +26,6 @@ export default {
components: {
Items
},
// props: {
// list: Array
// },
data() {
return {
finished: true,
......@@ -48,11 +45,14 @@ export default {
return this.list.filter((item, index) => index % 2);
}
},
mounted() {
this.onLoad();
},
methods: {
async onLoad() {
this.loading = true;
const [data = {}] = await getGoodsList({ pageNo: 1, pageSize: 10 });
this.list = [...this.list, ...data?.goodsList];
this.list = [...this.list, ...(data?.goodsList ?? [])];
this.loading = false;
}
}
......
......@@ -14,6 +14,7 @@ let protocol = window.location.protocol;
let payHost = protocol + '//mapi-qa.liangkebang.net/pay';
let shenceHost = 'https://bn.xyqb.com/sa?project=default'; // 测试地址
let talosHost = 'http://yapi.quantgroups.com/mock/351'; // 电商分期测试环境服务地址
let talosHost = 'http://talos-vcc2.liangkebang.net'; // 电商分期测试环境服务地址
let operatorHost = 'https://operator.liangkebang.com';
export default { talosHost, operatorHost, payHost, shenceHost, test: true };
const toBHost = 'https://tob.liangkebang.net';
export default { talosHost, operatorHost, payHost, shenceHost, test: true, toBHost };
......@@ -4,11 +4,13 @@ const operatorHost = protocol + '//auth.quantgroup.cn';
// const payHost = protocol + '//mapi.q-gp.com/pay';
const payHost = protocol + '//payapi.xyqb.com';
const shenceHost = 'https://bn.xyqb.com/sa?project=production';
const toBHost = 'https://tob.liangkebang.net';
export default {
// apiHost,
test: false,
shenceHost,
talosHost,
payHost,
toBHost,
operatorHost
};
......@@ -20,6 +20,7 @@ if (process.env.SENTRY_ENV !== 'test' && process.env.NODE_ENV === 'production')
.install();
}
Vue.prototype.util = new Bridge();
window.Bridge = Bridge;
saService.init(router);
......
......@@ -39,6 +39,7 @@ export function encryption(data = '') {
* @return {String} 加密后的数据16进制
*/
export async function encryptByDESModeEBC(message) {
console.log(message);
const [{ payPwdSalt }] = await desSalt();
var keyHex = CryptoJS.enc.Utf8.parse(payPwdSalt);
var encrypted = CryptoJS.DES.encrypt(message, keyHex, {
......
import HttpRequest from '@qg/ui-request';
import { Toast } from '@qg/cherry-ui';
import store from '@/store';
import { appVersion } from '@/service/validation.service';
const http = new HttpRequest(
{},
{},
{
headers: {
'x-user-terminal': 'H5',
version: appVersion || '7.9.0'
}
},
function(msg) {
Toast(msg);
},
......
......@@ -14,6 +14,7 @@ const localStorageParams = [
'formXcxPage'
];
const cookiesParams = ['h'];
const sessionStorageParams = ['target'];
export default {
// token校验,整个流程都是登陆后的
......@@ -28,7 +29,9 @@ export default {
cookiesParams.forEach(item => {
to.query[item] && Cookies.set(item, to.query[item]);
});
sessionStorageParams.forEach(item => {
to.query[item] && localStorage.set(item, to.query[item], 'sessionStorage');
});
(isWechat || isApp || Cookies.get('h') === '0') && store.commit('CHANGE_HEADER', false); // 改变header
document.body.className = store.state.pay.header ? 'has-header' : '';
store.commit('CHANGE_TITLE', meta?.title); // 改变title
......
export default {
get(key) {
let result = window.localStorage.getItem(key);
get(key, storageType = 'localStorage') {
let result = window[storageType].getItem(key);
try {
return JSON.parse(result);
} catch (e) {
return result;
}
},
set(key, value) {
set(key, value, storageType = 'localStorage') {
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);
return window[storageType].setItem(key, value);
},
remove(key) {
return window.localStorage.removeItem(key);
remove(key, storageType = 'localStorage') {
return window[storageType].removeItem(key);
},
clear() {
return window.localStorage.clear();
clear(storageType = 'localStorage') {
return window[storageType].clear();
}
};
......@@ -77,12 +77,12 @@ function payByWeixinH5(info) {
* @return:
*/
function payByALIH5(info) {
if (!info.order_string) return;
console.log('ali:', info.order_string);
if (!info.url) return;
console.log('ali:', info.url);
const aliWrap = document.createElement('div');
aliWrap.id = 'ALIWEB_WRAP';
aliWrap.setAttribute('id', 'ALIWEB_WRAP');
aliWrap.innerHTML = info.order_string;
aliWrap.innerHTML = info.url;
document.body.appendChild(aliWrap);
document.forms[0].submit();
......
import { isAndroid, isIOS } from './validation.service';
import { isAndroid, isIOS, isApp } from './validation.service';
import Clipboard from 'clipboard';
/**
......@@ -378,3 +378,53 @@ export function setClipboardData(
fakeEl.click();
document.body.removeChild(fakeEl);
}
export function getTokenFromNative() {
return new Promise((resolve, reject) => {
if (!isApp) {
reject();
console.log('not app or wxmp');
navToDlApp();
return;
}
const nativeBridge = new window.Bridge();
window.xyqbNativeEvent = function(res) {
const json = typeof res === 'string' ? JSON.parse(res) : res;
if (json.event === 'getTokenSuccess') {
const appData = json.data || {};
if (appData && appData.token) {
localStorage.set('vccToken', appData.token);
resolve(true);
} else {
reject();
}
} else {
reject();
}
};
nativeBridge.getToken();
});
}
export function navToDlApp() {
window.location.href = 'xyqb://openApp';
setTimeout(() => {
window.location.href = APP_DOWN_URL;
const nextPage = document.createElement('a');
nextPage.setAttribute('href', APP_DOWN_URL);
nextPage.click();
}, 2000);
}
export const APP_DOWN_URL = 'https://misc.lkbang.net/download/yxm.html';
export function throttle(fn, wait) {
let flag = true;
return function() {
if (flag) {
fn.apply(this, arguments);
flag = false;
setTimeout(() => {
flag = true;
}, wait);
}
};
}
......@@ -109,4 +109,10 @@ strong {
.text-14();
margin-bottom: @padding-xs;
}
}
.cr-dialog--header {
padding: @padding-xl;
&--isolated {
padding-bottom: 0;
}
}
\ No newline at end of file
......@@ -31,15 +31,13 @@
@cell-clear-color: @gray-4;
@field-label-width: 75px;
@dialog-width: 290px;
@dialog-font-size: 14px;
@dialog-border-radius: @border-radius-lg;
@dialog-message-font-size: 16px;
@dialog-has-title-message-text-color: @text-color;
@dialog-confirm-button-text-color: @red;
@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;
@tabs-nav-background-color: @background-color;
\ No newline at end of file
@tabs-nav-background-color: @background-color;
@loading-text-color: @white;
\ No newline at end of file
<template>
<p class="center-phone">
<div class="center-phone">
<span v-if="rechargeTel" class="center-phone-location"
>{{ isDefaultphone ? '默认号码' : '未知号码'
}}{{ phoneNoHome ? `(${phoneNoHome})` : '' }}</span
......@@ -10,9 +10,21 @@
class="center-phone-field"
placeholder="请输入手机号码"
@input="changeTelFormat"
@blur="searchPhoneNoHome"
@blur="searchPhoneNo(rechargeTel)"
@focus="inputBlur = true"
/>
</p>
<div class="center-phone__list" :class="{ show: inputBlur }">
<div
v-for="(item, index) in historyPhoneNoList"
:key="index"
class="center-phone__list-item"
@click="selectPhone(item)"
>
<span class="phone">{{ phoneFormat(item) }}</span>
<span v-if="index === 0" class="current">上次充值</span>
</div>
</div>
</div>
</template>
<script>
import api from '@/api/recharge.api';
......@@ -20,43 +32,68 @@ import { phoneFormat, phoneTrim, checkPhoneFormat } from '@/service/utils.servic
const { getPhoneHome } = api;
export default {
props: {
userPhoneInfo: Object
userPhoneInfo: {
type: Object,
default: () => {}
}
},
data() {
return {
phoneNoHome: null,
rechargeTel: null
rechargeTel: null,
inputBlur: false
};
},
computed: {
isDefaultphone: function() {
return this.phoneNo === this.userPhoneInfo?.phoneNo;
},
historyPhoneNoList() {
return this.userPhoneInfo?.historyPhoneNoList || [];
},
phoneNo: function() {
return phoneTrim(this.rechargeTel);
}
},
watch: {
userPhoneInfo: function(val) {
this.phoneNoHome = val?.phoneNoHome;
this.changeTelFormat(val?.phoneNo);
this.phoneNoHome = val.phoneNoHome;
}
},
created() {},
methods: {
phoneFormat,
changeTelFormat(phone) {
this.phoneNoHome = '';
this.rechargeTel = phoneFormat(phone);
if (this.rechargeTel.length > 12) {
this.queryhome();
}
},
async searchPhoneNoHome() {
async searchPhoneNo() {
this.inputBlur = false;
if (!this.phoneNo) return;
if (!checkPhoneFormat(this.phoneNo)) {
this.$toast.fail('请您输入正确的手机号');
this.$emit('input', { phoneNo: '', phoneNoHome: this.phoneNoHome });
this.input();
return;
}
!this.phoneHome && this.queryhome();
this.input();
},
selectPhone(phone) {
this.inputBlur = false;
if (phone) {
this.rechargeTel = phoneFormat(phone);
}
this.searchPhoneNo();
},
async queryhome() {
const [data] = await getPhoneHome(this.phoneNo);
this.phoneNoHome = data?.phoneHome;
this.input();
},
input() {
this.$emit('input', { phoneNo: this.phoneNo, phoneNoHome: this.phoneNoHome });
}
}
......@@ -64,8 +101,12 @@ export default {
</script>
<style lang="less">
.center {
position: relative;
&-phone {
border-bottom: @border-width-base solid @gray-2;
.cr-field:not(:last-child)::after {
display: none;
}
.cr-cell__title {
display: none;
}
......@@ -81,6 +122,46 @@ export default {
&-field {
text-indent: -2px;
}
&__list {
display: none;
position: absolute;
top: 100px;
width: 100%;
margin: auto;
left: -@padding-lg;
right: -@padding-lg;
z-index: 3;
background-color: @white;
box-shadow: 0px 7px 12px 0px rgba(0, 0, 0, 0.1);
&.show {
display: block;
}
&-item {
display: flex;
align-items: center;
padding: @padding-lg / 2 @padding-lg;
.phone {
color: @text-color;
.text-14();
margin-right: @padding-xs;
}
.phone-home {
color: @text-color;
.text-12();
max-width: 180px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
flex-shrink: 0;
overflow: hidden;
}
.current {
color: @text-grey;
.text-10();
margin-left: auto;
}
}
}
}
}
</style>
......@@ -12,7 +12,7 @@
:three-col="true"
/>
</cr-tab>
<cr-tab title="话费慢" :title-style="tabItemStyle" name="slowRecharge">
<cr-tab title="话费慢" :title-style="tabItemStyle" name="slowRecharge">
<PhoneRechargeList
:list="rechargeList.slowRecharge"
:info="selectedRechargeInfo"
......@@ -51,14 +51,15 @@ export default {
methods: {
async changeRechargeType(name) {
const [data] = await getSkuList(
this.phoneRecharge[`${name}SpuNo`],
this.phoneRecharge[`${name}SpuNos`],
this.phoneRecharge[`${name}Type`]
);
this.$emit('changeRechargetype', name);
this.rechargeList[name] = data?.rechargeList || [];
},
handleSkuSelected(item) {
this.selectedRechargeInfo = item;
this.$emit('selectedRecharge', item);
this.$emit('selectedRecharge', { rechargeInfo: item });
}
}
};
......
......@@ -20,6 +20,8 @@
</div>
</template>
<script>
import { getTokenFromNative } from '@/service/utils.service';
import localStorage from '@/service/localStorage.service';
export default {
props: {
value: Array
......@@ -43,7 +45,11 @@ export default {
}
});
},
goOrderList() {
async goOrderList() {
const token = localStorage.get('vccToken');
if (!token) {
await getTokenFromNative();
}
this.$router.push({ name: 'orderList' });
}
}
......
......@@ -13,4 +13,10 @@
.text-18();
}
}
.slowRechargeTip{
.text-12();
color: @gray-4;
text-align: center;
margin-bottom: @padding-sm;
}
}
\ No newline at end of file
......@@ -2,8 +2,19 @@
<div class="home">
<RechargeTop v-model="vipLife" />
<div class="center">
<RechargeInput v-model="rechargePhoneInfo" :user-phone-info="userPhoneInfo" />
<RechargeList :phone-recharge="phoneRecharge" @selectedRecharge="selectedRecharge" />
<RechargeInput
v-model="rechargePhoneInfo"
:user-phone-info="userPhoneInfo"
:list="historyRecordList"
/>
<RechargeList
:phone-recharge="phoneRecharge"
@selectedRecharge="selectedRecharge"
@changeRechargetype="rechargeType = $event"
/>
<p v-if="rechargeType === 'slowRecharge'" class="slowRechargeTip">
充值后预计最迟48小时内到账,请耐心等待
</p>
<cr-button
block
type="primary"
......@@ -24,6 +35,7 @@ import RechargeTop from './components/RechargeTop.vue';
import RechargeList from './components/RechargeList.vue';
import RechargeInput from './components/RechargeInput.vue';
import localStorage from '@/service/localStorage.service';
import { getTokenFromNative, throttle } from '@/service/utils.service';
const { getSpuList } = api;
export default {
components: {
......@@ -37,7 +49,8 @@ export default {
rechargeAmount: 0,
phoneRecharge: {},
userPhoneInfo: {},
rechargeType: null,
rechargeType: 'recharge',
historyRecordList: [],
rechargePhoneInfo: {},
selectedRechargeInfo: {}
};
......@@ -47,26 +60,36 @@ export default {
return this.rechargePhoneInfo.phoneNo && this.selectedRechargeInfo.salePrice;
}
},
created() {},
created() {
this.goOrder = throttle.call(this, this.goOrderApi, 1000);
},
async mounted() {
const [data] = await getSpuList();
if (data) {
this.vipLife = data.vipLife || [];
this.phoneRecharge = data.phoneRecharge || {};
this.userPhoneInfo = data.userPhoneInfo || {};
this.rechargePhoneInfo = data.userPhoneInfo || {};
localStorage.set('phoneNo', data.userPhoneInfo.phoneNo);
this.phoneRecharge = data?.phoneRecharge || {};
this.userPhoneInfo = data?.userPhoneInfo || {};
this.rechargePhoneInfo = data?.userPhoneInfo || {};
localStorage.set('phoneNo', data?.userPhoneInfo?.phoneNo);
}
},
methods: {
selectedRecharge(item) {
this.selectedRechargeInfo = item;
throttle,
selectedRecharge({ rechargeInfo }) {
this.selectedRechargeInfo = rechargeInfo;
},
async goOrder() {
async goOrderApi() {
/* 需要加防抖 */
const { skuNo, salePrice } = this.selectedRechargeInfo;
const token = localStorage.get('vccToken');
if (!token) {
await getTokenFromNative();
}
const [res] = await orderApi.orderCreate({
totalFee: salePrice,
registrationLocation: this.rechargePhoneInfo.phoneNoHome,
terminal: 'H5',
account: this.rechargePhoneInfo?.phoneNo,
registrationLocation: this.rechargePhoneInfo?.phoneNoHome,
virtualRechargeType: this.phoneRecharge[`${this.rechargeType}Type`],
skuList: [
{
......
......@@ -51,7 +51,12 @@
}
}
&__info {
&-right {
margin-left: auto;
color: @red !important;
}
&-item {
display: flex;
padding: 8px 0;
color: @text-grey;
.text-13();
......
......@@ -46,6 +46,7 @@
<div class="Od__item Od__info">
<div class="Od__info-item">
订单编号:<span>{{ orderInfo.orderDetail.orderNo || '' }}</span>
<span class="Od__info-right" @click="copyPwd(orderNo)">复制</span>
</div>
<div class="Od__info-item">
下单时间:<span>{{ orderInfo.orderDetail.orderTime || '' }}</span>
......@@ -78,7 +79,7 @@
v-if="orderInfo.orderStatusInfo.orderStatus === 11"
size="small"
plain
type="primary"
type="default"
shape="circle"
@click="openCancelPopup"
>
......@@ -98,7 +99,7 @@
v-if="orderInfo.orderStatusInfo.orderStatus === 21"
size="small"
plain
type="primary"
type="default"
shape="circle"
@click="orderNotify"
>
......@@ -115,12 +116,10 @@
再次购买
</cr-button>
</div>
<cancel-popup v-model="showCancelPopup" :order-info="currentOrder" />
</div>
</template>
<script>
import ListItem from '../orderList/components/ListItem.vue';
import CancelPopup from '../orderList/components/CancelPopup.vue';
import { setClipboardData } from '@/service/utils.service';
import orderApi from '@/api/order.api';
import img11 from '@/assets/images/order/11.png';
......@@ -138,11 +137,11 @@ const orderStatusImgs = {
export default {
name: 'OrderDetail',
components: {
ListItem,
CancelPopup
ListItem
},
data() {
return {
orderNo: '',
orderInfo: {
feeInfo: {},
orderDetail: {},
......@@ -151,8 +150,7 @@ export default {
skuList: [],
payDetail: {},
orderNo: ''
},
showCancelPopup: false
}
};
},
computed: {
......@@ -166,6 +164,9 @@ export default {
},
payType() {
return this.orderInfo.orderDetail.payType === 1 ? '微信' : '支付宝';
},
isKeyChange() {
return this.currentOrder.virtualChargeAttrs && this.currentOrder.virtualChargeAttrs.cardKey;
}
},
mounted() {
......@@ -182,25 +183,46 @@ export default {
'https://www.sobot.com/chat/h5/v2/index.html?sysnum=84ed0ad93caa47b0a9d1600824546b35&source=2';
},
openCancelPopup() {
this.showCancelPopup = true;
this.$dialog({
title: '取消订单',
message: '您真的要取消吗?',
confirmButtonText: '仍要取消',
cancelButtonText: '留下商品',
onConfirm: () => {
this.handleRadioSubmit();
}
});
},
async handleRadioSubmit() {
const [res] = await orderApi.orderCancel({
orderNo: this.currentOrder.orderNo,
cancelReason: '不想买了',
cancelReasonType: 4
});
if (res) {
this.$toast('已取消');
this.$set(this.orderInfo.orderStatusInfo, `orderStatus`, 51);
this.$set(this.orderInfo.orderStatusInfo, `orderStatusText`, '交易关闭');
}
},
toPay() {
this.$router.push({ path: '/pay', query: { orderNo: this.currentOrder.orderNo } });
this.$router.push({ path: '/pay', query: { orderNo: this.orderNo } });
},
toGoods() {
this.$router.push({ path: '/goods' });
this.$router.push({
path: this.isKeyChange ? '/vipLife' : '/home'
});
},
orderNotify() {
this.$toast.success('已通知卖家');
},
copyPwd(item) {
setClipboardData({
data: `${item.cardPassword}`,
data: '' + item,
success: () => {
this.$toast.success('已复制');
}
});
console.log(item);
}
}
};
......
......@@ -72,7 +72,7 @@ export default {
},
computed: {
reason() {
return this.reasonList.find(item => item.cancelReasonType === this.reasonList);
return this.reasonList.find(item => item.cancelReasonType === this.reasonType);
}
},
watch: {
......
......@@ -18,7 +18,7 @@
<div class="Ol__foot">
<div class="Ol__foot-settle">
<span>总价¥{{ item.totalFee }}</span>
<span>优惠¥{{ item.reduceFee }}</span>
<span v-if="item.reduceFee">优惠¥{{ item.reduceFee }}</span>
<span>
实付款<strong>¥{{ item.originalFee }}</strong>
</span>
......@@ -30,7 +30,7 @@
plain
type="default"
shape="circle"
@click="onOptionClick(item, 'cancel')"
@click.stop="onOptionClick(item, index, 'cancel')"
>
取消订单
</cr-button>
......@@ -40,7 +40,7 @@
plain
type="primary"
shape="circle"
@click="onOptionClick(item, 'pay')"
@click.stop="onOptionClick(item, index, 'pay')"
>
付款
</cr-button>
......@@ -50,7 +50,7 @@
plain
type="default"
shape="circle"
@click="onOptionClick(item, 'notify')"
@click.stop="onOptionClick(item, index, 'notify')"
>
提醒发货
</cr-button>
......@@ -60,7 +60,7 @@
plain
type="primary"
shape="circle"
@click="onOptionClick(item, 'again')"
@click.stop="onOptionClick(item, index, 'again')"
>
再次购买
</cr-button>
......@@ -119,8 +119,8 @@ export default {
onLoad() {
this.$emit(EVENT_LOADING);
},
onOptionClick(orderInfo, eventType) {
this.$emit(EVENT_CLICK, { orderInfo, eventType });
onOptionClick(orderInfo, index, eventType) {
this.$emit(EVENT_CLICK, { orderInfo: { ...orderInfo, index }, eventType });
},
toHome() {
this.$router.replace({ path: '/home' });
......
......@@ -12,26 +12,26 @@
<div v-if="it.count" class="Ol__body-row">
<span class="Ol__body-count">{{ it.count }}</span>
</div>
<div class="Ol__body-skus">
<div v-if="it.virtualChargeAttrs.account" class="Ol__body-sku">
<div v-if="it.virtualRechargeAttrs" class="Ol__body-skus">
<div v-if="it.virtualRechargeAttrs.account" class="Ol__body-sku">
<span>充值帐户:</span>
<span class="Ol__body-val">{{ it.virtualChargeAttrs.account }}</span>
<span class="Ol__body-val">{{ it.virtualRechargeAttrs.account }}</span>
</div>
<div v-if="it.virtualChargeAttrs.registrationLocation" class="Ol__body-sku">
<div v-if="it.virtualRechargeAttrs.registrationLocation" class="Ol__body-sku">
<span>归属地:</span>
<span class="Ol__body-val">{{ it.virtualChargeAttrs.account }}</span>
<span class="Ol__body-val">{{ it.virtualRechargeAttrs.registrationLocation }}</span>
</div>
<div v-if="it.virtualChargeAttrs.cardNo" class="Ol__body-sku">
<div v-if="it.virtualRechargeAttrs.cardNo" class="Ol__body-sku">
<span>卡号:</span>
<span class="Ol__body-val">{{ it.virtualChargeAttrs.cardNo }}</span>
<span class="Ol__body-val">{{ it.virtualRechargeAttrs.cardNo }}</span>
</div>
<div v-if="it.virtualChargeAttrs.cardPassword" class="Ol__body-sku">
<div v-if="it.virtualRechargeAttrs.cardPassword" class="Ol__body-sku">
<span>卡密:</span>
<span class="Ol__body-val">{{ it.virtualChargeAttrs.cardPassword }}</span>
<span class="Ol__body-val">{{ it.virtualRechargeAttrs.cardPassword }}</span>
<a
v-if="props.showCopy"
href="javascript:;"
@click="parent.copyPwd(it.virtualChargeAttrs)"
@click="parent.copyPwd(it.virtualRechargeAttrs.cardPassword)"
>
复制
</a>
......
......@@ -11,14 +11,12 @@
/>
</cr-tab>
</cr-tabs>
<cancel-popup v-model="showCancelPopup" :order-info="currentOrder" />
</div>
</template>
<script>
import orderApi from '@/api/order.api';
import List from './components/List';
import { isApp } from '@/service/validation.service';
import CancelPopup from './components/CancelPopup';
const commonParams = {
loading: false,
finished: false,
......@@ -29,13 +27,11 @@ const commonParams = {
export default {
name: 'OrderList',
components: {
List,
CancelPopup
List
},
data() {
return {
isApp,
showCancelPopup: false,
currentTab: 0,
navList: [
{
......@@ -44,22 +40,22 @@ export default {
...JSON.parse(JSON.stringify(commonParams))
},
{
state: 1,
state: 11,
title: '待付款',
...JSON.parse(JSON.stringify(commonParams))
},
{
state: 2,
state: 21,
title: '待发货',
...JSON.parse(JSON.stringify(commonParams))
},
{
state: 3,
state: 31,
title: '待收货',
...JSON.parse(JSON.stringify(commonParams))
},
{
state: 4,
state: 41,
title: '已完成',
...JSON.parse(JSON.stringify(commonParams))
}
......@@ -94,13 +90,11 @@ export default {
this.toGoods();
break;
default:
this.currentItems = {};
this.currentOrder = {};
break;
}
},
orderCancelPopup() {
this.showCancelPopup = true;
},
toPay() {
this.$router.push({ path: '/pay', query: { orderNo: this.currentOrder.orderNo } });
},
......@@ -113,12 +107,39 @@ export default {
setNavListData(key, val) {
this.$set(this.navList[this.currentTab], key, val);
},
orderCancelPopup() {
this.$dialog({
title: '取消订单',
message: '您真的要取消吗?',
confirmButtonText: '仍要取消',
cancelButtonText: '留下商品',
onConfirm: () => {
this.handleRadioSubmit();
}
});
},
async handleRadioSubmit() {
const [res] = await orderApi.orderCancel({
orderNo: this.currentOrder.orderNo,
cancelReason: '不想买了',
cancelReasonType: 4
});
if (res) {
this.$toast('已取消');
this.$set(this.navList[this.currentTab].list[this.currentOrder.index], `orderStatus`, 51);
this.$set(
this.navList[this.currentTab].list[this.currentOrder.index],
`orderStatusText`,
'交易关闭'
);
}
},
async getList() {
let { finished, page, pageSize, list, state: orderStatus } = this.navList[this.currentTab];
if (finished) return;
this.setNavListData('loading', true);
const [res] = await orderApi.orderList({
page,
pageNo: page,
pageSize,
orderStatus
});
......
......@@ -45,6 +45,7 @@ const IS_CREDIT_PAY = method =>
const PAYMENT_CODE_PAY = 1; // 支付密码
const SMS_VERIFICATION_CODE_PAY = 2; //短信验证码
const FACE_VERIFICATION_CODE_PAY = 4; //短信验证码
const PAY_SUCCESS = 3; // 支付成功
const PAY_PAYING = 2; //支付中
......@@ -70,7 +71,7 @@ function isDetentionFn() {
this.creditPayList.isGroupPay
) {
this.$dialog({
message: '使用组合支付部分金额可免使用40天哦!',
message: '使用组合支付部分金额可免使用40天哦!',
confirmButtonText: '组合支付',
cancelButtonText: '继续支付',
confirmButtonColor: '#EC1500',
......@@ -83,6 +84,7 @@ function isDetentionFn() {
if (this.creditPayList.payList[key].isRecommend) {
const type = this.creditPayList.payList[key].payType;
this.changePayType(type, this.creditPayList.payList[key].mergePayPretreatmentInfo);
this.isCheckAgreement = true;
this.pay();
return;
}
......@@ -94,7 +96,7 @@ function isDetentionFn() {
!this.creditPayList.isGroupPay
) {
this.$dialog({
message: '使用享花卡支付可免使用40天哦',
message: '使用享花卡支付可免使用40天哦',
confirmButtonText: '享花卡支付',
cancelButtonText: '继续支付',
confirmButtonColor: '#EC1500',
......@@ -104,6 +106,7 @@ function isDetentionFn() {
onConfirm: () => {
// 切换享花卡支付
this.changePayType(CREDIT_PAY);
this.isCheckAgreement = true;
this.pay();
}
});
......@@ -145,5 +148,6 @@ export {
ACCOUNT_APPLY_SUCCESS,
ACCOUNT_APPLY_AUDITING,
ACCOUNT_APPLY_AUDIT_FAIL,
SMS_VERIFICATION_CODE_PAY
SMS_VERIFICATION_CODE_PAY,
FACE_VERIFICATION_CODE_PAY
};
......@@ -23,11 +23,12 @@
export default {
name: 'Contract',
props: {
contractList: Array
contractList: Array,
value: Boolean
},
data() {
return {
isCheck: false
isCheck: this.value
};
},
methods: {
......@@ -35,7 +36,7 @@ export default {
window.location.href = url;
},
change(e) {
this.$emit('change', e);
this.$emit('input', e);
}
}
};
......@@ -48,14 +49,7 @@ export default {
align-items: flex-start;
color: @gray-5;
.text-10;
&-checkbox {
// margin-right: 2px;
// height: 14px;
}
&-list {
display: inline-flex;
justify-content: flex-start;
flex-wrap: wrap;
color: @gray-5;
span {
color: @red;
......
......@@ -6,14 +6,16 @@
<cr-image :src="value.icon" class="icon" mode="aspectFit" width="39" height="39" />
<div class="content-info-con">
<div class="content-info-tit">
<p class="content-info-tit">{{ value.name }}</p>
<p v-if="value.tagName" class="content-info-tit_tag">{{ value.tagName }}</p>
<div class="content-info-tit-wrap">
<p class="content-info-tit">{{ value.name }}</p>
<p v-if="value.tagName" class="content-info-tit_tag">{{ value.tagName }}</p>
</div>
<p v-if="isGroupPay && value.payAmt" class="content-info-amount">
{{ value.payAmt }}
</p>
</div>
<p>{{ value.accountStatusDesc }}</p>
</div>
<p v-if="isGroupPay && value.mergePayPretreatmentInfo" class="content-info-amount">
{{ value.mergePayPretreatmentInfo && value.mergePayPretreatmentInfo.creditPayAmt }}
</p>
</div>
<div
v-if="showCoupon && value.payType === 1"
......@@ -42,11 +44,11 @@
</template>
<script>
// import { registeredEvents } from '@/utils/sa';
const payTypeE = [
'PD_YXMMAEC_UserClickCashierSelectXiangHuaCardPay',
'PD_YXMMAEC_UserClickCashierSelectWechatPay'
];
const payTypeMiniAppE = ['c_cashierselectxianghuacardpay', 'c_cashierselectwechatpay'];
// const payTypeE = [
// 'PD_YXMMAEC_UserClickCashierSelectXiangHuaCardPay',
// 'PD_YXMMAEC_UserClickCashierSelectWechatPay'
// ];
// const payTypeMiniAppE = ['c_cashierselectxianghuacardpay', 'c_cashierselectwechatpay'];
export default {
name: 'PayCardItem',
inject: ['payCard', 'pay'],
......@@ -61,12 +63,12 @@ export default {
couponDisabled: Boolean
},
methods: {
changePayType({ payType }) {
changePayType({ payType, mergePayPretreatmentInfo }) {
if (this.disabled || this.value.disabled) {
return;
}
this.$emit('click');
this.pay.changePayType(payType);
this.pay.changePayType(payType, mergePayPretreatmentInfo);
},
openCouponModal() {
if (this.couponDisabled) return;
......@@ -110,7 +112,6 @@ export default {
}
.type-item {
width: 100%;
// height: 134rpx;
padding: 12px 8px 12px 12px;
box-sizing: border-box;
display: flex;
......@@ -123,7 +124,6 @@ export default {
&-content-info {
width: 100%;
display: flex;
// width: 308px;
align-items: center;
}
&-checkbox {
......@@ -141,6 +141,10 @@ export default {
margin-bottom: 2px;
display: flex;
align-items: center;
justify-content: space-between;
&-wrap {
display: flex;
}
&_tag {
display: inline-flex;
align-items: center;
......@@ -161,6 +165,9 @@ export default {
color: @font-color-light;
}
.content-info-amount {
width: 100px;
text-align: left;
word-break: break-all;
&::before {
content: '¥';
}
......
......@@ -8,16 +8,19 @@
:show-coupon="showCoupon"
:risk-limit="riskLimit"
/>
<p class="dashed">
<cr-checkbox
v-model="thirdPayInfo.isCheck"
shape="round"
checked-color="#EC1500"
:disabled="disabled || thirdPayInfo.disabled"
class="dashed-checkbox"
@click.native="changePayType(thirdPayInfo)"
/>
</p>
</div>
<div class="dashed">
<p class="dashed-line" />
<cr-checkbox
v-model="thirdPayInfo.isCheck"
shape="round"
checked-color="#EC1500"
:disabled="disabled || thirdPayInfo.disabled"
class="dashed-checkbox"
@click.native="changePayType(thirdPayInfo)"
/>
</div>
<div class="groupCard">
<PayCardItem :is-group-pay="true" :value="thirdPayInfo" />
</div>
<p class="group-more b-t" @click="openMore">更多支付组合<cr-icon type="arrow" size="15px" /></p>
......@@ -65,7 +68,13 @@ export default {
let temp = {};
for (const key in this.value) {
if (this.value[key].isRecommend || this.value[key].isCheck) {
temp = { ...this.value[key] };
const mergePayPretreatmentInfo = this.value[key]?.mergePayPretreatmentInfo || {};
temp = {
...this.value[key],
payAmt: mergePayPretreatmentInfo?.otherPayAmt
};
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
this.creditPayInfo.payAmt = mergePayPretreatmentInfo.creditPayAmt;
}
}
return temp;
......@@ -80,6 +89,7 @@ export default {
},
methods: {
changePayType({ payType, mergePayPretreatmentInfo }) {
console.log(mergePayPretreatmentInfo, 'mergePayPretreatmentInfo');
if (this.disabled || this.creditPayInfo.disabled) {
return;
}
......@@ -97,7 +107,7 @@ export default {
</script>
<style lang="less">
.groupCard {
width: 320px;
width: 100%;
}
.group-more {
.text-13;
......@@ -114,28 +124,21 @@ export default {
z-index: 2;
}
.dashed {
width: 309px;
margin: auto;
position: relative;
border-bottom: 1px dashed #dcdcdc;
width: 100%;
padding: 0 12px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
&-line {
width: 310px;
border-bottom: 1px dashed #dcdcdc;
}
&-checkbox {
width: 18px;
position: absolute;
right: -22px;
top: -8px;
}
&::after {
content: '';
width: 24px;
height: 28px;
position: absolute;
margin-top: -12px;
left: 50%;
margin-left: -12px;
background: url('../../../assets/images/addicon.png') no-repeat;
background-size: 100%;
}
}
.more-title {
.text-16;
display: flex;
......
<template>
<cr-overlay :show="value" @click="closeModal">
<cr-overlay :show="value">
<div class="sms-modal">
<div class="sms">
<p class="sms-icon"><cr-icon type="cross" color="#999999" @click="closeModal" /></p>
<p class="sms-title">请输入短信验证码</p>
<p class="sms-des">为保证您账户安全,此笔交易需要短信验证</p>
<p class="phone">已发送至 {{ getPhone() }}17611682272</p>
<p class="phone">已发送至 {{ getPhone() }}</p>
<cr-authcode-field
span-size="20px"
type="number"
......@@ -87,7 +87,7 @@ export default {
},
getPhone() {
const phone = localStorage.get('phoneNo');
const phoneS = phone.replace(/(\d{3})\d*(\d{4})/, '+86 $1 **** $2');
const phoneS = `${phone}`.replace(/(\d{3})\d*(\d{4})/, '+86 $1 **** $2');
return phoneS;
},
sendSa() {
......
import localStorage from '@/service/localStorage.service';
import config from '@/config/index';
const { toBHost } = config;
export const goUrlExtends = {
methods: {
goHome() {
// 商城地址
const tob = this.getTarget();
if (tob) {
window.location.replace = `${toBHost}`;
return;
}
this.$router.replace({ name: 'home' });
},
goOrderList() {
const tob = this.getTarget();
if (tob) {
window.location.replace = `${toBHost}/orderList`;
return;
}
this.$router.replace({ name: 'orderList' }, 'sessionStorage');
},
goOrderDetail() {
const tob = this.getTarget();
const orderNo = localStorage.get('orderNo')?.orderNo;
if (tob) {
window.location.replace = `${toBHost}/orderDetail?orderNo=${orderNo}`;
return;
}
this.$router.replace({
name: 'orderDetail',
query: { orderNo }
});
},
getTarget() {
const tob = localStorage.get('target', 'sessionStorage');
return tob;
}
}
};
This diff is collapsed.
......@@ -21,7 +21,7 @@
<cr-button shape="circle" class="actions__back" :plain="true" type="primary" @click="goHome"
>返回首页</cr-button
>
<cr-button shape="circle" type="primary" @click="goOrderDetail">查看订单</cr-button>
<cr-button shape="circle" type="primary" @click="goOrderList">查看订单</cr-button>
</div>
</div>
<div v-else class="card">
......@@ -47,41 +47,35 @@
<script>
import { registeredEvents } from '@/service/sa.service';
import RecoGoods from '@/components/RecoGoods.vue';
import localStorage from '@/service/localStorage.service';
import { goUrlExtends } from './extends';
export default {
components: { RecoGoods },
extends: goUrlExtends,
data() {
return {
money: '00.00',
orderNo: null,
isSuccess: null,
freeAmount: null
isSuccess: false,
freeAmount: 0
};
},
created() {
const { amount, orderNo, freeAmount, reason } = this.$route.query;
const { orderNo, reason } = this.$route.query;
const { success } = this.$route.meta;
console.log(this.$route.meta);
this.money = amount;
const amount = localStorage.get('amount');
this.money = amount.finalAmt;
this.orderNo = orderNo;
this.reason = reason || '';
this.isSuccess = success || false;
this.freeAmount = freeAmount;
this.freeAmount = amount.freeAmount;
},
methods: {
goHome() {
// 去页面
},
goOrderDetail() {
registeredEvents('PD_YXMMAEC_UserClickCashierCheckOrderBtn', {
order_id: this.orderNo
});
// 去订单详情页面
},
goPay() {
registeredEvents('PD_YXMMAEC_UserClickCashierPaymentAgainBtn', {
order_id: this.orderNo
});
this.$router.push({ name: 'pay', query: { order: this.orderNo } });
this.$router.replace({ name: 'pay', query: { orderNo: this.orderNo } });
}
}
};
......
......@@ -7,7 +7,7 @@
class="info__image"
src="../../assets/images/paying.png"
/>
<div class="info__desc">
<div v-if="init" class="info__desc">
<p class="info__text">{{ time }}s)支付中...</p>
</div>
</div>
......@@ -23,47 +23,73 @@
</div>
</template>
<script>
import { registeredEvents } from '@/service/sa.service';
import { queryPayStatus } from '@/api/pay.api';
import localStorage from '@/service/localStorage.service';
import { goUrlExtends } from './extends';
export default {
components: {},
extends: goUrlExtends,
data() {
return {
orderNo: null,
timer: null,
time: 10
time: 10,
init: false
};
},
created() {
const { orderNo } = this.$route.query;
this.orderNo = orderNo;
this.orderNo = this.$route.query.orderNo || localStorage.get('orderNo')?.orderNo;
},
mounted() {
this.timer = setInterval(() => {
this.time -= 1;
if (this.time % 2 === 0) {
queryPayStatus({ orderNo: this.orderNo });
this.$dialog({
message: '请确认订单已完成支付',
confirmButtonText: '已完成支付',
cancelButtonText: '重新支付',
confirmButtonColor: '#EC1500',
onCancel: () => {
this.goPay();
},
onConfirm: () => {
this.init = true;
this.loop();
}
if (this.time < 1) {
clearInterval(this.timer);
}
}, 2000);
});
},
beforeDestroy() {
clearInterval(this.timer);
},
methods: {
goHome() {
// 去页面
loop() {
this.query();
this.timer = setInterval(() => {
this.time -= 1;
if (this.time % 2 === 0) {
this.query();
}
if (this.time < 1) {
clearInterval(this.timer);
}
}, 2000);
},
goOrderDetail() {
registeredEvents('PD_YXMMAEC_UserClickCashierCheckOrderBtn', {
order_id: this.orderNo
});
// 去订单详情页面
goSuccess() {
// 支付成功
this.$router.replace({ name: 'paySuccess' });
},
goPay() {
registeredEvents('PD_YXMMAEC_UserClickCashierPaymentAgainBtn', {
order_id: this.orderNo
});
this.$router.push({ name: 'pay', query: { order: this.orderNo } });
this.$router.replace({ name: 'pay', query: { orderNo: this.orderNo } });
},
async query() {
const [data, error] = await queryPayStatus({ orderNo: this.orderNo });
if (error) {
this.$router.replace({
name: 'payFail',
query: { reason: error.message, orderNo: this.orderNo }
});
return;
}
if (+data?.payStatus === 3) {
this.goSuccess();
}
}
}
};
......
......@@ -2,7 +2,13 @@
<div class="Vl__account">
<cr-field v-model="accountMask" :placeholder="`请输入${info.name || ''}账号`" clearable>
<template #button>
<cr-image v-if="info.icon" :src="info.icon" width="0.64rem" height="0.64rem" />
<cr-image
v-if="info.icon"
:src="info.icon"
fit="contain"
width="0.64rem"
height="0.64rem"
/>
</template>
</cr-field>
<!-- <div class="Vl__list" :class="{ show: !inputBlur }">
......@@ -46,7 +52,7 @@ export default {
computed: {
accountMask: {
get() {
return this.info.rechargeAccountType !== 3 ? this.phoneFormat(this.value) : this.value;
return this.info.type !== 101 ? this.phoneFormat(this.value) : this.value;
},
set(val) {
this.$emit('input', val.replace(/\s/g, ''));
......
<template functional>
<div class="Vl__sku" :class="{ disabled: props.disabled, 'three-col': props.threeCol }">
<div
v-for="(item, index) in props.list"
:key="index"
class="Vl__sku-item"
:class="{
cheap: item.price - item.salePrice > 0,
active: props.info.skuNo === item.skuNo,
nohhird: (index + 1) % 3 !== 0
}"
@click="parent.handleSkuSelected(item, index)"
>
<div class="Vl__sku-name">
{{ props.threeCol ? item.salePrice : item.skuName }}{{ showUnit ? '' : '' }}
<template v-if="props.list.length">
<div
v-for="(item, index) in props.list"
:key="index"
class="Vl__sku-item"
:class="{
cheap: item.price - item.salePrice > 0,
active: props.info.skuNo === item.skuNo,
'no-stock': !item.hasStock,
nohhird: (index + 1) % 3 !== 0
}"
@click="item.hasStock && parent.handleSkuSelected(item, index)"
>
<div class="Vl__sku-name">
{{ props.threeCol ? item.salePrice : item.skuName }}{{ props.showUnit ? '' : '' }}
</div>
<div class="Vl__sku-price">售价{{ item.price }}</div>
</div>
<div class="Vl__sku-price">售价{{ props.threeCol ? item.price : item.salePrice }}</div>
<div class="Vl__sku-tag">优惠</div>
</div>
</template>
<cr-empty v-else class="Vl__sku-empty" image="commodity" description="暂无商品~" />
</div>
</template>
<script>
......@@ -49,6 +52,9 @@ export default {
align-content: flex-start;
position: relative;
z-index: 1;
&-empty {
flex-flow: wrap;
}
&.disabled::before {
content: ' ';
z-index: 2;
......@@ -85,13 +91,45 @@ export default {
position: relative;
margin-bottom: @padding-xs;
transition: all 0.1s linear;
&::before {
content: ' ';
background: @gray-2;
.text-10();
border-radius: 0 @border-radius-sm - 2 0 @border-radius-sm - 2;
padding: 0 @padding-unit;
position: absolute;
top: 0;
right: 0;
display: none;
}
// 优惠
&.cheap {
.Vl__sku-tag {
&::before {
content: '\4f18\60e0';
display: block;
color: @white;
background: linear-gradient(269deg, #ff5d00 12%, #ff1900 86%);
}
}
// 补货中
&.no-stock {
background: @white !important;
border-color: @grey-border !important;
pointer-events: none;
cursor: not-allowed;
&::before {
content: '\8865\8d27\4e2d';
display: block;
color: @white;
background: linear-gradient(90deg, #cecece 2%, #989898 98%);
}
.Vl__sku-name {
color: @gray-4 !important;
}
.Vl__sku-price {
color: @gray-4 !important;
}
}
&.active {
background: #fff5f5;
border: 1px solid @red;
......@@ -117,16 +155,6 @@ export default {
color: @gray-5;
.text-12();
}
&-tag {
background: @gray-2;
.text-10();
border-radius: 0 @border-radius-sm - 2 0 @border-radius-sm - 2;
padding: 0 @padding-unit;
position: absolute;
top: 0;
right: 0;
display: none;
}
}
}
</style>
<template>
<div ref="spuList" class="Vl__spu-wrapper">
<div class="Vl__spu" :style="{ width: numAddUnit(contentWidth) }">
<div class="Vl__spu" :style="{ minWidth: numAddUnit(contentWidth) }">
<div
v-for="(item, index) in list"
:key="index"
class="Vl__spu-item"
:class="{ 'Vl__spu-item_active': info.spuNo === item.spuNo }"
:class="{ 'Vl__spu-item_active': info.spuNos === item.spuNos }"
@click="handleSpuClick($event, item, index)"
>
<cr-image :src="item.icon" height="1.093333rem" width="1.093333rem" class="Vl__spu-icon" />
<cr-image
:src="item.icon"
height="1.093333rem"
width="1.093333rem"
fit="contain"
class="Vl__spu-icon"
/>
<div class="Vl__spu-name">{{ item.name }}</div>
</div>
<div class="Vl__spu-placeholder" :style="{ width: numAddUnit(placeholderWidth) }" />
</div>
</div>
</template>
......@@ -25,7 +30,7 @@ export default {
type: Array,
default: () => [
{
spuNo: '',
spuNos: '',
icon: '',
name: ''
}
......@@ -42,34 +47,44 @@ export default {
};
},
computed: {
contentWidth() {
return ITEM_WIDTH * (this.list.length + 2.34);
}
},
watch: {
contentWidth() {
this.$nextTick(() => {
this.listWrapper && this.listWrapper.refresh();
this.listWrapper.scrollTo(0, 0);
this.listWrapper.refresh();
});
return ITEM_WIDTH * this.list.length + this.placeholderWidth;
},
placeholderWidth() {
return ((this.list.length % 4) + 1.335) * ITEM_WIDTH;
}
},
mounted() {
this.$nextTick(() => {
this.listWrapper = new BScroll(this.$refs.spuList, {
click: true,
scrollX: true,
scrollY: false
});
});
this.createScroller();
},
beforeDestroy() {
this.listWrapper.destroy();
},
methods: {
createScroller() {
this.$nextTick(() => {
if (this.listWrapper) {
this.listWrapper.destroy();
}
this.listWrapper = new BScroll(this.$refs.spuList, {
click: true,
scrollX: true,
scrollY: false
});
});
},
numAddUnit(num) {
return num / 37.5 + 'rem';
},
handleSpuClick(e, item, index) {
this.$parent.handleSpuSelected(item, index);
const target = e.path.find(item => item.className.indexOf('Vl__spu-item') > -1);
console.dir(target);
this.listWrapper.scrollToElement(target, 500, -10, 0);
}
}
......
......@@ -34,7 +34,7 @@
position: fixed;
bottom: 0;
left: 0;
z-index: 2;
z-index: 9;
right: 0;
width: calc(100% - @padding-sm * 2);
background-color: @white;
......
......@@ -15,15 +15,16 @@
<cr-loading color="#ec1500" />
</div>
<template v-if="tips">
<div class="Vl__panel-title">温馨提示</div>
<div class="Vl__panel-tips" v-html="tips" />
<div class="Vl__panel-title">{{ tips.title }}</div>
<div class="Vl__panel-tips" v-html="tips.content" />
</template>
</div>
<div v-if="!hideFixedBottom" class="Vl__bottom">
<div class="Vl__bottom">
<cr-button type="primary" block shape="circle" :disabled="disabled" @click="goOrder">
立即充值
</cr-button>
</div>
<!-- v-show="!hideFixedBottom" -->
</div>
</template>
<script>
......@@ -34,6 +35,7 @@ import tipsData from '@/api/tips';
import SpuList from './components/SpuList.vue';
import SkuList from './components/SkuList.vue';
import AccountInput from './components/AccountInput.vue';
import { throttle } from '@/service/utils.service';
export default {
name: 'VipLife',
components: {
......@@ -56,13 +58,15 @@ export default {
},
computed: {
disabled() {
return this.spuInfo.rechargeAccountType !== 2 && !this.account;
return (this.spuInfo.rechargeAccountType !== 2 && !this.account) || !this.skuList.length;
},
spuList() {
return this.spuData[this.currentTab - 1] ? this.spuData[this.currentTab - 1].itemList : [];
},
tips() {
return tipsData[this.spuInfo.spuNo];
return this.spuInfo.type
? tipsData[this.spuInfo.type] || tipsData[+('' + this.spuInfo.type)[0]] || {}
: {};
}
},
mounted() {
......@@ -82,11 +86,11 @@ export default {
methods: {
handleTabChange(name) {
this.currentTab = name;
this.skuInfo = {};
this.updateSpuInfo(this.spuData[this.currentTab - 1].itemList[0]);
this.getSkuListDebounce();
},
handleSpuSelected(item) {
this.spuInfo = item;
this.updateSpuInfo(item);
this.getSkuListDebounce();
},
......@@ -107,31 +111,32 @@ export default {
},
getSkuListDebounce() {
this.showLoading = true;
this.skuList = [];
if (this.skuTimer) clearTimeout(this.skuTimer);
this.skuTimer = setTimeout(() => {
this.getSkuList();
}, 600);
},
async getSkuList() {
this.skuList = [];
const { spuNo: spuNos, type } = this.spuInfo;
const [res] = await rechargeApi.getSkuList({ spuNos, type });
const { spuNos, type } = this.spuInfo;
const [res] = await rechargeApi.getSkuList(spuNos, type);
if (res) {
this.skuList = res.rechargeList;
this.handleSkuSelected(res.rechargeList[0], 0);
const defaultItem = res.rechargeList.find(item => item.hasStock);
const defaultIndex = res.rechargeList.findIndex(item => item.hasStock);
defaultItem && this.handleSkuSelected(defaultItem, defaultIndex);
}
this.showLoading = false;
},
async goOrder() {
goOrder: throttle(async function() {
if (!this.account && this.spuInfo.rechargeAccountType !== 2)
return this.$toast.fail('请填写账号!');
if (!this.skuInfo.skuNo) return this.$toast.fail('请选择类型!');
const { skuNo, salePrice } = this.skuInfo;
const [res] = await orderApi.orderCreate({
account: this.account,
totalFee: salePrice,
orderCouponIds: '',
freightCouponIds: '',
virtualRechargeType: this.spuInfo.rechargeAccountType,
virtualRechargeType: this.spuInfo.type,
skuList: [
{
skuNo,
......@@ -140,7 +145,7 @@ export default {
]
});
res && this.$router.push({ path: '/pay', query: { orderNo: res.orderNo } });
}
}, 1000)
}
};
</script>
......
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