Authored by 邱骏

换了一些东西

Showing 48 changed files with 706 additions and 3613 deletions

Too many changes to show.

To preserve performance only 48 of 48+ files are displayed.

... ... @@ -2,13 +2,13 @@ import wx from './utils/wx';
import udid from './common/udid';
import event from './common/event';
import {verify} from './common/api';
import config from './common/config';
import Promise from './vendors/es6-promise';
import { MD5 } from './vendors/crypto';
import { wechatAuthLogin, verifySessionKey } from './common/login';
import { stringify } from './vendors/query-stringify';
import './router/index';
import {MD5} from './vendors/crypto';
import config from './common/config';
import Yas from './common/yas';
import './router/index'; // 新增的router
import {stringify} from './vendors/query-stringify'
let yas;
... ... @@ -19,100 +19,85 @@ App({
unionID: '',
sessionKey: '',
thirdSession: '',
systemInfo: {}
udid: '',
unionType: ''
},
reportData: {
awakeReported: false
},
onLaunch(options) {
onLaunch: function(options) {
this.globalData.udid = udid.get(); // 生成 UDID
verify.gen(); // 此处返回是是 Promise,需要调用接口的业务,最好在 then 里边执行
this.globalData.unionType = options.query.union_type || options.scene;
let timestamp = new Date().getTime() + ''
this.globalData.sid = MD5(timestamp);
yas = new Yas(this);
yas.report('YB_LAUNCH_APP');
},
onShow: function(options) {
udid.get(); // 生成 UDID
verify.gen(); // 此处返回是是 Promise,需要调用接口的业务,最好在 then 里边执行
let sysInfo = wx.getSystemInfoSync();
if (!sysInfo.screenHeight) {
sysInfo.screenHeight = sysInfo.windowHeight;
}
if (!sysInfo.screenWidth) {
sysInfo.screenWidth = sysInfo.windowWidth;
}
this.globalData.systemInfo = sysInfo;
wx.checkSession()
.then(() => { // 微信登录未过期
this.getWechatThirdSession();
this.getUserInfo();
this.getUnionID();
this.doLogin();
})
.catch(() => { // 微信登录过期
wx.setStorage({
key: 'thirdSession',
data: ''
});
wx.setStorage({
key: 'userInfo',
data: {}
});
wx.setStorage({
key: 'unionID',
data: ''
});
this.setUserInfo({});
this.setSessionKey('');
this.doLogin();
wx.getLocation({});
wx.checkSession().then(() => { // 微信登录未过期
this.getWechatThirdSession();
this.getUserInfo();
this.getUnionID();
this.doLogin();
}).catch(() => { // 微信登录过期
wx.setStorage({
key: 'thirdSession',
data: ''
});
wx.setStorage({
key: 'userInfo',
data: {}
});
this.globalData.sid = MD5(`${new Date().getTime()}`).toString();
wx.setStorage({
key: 'unionID',
data: ''
});
this.setUserInfo({});
this.setSessionKey('');
wx.getSystemInfo().then(res => {
this.globalData.systemInfo = res;
this.doLogin();
});
// 设置渠道来源
if (options && options.query && options.query.union_type) {
this.globalData.union_type = options.query.union_type;
}
// 设置微信场景
this.globalData.ch = options.scene;
yas = new Yas(this);
yas.report('YB_LAUNCH_APP');
},
onShow(options) {
// 设置微信场景
this.globalData.ch = options.scene;
// yas 登录成功回调上报
event.on('yas-login-type-report', params => {
yas.report('YB_MY_LOGIN', params);
});
// yas 注册成功后上报
event.on('yas-user-register-success', params => {
yas.report('YB_REGISTER_SUCCESS', params);
});
yas.report('YB_ENTER_FOREGROUND');
yas.report('YB_ENTER_FOREGROUND'); // 系统-程序切换置前台上报
if (this.reportData.awakeReported === false) {
let path = options.path;
let path = options.path || ' ';
if (Object.keys(options.query).length) {
if(Object.keys(options.query).length) {
path = `${path}?${stringify(options.query)}`;
}
yas.report('YB_AWAKE_MP', {PAGE_PATH: path});
yas.report('YB_AWAKE_MP', { PAGE_PATH: path }); // 唤起事件,即每次启动后获取到原始的推广路径时上报该事件,以对推广渠道数据进行监测;
this.reportData.awakeReported = true;
}
},
onHide() {
yas.report('YB_ENTER_BACKGROUND');
onHide: function() {
yas.report('YB_ENTER_BACKGROUND'); // 系统 - 程序切换置后台上报
},
doLogin() {
this.getSessionKey();
event.on('login-type-report', params => {
yas.report('YB_MY_LOGIN', params);
});
setTimeout(() => {
this.wechatAuthLogin();
}, 1000);
doLogin: function() {
// 默认自动登录,退出不走自动登录
if (!this._getSync('disableAutoLogin')) {
this.getSessionKey();
return Promise.resolve(this.wechatAuthLogin());
}
},
_getSync(key) {
_getSync: function(key) {
try {
return wx.getStorageSync(key);
} catch (e) {
... ... @@ -120,44 +105,47 @@ App({
return {};
}
},
_setSync(key, value) {
_setSync: function(key, value) {
try {
wx.setStorageSync(key, value);
} catch (e) {
console.log(`wx.setStorageSync set ${key} failed.`);
}
},
getWechatThirdSession() {
_removeSync: function(key) {
try {
wx.removeStorageSync(key);
} catch (e) {
console.log(`wx.removeStorageSync del ${key} failed.`);
}
},
getWechatThirdSession: function() {
this.globalData.thirdSession = this._getSync('thirdSession');
return this.globalData.thirdSession;
},
setWechatThirdSession(session) {
setWechatThirdSession: function(session) {
this.globalData.thirdSession = session;
wx.setStorage({
key: 'thirdSession',
data: this.globalData.thirdSession
});
},
isLogin() {
return !!this.globalData.userInfo.uid;
},
getUid() {
return this.globalData.userInfo.uid || '';
getUid: function() {
return this.globalData.userInfo.uid || 0;
},
getReportUid() {
return this.globalData.userInfo.uid || this._getSync('userInfo').uid || '';
},
getUserInfo() {
getUserInfo: function() {
this.globalData.userInfo = this._getSync('userInfo');
return this.globalData.userInfo;
},
getUnionID() {
getUnionID: function() {
this.globalData.unionID = this._getSync('unionID');
return this.globalData.unionID;
},
getSessionKey() {
getSessionKey: function() {
this.globalData.sessionKey = this._getSync('sessionKey');
return this.globalData.sessionKey;
},
getOpenID() {
getOpenID: function() {
let openid;
if (this.globalData.openID) {
... ... @@ -168,7 +156,7 @@ App({
this.globalData.openID = openid;
return openid;
},
setOpenID(openID) {
setOpenID: function(openID) {
if (openID) {
this.globalData.openID = openID;
wx.setStorage({
... ... @@ -177,7 +165,7 @@ App({
});
}
},
setUnionID(unionID) {
setUnionID: function(unionID) {
this.globalData.unionID = unionID;
wx.setStorage({
key: 'unionID',
... ... @@ -185,42 +173,39 @@ App({
});
event.emit('wx-union-id-update');
},
setUserInfo(user) {
setUserInfo: function(user) {
this.globalData.userInfo = user;
wx.setStorage({
key: 'userInfo',
data: this.globalData.userInfo
});
},
setSessionKey(sessionKey) {
setSessionKey: function(sessionKey) {
this.globalData.sessionKey = sessionKey;
this._setSync('sessionKey', sessionKey);
},
resumeUserInfo() {
resumeUserInfo: function() {
this.globalData.userInfo = this._getSync('userInfo');
},
resumeSessionKey() {
resumeSessionKey: function() {
this.globalData.sessionKey = this._getSync('sessionKey');
},
wechatAuthLogin() {
wechatAuthLogin: function() {
if (!this.globalData.userInfo.uid || !this.globalData.sessionKey) {
return wechatAuthLogin()
.then(res => {
if (res.code === 10003) { // 微信号已绑定手机号
this.setUserInfo(res.data);
this.setSessionKey(res.data.sessionKey);
event.emit('user-login-success');
event.emit('login-type-report', {LOGIN_TYPE: 4});
}
return wechatAuthLogin().then(res => {
if (res.code === 10003) { // 微信号已绑定手机号
this.setUserInfo(res.data);
this.setSessionKey(res.data.sessionKey);
event.emit('user-login-success');
}
if (res.code === 10004) { // 微信号未绑定手机号
// 自动登录未绑定静默处理、不强制绑定
}
})
.catch(() => {});
if (res.code === 10004) { // 微信号未绑定手机号
// 自动登录未绑定静默处理、不强制绑定
}
}).catch(() => {});
}
verifySessionKey().then(ves => {
return verifySessionKey().then(ves => {
if (ves.code !== 200) { // sessionKey已过期
// 清理原存储的用户信息
... ... @@ -232,38 +217,31 @@ App({
event.emit('user-login-success');
return Promise.resolve({});
}
})
.then(res => {
if (res.code === 10003) { // 微信号已绑定手机号
this.setUserInfo(res.data);
this.setSessionKey(res.data.sessionKey);
event.emit('user-login-success');
event.emit('login-type-report', {LOGIN_TYPE: 4});
}
}).then(res => {
if (res.code === 10003) { // 微信号已绑定手机号
this.setUserInfo(res.data);
this.setSessionKey(res.data.sessionKey);
event.emit('user-login-success');
}
if (res.code === 10004) { // 微信号未绑定手机号
// 自动登录未绑定静默处理、不强制绑定
}
})
.catch(() => {});
if (res.code === 10004) { // 微信号未绑定手机号
// 自动登录未绑定静默处理、不强制绑定
}
event.emit('enable-tap-login');
}).catch(() => {
event.emit('enable-tap-login');
});
},
clearUserSession() {
clearUserSession: function() {
this.setUserInfo({});
this.setSessionKey('');
},
getMiniappType() {
return config.mini_app_type;
},
getUnionType() {
return config.unionType;
getReportUid() {
return this.globalData.userInfo.uid || this._getSync('userInfo').uid || '';
},
getAppId() {
return config.appid;
},
getSystemInfo() {
return this.globalData.systemInfo;
},
getPvid() {
return MD5(`${new Date().getTime()}${udid.get()}`).toString();
}
... ...
{
"pages": [
"pages/index/index",
"pages/cart/ensure/ensure",
"pages/cart/invoice/invoice",
"pages/pay/success",
"pages/home/home",
"pages/home/order/order",
"pages/home/order/detail",
"pages/home/address/list",
"pages/home/service/service",
"pages/home/order/express/express",
"pages/account/bindMobile",
"pages/account/chooseArea",
"pages/product/list/list",
"pages/product/list/shop",
"pages/product/search/search",
"pages/product/detail/detail",
"pages/product/category/category"
"pages/account/bindMobile",
"pages/webview/webview"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "限定发售",
"navigationBarTextStyle": "black",
"backgroundColor": "#f0f0f0",
"backgroundTextStyle": "dark"
"backgroundColor": "#f0f0f0"
},
"tabBar": {
"borderStyle": "#e0e0e0",
"color": "#b0b0b0",
"selectedColor": "#444444",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/images/home-light.png",
"selectedIconPath": "static/images/home-dark.png"
},
{
"pagePath": "pages/product/category/category",
"text": "分类",
"iconPath": "static/images/category-light.png",
"selectedIconPath": "static/images/category-dark.png"
},
{
"pagePath": "pages/home/home",
"text": "我的",
"iconPath": "static/images/home-light.png",
"selectedIconPath": "static/images/home-dark.png"
}
]
}
"debug": true
}
... ...
.clearfix:after {
content: "";
display: block;
clear: both;
}
.right {
float: right;
}
.left {
float: left;
}
.hide {
display: none;
}
@import "./iconfont.wxss";
@import "./vendors/zanui/index.wxss";
/** app.wxss **/
... ...
... ... @@ -106,7 +106,7 @@ const api = {
verify.gen();
}
if (resultData.code && resultData.code === params.code) {
if (resultData.code === params.code) {
return resultData.data || {};
}
... ... @@ -115,9 +115,7 @@ const api = {
app.clearUserSession();
} else {
console.error('api statusCode:', result.statusCode);
return {
result
};
return result && result.data || {};
}
}).catch(err => {
console.error(err);
... ... @@ -137,11 +135,11 @@ const api = {
},
addParams(params) {
return Object.assign({
business_line: config.apiParams.business_line,
client_type: config.apiParams.client_type,
app_version: config.apiParams.app_version,
union_type: config.unionType, // 渠道号
udid: udid.get()
miniapp_version: config.apiParams.miniapp_version,
udid: udid.get(),
business_line: 'miniappOffshop'
}, params);
},
get(params) {
... ...
const config = {
domains: {
// test3
// api: 'http://api-test3.yohops.com:9999',
// production
// api: 'https://api.yoho.cn',
// service: 'https://api.yoho.cn',
// test1
// api: 'http://api-test1.yohops.com:9999',
// gray
// api: 'http://apigray.yoho.cn',
// store: 'http://openstore.yohops.com',
// production
api: 'https://api.yoho.cn',
// test
api: 'http://api-test3.dev.yohocorp.com',
service: 'http://api-test3.dev.yohocorp.com',
yasApi: 'https://analysis.yohobuy.com/yas_mobile'
},
apiParams: {
client_type: 'miniapp',
business_line: 'miniappReds',
private_key: 'b43890b0a296ff3c7b8c260ca763980b',
app_version: '6.4.0'
app_version: '6.6.0',
miniapp_version: '0.0.1'
},
appid: 'wx66ecf50a505afefa', // 业务中使用、与package.config.json内appid保持一致
// unionType: '100000000011368', // 渠道号后台写死【测试】
unionType: '100000000011678', // 渠道号后台写死【线上得宝测试店铺测试渠道号】
mini_app_type: '3', // 小程序类型
resourceContentCode: {
home: {
top: '72c65730150543d295532c942b0e5a33'
}
}
unionType: '', // 渠道号
MINI_APP_DOMAIN: 'miniapp.yohobuy.com',
appid: 'wx39f299b6485cf97a', // 业务中使用、与package.config.json内appid保持一致
business_line: 'miniappLimitSale' // 业务线
};
export default config;
... ...
export default {
listeners: [],
on(type, handle) {
// first remove and add
this.off(type, handle);
if (typeof handle === 'function') {
console.debug(`listen event ${type}`);
this.listeners.push([type, handle]);
}
},
off(type, handle) {
let index = -1;
if (typeof handle === 'function' &&
this.listeners.some(([itype, ihandle]) => {
index++;
return itype === type && handle.name && ihandle.name === handle.name;
})
) {
this.listeners.splice(index, 1);
}
},
emit(type, ...params) {
this.listeners.forEach(([listenType, handle]) => type === listenType && handle(...params));
console.debug(`receive event ${type}: ${JSON.stringify(params)}`);
... ...
// 反斜杠转文字,type= -1:年月日,0:月日,1:日
const slashToString = (date, type = -1) => {
let newDate = '';
let dateString = ['年', '月', '日'];
date.split('/').forEach((val, index) => {
if (index <= type) {
return;
} else {
newDate = newDate + date.split('/')[index] + dateString[index];
}
});
return newDate;
};
module.exports = {
slashToString: slashToString
};
... ...
import wx from '../utils/wx';
import {stringify} from '../vendors/query-stringify';
const appData = {
yohobuy: {
appId: 'wx084ab813d88c594b',
page: {
productDetail: '/pages/goodsDetail/goodsDetail',
brandDetail: '/pages/goodsList/brand',
guangDetail: 'pages/guang/detail'
}
},
anotherApp: {
appId: 'wx084ab813d88c594b',
page: {
home: '/pages/goodsDetail/goodsDetail'
}
},
};
export default function(params) {
let navigateToMiniParams = {
appId: appData[params.app].appId,
path: params.path || `${appData[params.app].page[params.page]}?${stringify(params.data)}`
};
return wx.navigateToMiniProgram(navigateToMiniParams);
}
... ...
... ... @@ -2,6 +2,7 @@ import wx from '../utils/wx';
import event from '../common/event';
import Promise from '../vendors/es6-promise';
import accountModel from '../models/account/index';
import config from '../common/config';
/**
* 用户未授权-发送验证码
... ... @@ -14,7 +15,7 @@ function sendVerifyCode(area, mobile, degrees) {
}
/**
* 用户已授权-发送验证码
* 用户已授权-发送验证码`
* @param mobile 手机号
* @param area 国家码
* @param degrees 验证码
... ... @@ -40,7 +41,8 @@ function isNeedImgCheck() {
function getVerifyCode(area, mobile, degrees) {
let app = getApp();
if (!app.globalData.unionID) {
// disableAutoLogin为用户退出,则直接走手机验证码登录接口
if (!app.globalData.unionID || app._getSync('disableAutoLogin')) {
return sendVerifyCode(area, mobile, degrees);
}
... ... @@ -74,9 +76,13 @@ function checkVerifyCode(area, mobile, verifyCode) {
* @param verifyCode
*/
function bindMobileAction(area, mobile, verifyCode) {
if (!getApp().globalData.unionID) {
let app = getApp();
// disableAutoLogin为用户退出,则直接走手机验证码登录接口
if (!app.globalData.unionID || app._getSync('disableAutoLogin')) {
return autoSignin(area, mobile, verifyCode);
}
return checkVerifyCode(area, mobile, verifyCode);
}
... ... @@ -89,71 +95,79 @@ function bindMobileAction(area, mobile, verifyCode) {
function wechatUserIsBind(unionID, nickName) {
let app = getApp();
return accountModel.wechatUserIsBind(unionID, nickName)
.then(data => {
wx.hideLoading();
if (data.data &&
data.data.is_bind &&
data.data.is_bind === 'Y') { // 已经绑定
let userInfo = {};
userInfo.is_bind = data.data.is_bind;
userInfo.mobile = data.data.mobile;
userInfo.ssouid = data.data.ssouid;
userInfo.uid = data.data.uid;
userInfo.sessionKey = data.data.session_key;
app.setUserInfo(userInfo);
app.setSessionKey(userInfo.sessionKey);
return Promise.resolve({
code: 10003,
data: userInfo,
message: '微信用户已绑定手机号'
});
} else {
return Promise.resolve({
code: 10004,
message: '微信用户未绑定手机号'
});
}
});
return accountModel.wechatUserIsBind(unionID, nickName).then(data => {
wx.hideLoading();
if (data.data &&
data.data.is_bind &&
data.data.is_bind === 'Y') { // 已经绑定
let userInfo = {};
userInfo.is_bind = data.data.is_bind;
userInfo.mobile = data.data.mobile;
userInfo.ssouid = data.data.ssouid;
userInfo.uid = data.data.uid;
userInfo.sessionKey = data.data.session_key;
app._removeSync('disableAutoLogin');
app.setUserInfo(userInfo);
app.setSessionKey(userInfo.sessionKey);
// 登录成功回调
event.emit('yas-login-type-report', { LOGIN_TYPE: 4 });
return Promise.resolve({
code: 10003,
data: userInfo,
message: '微信用户已绑定手机号'
});
} else {
return Promise.resolve({
code: 10004,
message: '微信用户未绑定手机号'
});
}
});
}
/**
* 获取unionID、如果用户拒绝授权则无法获得unionID
* 获取unionID、如果用户拒绝授权则无法获得unionID<废弃>
* @param srd_session
* @param showMsg
* @returns {Promise.<T>}
*/
function getUnionID(srd_session, showMsg) {
let nickName;
let app = getApp();
let nickName;
return wx.getUserInfo()
.then(res => {
let userInfo = res.userInfo;
nickName = userInfo.nickName;
return accountModel.decodeUserInfo(srd_session, res.encryptedData, res.iv);
})
.then(data => {
if (data.data.union_id) {
app.setUnionID(data.data.union_id);
return wechatUserIsBind(data.data.union_id, nickName);
}
})
.catch(() => {
let msg = {
succeed: false,
message: '使用微信小程序登录需要微信授权,您已经拒绝了该请求,请删除小程序重新进入。'
};
return wx.getSetting().then(rset => {
if (rset.authSetting['scope.userInfo']) {
return wx.getUserInfo().then(res => {
let userInfo = res.userInfo;
if (showMsg) {
msg.code = 10001;
}
return Promise.reject(msg);
});
nickName = userInfo.nickName;
event.emit('enable-tap-login');
return accountModel.decodeUserInfo(srd_session, res.encryptedData, res.iv);
});
}
return rset;
}).then(data => {
if (data && data.data && data.data.union_id) {
app.setUnionID(data.data.union_id);
return wechatUserIsBind(data.data.union_id, nickName);
}
}).catch(() => {
let msg = {
succeed: false,
message: '使用微信小程序登录需要微信授权,您已经拒绝了该请求,请删除小程序重新进入。'
};
if (showMsg) {
msg.code = 10001;
}
event.emit('enable-tap-login');
return Promise.reject(msg);
});
}
/**
... ... @@ -161,44 +175,56 @@ function getUnionID(srd_session, showMsg) {
* @param showMsg
* @returns {Promise.<T>}
*/
function wechatAuthLogin(showMsg) { // showMsg: 是否显示拒绝授权提示
function wechatAuthLogin() {
let app = getApp();
return wx.login()
.then(res => {
if (res.code) {
return accountModel.wechatMiniAppLogin(res.code);
}
})
.then(data => {
if (data.code !== 200) {
return Promise.reject({
succeed: false,
message: data.message
});
return wx.login().then(res => {
if (res.code) {
return accountModel.wechatMiniAppLogin(res.code);
}
}).then(data => {
if (data.code !== 200) {
return Promise.reject({
succeed: false,
message: data.message
});
} else {
data = data.data;
app.setOpenID(data.openid);
app.setWechatThirdSession(data.srd_session);
if (data.unionid) {
app.setUnionID(data.unionid);
event.emit('enable-tap-login');
return wechatUserIsBind(data.unionid, '');
} else {
data = data.data;
app.setOpenID(data.openid);
app.setWechatThirdSession(data.srd_session);
// 如果unionID不存在(未使用过任何有货微信产品的全新用户),
// 调用getUnionID函数,再次获取unionID
if (!data.unionid) {
return getUnionID(data.srd_session, showMsg);
} else {
wx.getUserInfo();
app.setUnionID(data.unionid);
return wechatUserIsBind(data.unionid, '');
}
// 如果没有返回unionID,则把原来的清空
wx.setStorage({
key: 'unionID',
data: ''
});
}
})
.catch(err => {
return Promise.reject(err);
});
// return getUnionID(data.srd_session, showMsg);
}
}).catch(err => {
event.emit('enable-tap-login');
return Promise.reject(err);
});
}
/**
* [跳转手动登录页面]
* @return {[type]} [description]
*/
function tapGoLogin() {
return wx.navigateTo({
url: '/pages/account/bindMobile',
});
}
/**
* 用户手动点击登录
* 用户手动点击登录<废弃>
* @returns {Promise.<T>}
*/
function tapToLogin() {
... ... @@ -206,46 +232,45 @@ function tapToLogin() {
let router = global.router;
if (wx.getSetting) {
return wx.getSetting()
.then(res => {
if (res.authSetting['scope.userInfo']) {
return router.go('bindMobile');
} else {
return wx.showModal({
title: '',
content: '检测到您未打开微信用户信息授权,开启后即可进行登录',
confirmText: '去开启',
confirmColor: '#000000'
});
}
})
.then(res => {
if (res.confirm) {
return wx.openSetting();
}
return wx.getSetting().then(res => {
if (res.authSetting['scope.userInfo']) {
return router.goUrl(`${config.MINI_APP_DOMAIN}/pages/account/bindMobile`);
} else {
return wx.showModal({
title: '',
content: '检测到您未打开微信用户信息授权,开启后即可进行登录',
confirmText: '去开启',
confirmColor: '#000000'
});
}
}).then(res => {
if (res.confirm) {
return wx.openSetting();
}
if (res.cancel) {
return router.go('bindMobile');
}
})
.then(res => {
if (res.authSetting['scope.userInfo'] && res.authSetting['scope.userInfo'] === true) {
return getUnionID(app.getWechatThirdSession());
}
})
.then(res => {
if (res.code === 10003) { // 已经绑定手机号
app.setUserInfo(res.data);
app.setSessionKey(res.data.sessionKey);
event.emit('user-login-success');
event.emit('login-type-report', {LOGIN_TYPE: 4});
}
if (res.cancel) {
return wx.navigateTo({
url: '/pages/account/bindMobile',
});
}
}).then(res => {
if (res.authSetting['scope.userInfo'] && res.authSetting['scope.userInfo'] === true) {
return getUnionID(app.getWechatThirdSession());
}
}).then(res => {
if (res.code === 10003) { // 已经绑定手机号
app._removeSync('disableAutoLogin');
app.setUserInfo(res.data);
app.setSessionKey(res.data.sessionKey);
event.emit('user-login-success');
}
if (res.code === 10004) { // 手动授权登录未绑定强制绑定
return router.go('bindMobile');
}
})
.catch(() => {});
if (res.code === 10004) { // 手动授权登录未绑定强制绑定
return wx.navigateTo({
url: '/pages/account/bindMobile',
});
}
}).catch(() => {});
} else {
return wx.showModal({
title: '提示',
... ... @@ -286,7 +311,7 @@ function decodePhoneNumber(iv, encryptedData) {
* @param e
*/
function getPhoneNumber(e) {
const app = getApp();
let app = getApp();
let router = global.router;
if (e.detail.errMsg === 'getPhoneNumber:ok') {
... ... @@ -294,64 +319,142 @@ function getPhoneNumber(e) {
let countryCode;
wx.showLoading();
decodePhoneNumber(e.detail.iv, e.detail.encryptedData)
.then(res => {
phoneNumber = res.data.phoneNumber;
countryCode = res.data.countryCode;
decodePhoneNumber(e.detail.iv, e.detail.encryptedData).then(res => {
phoneNumber = res.data.phoneNumber;
countryCode = res.data.countryCode;
if (res.data.phoneNumber && res.data.countryCode) {
return _bindMiniAppByAuto(res.data.phoneNumber, res.data.countryCode);
}
if (res.data.phoneNumber && res.data.countryCode) {
return _bindMiniAppByAuto(res.data.phoneNumber, res.data.countryCode);
}
return {};
}).then(res => {
wx.hideLoading();
if (res.code === 200) {
let userInfo = {};
return Promise.reject({});
})
.then(res => {
wx.hideLoading();
if (res.code === 200) {
let userInfo = {};
userInfo.uid = res.data.uid;
userInfo.is_bind = res.data.is_bind || '';
userInfo.mobile = res.data.profile;
userInfo.ssouid = res.data.ssouid;
userInfo.sessionKey = res.data.session_key;
app.setUserInfo(userInfo);
app.setSessionKey(userInfo.sessionKey);
event.emit('user-login-success');
if (res.data && res.data.is_register === 0) {
event.emit('bind-auto-register-type-report', {YB_REGISTER_SUCCESS: 5});
}
} else {
return wx.showModal({
title: '提示',
content: res.message || '该手机已是yoho账户,请使用手机号动态登录'
});
}
userInfo.uid = res.data.uid;
userInfo.is_bind = res.data.is_bind || '';
userInfo.mobile = res.data.profile;
userInfo.ssouid = res.data.ssouid;
userInfo.sessionKey = res.data.session_key;
app._removeSync('disableAutoLogin');
app.setUserInfo(userInfo);
app.setSessionKey(userInfo.sessionKey);
})
.then(res => {
if (res && res.confirm) {
router.go('bindMobile', {phone: phoneNumber, area: countryCode});
if (e.currentTarget && !e.currentTarget.dataset.notJump) {
wx.navigateBack(); // 先执行这个,然后在执行event
}
})
.catch(() => {
router.go('bindMobile', {phone: phoneNumber, area: countryCode});
});
event.emit('user-login-success');
event.emit('yas-user-register-success', { REG_TYPE: 5 });//注册成功调用埋点事件
wx.showToast({
icon: 'none',
title: '手机号授权成功!\r\n为享受更多权益,已为您注册有货会员!',
duration: 3000
});
} else {
return wx.showModal({
title: '提示',
content: res.message || '该手机已是yoho账户,请使用手机号动态登录'
});
}
}).then(res => {
if (res && res.confirm) {
router.goUrl(`${config.MINI_APP_DOMAIN}/pages/account/bindMobile?phone=${phoneNumber}&area=${countryCode}`);
}
}).catch(() => {
router.goUrl(`${config.MINI_APP_DOMAIN}/pages/account/bindMobile?phone=${phoneNumber}&area=${countryCode}`);
});
} else {
router.go('bindMobile');
wx.navigateTo({
url: '/pages/account/bindMobile'
});
}
}
function getUserInfo(e) {
let app = getApp();
if (e.detail.errMsg !== 'getUserInfo:ok') {
return Promise.reject({
code: 500,
message: 'getUserInfo authorize fail'
});
}
wx.showLoading();
event.emit('enable-tap-login');
return accountModel.decodeUserInfo(
app.getWechatThirdSession(),
e.detail.encryptedData,
e.detail.iv
).then(res => {
if (res.data && res.data.union_id) {
app.setUnionID(res.data.union_id);
return wechatUserIsBind(res.data.union_id, e.detail.userInfo.nickName);
}
return res;
}).then(res => {
wx.hideLoading();
if (res.code === 10003) { // 微信号已绑定手机号
event.emit('user-login-success');
wx.showToast({
icon: 'none',
title: '登录成功!',
duration: 3000
});
} else if (res.code === 10004) { // 微信用户未绑定手机号
wx.showToast({
icon: 'none',
title: '该微信号未绑定yoho手机账号,请再次单击绑定手机号',
duration: 3000
});
}
// 登录成功或者失败回调
event.emit('user-login-callback', res);
return res;
}).catch(err => {
console.log(err, 'err:getUserInfo--');
wx.hideLoading();
});
}
/**
* [获取登录按钮类型]
* @return {[type]} [description]
*/
function getLoginButtonType() {
let app = getApp() || {};
if (app && app.getUid()) {
return ''; // 已经是登录状态,合法用户
}
let isUnionID = app && app.globalData.unionID;// 如果有unionID情况
let isPhoneNumber = isUnionID ? !(app && app.getUid()) : false; // 如果有unionID且没有uid,可以获取手机号自动绑定登录
if (app._getSync('disableAutoLogin')) { // 手动退出,走手机号登录页面
return 'tapGoLogin';
} else if (!isUnionID) {
return 'getUserInfo';
} else if (isPhoneNumber) {
return 'getPhoneNumber';
}
return ''; // 已经是登录状态,合法用户
}
export {
module.exports = {
wechatAuthLogin,
isNeedImgCheck,
getVerifyCode,
bindMobileAction,
tapToLogin,
tapToLogin, // <废弃>
tapGoLogin,
verifySessionKey,
getPhoneNumber
getPhoneNumber,
getUserInfo,
getLoginButtonType
};
... ...
/**
* 资源码配置文件
*/
export default {
home: {
top: '2d3995ed8d15dfcf70edc3c0e6d89869',
middle: '40972876b41759ead80b29f512faaa21',
bottom: 'e6602cdf36d83a1d2a5cdaebc2cdde48'
},
brand: {
search: 'b917a110b2d9c85664b898b6ed122666'
},
clock: {
top: '89f34b0f6a271e81ac9a6875a15ea7da'
}
};
... ...
import wx from '../utils/wx';
// import gominiapp from './gominiapp';
import gominiapp from '../router/jump-to-miniapp.js';
import { parse, stringify } from '../vendors/query-stringify';
import event from '../common/event';
export default {
scanCode: function() {
wx.scanCode().then(res => {
const domRex = /^http(s)?:\/\/o\.yohobuy\.com/;
const splitAry = res.result.split('?');
const skn = parse(splitAry[1]).skn;
if (domRex.test(res.result) && skn) {
event.emit('scan-success', {URL: res.result}); // 扫码成功后上报
gominiapp({
app: 'yohobuy',
page: 'productDetail',
data: {
productSkn: skn
}
});
} else {
wx.showModal({
content: '您扫描的二维码对应链接格式不正确,请重新扫码',
showCancel: false
});
}
});
},
notJump: function() {
// 配置不跳转连接,解决后台URL必须配置问题
}
};
... ...
... ... @@ -10,7 +10,7 @@ export default {
}
udid = uuid();
udid = uuid().replace(/-/g, '');
wx.setStorageSync('udid', udid);
return udid;
... ...
import config from './config';
import rules from '../router/rules';
import {MD5} from '../vendors/crypto';
import {parse} from '../vendors/query-stringify';
import { MD5 } from '../vendors/crypto';
import { parse, stringify } from '../vendors/query-stringify';
export default class yas {
constructor(app) {
... ... @@ -14,8 +14,8 @@ export default class yas {
dm: '', // 设备型号
res: '', // 屏幕大小
osv: '', // 系统版本
ak: 'yhshop_mp',
ch: config.unionType,
ak: 'yohostore_mp',
ch: this.app.globalData.unionType,
udid: this.app.globalData.udid
};
... ... @@ -25,7 +25,7 @@ export default class yas {
self.language = res.language;
if (res.platform === 'devtools') {
self.devEnv = true;
self.devEnv = true; //判断开发环境
}
Object.assign(self.deviceInfo, {
... ... @@ -51,7 +51,7 @@ export default class yas {
return wx.request({
url: config.domains.yasApi,
data: {_mlogs: JSON.stringify(params)},
data: { _mlogs: JSON.stringify(params) },
method: 'POST',
header: {
'content-type': 'application/x-www-form-urlencoded',
... ... @@ -61,8 +61,23 @@ export default class yas {
}
report(event, info) {
let self = this;
for(let key in info) {
info[key] = decodeURIComponent(info[key]);
}
const pageNameMap = {};
for (let i in rules) {
if (rules.hasOwnProperty(i) && rules[i].path) {
pageNameMap[rules[i].path] = i;
}
}
if (event === 'YB_SHARE_RESULT_L') {
info.PAGE_NAME = pageNameMap['/' + info.PATH];
}
let userInfo = info || {};
let statusInfo = {ln: this.language};
let statusInfo = { ln: this.language };
if (this.app) {
Object.assign(userInfo, {
... ... @@ -97,6 +112,7 @@ export default class yas {
}
},
complete() {
// console.log('yasReport:', event, info);
return resolve(self.uploadData({
status: statusInfo,
device: self.deviceInfo,
... ... @@ -105,7 +121,7 @@ export default class yas {
ts: new Date().getTime(),
op: event,
uid: self.app.getReportUid(),
sid: self.app.globalData.sid || '',
sid: MD5(self.app.globalData.sid).toString() || '',
}]
}));
}
... ... @@ -117,10 +133,11 @@ export default class yas {
let currentPage = pages[pages.length - 1];
let path = `/${currentPage.route}`,
options = currentPage.options || {},
copyOptions = Object.assign({}, options), // 拷贝options对象,用于获取当前页面参数
fromPage = options.fromPage || '',
fromParam = parse(decodeURIComponent(options.fromParam || ''));
let info = {PV_ID: pvid || this.pvid};
let info = { PV_ID: pvid || this.pvid };
for (let i in rules) {
if (rules.hasOwnProperty(i) && rules[i].path === path) {
... ... @@ -129,9 +146,11 @@ export default class yas {
PAGE_NAME: rules[i].report && rules[i].report.pageName || i,
FROM_PAGE_NAME: fromPage && rules[fromPage].report && rules[fromPage].report.pageName || fromPage
});
delete copyOptions.fromPage; // 删除拷贝对象的两个from属性
delete copyOptions.fromParam;
info.PAGE_PARAM = '';
info.FROM_PAGE_PARAM = '';
info.PAGE_PARAM = stringify(copyOptions); // 获取当前页param
info.FROM_PAGE_PARAM = ''; //decodeURIComponent(options.fromParam || ''); // 获取来源页param
if (rules[i].report && rules[i].report.paramKey) {
info.PAGE_PARAM = decodeURIComponent(options[rules[i].report.paramKey] || '');
}
... ...
import {
tapGoLogin,
getPhoneNumber,
getUserInfo
} from '../../common/login';
Component({
properties: {
openType: {
type: String,
value: ''
}
},
methods: {
tapGoLogin,
getPhoneNumber,
getUserInfo
}
});
... ...
{
"navigationBarTitleText": "发票信息"
"component": true
}
... ...
<block wx:if="{{openType === 'tapGoLogin'}}">
<button
bindtap="tapGoLogin"
class="user-button-type"></button>
</block>
<block wx:elif="{{openType}}">
<button
open-type="{{openType}}"
bindgetphonenumber="getPhoneNumber"
bindgetuserinfo="getUserInfo"
class="user-button-type"></button>
</block>
... ...
.user-button-type {
width: 100%;
height: 100%;
opacity: 0;
}
... ...
import wx from '../../utils/wx';
let systemInfo = wx.getSystemInfoSync();
Component({
properties: {
isTop: { //是否展示返回顶部按钮
type: Boolean,
value: false
},
isShare: { // 是否显示分享
type: Boolean,
value: false
}
},
data: {
isTopShow: true,
indicatorAnimation: {},
height: 0,
scrollTop: 0
},
ready: function() {
this.setData({height: systemInfo.windowHeight});
},
methods: {
tapComponentsMore: function() { // 滚动底部 加载更多 回调
this.triggerEvent('tapLoadMore', {});
},
backToTop: function() { // 返回顶部
this.setData({scrollTop: 0});
},
onScroll: function(e) {
if (this.data.isTop) { // 返回顶部按钮显示 不显示控制
let { scrollTop } = e.detail || {};
let isTopShow = scrollTop > systemInfo.windowHeight * 2 ? true : false;
if (isTopShow !== this.data.isTopShow) {
let animtionIndicator = wx.createAnimation({
duration: 300,
timingFunction: 'linear',
});
if (isTopShow) {
animtionIndicator.opacity(1).step();
} else {
animtionIndicator.opacity(0).step();
}
this.setData({
indicatorAnimation: animtionIndicator.export(),
isTopShow: isTopShow
});
}
}
}
}
});
... ...
{
"navigationBarTitleText": "管理地址"
"component": true
}
... ...
<scroll-view class="news-page"
scroll-y="true"
style="height:{{height}}px;"
scroll-with-animation="true"
scroll-top="{{scrollTop}}"
bindscroll="onScroll"
bindscrolltolower="tapComponentsMore">
<slot />
</scroll-view>
<view class="quicknavigation">
<view class="quicknavigation-content">
<button class="share-btn" plain="true" type="default" hover-class="none" open-type="share" wx:if="{{isShare}}">
<image class="img-share" src="/static/images/my-scroll-view/share@3x.png"></image>
</button>
<button class="back-btn" plain="true" animation="{{indicatorAnimation}}" wx:if="isTop"
type="default" hover-class="none" bindtap="backToTop">
<image class="img-back" src="/static/images/my-scroll-view/backtop@3x.png"></image>
</button>
</view>
</view>
... ...
.quicknavigation {
position: fixed;
display: flex;
flex-direction: column;
width: 44px;
right: 15px;
bottom: 100rpx;
z-index: 1300;
}
.quicknavigation-content {
display: flex;
flex-direction: column;
width: 44px;
justify-content: flex-end;
align-self: center;
align-items: center;
}
.quicknavigation .quicknavigation-content image {
width: 44px;
height: 44px;
bottom: 0;
}
.quicknavigation .quicknavigation-content button {
border: none;
line-height: 1.8;
padding: 0;
margin: 0;
}
.quicknavigation .quicknavigation-content button.back-btn {
opacity: 0;
}
... ...
import ensureModel from '../../../models/cart/ensure';
import addressModel from '../../../models/home/address';
import commonModel from '../../../models/common';
import wechatAddressUtil from '../../../utils/wechat-address';
import { wechatPay } from '../../../utils/wechat-pay';
import Yas from '../../../common/yas';
const SKU_TYPE = 'O';
const PAYMENT = { // 支付类型
ID: 15,
TYPE: 1,
};
const ORDER_TYPE = { // 结算订单类型
BUYNOW: 'buynow'
};
const router = global.router;
const app = getApp();
let yas;
function formatPaymentData(data, yasInfo) {
data = data || {};
let info = {
choosedAddress: data.delivery_address || '',
goodsList: data.goods_list || [],
deliveryWayList: data.delivery_way || [],
deliveryTimeList: data.delivery_time || [],
promotionList: data.shopping_cart_data.promotion_formula_list,
paymentAmount: data.shopping_cart_data.last_order_amount
};
yasInfo = yasInfo || {};
info.goodsList.map(value => {
if (value.goods_type === 'gift' || value.goods_type === 'price_gift') {
value.sales_price = value.last_price;
}
yasInfo.skns && yasInfo.skns.push(value.product_skn);
yasInfo.skus && yasInfo.skus.push(value.product_sku);
yasInfo.pids && yasInfo.pids.push(value.product_id);
return value;
});
let selectWay,
selectTime;
if (info.deliveryWayList.length) {
info.deliveryWayList.map(value => {
if (value.default === 'Y') {
value.checked = true;
selectWay = value;
}
});
if (!selectWay) {
selectWay = info.deliveryWayList[0];
info.deliveryWayList[0].checked = true;
}
info.deliveryWayId = selectWay.delivery_way_id;
info.deliveryWayText = `${selectWay.delivery_way_name}:运费¥${selectWay.delivery_way_cost}`;
}
if (info.deliveryTimeList.length) {
info.deliveryTimeList.map(value => {
if (value.default === 'Y') {
value.checked = true;
selectTime = value;
}
});
if (!selectTime) {
selectTime = info.deliveryTimeList[0];
info.deliveryTimeList[0].checked = true;
}
info.deliveryTimeId = selectTime.delivery_time_id;
info.deliveryTimeText = selectTime.delivery_time_string || '';
}
return info;
}
Page({
data: {
choosedAddress: {},
goodsList: [],
deliveryWayText: '',
deliveryWayEditStatus: false,
deliveryWayList: [],
deliveryTimeText: '',
deliveryTimeEditStatus: false,
deliveryTimeList: [],
invoiceNeedStatus: false,
promotionList: [],
paymentAmount: ''
},
onLoad(options) {
this.orderData = options;
this.yasInfo = {
skns: [],
skus: [],
pids: []
};
this.loadEnsurePayment({buyNumber: this.orderData.buyNumber, productSku: this.orderData.productSku});
yas = new Yas(app);
yas.pageOpenReport();
},
loadEnsurePayment(options) {
if (options.productSku) {
this.orderType = ORDER_TYPE.BUYNOW;
ensureModel.buynowPayment({
sku_type: SKU_TYPE,
product_sku: options.productSku,
buy_number: options.buyNumber || 1,
yoho_coin_mode: 0,
is_support_apple_pay: 'N',
}).then(res => {
if (res.code !== 200) {
wx.showModal({
content: res.message || '网络异常,请稍后重试',
showCancel: false,
confirmText: '好的',
});
return;
}
let data = formatPaymentData(res.data, this.yasInfo);
Object.assign(this.orderData, {
productSku: options.productSku,
buyNumber: options.buyNumber || 1,
deliveryWayId: data.deliveryWayId,
deliveryTimeId: data.deliveryTimeId
});
this.setData(data);
}).catch(() => {
wx.showModal({
content: '网络异常,请稍后重试',
showCancel: false,
confirmText: '好的',
});
});
}
},
buynowCompute(data) {
if (typeof data === 'object') {
Object.assign(this.orderData, data);
}
ensureModel.buynowCompute({
cart_type: 'ordinary',
sku_type: SKU_TYPE,
product_sku: this.orderData.productSku,
buy_number: this.orderData.buyNumber,
delivery_way: this.orderData.deliveryWayId,
payment_type: 1, // 支付方式,1 在线支付 2 货到付款
}).then(res => {
if (res.code === 200) {
let comp = res.data || {};
this.setData({
promotionList: comp.promotion_formula_list,
paymentAmount: comp.last_order_amount
});
}
});
},
showToast(title) {
wx.showToast({
title: title,
icon: 'none',
duration: 2000
});
},
chooseAddress() {
router.go('address', {
type: 'select',
id: this.data.choosedAddress.address_id
});
},
chooseAddressCallback(address) {
this.setData({choosedAddress: address});
},
enterAddress() {
router.go('address', {type: 'add'});
},
chooseWechatAddress() {
wechatAddressUtil.choose(res => {
addressModel.saveWechatAddressData(res).then(result => {
if (result.code === 200) {
this.chooseAddressCallback(result.data);
} else {
wx.showToast({
title: result.message,
icon: 'none',
duration: 1500
});
}
});
});
},
toggleDeliveryWayList() {
this.setData({deliveryWayEditStatus: !this.data.deliveryWayEditStatus});
},
changeDeliveryWay(e) {
let id = e.currentTarget.dataset.id;
let name = e.currentTarget.dataset.name;
let list = this.data.deliveryWayList;
if (list.length) {
list.map(item => {
item.checked = (+item.delivery_way_id === +id);
});
}
this.buynowCompute({deliveryWayId: id});
this.setData({
deliveryWayText: name,
deliveryWayEditStatus: false,
deliveryWayList: list
});
},
toggleDeliveryTimeList() {
this.setData({deliveryTimeEditStatus: !this.data.deliveryTimeEditStatus});
},
changeDeliveryTime(e) {
let id = e.currentTarget.dataset.id;
let name = e.currentTarget.dataset.name;
let list = this.data.deliveryTimeList;
if (list.length) {
list.map(item => {
item.checked = (+item.delivery_time_id === +id);
});
}
this.orderData.deliveryTimeId = id;
this.setData({
deliveryTimeText: name,
deliveryTimeEditStatus: false,
deliveryTimeList: list
});
},
toggleInvoiceWrap(e) {
let data = {invoiceNeedStatus: e.detail.value};
if (!this.data.invoiceInfo) {
let address = this.data.choosedAddress || {};
data.invoiceInfo = {
invoiceType: 2,
invoiceCompany: false,
invoiceTitle: '',
invoiceTitleShow: '个人',
invoiceContent: 12,
taxNumber: '',
receiver: address.mobile || ''
};
}
this.setData(data);
},
changeInvoiceInfo() {
let skey = `invoice${Date.parse(new Date())}`;
try {
wx.setStorageSync(skey, this.data.invoiceInfo);
} catch (e) {
console.log('invoice info setStorageSync error');
}
router.go('cartInvoice', {skey: skey});
},
changeInvoiceCallback(invoice) {
if (!invoice.invoiceCompany && !invoice.invoiceTitle) {
invoice.invoiceTitleShow = '个人';
} else {
invoice.invoiceTitleShow = invoice.invoiceTitle;
}
this.setData({invoiceInfo: invoice});
},
submitOrder(e) {
this.formId = e.detail.formId;
if (this.orderType === ORDER_TYPE.BUYNOW) {
this.buynowOrderSubmit();
} else {
// 普通购物车下单
}
},
buynowOrderSubmit() {
if (this.orderSubmiting) {
return;
}
let param = {
sku_type: SKU_TYPE,
product_sku: this.orderData.productSku,
buy_number: this.orderData.buyNumber,
payment_id: PAYMENT.ID,
payment_type: PAYMENT.TYPE,
qhy_union: JSON.stringify({client_id: app.getUnionType()})
};
if (this.orderData.deliveryWayId) {
param.delivery_way = this.orderData.deliveryWayId;
}
if (this.orderData.deliveryTimeId) {
param.delivery_time = this.orderData.deliveryTimeId;
}
if (this.data.choosedAddress && this.data.choosedAddress.address_id) {
param.address_id = this.data.choosedAddress.address_id;
} else {
return this.showToast('请选择收件地址');
}
if (this.data.invoiceNeedStatus) {
let invoiceInfo = this.data.invoiceInfo;
Object.assign(param, {
invoices_title: invoiceInfo.invoiceTitleShow,
invoices_type: invoiceInfo.invoiceType,
invoice_content: invoiceInfo.invoiceContent,
buyerTaxNumber: invoiceInfo.taxNumber,
invoice_payable_type: invoiceInfo.invoiceCompany ? 2 : 1,
receiverMobile: invoiceInfo.receiver
});
}
if (+param.invoices_type === 2 && !param.receiverMobile) {
return this.showToast('请填写电子发票接收手机号');
}
this.orderSubmiting = true;
ensureModel.buynowSubmit(param).then(res => {
this.orderSubmiting = false;
if (res.code === 200) {
let data = res.data;
// yas上报
yas.report('YB_SC_ORD', {
ORD_NUM: data.order_code + '',
PRD_SKN: this.yasInfo.skns.join(','),
RPD_SKU: this.yasInfo.skus.join(','),
PRD_ID: this.yasInfo.pids.join(','),
ORDER_TYPE: 102 // 101购物车下单,102立即购买下单
});
// 上报formID
commonModel.addWechatFormId({
order_code: data.order_code,
openId: app.getOpenID(),
miniapp_type: app.getMiniappType(),
formId: this.formId
});
data.needJump = true;
wechatPay(data);
} else {
wx.showModal({
content: res.message,
showCancel: false,
confirmText: '好的',
});
}
}).catch(() => {
this.orderSubmiting = false;
});
}
});
<wxs src="../../../wxs/helper.wxs" module="helper" />
<view class="container">
<view class="address-wrap">
<address-card address="{{choosedAddress}}" bind:chooseAddress="chooseAddress" bind:addAddressByLocal="enterAddress" bind:addAddressByWechat="chooseWechatAddress"></address-card>
</view>
<view class="split-line"></view>
<view class="goods-list">
<block wx:if="{{goodsList.length}}">
<order-item wx:for="{{goodsList}}" wx:key="unique" item="{{item}}" index="{{index}}"></order-item>
</block>
<order-item wx:else frame="true"></order-item>
</view>
<view class="split-line"></view>
<view class="choose-wrap">
<view class="choose-item delivery-way">
配送方式
<view class="change-btn" bindtap="toggleDeliveryWayList">
<text class="btn-text">{{deliveryWayText}}</text>
<text class="iconfont {{deliveryWayEditStatus ? 'icon-top' : 'icon-bottom'}}"></text>
</view>
</view>
<view wx:if="{{deliveryWayEditStatus}}" class="edit-wrap delivery-way-wrap">
<view wx:for="{{deliveryWayList}}" wx:key="{{index}}" class="edit-item delivery-way-item" data-id="{{item.delivery_way_id}}" data-name="{{item.delivery_way_name}}:运费¥{{item.delivery_way_cost}}" bindtap="changeDeliveryWay">
<text class="left-name">{{item.delivery_way_name}}: 运费¥{{item.delivery_way_cost}}</text>
<text class="iconfont {{item.checked ? 'icon-round-checked' : 'icon-round'}}"></text>
</view>
</view>
<view class="choose-item delivery-time">
送货时间
<view class="change-btn" bindtap="toggleDeliveryTimeList">
<text class="btn-text">{{deliveryTimeText}}</text>
<text class="iconfont {{deliveryTimeEditStatus ? 'icon-top' : 'icon-bottom'}}"></text>
</view>
</view>
<view wx:if="{{deliveryTimeEditStatus}}" class="edit-wrap delivery-way-wrap">
<view wx:for="{{deliveryTimeList}}" wx:key="unique" class="edit-item delivery-way-item" data-id="{{item.delivery_time_id}}" data-name="{{item.delivery_time_string}}" bindtap="changeDeliveryTime">
<text class="left-name">{{item.delivery_time_string}}</text>
<text class="iconfont {{item.checked ? 'icon-round-checked' : 'icon-round'}}"></text>
</view>
</view>
<view class="choose-item invoice">
发票
<switch checked="{{invoiceNeedStatus}}" class="switch" bindchange="toggleInvoiceWrap"/>
</view>
<view wx:if="{{invoiceNeedStatus}}" class="choose-item invoice">
发票信息
<view class="change-btn" bindtap="changeInvoiceInfo">
<text class="btn-text">{{invoiceInfo.invoiceType === 2 ? '电子发票' : '纸质发票'}} - {{invoiceInfo.invoiceTitleShow}}</text>
<text class="iconfont icon-right"></text>
</view>
</view>
</view>
<view class="split-line"></view>
<view class="payment-wrap">
<view wx:for="{{promotionList}}" wx:key="unique" class="payment-cell">
<text class="name">{{item.promotion}}</text>
<text class="price">{{item.promotion_amount}}</text>
</view>
<view class="payment-cell">
<text class="name">实付金额</text>
<text class="price red">¥{{helper.round(paymentAmount)}}</text>
</view>
</view>
<view class="submit-wrap">
<form bindsubmit="submitOrder" report-submit='true'>
<button formType="submit" class="submit-btn">使用微信安全支付</button>
</form>
</view>
</view>
page {
background-color: #f0f0f0;
}
.container {
color: #444;
padding-top: 210rpx;
}
.container .red {
color: #d0021b;
}
.address-wrap {
width: 100%;
border-top: 1rpx solid #e0e0e0;
position: fixed;
top: 0;
z-index: 10;
}
.split-line {
width: 100%;
height: 20rpx;
}
.goods-list {
padding-left: 30rpx;
background-color: #fff;
}
.goods-list .goods-item:last-child {
border-bottom: 0;
}
.choose-wrap {
background-color: #fff;
}
.choose-wrap .choose-item {
height: 88rpx;
line-height: 88rpx;
font-size: 32rpx;
margin-left: 30rpx;
border-bottom: 1rpx solid #e0e0e0;
padding-right: 30rpx;
overflow: hidden;
}
.choose-wrap .choose-item:last-child {
border-bottom: 0;
}
.choose-wrap .switch {
float: right;
}
.choose-wrap .change-btn {
float: right;
display: inline-block;
font-size: 28rpx;
}
.choose-wrap .change-btn .iconfont {
font-size: 40rpx;
color: #e0e0e0;
margin-left: 10rpx;
vertical-align: middle;
}
.choose-wrap .change-btn .btn-text {
width: 400rpx;
display: inline-block;
vertical-align: top;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.choose-wrap .edit-wrap {
background-color: #f0f0f0;
font-size: 28rpx;
margin-top: -1rpx;
}
.choose-wrap .edit-wrap .edit-item {
width: 100%;
line-height: 80rpx;
padding: 0 30rpx;
border-bottom: 1rpx solid #fff;
box-sizing: border-box;
}
.choose-wrap .edit-wrap .edit-item:last-child {
border-bottom: 0;
}
.choose-wrap .edit-wrap .left-name {
max-width: 80%;
word-break: break-all;
display: inline-block;
}
.choose-wrap .edit-wrap .iconfont {
float: right;
}
.payment-wrap {
padding: 10rpx 30rpx;
background-color: #fff;
}
.payment-wrap .payment-cell {
line-height: 54rpx;
font-size: 28rpx;
}
.payment-wrap .payment-cell .price {
float: right;
}
.submit-wrap {
padding: 60rpx 30rpx;
}
.submit-wrap .submit-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
font-size: 32rpx;
color: #fff;
background-color: #444;
border-radius: 8rpx;
box-sizing: border-box;
}
import Yas from '../../../common/yas';
let yas;
Page({
data: {
invocesType: 2
},
onLoad(options) {
if (!options.skey) {
return;
}
this.tryToDo(() => {
let invoice = wx.getStorageSync(options.skey) || {};
this.setData(invoice);
this.defaultReceiver = invoice.receiver;
});
this.tryToDo(() => {
wx.removeStorage({key: options.skey});
});
yas = new Yas();
yas.pageOpenReport();
},
tryToDo(fn) {
try {
fn();
} catch (e) {
console.log(JSON.stringify(e));
}
},
validateInvoceInfo() {
const info = this.data || {};
const receiver = this.defaultReceiver;
let isPass = true;
if (info.invoiceCompany && (!info.invoiceTitle || !info.taxNumber)) {
isPass = false;
}
if (isPass && info.invocesType * 1 === 2) {
if (!info.receiver) {
isPass = false;
} else if (info.receiver !== receiver && !/^[0-9]{11,18}$/.test(info.receiver)) {
isPass = false;
}
}
if (isPass !== this.data.canSubmit) {
this.setData({canSubmit: isPass});
}
return isPass;
},
showInvoceNotice() {
wx.showModal({
title: '发票须知',
content: '1、发票金额不含优惠券/有货币/红包/优惠券/优惠码/运费,只包含商品实付金额;\r\n2、电子发票是税务局认可的、有效的收付款凭证,其法律效力、基本用途及使用规则同纸质发票,如需纸质发票可自行下载打印;', // eslint-disable-line
confirmText: '我知道了',
showCancel: false
});
},
changeTitleType(e) {
let isCompany = e.currentTarget.dataset.type === 'company';
if (isCompany !== this.data.invoiceCompany) {
this.setData({invoiceCompany: isCompany});
this.validateInvoceInfo();
}
},
changeTitle(e) {
this.data.invoiceTitle = e.detail.value;
this.validateInvoceInfo();
},
changeTaxNumber(e) {
this.data.taxNumber = e.detail.value;
this.validateInvoceInfo();
},
changeReceiver(e) {
this.data.receiver = e.detail.value;
this.validateInvoceInfo();
},
invoiceSubmit() {
if (!this.validateInvoceInfo()) {
return;
}
let currentPages = getCurrentPages();
if (currentPages.length > 1 && currentPages[currentPages.length - 2].changeInvoiceCallback) {
currentPages[currentPages.length - 2].changeInvoiceCallback(this.data);
}
wx.navigateBack({delta: 1});
}
});
<view class="contailer">
<view class="invoice-type">
<view>发票类型 电子发票
<text class="iconfont icon-wenhao notice-btn" catchtap="showInvoceNotice"></text>
</view>
<view class="tip">
<text class="iconfont icon-warn-fill"></text>
<text>电子发票与纸质发票具备同等法律效力,可支持报销入账</text>
</view>
</view>
<view class="invoice-title">发票信息</view>
<view class="invoice-info">
<view class="title-type">
<text class="iconfont {{invoiceCompany ? 'icon-round' : 'icon-round-checked'}}" data-type="personal" catchtap="changeTitleType"></text>
<text class="type-name" data-type="personal" catchtap="changeTitleType">个人</text>
<text class="iconfont {{invoiceCompany ? 'icon-round-checked' : 'icon-round'}}" data-type="company" catchtap="changeTitleType"></text>
<text class="type-name" data-type="company" catchtap="changeTitleType">单位</text>
</view>
<view class="info-item">
<text class="left-cell">发票抬头</text>
<input class="right-cell" placeholder="{{invoiceCompany ? '请输入单位名称' : '个人(可修改)'}}" data-name="reciver" maxlength="18" bindinput="changeTitle" value="{{invoiceTitle}}"/>
</view>
<view class="info-item {{invoiceCompany ? '' : 'hide'}}">
<text class="left-cell">税号</text>
<input class="right-cell" placeholder="请输入正确的纳税人识别号" data-name="reciver" maxlength="18" bindinput="changeTaxNumber" value="{{taxNumber}}"/>
</view>
</view>
<view class="invoice-title">收票人信息</view>
<view class="invoice-reciver">
<text class="left-cell">手机号</text>
<input class="right-cell" placeholder="可通过手机号在发票服务平台查询" data-name="reciver" maxlength="18" type="number" bindinput="changeReceiver" value="{{receiver}}"/>
</view>
<button class="submit-btn {{canSubmit ? '' : 'disabled'}}" bindtap="invoiceSubmit">确认</button>
</view>
page {
display: block;
min-height: 100%;
background-color: #f0f0f0;
}
.contailer {
font-size: 32rpx;
}
.invoice-type {
background-color: #fff;
padding: 20rpx 30rpx;
margin-top: 20rpx;
}
.invoice-type .notice-btn {
float: right;
font-size: 32rpx;
color: #888;
display: inline-block;
padding-left: 40rpx;
}
.invoice-type .tip {
font-size: 24rpx;
margin-top: 16rpx;
color: #888;
}
.invoice-type .tip .iconfont {
margin-right: 6rpx;
}
.invoice-title {
line-height: 90rpx;
padding: 0 30rpx;
}
.invoice-info,
.invoice-reciver {
line-height: 80rpx;
padding-left: 30rpx;
background-color: #fff;
}
.invoice-info .title-type > text {
display: inline-block;
}
.invoice-info .title-type .iconfont {
font-size: 34rpx;
}
.invoice-info .title-type .type-name {
padding: 0 16rpx;
margin-right: 40rpx;
}
.invoice-info .info-item {
border-top: 1rpx solid #e0e0e0;
overflow: hidden;
}
.invoice-info .right-cell,
.invoice-reciver .right-cell {
float: right;
font-size: 24rpx;
width: 540rpx;
margin-right: 30rpx;
height: 80rpx;
}
.invoice-info .hide {
display: none;
}
.submit-btn {
height: 80rpx;
line-height: 78rpx;
margin: 50rpx 30rpx;
background-color: #444;
color: #fff;
}
.submit-btn.disabled {
background-color: #999;
}
import addressModel from '../../../models/home/address';
import wechatAddressUtil from '../../../utils/wechat-address';
import Yas from '../../../common/yas';
const PAGE_TYPE_ADD = 'add';
const PAGE_TYPE_SELECT = 'select';
const AREA_CACHE_KEY = 'address_provinces_cache';
let CACHE_AREA_LIST = {};
let yas;
const validateAddress = function(data) {
const errorTip = {
consignee: '请输入正确的收件人姓名',
area_code: '请选择省市区',
mobile: '请输入正确的手机号',
address: '请输入详细的收件地址'
};
const regx = {
consignee: /^([\u4e00-\u9fa5\w*]{1,20})$/,
area_code: /^[0-9]{6,9}$/,
mobile: /^\d{3}(\d{4}|\*{4})\d{4,11}$/
};
let pass = true;
let errorType;
data = data || {};
for (let i in data) {
if (data.hasOwnProperty(i) &&
regx[i] &&
!regx[i].test(data[i])) {
pass = false;
!errorType && (errorType = i);
}
}
if (data.hasOwnProperty('address') && !data.address) {
pass = false;
!errorType && (errorType = 'address');
}
if (!pass) {
wx.showToast({
title: errorTip[errorType] || '请输入正确的信息',
icon: 'none',
duration: 2000
});
}
return pass;
};
Page({
data: {
showEditAddrPage: false,
editAddrPageData: {},
areaPicker: false,
pickerProvice: [],
pickerCity: [],
pickerArea: [],
addressList: []
},
onLoad(options) {
this.loadOptions = options || {};
if (options.type === PAGE_TYPE_ADD) {
wx.setNavigationBarTitle({title: '新增地址'});
this.setData({
showEditAddrPage: true,
editAddrPageData: {}
});
return;
} else if (options.type === PAGE_TYPE_SELECT) {
options.id = decodeURIComponent(options.id);
this.setData({
selectedId: options.id
});
}
try {
let area = wx.getStorageSync(AREA_CACHE_KEY);
if (area) {
CACHE_AREA_LIST = JSON.parse(area);
}
} catch (e) {
console.log(JSON.stringify(e));
}
this.loadAddrList();
yas = new Yas();
yas.pageOpenReport();
},
loadAddrList() {
addressModel.addressList().then(res => {
if (res.code === 200) {
let list = res.data;
this.setData({
addressEmpty: !list || !list.length,
addressList: list
});
}
});
},
loadAreaList(id) {
if (CACHE_AREA_LIST[id]) {
return Promise.resolve(CACHE_AREA_LIST[id]);
}
return addressModel.areaList(id).then(res => {
if (res.code !== 200) {
return [];
}
CACHE_AREA_LIST[id] = res.data;
wx.setStorage({
key: AREA_CACHE_KEY,
data: JSON.stringify(CACHE_AREA_LIST)
});
return res.data || [];
});
},
getAreaInfo(areaCode, resData) {
resData = resData || {};
resData.value = resData.value || [];
resData.valueName = resData.valueName || [];
let id = 0;
let type = 'provice';
let select;
if (areaCode) {
areaCode = areaCode.toString();
switch (resData.value.length) {
case 1:
id = areaCode.substring(0, 2);
select = areaCode.substring(0, 4);
type = 'city';
break;
case 2:
id = areaCode.substring(0, 4);
select = areaCode.substring(0, 6);
type = 'area';
break;
case 3:
id = areaCode.substring(0, 6);
select = areaCode;
type = 'street';
break;
default:
select = areaCode.substring(0, 2);
break;
}
}
return this.loadAreaList(id).then(list => {
if (!list.length) {
resData.fail = true;
return resData;
}
let selectIndex;
list.map((val, key) => {
if (+val.id === +select) {
selectIndex = key;
}
});
if (typeof selectIndex === 'undefined') {
selectIndex = 0;
areaCode = list[0].id;
}
resData.value.push(selectIndex);
resData.valueName.push(list[selectIndex].caption || '');
resData[type] = list;
if (resData.value.length < 3) {
return this.getAreaInfo(areaCode, resData);
}
resData.areaCode = list[selectIndex].id;
return Promise.resolve(resData);
});
},
setDefaultAddr(e) {
const that = this;
let selectIndex = e.currentTarget.dataset.key;
let addressList = this.data.addressList,
addr = addressList[selectIndex];
if (addr) {
addressModel.setDefaultAddress(addr.address_id).then(res => {
if (res.code !== 200) {
return;
}
addressList.map(item => {
item.is_default = addr.address_id === item.address_id ? 'Y' : 'N';
});
that.setData({addressList});
});
}
},
chooseAddr(e) {
if (this.loadOptions.type !== PAGE_TYPE_SELECT) {
return;
}
let selectIndex = e.currentTarget.dataset.key;
this.backToPrePage(this.data.addressList[selectIndex]);
},
backToPrePage(address) {
let currentPages = getCurrentPages();
if (address && currentPages.length > 1 &&
currentPages[currentPages.length - 2].chooseAddressCallback) {
currentPages[currentPages.length - 2].chooseAddressCallback(address);
}
wx.navigateBack({delta: 1});
},
deleteAddr(e) {
const that = this;
let selectIndex = e.currentTarget.dataset.key;
let selectId = e.currentTarget.dataset.id;
if (!selectId) {
return;
}
wx.showModal({
title: '提示',
content: '确认删除收货地址?',
cancelText: '取消',
confirmText: '确认',
confirmColor: '#000',
success: function(confirm) {
confirm.confirm && addressModel.deleteAddress(selectId).then(res => {
if (res.code === 200) {
let addressList = that.data.addressList;
addressList.splice(selectIndex, 1);
that.setData({
showEditAddrPage: false,
addressList
});
}
});
}
});
},
showEditAddrPage(e) {
let selectIndex = e.currentTarget.dataset.key;
let address = this.data.addressList[selectIndex] || {};
wx.setNavigationBarTitle({title: address.address_id ? '编辑地址' : '新增地址'});
address.index = selectIndex;
this.setData({
showEditAddrPage: true,
editAddrPageData: address
});
this.editAddress = Object.assign({changed: false}, address);
},
saveAddr() {
const that = this;
let address = this.data.editAddrPageData;
if (this.editAddress && !this.editAddress.changed) {
return that.setData({showEditAddrPage: false});
}
if (validateAddress(address)) {
addressModel.saveAddressData({
id: address.address_id,
consignee: address.consignee,
area_code: address.area_code,
address: address.address,
mobile: address.mobile,
is_default: address.is_default
}).then(result => {
if (!result || result.code !== 200) {
return wx.showModal({
content: result.message || '保存失败,请稍后重试',
confirmText: '好的',
showCancel: false
});
}
let addressList = this.data.addressList;
if (address.address_id) {
addressList.map(item => {
if (item.address_id === address.address_id) {
Object.assign(item, result.data || address);
}
});
} else if (this.loadOptions.type === PAGE_TYPE_ADD) {
this.backToPrePage(result.data);
} else {
addressList.unshift(result.data);
}
that.setData({
addressEmpty: false,
showEditAddrPage: false,
addressList
});
});
}
},
addWechatAddr() {
wechatAddressUtil.choose(res => {
addressModel.saveWechatAddressData(res).then(result => {
if (result.code === 200) {
let addressList = this.data.addressList;
addressList.unshift(result.data);
this.setData({addressList});
} else {
wx.showToast({
title: result.message,
icon: 'none',
duration: 1500
});
}
});
});
},
hideAreaPicker() {
if (this.data.areaPicker) {
this.setData({areaPicker: false});
}
},
chooseArea() {
if (this.data.areaPicker) {
return;
}
let editAddrPageData = this.data.editAddrPageData;
this.getAreaInfo(editAddrPageData.area_code).then(res => {
res = res || {};
this.setData({
areaPicker: true,
pickerProvice: res.provice || [],
pickerCity: res.city || [],
pickerArea: res.area || [],
areaValue: res.value
});
});
},
areaPickerChange(e) {
const val = e.detail.value;
const info = this.data;
const oldCode = info.areaValue;
const pickerArr = ['pickerProvice', 'pickerCity', 'pickerArea'];
let obj = {};
let code;
for (let i = 0; i < pickerArr.length; i++) {
let select = info[pickerArr[i]][val[i]];
obj[pickerArr[i]] = select;
if (i < 2 && val[i] !== oldCode[i]) {
code = select.id;
}
}
let editData = info.editAddrPageData;
if (code) {
this.getAreaInfo(code).then(res => {
res = res || {};
editData.area = res.valueName.join(' ');
editData.area_code = res.areaCode;
this.setData({
editAddrPageData: editData,
pickerProvice: res.provice || [],
pickerCity: res.city || [],
pickerArea: res.area || [],
areaValue: res.value
});
});
} else {
editData.area = `${obj[pickerArr[0]].caption} ${obj[pickerArr[1]].caption} ${obj[pickerArr[2]].caption}`;
editData.area_code = obj[pickerArr[2]].id;
if (this.editAddress.area_code !== editData.area_code) {
this.editAddress.changed = true;
}
this.setData({editAddrPageData: editData});
}
},
onInputChanged(e) {
let name = e.currentTarget.dataset.name;
this.data.editAddrPageData = this.data.editAddrPageData || {};
this.data.editAddrPageData[name] = e.detail.value;
this.editAddress = this.editAddress || {};
if (this.editAddress[name] !== this.data.editAddrPageData[name]) {
this.editAddress.changed = true;
}
}
});
<import src="./template/editor/editor.wxml"/>
<view wx:if="{{showEditAddrPage}}" class="container">
<template is="addressEditer" data="{{...editAddrPageData, areaPicker, pickerProvice, pickerCity, pickerArea, areaValue}}"/>
</view>
<view wx:else class="container">
<view wx:if="{{addressEmpty}}" class="empty-address">
<image src="https://cdn.yoho.cn/yoho-brand-shop/assets/img/home/location.png" class="empty-img"></image>
<view>尚无地址,点击底部新增</view>
</view>
<view wx:for="{{addressList}}" wx:key="{{item.address_id}}" class="addr-item" data-key="{{index}}" bindtap="chooseAddr">
<view wx:if="{{item.address_id === selectedId}}" class="selected"><text class="iconfont icon-duihao"></text></view>
<view class="info">
<text class="name">{{item.consignee}}</text>
<text class="phone">{{item.mobile}}</text>
<text class="direction">{{item.area + ' ' + item.address}}</text>
</view>
<view class="options">
<block wx:if="{{item.is_default === 'Y'}}">
<text class="iconfont icon-round-checked left-icon"></text>
<text class="left-icon"> 默认地址</text>
</block>
<block wx:else>
<text class="iconfont icon-round left-icon" data-key="{{index}}" catchtap="setDefaultAddr"></text>
<text class="left-icon" data-key="{{index}}" catchtap="setDefaultAddr"> 设为默认</text>
</block>
<text class="iconfont icon-delete right-icon" data-key="{{index}}" data-id="{{item.address_id}}" catchtap="deleteAddr"> 删除</text>
<text class="iconfont icon-edit right-icon" data-key="{{index}}" catchtap="showEditAddrPage"> 编辑</text>
</view>
</view>
<view class="option-wrap">
<button bindtap="showEditAddrPage" class="enter-address-btn">
<text class="iconfont icon-plus"></text>
手动添加
</button>
<button bindtap="addWechatAddr" class="wechat-address-btn">
<text class="iconfont icon-wechat"></text>
微信添加
</button>
</view>
</view>
@import "./template/editor/editor.wxss";
page {
display: block;
min-height: 100%;
background-color: #f0f0f0;
}
.container {
color: #444;
font-size: 28rpx;
padding-bottom: 100rpx;
}
.empty-address {
text-align: center;
padding-top: 240rpx;
}
.empty-address .empty-img {
width: 150rpx;
height: 150rpx;
display: block;
margin: 20rpx auto;
}
.addr-item {
background-color: #fff;
margin-bottom: 20rpx;
position: relative;
}
.addr-item .selected {
width:0;
height:0;
border-width: 34rpx;
border-style:solid;
border-color:red red transparent transparent;
position: absolute;
top: 0;
right: 0;
}
.addr-item .selected .iconfont {
color: #fff;
position: absolute;
top: -24rpx;
right: -30rpx;
z-index: 10;
font-weight: bold;
}
.addr-item .info {
padding: 30rpx;
}
.addr-item .name,
.addr-item .phone {
display: inline-block;
max-width: 40%;
overflow: hidden;
margin-right: 30rpx;
}
.addr-item .direction {
display: block;
color: #888;
margin-top: 10rpx;
word-break:break-all;
}
.addr-item .options {
font-size: 24rpx;
line-height: 70rpx;
padding: 0 30rpx;
border-top: 1px solid #e0e0e0;
}
.addr-item .options .iconfont {
font-size: 24rpx;
}
.addr-item .options .iconfont:before {
font-size: 28rpx;
vertical-align: middle;
position: relative;
top: 1rpx;
}
.addr-item .options .left-icon {
color: #555;
}
.addr-item .options .right-icon {
float: right;
color: #000;
margin-left: 50rpx;
}
.option-wrap {
width: 100%;
padding: 18rpx 30rpx;
background: #fff;
box-sizing: border-box;
position: fixed;
bottom: 0;
left: 0;
}
.option-wrap button {
width: 47%;
height: 60rpx;
line-height: 58rpx;
font-size: 28rpx;
color: #444;
border: 1rpx solid #444;
background: #fff;
display: inline-block;
vertical-align: middle;
}
.option-wrap button:after {
border: 0;
}
.option-wrap .wechat-address-btn {
float: right;
color: #34c538;
border-color: #34c538;
}
<template name="addressEditer">
<view class="edit-wrap">
<view class="edit-row">
<text class="left-cell">收货人</text>
<input data-name="consignee" class="right-cell" placeholder="姓名" maxlength="20" bindinput="onInputChanged" value="{{consignee}}"/>
</view>
<view class="edit-row">
<text class="left-cell">手机号码</text>
<input type="number" data-name="mobile" class="right-cell" placeholder="手机号码" maxlength="18" bindinput="onInputChanged" value="{{mobile}}"/>
</view>
<view class="edit-row" bindtap="chooseArea">
<text class="left-cell">选择地区</text>
<input class="right-cell" disabled="disabled" placeholder="地区信息" value="{{area}}"/>
</view>
<view class="edit-row">
<text class="left-cell">详细地址</text>
<input data-name="address" class="right-cell" placeholder="详细街道地址" maxlength="50" bindinput="onInputChanged" value="{{address}}"/>
</view>
</view>
<button class="option-btn save-btn" catchtap="saveAddr">确认</button>
<button wx:if="{{address_id}}" class="option-btn delete-btn" data-key="{{index}}" data-id="{{address_id}}" catchtap="deleteAddr">删除地址</button>
<view class="aaa">{{editeAddressPage}}</view>
<view wx:if="{{areaPicker}}" class="picker-mask" catchtap="hideAreaPicker"></view>
<picker-view wx:if="{{areaPicker}}" class="picker-view" indicator-style="height: 50px;" style="width: 100%; height: 300px;" value="{{areaValue}}" bindchange="areaPickerChange">
<picker-view-column data-type="provice1">
<view wx:for="{{pickerProvice}}" wx:key="unique" class="picker-item">
<text class="picker-text">{{item.caption}}</text>
</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{pickerCity}}" wx:key="unique" class="picker-item">
<text class="picker-text">{{item.caption}}</text>
</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{pickerArea}}" wx:key="unique" class="picker-item">
<text class="picker-text">{{item.caption}}</text>
</view>
</picker-view-column>
</picker-view>
</template>
.edit-wrap {
background-color: #fff;
padding-left: 30rpx;
margin-bottom: 50rpx;
}
.edit-wrap .edit-row {
border-bottom: 1rpx solid #e0e0e0;
padding: 10rpx 0;
}
.edit-wrap .edit-row:last-child {
border-bottom: 0;
}
.edit-wrap .edit-row .left-cell,
.edit-wrap .edit-row .right-cell {
height: 80rpx;
line-height: 80rpx;
display: inline-block;
vertical-align: middle;
}
.edit-wrap .edit-row .right-cell {
float: right;
width: 540rpx;
margin-right: 30rpx;
}
.option-btn {
height: 80rpx;
line-height: 80rpx;
margin: 20rpx 30rpx;
color: #fff;
background-color: #444;
}
.option-btn.delete-btn {
background-color: #aaa;
}
.picker-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 10;
}
.picker-view {
position: fixed;
left: 0;
bottom: 0;
z-index: 20;
}
.picker-view .picker-item {
line-height: 92rpx;
text-align: center;
}
.picker-view .picker-text {
max-width: 60%;
margin: 0 auto;
display: block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
import orderModel from '../../../models/home/order';
import commonModel from '../../../models/common';
import orderHandle from './order-handle';
import Yas from '../../../common/yas';
const router = global.router;
let app = getApp();
let yas;
Page({
data: {
receiveAddress: {},
reason: []
},
onLoad(options) {
if (!options.orderCode || !app.getUid()) {
return router.go('userCenter', {}, 'switchTab');
}
this.loadOrderDetail(options.orderCode);
yas = new Yas(app);
yas.pageOpenReport();
},
loadOrderDetail(orderCode) {
this.orderCode = orderCode;
orderModel.getOrderDetail(orderCode).then(res => {
if (res.code === 200) {
let data = res.data;
if (data.counter_flag === 'Y' &&
data.is_cancel !== 'Y' && data.pay_lefttime > 0) {
this.timeCountDown(parseInt(data.pay_lefttime));
}
let links = data.links || [];
this.setData({
pageLoaded: true,
receiveAddress: {
consignee: data.user_name,
address: data.address,
area: data.area,
mobile: data.mobile,
hideRightIcon: true
},
orderCode: data.order_code,
orderStatus: data.status_str,
createTime: this.formatDate(data.create_time),
goodsList: data.order_goods || [],
promotionList: data.promotion_formulas || [],
paymentAmount: data.payment_amount,
attribute: data.attribute,
mobile: data.mobile,
links: links
});
if (links.indexOf('refundApply') > -1) {
this.loadRefundReason(); // 获取退款理由
}
}
});
},
loadRefundReason() {
if (this.hasSetReason) {
return;
}
orderHandle.getRefundReason(res => {
this.setData({reason: res});
this.hasSetReason = true;
});
},
timeCountDown(second) {
const that = this;
this.setData({payLeftTime: this.formatSecond(second)});
this.timer = setInterval(function() {
let payLeftTime = '';
second--;
if (second > 0) {
payLeftTime = that.formatSecond(second);
} else {
clearInterval(that.timer);
that.loadOrderDetail(that.orderCode);
}
that.setData({payLeftTime});
}, 1000);
},
fill2(m) {
m = m || 0;
return m < 10 ? `0${m}` : m;
},
formatDate(time) {
time = new Date(time * 1000);
return `${time.getFullYear()}-${this.fill2(time.getMonth() + 1)}-${this.fill2(time.getDate())}` +
` ${this.fill2(time.getHours())}:${this.fill2(time.getMinutes())}:${this.fill2(time.getSeconds())}`;
},
formatSecond(second) {
let hr = Math.floor(second / 3600);
let min = Math.floor((second - hr * 3600) / 60);
let sec = second % 60;
return `${this.fill2(hr)}:${this.fill2(min)}:${this.fill2(sec)}`;
},
submitFormId(e) {
// 上报formID
commonModel.addWechatFormId({
order_code: this.orderCode,
openId: app.getOpenID(),
miniapp_type: app.getMiniappType(),
formId: e.detail.formId
});
},
cancelOrder() {
orderHandle.cancelOrder(this.orderCode, res => {
if (res && res.code === 200) {
wx.navigateBack({delta: 1});
}
});
},
payNow() {
orderHandle.payNow({
order_code: this.orderCode,
order_amount: this.data.paymentAmount
});
},
deleteOrder() {
orderHandle.deleteOrder(this.orderCode, res => {
if (res && res.code === 200) {
wx.navigateBack({delta: 1});
}
});
},
viewExpress() {
orderHandle.expressDetail(this.orderCode);
},
confirmOrder() {
orderHandle.confirmReceive(this.orderCode, res => {
if (res && res.code === 200) {
wx.navigateBack({delta: 1});
}
});
},
refundOrder() {
let that = this;
wx.showModal({
content: '申请退款后,本单享有的优惠可能会一并取消,确定申请吗?',
cancelText: '取消',
confirmText: '确定',
confirmColor: '#FF0000',
success(res) {
if (res.confirm) {
that.loadRefundReason();
that.setData({showReason: true});
}
}
});
},
hidePicker(e) {
if (e.target.id === 'reason-picker') {
this.setData({showReason: false});
}
},
reasonChange(e) {
this.reasonIndex = e.detail.value[0];
},
reasonSure() {
orderHandle.refundNow(this.orderCode, this.data.reason[this.reasonIndex || 0], res => {
if (res && res.code === 200) {
wx.navigateBack({delta: 1});
}
});
this.setData({showReason: false});
}
});
{
"navigationBarTitleText": "订单详情",
"usingComponents": {
"address-card": "/components/address/card/card",
"order-item": "/components/product/order-item/order-item"
}
}
<import src="./template/reason/reason.wxml"/>
<view wx:if="{{pageLoaded}}" class="container">
<view wx:if="{{attribute == 3}}" class="reciever-moble">
手机号码:<text class="right">{{mobile}}</text>
</view>
<view wx:else class="address-wrap">
<address-card address="{{receiveAddress}}"></address-card>
</view>
<view class="order-info">
<view>订单编号:{{orderCode}}</view>
<view class="gray">订单状态:{{orderStatus}}</view>
<view class="gray">下单时间:<b class="createTime">{{createTime}}</b></view>
</view>
<view class="goods-list">
<order-item wx:for="{{goodsList}}" wx:key="unique" item="{{item}}" index="{{index}}"></order-item>
</view>
<view class="payment-wrap">
<view wx:for="{{promotionList}}" wx:key="unique" class="payment-cell">
<text class="name">{{item.promotion}}</text>
<text class="price">{{item.promotion_amount}}</text>
</view>
<view class="payment-cell">
<text class="name">实付金额</text>
<text class="price red">¥{{paymentAmount}}</text>
</view>
</view>
<view class="bottom-options">
<view wx:if="{{payLeftTime}}" class="time-left">
<text class="iconfont icon-time-fill"></text>
<text>剩余 {{payLeftTime}}</text>
</view>
<view class="right-block">
<view wx:if="{{attribute == 9}}" class="only-app-tips">*此订单只能在APP端操作</view>
<form bindsubmit="submitFormId" report-submit='true'>
<block wx:for="{{links}}" wx:for-item="link" wx:key="unique">
<button wx:if="{{link === 'closeOrder'}}" formType="submit" class="option-btn" catchtap="cancelOrder">取消订单</button>
<view wx:if="{{link === 'buyNow'}}" class="option-btn red-btn" catchtap="payNow">立即付款</view>
<view wx:if="{{link === 'delOrder'}}" class="option-btn" catchtap="deleteOrder">删除订单</view>
<view wx:if="{{link === 'getExpress'}}" class="option-btn" catchtap="viewExpress">查看物流</view>
<button wx:if="{{link === 'confirm'}}" formType="submit" class="option-btn red-btn" catchtap="confirmOrder">确认收货</button>
<button wx:if="{{link === 'refundApply'}}" formType="submit" class="option-btn" catchtap="refundOrder">申请退款</button>
</block>
</form>
</view>
</view>
<template is="reason" data="{{reason, showReason}}"></template>
</view>
@import "./template/reason/reason.wxss";
page {
background-color: #f0f0f0;
}
.red {
color: #d0021b;
}
.gray {
color: #b0b0b0;
}
.container {
padding-top: 1rpx;
padding-bottom: 100rpx;
}
button:after{
border: none;
}
.reciever-moble {
background-color: #fff;
padding: 0 30rpx;
line-height: 80rpx;
font-size: 28rpx;
margin-bottom: 20rpx;
}
.address-wrap {
border-top: 1rpx solid #e0e0e0;
margin-bottom: 20rpx;
}
.order-info,
.payment-wrap {
background-color: #fff;
padding: 10rpx 30rpx;
line-height: 54rpx;
font-size: 24rpx;
margin-bottom: 20rpx;
}
.goods-list {
background-color: #fff;
padding-left: 30rpx;
margin-bottom: 20rpx;
}
.payment-wrap .price {
float: right;
}
.bottom-options {
height: 100rpx;
padding-top: 20rpx;
padding-right: 30rpx;
background-color: #fff;
box-sizing: border-box;
position: fixed;
left: 0;
right: 0;
bottom: 0;
}
.bottom-options .time-left {
width: 100%;
height: 60rpx;
line-height: 60rpx;
font-size: 24rpx;
background-color: #fff;
text-align: center;
border-bottom: 1rpx solid #e0e0e0;
position: absolute;
top: -60rpx;
}
.bottom-options .time-left .iconfont {
color: #444;
font-size: 26rpx;
margin-right: 6rpx;
}
.bottom-options .right-block {
float: right;
}
.bottom-options .only-app-tips {
line-height: 60rpx;
font-size: 28rpx;
color: #444;
}
.bottom-options .option-btn {
width: 140rpx;
height: 60rpx;
line-height: 58rpx;
font-size: 28rpx;
color: #444;
background-color: #fff;
margin-left: 30rpx;
border: 1rpx solid #444;
border-radius: 4rpx;
text-align: center;
box-sizing: border-box;
display: inline-block;
vertical-align: top;
padding: 0;
}
.bottom-options .red-btn {
background-color: #d0021b;
border-color: #d0021b;
color: #fff;
}
import wx from '../../../../utils/wx';
import Yas from '../../../../common/yas';
import orderModel from '../../../../models/home/order';
let app = getApp();
const windowHeights = app.globalData.systemInfo.windowHeight;
const windowWidth = app.globalData.systemInfo.windowWidth;
const pixelRatio = app.globalData.systemInfo.pixelRatio;
let sc = windowWidth * pixelRatio / 750;
let listH = parseInt((windowHeights * pixelRatio) / sc - 221) - 5;
let yas;
Page({
data: {
dot1: './images/1@2x.png',
dot2: './images/2@2x.png',
listH,
logo: '',
hasOrder: false,
orderID: '',
logisticsCompany: '',
order_code: '',
list: null
},
onLoad: function(options) {
let order_code = options.order_code;
this.setData({
order_code
});
this.expressDetail();
yas = new Yas(app);
yas.pageOpenReport();
},
copyExpressNo: function() {
wx.setClipboardData({data: this.data.orderID})
.then(() => {
wx.showModal({
content: '已复制到剪贴板!',
showCancel: false,
confirmText: '确定',
});
});
},
expressDetail: function() {
let params = {
method: 'app.express.li',
uid: app.getUid(),
fromPage: 'iFP_Logistics',
order_code: this.data.order_code,
physical_channel: 1
};
orderModel.expressDetail(params)
.then(data => {
if (data && data.code === 200) {
let list = data.data.express_detail;
let hasOrder = true;
let logo = data.data.logo;
let logisticsCompany = data.data.caption;
let orderID = data.data.express_number;
this.setData({
logisticsCompany,
orderID,
logo,
list,
hasOrder
});
} else {
wx.showModal({
content: data.message,
showCancel: false,
confirmText: '确定'
});
}
});
}
});
<block wx:if="{{hasOrder}}">
<view class='header'>
<view class='rigthView'>
<image class='image' src='{{logo}}'></image>
</view>
<view class='leftView'>
<text class="text">物流公司: {{orderID}}</text>
<view class='textTelView'>
<text class="text">快递单号: {{logisticsCompany}}</text>
<view class='textTelButton'>
<text class="buttontext" bindtap="copyExpressNo">复制</text>
</view>
</view>
</view>
</view>
<view class="space">
</view>
<view class="detailTitleView">
<text class="detailTitle">物流详情</text>
</view>
<view class="line">
</view>
<view style="width: 100%;height: {{listH}}rpx;">
<scroll-view scroll-y style="height: 100%;">
<block wx:for="{{list}}" wx:key="unique">
<view class="cell">
<block wx:if="{{index == 0}}">
<view class="cellLeft">
<view class="HLine">
<image class="dot" src="../../../../static/images/exp-dot1@2x.png"></image>
</view>
</view>
<view class="cellRight" style='color: black'>
<text class="text1">{{item.accept_address}}</text>
<text class="text2">{{item.acceptTime}}</text>
</view>
</block>
<block wx:else>
<view class="cellLeft">
<view class="HLine">
<image class="dot" src="../../../../static/images/exp-dot1@2x.png"></image>
</view>
</view>
<view class="cellRight" style='color: #e0e0e0'>
<text class="text1">{{item.accept_address}}</text>
<text class="text2">{{item.acceptTime}}</text>
</view>
</block>
</view>
<view class="cellLine">
</view>
</block>
</scroll-view>
</view>
</block>
.header {
background-color: white;
height: 100rpx;
display: flex;
flex-direction: row;
}
.header .rigthView{
background-color: white;
height: 100rpx;
width: 18%;
}
.header .rigthView .image{
background-color: gray;
height: 80rpx;
width: 80rpx;
margin-left: 30rpx;
margin-top: 10rpx;
}
.header .leftView{
background-color: white;
height: 80rpx;
width: 82%;
margin-top: 10rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.header .leftView .text{
background-color: white;
height: 40rpx;
font-size: 28rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.header .leftView .textTelView{
background-color: white;
height: 40rpx;
display: flex;
flex-direction: row;
}
.header .leftView .textTelView .textTel{
background-color: white;
height: 40rpx;
font-size: 28rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.header .leftView .textTelView .textTelButton{
width: 61rpx;
height: 28rpx;
justify-content: center;
display: flex;
border: 1rpx solid #000;
border-radius: 6rpx;
margin-left: 30rpx;
margin-top: 2px;
line-height: 28rpx;
}
.header .leftView .textTelView .textTelButton .buttontext{
font-size: 21rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.space {
width: 100%;
height: 20rpx;
background-color: #f0f0f0;
border-bottom-style:solid;
border-bottom-width: 1rpx;
border-bottom-color: #e0e0e0;
border-top-style:solid;
border-top-width: 1rpx;
border-top-color: #e0e0e0;
}
.detailTitleView {
width: 100%;
height: 100rpx;
background-color: white;
display: flex;
align-items: center;
}
.detailTitleView .detailTitle{
font-size: 34rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
margin-left: 27rpx;
}
.line {
width: 100%;
height: 1rpx;
background-color: #f0f0f0;
}
.cell {
background-color: white;
height: 100rpx;
display: flex;
flex-direction: row;
}
.cellLine {
width: 84%;
height: 1rpx;
background-color: #f0f0f0;
margin-left: 16%;
}
.cell .cellLeft{
background-color: white;
height: 100rpx;
width: 16%;
}
.cell .cellLeft .HLine{
background-color: #f0f0f0;
height: 100rpx;
width: 2rpx;
margin-left: 63rpx;
}
.cell .cellLeft .dot{
height: 17rpx;
width: 16rpx;
margin-left: -6rpx;
margin-top: 25rpx;
}
.cell .cellRight{
background-color: white;
height: 100rpx;
width: 84%;
display: flex;
flex-direction: column;
justify-content: center;
}
.cell .cellRight .text1{
background-color: white;
height: 40rpx;
width: 84%;
font-size: 28rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.cell .cellRight .text2{
background-color: white;
height: 40rpx;
width: 84%;
font-size: 24rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
\ No newline at end of file
import wx from '../../../utils/wx';
import orderModel from '../../../models/home/order';
import { wechatPay } from '../../../utils/wechat-pay';
const REASON_CACHE_KEY = 'refund_reason_cache';
let app = getApp();
let router = global.router;
export default {
deleteOrder(orderCode, callback) {
if (!orderCode) {
return;
}
wx.showModal({
title: '确认删除该订单吗?',
content: '删除了的订单不可恢复!',
cancelText: '取消',
confirmText: '确定',
confirmColor: '#FF0000'
}).then(res => {
if (res.confirm) {
orderModel.delOrder({order_code: orderCode}).then(json => {
callback && callback(json);
});
}
});
},
confirmReceive(orderCode, callback) {
if (!orderCode) {
return;
}
wx.showModal({
title: '确认收货',
content: '请您收到货后再点击“确认”!',
cancelText: '取消',
confirmText: '确定',
confirmColor: '#FF0000'
}).then(res => {
if (res.confirm) {
orderModel.confirmReceive({order_code: orderCode, miniapp_type: app.getMiniappType()}).then(json => {
callback && callback(json);
});
}
});
},
cancelOrder(orderCode, callback) {
if (!orderCode) {
return;
}
wx.showModal({
title: '取消订单',
content: '确认取消该订单吗?',
cancelText: '返回',
confirmText: '取消订单',
confirmColor: '#000000'
}).then(res => {
if (res.confirm) {
orderModel.cancelOrder({order_code: orderCode}).then((json) => {
if (json.code !== 200) {
wx.showModal({title: json.message, showCancel: false});
}
callback && callback(json);
});
}
});
},
expressDetail(orderCode) {
if (!orderCode) {
return;
}
router.go('orderExpress', {order_code: orderCode});
},
payNow(data, callback) {
if (!data.order_code) {
return;
}
wechatPay(data, callback);
},
refundNow(orderCode, reason, callback) {
orderModel.refundOrder({
order_code: orderCode,
reason_id: reason.reason_id,
reason: reason.reason,
fromPage: 'aFP_MineOrderContent'
}).then(json => {
callback && callback(json);
});
},
getRefundReason(callback) {
let reason;
try {
reason = wx.getStorageSync(REASON_CACHE_KEY);
if (reason) {
reason = JSON.parse(reason);
}
} catch (e) {
console.log(JSON.stringify(e));
}
if (reason) {
return callback && callback(reason);
}
orderModel.getRefundSeason().then(res => {
if (res.code === 200) {
wx.setStorage({
key: REASON_CACHE_KEY,
data: JSON.stringify(res.data)
});
return callback && callback(res.data);
}
});
},
};
import wx from '../../../utils/wx';
import Yas from '../../../common/yas';
import orderHandle from './order-handle';
import commonModel from '../../../models/common';
import orderModel from '../../../models/home/order';
import formatImage from '../../../utils/formatImage';
// 获取应用实例
let app = getApp();
let yas;
let {windowHeight} = app.getSystemInfo();
let timer;
Page({
data: {
windowHeight,
orderType: 1,
ordersList: [],
reason: [],
orderCode: ''
},
onLoad: function(options) {
let type = options.type || 1;
this.setData({
orderType: type
});
if (!app.getUid()) {
wx.switchTab({
url: '/pages/home/home',
});
}
yas = new Yas(app);
yas.pageOpenReport();
},
onShow: function() {
this.getOrders(this.data.orderType);
},
startTimer: function() {
let that = this;
timer = setInterval(function() {
let orders = that.data.ordersList;
for (let i = 0; i < orders.length; i++) {
let item = orders[i];
let pay_lefttime = parseInt(item.pay_lefttime);
if (item.counter_flag === 'Y' && item.is_cancel !== 'Y' && pay_lefttime > 0) {
item.pay_lefttime = pay_lefttime - 1;
item.time_left = that.formatDate(pay_lefttime - 1);
if (item.pay_lefttime === 0) {
that.getOrders(this.data.orderType);
}
} else {
item.pay_lefttime = 0;
}
}
that.setData({
ordersList: orders,
});
}, 1000);
},
stopTimer: function() {
clearInterval(timer);
},
add0: function(m) {
return m < 10 ? '0' + m : m;
},
formatDate: function(second) {
var dateStr = '';
var hr = Math.floor(second / 3600);
var min = Math.floor((second - hr * 3600) / 60);
var sec = (second - hr * 3600 - min * 60);
dateStr = this.add0(hr) + ':' + this.add0(min) + ':' + this.add0(sec);
return dateStr;
},
formatImgUrl: function(res) {
res.data.order_list && res.data.order_list.map((item) => {
item.order_goods && item.order_goods.map(good => {
good.goods_image = formatImage.image(good.goods_image, 100, 134);
});
});
},
formatOrders: function(orders) {
let _orders = [];
let needTimer = false;
orders && orders.map((item)=>{
item.pay_lefttime = parseInt(item.pay_lefttime);
item.time_left = this.formatDate(parseInt(item.pay_lefttime));
if (item.counter_flag === 'Y' && item.is_cancel !== 'Y' && parseInt(item.pay_lefttime) > 0) {
needTimer = true;
}
for (let i = 0; i < item.order_goods.length; i++) {
if (Number(item.order_goods[i].real_pay_price).toFixed(2) === Number(item.order_goods[i].sales_price).toFixed(2) || !item.order_goods[i].real_pay_price) { // eslint-disable-line
item.order_goods[i].real_pay_price = item.order_goods[i].goods_price ? item.order_goods[i].goods_price : item.order_goods[i].sales_price; // eslint-disable-line
item.order_goods[i].sales_price = '';
}
if (item.order_goods[i].sales_price) {
item.order_goods[i].sales_price = Number(item.order_goods[i].sales_price).toFixed(2);
}
}
_orders.push(item);
});
if (needTimer) {
this.stopTimer();
this.startTimer();
} else {
this.stopTimer();
}
return _orders;
},
getOrders: function(type) {
let params = {
type,
uid: app.getUid(),
page: 1,
limit: 50
};
wx.showLoading({title: '加载中'});
orderModel.getOrders(params)
.then(res => {
if (res.code === 200) {
this.formatImgUrl(res);
let orders = res.data.order_list;
orders = this.formatOrders(orders);
this.setData({
ordersList: orders,
showEmptyContainer: res.data.order_list.length === 0
});
wx.hideLoading();
}
}).catch(() => {
wx.hideLoading();
});
},
loadRefundReason() {
if (this.hasSetReason) {
return;
}
orderHandle.getRefundReason(res => {
this.setData({reason: res});
this.hasSetReason = true;
});
},
navToOrderDetail(e) {
let code = e.currentTarget.dataset.order_code;
global.router.go('orderDetail', {orderCode: code});
},
delOrder: function(e) {
const code = e.target.dataset.code;
orderHandle.deleteOrder(code, res => {
if (res && res.code === 200) {
this.getOrders(this.data.orderType);
}
});
},
confirmReceive: function(e) {
let code = e.currentTarget.dataset.code;
orderHandle.confirmReceive(code, res => {
if (res && res.code === 200) {
this.getOrders(this.data.orderType);
}
});
},
cancelOrder: function(e) {
let code = e.currentTarget.dataset.code;
orderHandle.cancelOrder(code, res => {
if (res && res.code === 200) {
this.getOrders(this.data.orderType);
}
});
},
expressDetail: function(e) {
let code = e.currentTarget.dataset.code;
orderHandle.expressDetail(code);
},
payNow: function(e) {
let code = e.currentTarget.dataset.code;
let amount = e.currentTarget.dataset.amount;
orderHandle.payNow({ order_code: code, order_amount: amount});
},
goShopping: function() {
wx.switchTab({url: '/pages/index/index'});
},
changeType: function(e) {
const { type } = e.currentTarget.dataset;
this.setData({
orderType: type
});
this.getOrders(type);
},
refundOrder(e) {
this.refundOrderCode = e.currentTarget.dataset.code;
wx.showModal({
content: '申请退款后,本单享有的优惠可能会一并取消,确定申请吗?',
cancelText: '取消',
confirmText: '确定',
confirmColor: '#FF0000'
}).then(res => {
if (res.confirm) {
this.loadRefundReason();
this.setData({showReason: true});
}
});
},
hidePicker(e) {
if (e.target.id === 'reason-picker') {
this.setData({showReason: false});
}
},
reasonChange(e) {
this.reasonIndex = e.detail.value[0];
},
reasonSure() {
orderHandle.refundNow(this.refundOrderCode,
this.data.reason[this.reasonIndex || 0], res => {
if (res && res.code === 200) {
this.getOrders(this.data.orderType);
}
});
this.setData({showReason: false});
},
submitFormId: function(e) {
// 上报formID
commonModel.addWechatFormId({
order_code: e.detail.value.orderCode,
openId: app.getOpenID(),
miniapp_type: app.getMiniappType(),
formId: e.detail.formId
});
}
});
{
"navigationBarTitleText": "我的订单",
"usingComponents": {
"copyright": "/components/layout/copyright/copyright",
"product-list": "/components/product/list",
"product-list-filter": "/components/product/list-filter"
}
}
\ No newline at end of file
<import src="./template/item/item.wxml"/>
<import src="./template/reason/reason.wxml"/>
<scroll-view class="page-container">
<view class="order-types">
<view class="type {{orderType == 1 ? 'active' : ''}}" data-type="1" bindtap="changeType">
<view class="type-text" >全部</view>
</view>
<view class="type {{orderType == 2 ? 'active' : ''}}" data-type="2" bindtap="changeType">
<view class="type-text" >待付款</view>
</view>
<view class="type {{orderType == 3 ? 'active' : ''}}" data-type="3" bindtap="changeType">
<view class="type-text" >待发货</view>
</view>
<view class="type {{orderType == 4 ? 'active' : ''}}" data-type="4" bindtap="changeType">
<view class="type-text" >待收货</view>
</view>
</view>
<view class="list-container" style="min-height:{{windowHeight}}px;">
<view class="firstscreen-orders">
<block wx:for="{{ordersList}}" wx:key="order_code">
<template is="orderItem" data="{{item}}"></template>
</block>
<view wx:if="{{showEmptyContainer}}" class="zero-order">
<image src="../../../static/images/empty@2x.png" style="width:220rpx;height:220rpx"></image>
<br />
<view style="font-size:30rpx;text-align:center;margin-top:20rpx">您还没有任何订单,赶快去逛逛吧</view>
<button bindtap="goShopping" class="shopping-btn">去逛逛</button>
</view>
</view>
<copyright class="copyright"></copyright>
</view>
</scroll-view>
<template is="reason" data="{{reason, showReason}}"></template>
@import "./template/item/item.wxss";
@import "./template/reason/reason.wxss";
button:after{
border: none;
}
.page-container {
background-color: #f2f2f2;
box-sizing: border-box;
}
.list-container {
padding-top: 100rpx;
box-sizing: border-box;
position: relative;
padding-bottom: 180rpx;
}
.list-container .copyright {
position: absolute;
bottom: 0;
right: 0;
left: 0;
}
.list-container .zero-order {
padding-top: 100rpx;
}
.order-types {
display: flex;
position: fixed;
top: 0;
width: 100%;
z-index: 1001;
background: #fff;
border-bottom: 1rpx solid #e0e0e0;
border-top: 1rpx solid #e0e0e0;
}
.order-types > .type {
flex: 1;
height: 81rpx;
line-height: 81rpx;
color: #b0b0b0;
font-size: 23.4rpx;
text-align: center;
}
.order-types .type-text {
display: block;
height: 100%;
width: 100%;
color: #b0b0b0;
font-size: 28rpx;
font-family: PingFang-SC-Regular;
letter-spacing: -0.39rpx;
}
.order-types > view.active .type-text {
color: #222;
}
.order-page .order:last-child {
margin-bottom: 0;
}
.order-page .order {
position: relative;
display: block;
background: #fff;
margin-bottom: 20rpx;
border-top: 1rpx solid #e0e0e0;
border-bottom: 1rpx solid #e0e0e0;
}
.order-page .order .header {
border-bottom: 1rpx solid #e0e0e0;
}
.order-page .order .footer, .order-page .order .header {
height: 91rpx;
line-height: 81rpx;
font-size: 27rpx;
padding: 0 27rpx;
color: #444444;
}
.order-page .order .order-status {
float: right;
}
.order-page .order-tip {
font-size: 25.2rpx;
margin-left: 15rpx;
color: red;
margin-top: 10rpx;
}
.order-good:last-child {
border-bottom: none;
margin-bottom: 0rpx;
}
image {
display: block;
margin: 0 auto;
max-width: 100%;
border: 0;
}
a {
outline: none;
color: #444444;
text-decoration: none;
}
.shopping-btn {
width: 65%;
height: 90rpx;
font-size: 30rpx;
line-height: 90rpx;
text-align: center;
margin-top: 150rpx;
background-color: #444444;
color: white;
}
.addr-item {
text-align: center;
}
.mask{
position:fixed;
top:0;
left:0;
background-color: #333;
filter: alpha(opacity=30);
opacity: 0.3;
width:100%;
height:100%;
z-index:1009
}
.picker-view{
z-index:1100;
background-color:white;
position:fixed;
bottom:0;
left:0;
width: 100%;
height: 400rpx;
}
.chooseBtn{
position: fixed;
background-color: white;
width: 80rpx;
height: 40rpx;
color: #444444;
font-size: 28rpx;
bottom: 340rpx;
right: 0;
z-index: 1101;
}
<template name="orderItem">
<view class="order" data-order_code="{{item.order_code}}" bindtap="navToOrderDetail">
<view class="header">
订单编号:{{item.order_code}}
<view class="order-status">{{item.status_str}}</view>
</view>
<view class="order-goods">
<block wx:for="{{item.order_goods}}" wx:for-item="good" wx:key="product_id">
<view class="order-good" data-id="">
<view class="thumb-wrap">
<image class="thumb" src="{{good.goods_image}}"></image>
<view class="goods-type price-gift-tag" wx:if="{{good.goods_type === 'price_gift'}}">
<text>加价购</text>
</view>
<view class="goods-type gift-tag" wx:if="{{good.goods_type === 'gift'}}">
<text>赠品</text>
</view>
<view class="goods-type virtual-tag" wx:if="{{good.goods_type === 'ticket'}}">
<text>虚拟商品</text>
</view>
<view class="goods-type advance-tag" wx:if="{{good.goods_type === 'advance'}}">
<text>预售</text>
</view>
</view>
<view class="deps">
<view class="name row">{{good.product_name}}</view>
<view class="row">
<view class="color">
颜色:{{good.color_name}}
</view>
<view class="size">
尺码:{{good.size_name}}
</view>
</view>
<view class="row price-wrap">
<view class="price">
¥{{good.real_pay_price}}
</view>
<view wx:if="{{good.sales_price}}" style='text-decoration:line-through;color: #B0B0B0'>
¥{{good.sales_price}}
</view>
<view class="count">
× {{good.buy_number}}
</view>
</view>
</view>
</view>
</block>
</view>
<view class="footer">
共{{item.buy_total}}件商品 实付
<view class="sum-cost">¥{{item.amount}}</view>
(含运费¥{{item.shipping_cost}})
</view>
<view wx:if="{{item.attribute == 9}}" class="order-opt" style='font-size:28rpx;color:#444444'>*此订单只能在APP端操作</view>
<view wx:elif="{{item.links.length > 0}}" class="order-opt">
<block wx:if="{{item.counter_flag == 'Y' && item.is_cancel != 'Y' && item.pay_lefttime > 0}}">
<view class="counterView">
<text class="iconfont icon-time-fill"></text>
<text class="counter">剩余 {{item.time_left}}</text>
</view>
</block>
<form bindsubmit="submitFormId" report-submit='true'>
<block wx:for="{{item.links}}" wx:for-item="link" wx:key="order_code">
<block wx:if="{{link == 'closeOrder'}}">
<button class="btn cancel" formType="submit" catchtap="cancelOrder"
plain="true" data-code="{{item.order_code}}">取消订单</button>
</block>
<block wx:if="{{link == 'buyNow'}}">
<view class="btn pay" catchtap="payNow" data-code="{{item.order_code}}"
data-amount="{{item.amount}}">立即付款</view>
</block>
<block wx:if="{{link == 'delOrder'}}">
<view class="btn cancel" catchtap="delOrder" data-code="{{item.order_code}}">删除订单</view>
</block>
<block wx:if="{{link == 'getExpress'}}">
<view class="btn cancel" catchtap="expressDetail" data-code="{{item.order_code}}">查看物流</view>
</block>
<block wx:if="{{link == 'confirm'}}">
<button class="btn confirm" formType="submit" catchtap="confirmReceive"
data-code="{{item.order_code}}">确认收货</button>
</block>
<block wx:if="{{link == 'refundApply'}}">
<button class="btn refund" formType="submit" plain='true' catchtap="refundOrder" plain="true"
data-code="{{item.order_code}}">申请退款</button>
</block>
</block>
<input type="text" name="orderCode" class="hide-code" value="{{item.order_code}}"/>
</form>
</view>
</view>
</template>
.order:last-child {
margin-bottom: 0;
}
.order {
position: relative;
display: block;
background: #fff;
margin-bottom: 20rpx;
border-top: 1rpx solid #e0e0e0;
border-bottom: 1rpx solid #e0e0e0;
}
.order .header {
border-bottom: 1rpx solid #e0e0e0;
}
.order .footer, .order .header {
height: 91rpx;
line-height: 90rpx;
font-size: 28rpx;
padding: 0 28rpx;
color: #444444;
}
.order .order-status {
float: right;
font-family: PingFang-SC-Medium;
font-size: 28rpx;
color: #D0021B;
letter-spacing: -0.39px;
}
.order-good {
position: relative;
margin-left: 30.6rpx;
height: 174rpx;
border-bottom: 1rpx solid #e0e0e0;
font-size: 23.4rpx;
padding: 20rpx 0;
box-sizing:border-box;
}
.order-tip {
font-size: 25.2rpx;
margin-left: 15rpx;
color: red;
margin-top: 10rpx;
}
.order-good:last-child {
border-bottom: none;
margin-bottom: 0rpx;
}
.order-good .thumb-wrap {
position: relative;
float: left;
width: 100rpx;
height: 134rpx;
}
.order-good .thumb {
width: 100%;
height: 100%;
}
.order-good .thumb-wrap .goods-type {
width: 100%;
height: 30rpx;
line-height: 30rpx;
font-size: 20rpx;
background-color: #444;
color: #fff;
text-align: center;
position: absolute;
left: 0;
bottom: 0;
}
.order-good .thumb-wrap .price-gift-tag {
background-color: #fc1261;
}
.order-good .thumb-wrap .gift-tag {
background-color: #85c45c;
}
.order-good .thumb-wrap .virtual-tag {
background-color: #c80813;
}
.order-good .deps {
margin-left: 121.5rpx;
}
.order-good .name {
max-width: 70%;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-family: PingFang-SC-Regular;
font-size: 28rpx;
color: #444;
letter-spacing: -0.4rpx;
line-height: 34rpx;
margin-bottom: 10rpx;
}
.order-good .row:nth-child(2) {
height: 40.5rpx;
line-height: 40.5rpx;
width: 90%;
}
.order-good .row .color {
display: inline-block;
max-width: 200rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
vertical-align: bottom;
font-family: PingFang-SC-Regular;
font-size: 24rpx;
color: #B0B0B0;
letter-spacing: -0.34rpx;
}
.order-good .row .size {
display: inline-block;
vertical-align: bottom;
padding-left: 20rpx;
font-family: PingFang-SC-Regular;
font-size: 24rpx;
color: #B0B0B0;
letter-spacing: -0.34rpx;
}
.order-good .color, .order-good .size {
color: #b6b6b6;
}
.order-good .price-wrap {
position: absolute;
top: 20rpx;
right: 27rpx;
text-align: right;
}
.order-good .price {
color: #d0021b;
}
.order-good .count {
display: block;
text-align: right;
font-family: PingFang-SC-Regular;
font-size: 24rpx;
color: #B0B0B0;
margin-top: 10rpx;
letter-spacing: -0.34rpx;
}
.order .footer {
text-align: right;
border-top: 1rpx solid #e0e0e0;
}
.order .sum-cost {
color: #d0021b;
margin-left: 4.5rpx;
display: inline-block;
}
.order .order-opt {
position: relative;
height: 100rpx;
padding-right: 30rpx;
border-top: 1rpx solid #e0e0e0;
text-align: right;
display: flex;
flex-direction:row;
justify-content:flex-end;
padding-top: 20rpx;
box-sizing: border-box;
overflow: hidden;
}
.order .order-opt .counterView{
position: absolute;
left: 33rpx;
top: 20rpx;
height: 60rpx;
bottom: 0rpx;
display: flex;
flex-direction:row;
align-items: center;
box-sizing: border-box;
}
.order .order-opt .counterView .iconfont{
color: #444;
}
.order .order-opt .counterView .counter{
margin-left: 10rpx;
font-size: 24rpx;
text-align: center;
}
.order .order-opt .btn {
display: inline-block;
height: 60rpx;
line-height: 60rpx;
width: 140rpx;
font-size: 25rpx;
text-align: center;
border: 1rpx solid #444444;
color: #444444;
border-radius: 4rpx;
box-sizing: border-box;
vertical-align: middle;
}
.order .order-opt .hide-code {
opacity: 0;
margin-top: 100rpx;
font-size: 0;
}
.button {
height: 54rpx;
line-height: 54rpx;
width: 130rpx;
padding-left: 1rpx;
padding-right: 1rpx;
font-size: 25rpx;
text-align: center;
margin-right: 1rpx;
}
a {
outline: none;
color: #444444;
text-decoration: none;
}
.order .order-opt .pay {
background: #d0021b;
color: #fff;
border: none;
font-size: 25rpx;
margin-left: 30rpx;
line-height: 58rpx;
border: 1rpx solid #d0021b;
}
.order .order-opt .confirm {
background: #d0021b;
color: #fff;
margin-left: 30rpx;
border: none;
line-height: 58rpx;
border: 1rpx solid #d0021b;
}
.btn.cancel,
.btn.refund,
.btn.confirm {
box-sizing: content-box;
padding: 0;
margin: 0;
}
.btn.refund {
margin-left: 30rpx;
}
<template name="reason">
<view wx:if="{{showReason}}" id="reason-picker" class="reason-picker" catchtap="hidePicker">
<picker-view class="picker-view" value="{{reasonValue}}" bindchange="reasonChange" indicator-style="height: 50rpx;">
<picker-view-column>
<view wx:for="{{reason}}" wx:key="unique" class="addr-item">{{item.reason}}</view>
</picker-view-column>
</picker-view>
<view class="picker-option" bindtap="reasonSure">确定</view>
</view>
</template>
.reason-picker {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
}
.reason-picker:after {
content: '';
width: 100%;
height: 100%;
background-color: #333;
filter: alpha(opacity=30);
opacity: 0.3;
position: absolute;
top:0;
left:0;
z-index: -1;
}
.reason-picker .picker-view{
width: 100%;
height: 400rpx;
background-color: white;
position: absolute;
bottom: 0;
left: 0;
text-align: center;
z-index: 0;
}
.reason-picker .picker-option {
height: 80rpx;
line-height: 80rpx;
color: #444;
background-color: white;
padding: 0 30rpx;
font-size: 28rpx;
position: absolute;
bottom: 320rpx;
right: 0;
z-index: 1;
}