提交 5d7878b1 authored 作者: pengxiaohui's avatar pengxiaohui

调试购买下单页面接口

上级 c021d5ec
module.exports = { module.exports = {
domain: 'dev.ezijing.com', domain: 'dev.ezijing.com',
url: 'https://learn-api.ezijing.com/api', url: 'https://h5-shop2.ezijing.com/api',
// apiBaseURL: 'https://zy2.ezijing.com/',
webpack: { webpack: {
externals: { externals: {
CKEDITOR: 'window.CKEDITOR', CKEDITOR: 'window.CKEDITOR',
...@@ -10,16 +9,16 @@ module.exports = { ...@@ -10,16 +9,16 @@ module.exports = {
regeneratorRuntime: 'window.regeneratorRuntime', regeneratorRuntime: 'window.regeneratorRuntime',
wx: 'window.wx', wx: 'window.wx',
WeixinJSBridge: 'window.WeixinJSBridge' WeixinJSBridge: 'window.WeixinJSBridge'
},
devServer: {
proxy: {
'/api/shop': {
target: 'http://172.16.3.11:8089',
changeOrigin: true,
pathRewrite: { '^/api/shop': '' }
}
}
} }
// devServer: {
// proxy: {
// '/api/shop': {
// target: 'http://172.16.3.11:8089',
// changeOrigin: true,
// pathRewrite: { '^/api/shop': '' }
// }
// }
// }
}, },
ProvidePlugin: {}, ProvidePlugin: {},
others: { others: {
......
...@@ -16,4 +16,13 @@ export function sendCode(data) { ...@@ -16,4 +16,13 @@ export function sendCode(data) {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data data
}) })
}
// 通过手机号验证码注册并登陆
export function phoneCodeLogin(data) {
return httpRequest({
url: '/api/usercenter/user/register-and-login-by-mobile',
method: 'post',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data
})
} }
\ No newline at end of file
...@@ -17,4 +17,10 @@ export function getGoodsList(data) { ...@@ -17,4 +17,10 @@ export function getGoodsList(data) {
*/ */
export function getGoodsSpecs(data) { export function getGoodsSpecs(data) {
return httpRequest.post('/api/shop/commodity/spu/spec/value/search', data) return httpRequest.post('/api/shop/commodity/spu/spec/value/search', data)
}
/**
* 创建订单
*/
export function createOrder(data) {
return httpRequest.post('/api/shop/order/add', data)
} }
\ No newline at end of file
<template> <template>
<van-popup v-model="popupVisiable" position="bottom" class="buy-popup" :style="{ height: '60%' }" > <van-popup v-model="popupVisiable" position="bottom" class="buy-popup" :style="{ height: '60%' }" >
<h5>手机号登录</h5> <h5>手机号登录</h5>
<van-form :show-error="false" @failed="handFailed" @submit="handleSuccess"> <van-form :show-error="false" @submit="handleSuccess">
<van-field v-model="form.phone" name="phone" label="手机号" placeholder="请输入您的手机号" :rules="[{ required: true, message: '请输入您的手机号' }, { pattern: /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/, message: '手机号格式有误' }]" clearable/> <van-field v-model="form.mobile" name="mobile" label="手机号" placeholder="请输入您的手机号" :rules="[{ required: true, message: '请输入您的手机号' }, { pattern: /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/, message: '手机号格式有误' }]" clearable/>
<van-field v-model="form.code" name="code" label="验证码" placeholder="请输入手机验证码" :rules="[{ required: true, message: '请输入手机验证码' }]" clearable> <van-field v-model="form.code" name="code" label="验证码" placeholder="请输入手机验证码" :rules="[{ required: true, message: '请输入手机验证码' }]" clearable>
<template #button> <template #button>
<van-button class="code-btn" native-type="button" size="small" type="primary" color="#F8F8F8" :disabled="btnDisabled" id="checkedCode" @click="sendCode">获取验证码</van-button> <van-button class="code-btn" native-type="button" size="small" type="primary" color="#F8F8F8" :disabled="btnDisabled" id="checkedCode" @click="sendCode">获取验证码</van-button>
</template> </template>
</van-field> </van-field>
<div style="margin: 16px;"> <div style="margin: 16px;">
<van-button type="primary" round block color="#C01540" size="small">登录</van-button> <van-button type="primary" round block color="#C01540" size="small" :disabled="payBtnDisabled">登录</van-button>
</div> </div>
</van-form> </van-form>
</van-popup> </van-popup>
</template> </template>
<script> <script>
import { Toast } from 'vant' import { Toast } from 'vant'
import { phoneCodeLogin, sendCode } from '@/api/account'
import store from '@/store'
const MOBILE_REG = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/ const MOBILE_REG = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
export default { export default {
props: { props: {
...@@ -29,9 +31,10 @@ export default { ...@@ -29,9 +31,10 @@ export default {
popupVisiable: this.value, popupVisiable: this.value,
btnDisabled: false, btnDisabled: false,
form: { form: {
phone: '', mobile: '',
code: '' code: ''
} },
payBtnDisabled: false
} }
}, },
watch: { watch: {
...@@ -47,16 +50,13 @@ export default { ...@@ -47,16 +50,13 @@ export default {
} }
}, },
methods: { methods: {
handFailed(val) {
console.log(val)
},
handleSuccess(val) { handleSuccess(val) {
console.log(val) this.fetchPhoneCodeLogin()
}, },
sendCode() { sendCode() {
if (!this.form.phone) { if (!this.form.mobile) {
Toast('请填写手机号') Toast('请填写手机号')
} else if (!MOBILE_REG.test(this.form.phone)) { } else if (!MOBILE_REG.test(this.form.mobile)) {
Toast('手机号格式错误') Toast('手机号格式错误')
} else { } else {
this.fetchSendCode() this.fetchSendCode()
...@@ -80,7 +80,32 @@ export default { ...@@ -80,7 +80,32 @@ export default {
} }
}, 1000) }, 1000)
}, },
fetchSendCode() {} fetchSendCode() {
const params = {
account: this.form.mobile,
service: 'ezijing.com'
}
sendCode(params).then(res => {
if (res && res.code === 0) {
Toast.success('验证码发送成功')
} else {
Toast.error(res.msg || '发送验证码失败')
}
})
},
fetchPhoneCodeLogin() {
this.payBtnDisabled = true
phoneCodeLogin(this.form).then(async res => {
if (res.code === 0) {
await store.dispatch('checkLogin')
Toast.success('登录成功')
this.$emit('input', false)
this.$emit('loginSuccess')
} else {
Toast.error(res.msg || '登录失败')
}
})
}
} }
} }
</script> </script>
......
import store from '@/store'
export default class Before {
constructor(opt) {
this.opt = opt || {}
}
async update(to, from, next) {
// 设置游客用户信息
const { user_id: userId, student_id: studentId } = to.query
if (userId && studentId) {
store.commit('setGuestUser', { user_id: userId, student_id: studentId })
}
// 创建游客用户
// await store.dispatch('createGuestUser')
const isLogin = store.state.isLogin || (await store.dispatch('checkLogin'))
isLogin && wx.miniProgram.postMessage({ data: { token: store.state.token } })
if (to.meta.requiredLogin && !isLogin) {
store.state.isWeapp
? wx.miniProgram.redirectTo({ url: '/pages/login/index' })
: next(`/login?redirect_uri=${encodeURIComponent(window.location.href)}`)
return
}
next()
}
}
...@@ -8,7 +8,7 @@ import './style.scss' // 公共样式 ...@@ -8,7 +8,7 @@ import './style.scss' // 公共样式
import './assets/rem/rem.js' import './assets/rem/rem.js'
import MetaInfo from 'vue-meta-info' import MetaInfo from 'vue-meta-info'
import createBefore from './components/beforeEnter' import createBefore from './utils/beforeEnter'
// vant // vant
import Vant from 'vant' import Vant from 'vant'
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
<van-popup v-model="popupVisiable" position="bottom" class="buy-popup" :style="{ height: '60%' }" > <van-popup v-model="popupVisiable" position="bottom" class="buy-popup" :style="{ height: '60%' }" >
<div class="goods-card van-hairline--bottom"> <div class="goods-card van-hairline--bottom">
<div class="thumb"> <div class="thumb">
<img :src="goodsBuyInfo.thumb"> <img :src="thumb">
</div> </div>
<div class="content"> <div class="content">
<div class="price"><span>{{goodsBuyInfo.price}}</span></div> <div class="price"><span>{{price}}</span></div>
<p class="surplus">剩余 {{goodsBuyInfo.surplus}}</p> <p class="surplus">剩余 {{surplus}}</p>
</div> </div>
</div> </div>
<van-field label="规格" class="tag-item"> <van-field label="规格" class="tag-item">
...@@ -53,9 +53,11 @@ export default { ...@@ -53,9 +53,11 @@ export default {
goodsBuyInfo: { goodsBuyInfo: {
thumb: 'https://webapp-pub.oss-cn-beijing.aliyuncs.com/shop-h5/goods_01.png', thumb: 'https://webapp-pub.oss-cn-beijing.aliyuncs.com/shop-h5/goods_01.png',
price: '350.00', price: '350.00',
surplus: 20, surplus: 20
count: 1
}, },
thumb: '',
price: '',
surplus: 0,
spec: '', spec: '',
specList: [], specList: [],
form: { form: {
...@@ -94,6 +96,7 @@ export default { ...@@ -94,6 +96,7 @@ export default {
options: { options: {
handler(nv) { handler(nv) {
// const specs = nv.specs // const specs = nv.specs
this.thumb = nv.thumb
const fields = typeof nv.fields === 'string' ? JSON.parse(nv.fields) : undefined const fields = typeof nv.fields === 'string' ? JSON.parse(nv.fields) : undefined
if (Array.isArray(fields)) { if (Array.isArray(fields)) {
this.assembleFields(fields) this.assembleFields(fields)
...@@ -112,24 +115,26 @@ export default { ...@@ -112,24 +115,26 @@ export default {
}, },
methods: { methods: {
handleTagSelected(val) { handleTagSelected(val) {
console.log(val) this.price = val.price
this.goodsBuyInfo.price = val.price this.surplus = val.stock
this.goodsBuyInfo.surplus = val.stock
}, },
handleSuccess(val) { handleSuccess(val) {
const fields = [] const fields = []
for (const key in val) { for (const key in val) {
if (val[key] && key.includes('field')) { if (val[key] && key.includes('field')) {
console.log(this.fieldsMap[key])
const obj = Object.assign({}, this.fieldsMap[key].sourceData, { value: val[key] }) const obj = Object.assign({}, this.fieldsMap[key].sourceData, { value: val[key] })
fields.push(obj) fields.push(obj)
} }
} }
console.log(fields) const params = {
// const params = { shop_id: this.shop_id,
// shop_id: this.shop_id, spu_id: this.spu_id,
// spu_id: this.spu_id sku_id: this.spec,
// } buy_count: this.form.count,
payment_method: '8',
app_button_text: JSON.stringify(fields)
}
this.$emit('placeOrder', params)
}, },
assembleFields(list) { assembleFields(list) {
const fieldsMap = {} const fieldsMap = {}
...@@ -158,7 +163,6 @@ export default { ...@@ -158,7 +163,6 @@ export default {
fieldsMap[field.key] = field fieldsMap[field.key] = field
}) })
this.fieldsMap = fieldsMap this.fieldsMap = fieldsMap
console.log(fieldsMap)
}, },
fetchGoodsSpecs() { fetchGoodsSpecs() {
const params = { const params = {
...@@ -169,8 +173,8 @@ export default { ...@@ -169,8 +173,8 @@ export default {
this.specList = res.data this.specList = res.data
const [first = {}] = res.data const [first = {}] = res.data
this.spec = first.spec_value_ids this.spec = first.spec_value_ids
this.goodsBuyInfo.price = first.price this.price = first.price
this.goodsBuyInfo.surplus = first.stock this.surplus = first.stock
}) })
} }
} }
......
<template> <template>
<div class="buy-container"> <div class="buy-container">
<van-swipe class="my-swipe" indicator-color="white"> <van-swipe class="my-swipe" indicator-color="white">
<van-swipe-item class="video" v-if="details.main_chart_oss"> <van-swipe-item class="video" v-if="details.main_chart_oss" @click="handleVideoClick">
<video :src="details.main_chart_oss" controls="controls" @click="handleVideoClick" ref="video"></video> <video :src="details.main_chart_oss" controls="controls" ref="video"></video>
<van-icon :name="videoPlay ? 'pause-circle-o':'play-circle-o'" /> <van-icon :name="videoPlay ? 'pause-circle-o':'play-circle-o'" />
</van-swipe-item> </van-swipe-item>
<van-swipe-item v-for="item in imgList" :key="item.url"> <van-swipe-item v-for="item in imgList" :key="item.url">
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
</div> </div>
</div> </div>
<div class="item shop-item"> <div class="item shop-item">
<van-cell value="进点逛逛" is-link> <van-cell value="进点逛逛" is-link @click="navShop(shopInfo.shop_id)">
<!-- 使用 title 插槽来自定义标题 --> <!-- 使用 title 插槽来自定义标题 -->
<template #title> <template #title>
<img class="shop-logo" :src="shopInfo.shop_logo"> <img class="shop-logo" :src="shopInfo.shop_logo">
...@@ -41,14 +41,16 @@ ...@@ -41,14 +41,16 @@
<div class="bottom-bar"> <div class="bottom-bar">
<van-button type="primary" round block color="#C01540" size="small" @click="popupVisiable = true">立即购买</van-button> <van-button type="primary" round block color="#C01540" size="small" @click="popupVisiable = true">立即购买</van-button>
</div> </div>
<buy-popup v-model="popupVisiable" :options="popupOptions"/> <buy-popup v-model="popupVisiable" :options="popupOptions" @placeOrder="handlePlaceOrder"/>
<phone-code-login-popup v-model="loginPopupVisiable" /> <phone-code-login-popup v-model="loginPopupVisiable" @loginSuccess="handleHasLogin"/>
</div> </div>
</template> </template>
<script> <script>
import BuyPopup from './components/BuyPopup.vue' import BuyPopup from './components/BuyPopup.vue'
import PhoneCodeLoginPopup from '@/components/PhoneCodeLoginPopup.vue' import PhoneCodeLoginPopup from '@/components/PhoneCodeLoginPopup.vue'
import { getGoodsList, getShopList } from '@/api/common.js' import { getGoodsList, getShopList, createOrder } from '@/api/common.js'
import store from '@/store'
import { mapGetters } from 'vuex'
export default { export default {
components: { BuyPopup, PhoneCodeLoginPopup }, components: { BuyPopup, PhoneCodeLoginPopup },
data() { data() {
...@@ -59,18 +61,20 @@ export default { ...@@ -59,18 +61,20 @@ export default {
details: {}, details: {},
imgList: [], imgList: [],
shopInfo: {}, shopInfo: {},
popupOptions: {} popupOptions: {},
orderInfo: {}
} }
}, },
computed: { computed: {
...mapGetters(['user']),
query() { query() {
return this.$route.query return this.$route.query
}, },
goods_id () { goods_id () {
return this.query.id || '6805043172159258624' return this.query.goods_id || '6805043172159258624'
}, },
shop_id () { shop_id () {
return this.query.s_id || '6800681447305773056' return this.query.shop_id || '6800681447305773056'
} }
}, },
beforeMount() { beforeMount() {
...@@ -87,6 +91,26 @@ export default { ...@@ -87,6 +91,26 @@ export default {
} }
this.videoPlay = !this.videoPlay this.videoPlay = !this.videoPlay
}, },
navShop(id) {
this.$router.push({ path: '/shop', query: { shop_id: id } })
},
async handlePlaceOrder(val) {
this.orderInfo = val
this.popupVisiable = false
const isLogin = store.state.isLogin || (await store.dispatch('checkLogin'))
if (isLogin) {
this.handleHasLogin()
} else {
this.loginPopupVisiable = true
}
},
handleHasLogin() {
const params = Object.assign({}, this.orderInfo)
params.customer_id = this.user.id
params.customer_phone = this.user.phone || ''
console.log(params)
this.fetchPlaceOrder(params)
},
fetchGoodsDetails() { fetchGoodsDetails() {
const params = { const params = {
shop_id: this.shop_id, shop_id: this.shop_id,
...@@ -102,7 +126,8 @@ export default { ...@@ -102,7 +126,8 @@ export default {
} }
this.popupOptions = { this.popupOptions = {
specs: first.spec, specs: first.spec,
fields: first.app_button_text fields: first.app_button_text,
thumb: this.imgList[0] ? this.imgList[0].url : ''
} }
} }
}) })
...@@ -117,6 +142,11 @@ export default { ...@@ -117,6 +142,11 @@ export default {
this.shopInfo = first this.shopInfo = first
} }
}) })
},
fetchPlaceOrder(params) {
createOrder(params).then(res => {
console.log(res)
})
} }
} }
} }
......
...@@ -38,10 +38,7 @@ export default { ...@@ -38,10 +38,7 @@ export default {
components: { AppSearchBar }, components: { AppSearchBar },
data() { data() {
return { return {
goodsList: [ goodsList: []
{ price: '350.00', num: 2, desc: '紫荆-Kelley MSF五期班开学典礼晚宴', title: '紫荆-Kelley MSF五期班开学典礼晚宴', thumb: 'https://webapp-pub.oss-cn-beijing.aliyuncs.com/shop-h5/goods_01.png', id: '111', pay_count: 222 },
{ price: '10.00', num: 2, desc: '描述信息', title: '商品标题', thumb: 'https://img01.yzcdn.cn/vant/ipad.jpeg', id: '222', pay_count: 222 }
]
} }
}, },
computed: { computed: {
...@@ -52,7 +49,7 @@ export default { ...@@ -52,7 +49,7 @@ export default {
}, },
methods: { methods: {
handleClick(val) { handleClick(val) {
this.$router.push({ path: 'buy', query: { id: val.spu_id, s_id: val.shop_id } }) this.$router.push({ path: 'buy', query: { spu_id: val.spu_id, shop_id: val.shop_id } })
}, },
imgJsonParse(val) { imgJsonParse(val) {
if (typeof val === 'string' && typeof JSON.parse(val) === 'object') { if (typeof val === 'string' && typeof JSON.parse(val) === 'object') {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<div class="search-bar"> <div class="search-bar">
<van-icon name="arrow-left" /> <van-icon name="arrow-left" />
<van-search <van-search
v-model="value" v-model="search"
shape="round" shape="round"
size="small" size="small"
background="#f7f7f7" background="#f7f7f7"
...@@ -11,20 +11,51 @@ ...@@ -11,20 +11,51 @@
/> />
</div> </div>
<van-tabs v-model="active" sticky> <van-tabs v-model="active" sticky>
<van-tab title="标签 1"></van-tab> <van-tab title="全部"></van-tab>
<van-tab title="标签 2"></van-tab> <van-tab title="待付款"></van-tab>
<van-tab title="标签 3"></van-tab> <van-tab title="待发货"></van-tab>
<van-tab title="标签 4"></van-tab> <van-tab title="已完成"></van-tab>
</van-tabs> </van-tabs>
<div class="content"></div> <ul class="order-list">
<li class="order-item" v-for="item in list" :key="item.id">
<div class="thumb">
<img :src="item.thumb">
</div>
<div class="content">
<div class="status-row">{{item.status | statusFilter}}</div>
<div class="title-row">
<div class="title van-ellipsis">{{item.spu_name}}</div>
<div class="price">{{item.price}}</div>
</div>
<div class="spec-row">
<p class="spec">{{item.spec}}</p>
</div>
<div class="sum_pay">需付款¥{{item.sum_pay}}</div>
</div>
</li>
</ul>
</div> </div>
</template> </template>
<script> <script>
const statusMap = {
0: '等待买家付款',
1: '卖家已发货',
2: '交易完成'
}
export default { export default {
data() { data() {
return { return {
search: '',
active: '', active: '',
list: [] list: [
{ price: '350.00', num: 2, desc: '紫荆-Kelley MSF五期班开学典礼晚宴', spu_name: '紫荆-Kelley MSF五期班开学典礼晚宴', thumb: 'https://webapp-pub.oss-cn-beijing.aliyuncs.com/shop-h5/goods_01.png', id: '111', pay_count: 222, status: 0, spec: '红,20', sum_pay: '700.00' },
{ price: '10.00', num: 1, desc: '描述信息', spu_name: '商品标题', thumb: 'https://img01.yzcdn.cn/vant/ipad.jpeg', id: '222', pay_count: 222, status: 1, spec: '红,L', sum_pay: '10.00' }
]
}
},
filters: {
statusFilter(val) {
return statusMap[val]
} }
} }
} }
...@@ -52,4 +83,48 @@ export default { ...@@ -52,4 +83,48 @@ export default {
} }
} }
} }
.order-item{
background:#fff;
position:relative;
box-sizing:border-box;
padding:4vw 0 4vw 30vw;
height:36vw;
margin-top:15px;
border-radius:3px;
.thumb{
width:26vw;
height:26vw;
position:absolute;
left:0;
top:5vw;
img{
width:80%;
display:block;
margin:10% auto;
}
}
.content{
display:flex;
flex-direction:column;
height:100%;
padding-right:10px;
.status-row{
line-height:0.48rem;
color:#C01540;
text-align:right;
}
.title-row{
line-height:30px;
flex:1;
display:flex;
.price{
font-size:13px;
}
.title{
font-size:14px;
flex:1;
}
}
}
}
</style> </style>
\ No newline at end of file
...@@ -6,6 +6,12 @@ export default [ ...@@ -6,6 +6,12 @@ export default [
name: 'Index', name: 'Index',
component: () => import('../pages/home/index.vue') component: () => import('../pages/home/index.vue')
}, },
/* 店铺 */
{
path: '/shop',
name: 'Shop',
component: () => import('../pages/home/index.vue')
},
/* 商品购买页 */ /* 商品购买页 */
{ {
path: '/buy', path: '/buy',
......
...@@ -35,9 +35,9 @@ httpRequest.interceptors.response.use( ...@@ -35,9 +35,9 @@ httpRequest.interceptors.response.use(
function(response) { function(response) {
const { data } = response const { data } = response
if (data.code) { if (data.code) {
if (![1010, 1001].includes(data.code)) { // if (![1010, 1001].includes(data.code)) {
Toast.fail(data.msg || data.message) // Toast.fail(data.msg || data.message)
} // }
return Promise.reject(data) return Promise.reject(data)
} }
return data return data
......
import store from '@/store'
export default class Before {
constructor(opt) {
this.opt = opt || {}
}
async update(to, from, next) {
const isLogin = store.state.isLogin || (await store.dispatch('checkLogin'))
if (!isLogin) {
// window.location.href = `${webConf.others.loginUrl}?rd=${encodeURIComponent(window.location.href)}`
next()
}
next()
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论