提交 c9d71726 authored 作者: sin's avatar sin

clone 开源的 Shopping

上级 78945c61
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
## 基于Vue实现开箱即用移动端商城的单页应用
>这是开箱即用移动端商城的框架。只需要后端返回标准接口数据,前端配置接口地址等信息,标准商城的页面不需要做任何调整。
## 特性
- 开箱即用,集成后台接口格式,前端可做二次开发以实现自有业务
- 首页是由图片广告、图文导航、商品、公告、搜索、文本、标题、辅助空白、辅助线、方格等组件根据后端接口数据动态渲染,可根据后端返回的数据渲染出N种首页效果
- 定制主题
## 手机预览
可以手机扫码以下二维码访问手机端 demo:
![](./docs/static/qrcode.png)
![](./docs/static/show1.jpg)
![](./docs/static/show2.jpg)
![](./docs/static/show3.jpg)
## 技术栈
- vue
- [vue cli 3](https://cli.vuejs.org/zh/guide/installation.html)
- [vant](https://github.com/youzan/vant)
- less
- [vue-router](https://router.vuejs.org/zh/installation.html)
- [axios](https://github.com/axios/axios)
- [babel-plugin-import](https://github.com/ant-design/babel-plugin-import)
## 快速上手
```
# 安装 Vue Cli 3
npm install -g @vue/cli
npm install
npm run dev
npm run build
```
调整src/config/env.js的配置信息
```
baseUrl: 域名地址
dataSources:数据源(local=本地)
```
## 进度
- [x] 界面样式
- [ ] 数据通过接口绑定
- [ ] 定制主题
- [ ] 代码重构优化
## 页面
```
- 首页
- 分类
- 商品
- 详情
- 列表
- 购物车
- 提交订单
- 会员
- 会员中心
- 账户管理
- 订单
- 列表
- 详情
- 追踪
- 售后
- 申请
- 列表
- 详情
- 进度详情
- 我的优惠券
- 我的收藏
- 收货地址
- 列表
- 编辑
- 手机登录
- 手机注册
```
module.exports = {
presets: ['@vue/app'],
plugins: [
[
'import',
{ libraryName: 'vant', libraryDirectory: 'es', style: true },
'vant'
]
]
};
{
"name": "shop-vue",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.18.0",
"vant": "^1.3.1",
"vue": "^2.5.17",
"vue-router": "^3.0.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.4.1",
"@vue/cli-plugin-eslint": "^3.4.1",
"@vue/cli-service": "^3.4.1",
"babel-plugin-import": "^1.8.0",
"less": "^3.8.1",
"less-loader": "^4.1.0",
"vue-lazyload": "^1.2.6",
"vue-template-compiler": "^2.5.17"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"Android >= 4.0",
"iOS >= 7"
]
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no, viewport-fit=cover">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
import './assets/style/common.css';
export default {
name: 'app'
}
</script>
import request from "../config/request";
export function GetPage() {
return request({
url: '/Page/GetPage',
method: 'get',
})
}
export function getProduct(id) {
return request({
url: '/Page/Product',
method: 'get',
params: { id }
})
}
\ No newline at end of file
import request from "../config/request";
export function GetUserIndex() {
return request({
url: '/User/GetUserIndex',
method: 'get',
})
}
export function GetFavorite(data){
return request({
url: '/User/GetFavorite',
method: 'post',
params: { data }
})
}
export function DelFavorite(id){
return request({
url: '/User/DelFavorite',
method: 'get',
params: { id:id }
})
}
export function GetAddressList(){
return request({
url: '/User/GetAddressList',
method: 'get',
})
}
export function GetAddressById(id){
return request({
url: '/User/GetAddressById',
method: 'get',
params: { id }
})
}
export function SaveAddress(data){
return request({
url: '/User/SaveAddress',
method: 'post',
params: { data }
})
}
export function DelAddress(data){
return request({
url: '/User/DelAddress',
method: 'post',
params: { data }
})
}
export function GetCoupon(data){
return request({
url: '/User/GetCoupon',
method: 'Post',
params: { data }
})
}
export function ExchangeCoupon(code){
return request({
url: '/User/ExchangeCoupon',
method: 'Post',
params: { code:code }
})
}
\ No newline at end of file
body {margin:0px; padding:0px; color:rgb(34, 34, 34); font-family:Helvetica,"Hiragino Sans GB","Microsoft YaHei",Simsun,"Droid Sans Fallback",sans-serif; text-decoration:none; background:#fff;-webkit-tap-highlight-color:rgba(0,0,0,0); }
body,div,dl,dt,dd,ol,ul,li,h1,h2,h3,h4,h5,h6,h7,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0px; padding:0px;}
ul{list-style:none;}
li{list-style:none;}
img {border:0px currentColor;vertical-align:top;}
ol {list-style:none; margin:0px; padding:0px;}
a{color:rgb(0, 0, 0); text-decoration:none;}
\ No newline at end of file
差异被折叠。
<template>
<van-cell-group class="additional">
<van-card
:title="product.title"
:desc="product.desc"
:num="(iscard?null:product.quantity)"
style="background:#fff"
>
<template slot="thumb">
<img :src="product.imageURL" />
<p v-if="product.imageTag!=null&&product.imageTag!=''" class="image_tag">{{product.imageTag}}</p>
</template>
<template slot="tags">
<p class="price" v-if="product.price!=null&&product.price!=''" >
<span>{{product.price}}</span>
<van-tag v-if="product.tags!=null" v-for="tag in product.tags" :key="tag" plain type="danger">{{tag}}</van-tag>
</p>
<van-stepper v-if="iscard" v-model="product.quantity" :max="product.max" :min="product.min" />
</template>
</van-card>
<van-cell v-for="(gift,j) in product.gift" :key="j" :value="'x'+gift.quantity" >
<template slot="title">
<van-tag type="danger" v-if="j==0" >赠品</van-tag>
<span class="van-cell-text" :style="(j>0?'margin-left: 35px;':'')" >{{gift.title}}</span>
</template>
</van-cell>
<slot />
</van-cell-group>
</template>
<script>
export default {
name:'product-card',
props:{
product:Object,
iscard: {
type: Boolean,
default: false
},
}
}
</script>
<style lang="less">
.additional {
.van-cell {
padding: 0 15px;
font-size: 12px;
}
.van-cell:not(:last-child)::after{
border:0;
}
.van-card__title{
font-size: 14px;
}
.van-cell__title {
flex: 10;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.van-tag {
line-height: 12px;
margin-right: 5px;
}
.price {
color: #e93b3d;
font-size: 10px;
overflow: hidden;
height: 18px;
span {
font-size: 16px;
margin-right: 5px;
}
.van-tag{
font-size: 12px;
}
}
.van-stepper{
position: absolute;
bottom: 5px;
right: 5px;
&__plus{
width: 30px;
}
&__minus{
width: 30px;
}
}
.image_tag{
position: absolute;
bottom: 0;
width: 90px;
height: 20px;
line-height: 20px;
font-size: 10px;
color: #fff;
text-align: center;
background-color: rgba(0,0,0,.7);
}
}
.additional::after{
border-color: #f7f7f7;
}
</style>
<template>
<div style="height:50px;">
<van-tabbar >
<van-tabbar-item icon="wap-home" to="/home">首页</van-tabbar-item>
<van-tabbar-item icon="wap-nav" to="/category" >分类</van-tabbar-item>
<van-tabbar-item icon="cart" to="/cart" >购物车</van-tabbar-item>
<van-tabbar-item icon="contact" to="/user/index">我的</van-tabbar-item>
</van-tabbar>
</div>
</template>
<script>
import { Tabbar, TabbarItem } from "vant";
export default {
name:'navigate',
components:{
[Tabbar.name]: Tabbar,
[TabbarItem.name]: TabbarItem,
}
}
</script>
<template>
<van-nav-bar
:title="title"
left-text=""
left-arrow
@click-left="onBack"
/>
</template>
<script>
import { NavBar } from 'vant';
export default {
name:'headerNav',
components:{
[NavBar.name]: NavBar,
},
props:{
title:String,
},
methods: {
onBack() {
history.back();
},
}
}
</script>
<style>
</style>
<template>
<div class="cap-cube" style="font-size:100%;width:100%;">
<div v-for="(item,index) in data.images" :key="index" class="cap-cube__item" :style="'width:'+item.imgwidth+'rem;'+item.style">
<a :href="item.link">
<img :src="item.src+'?w=375'" :style="'width:'+item.imgwidth+'rem;'" />
</a>
</div>
<div style="clear:both;"></div>
</div>
</template>
<script>
export default {
name: "cube",
props: {
data: Object
},
created: function() {
var gap = this.data.imagegap;
var margin = gap / 2;
var width = 375;
var max = 0;
switch (this.data.type) {
case "1":
max = 2;
width = (width - margin * 2) / 2;
break;
case "2":
max = 3;
width = (width - margin * 4) / 3;
break;
case "3":
max = 4;
width = (width - margin * 6) / 4;
break;
case "4":
max = 4;
width = (width - margin * 2) / 2;
break;
case "5":
max = 3;
width = (width - margin * 2) / 2;
break;
case "6":
max = 3;
width = (width - margin * 2) / 2;
break;
case "7":
max = 4;
width = (width - margin * 2) / 2;
break;
}
margin = margin / 50;
width = width / 50;
var imagelist = [];
for (var i = 0; i < max; i++) {
var imgwidth = width;
var item = this.data.imagelist[i];
var style = "";
switch (this.data.type) {
case "1":
{
if (i == 0) {
style = "margin-right:" + margin + "rem;";
} else {
style = "margin-left:" + margin + "rem;";
}
}
break;
case "2":
{
if (i == 0) {
style = "margin-right:" + margin + "rem;";
} else if (i == 1) {
style = "margin:0 " + margin + "rem;";
} else {
style = "margin-left:" + margin + "rem;";
}
}
break;
case "3":
{
if (i == 0) {
style = "margin-right:" + margin + "rem;";
} else if (i == 1 || i == 2) {
style = "margin:0 " + margin + "rem;";
} else {
style = "margin-left:" + margin + "rem;";
}
}
break;
case "4":
{
if (i == 0) {
style =
"margin-right:" +
margin +
"rem;margin-bottom:" +
margin +
"rem;";
} else if (i == 1) {
style =
"margin-left:" +
margin +
"rem;margin-bottom:" +
margin +
"rem;";
} else if (i == 2) {
style =
"margin-right:" + margin + "rem;margin-top:" + margin + "rem;";
} else {
style =
"margin-left:" + margin + "rem;margin-top:" + margin + "rem;";
}
}
break;
case "5":
{
if (i == 0) {
style = "margin-right:" + margin + "rem;";
} else if (i == 1) {
style =
"margin-left:" +
margin +
"rem;margin-bottom:" +
margin +
"rem;";
} else {
style =
"margin-left:" + margin + "rem;margin-top:" + margin + "rem;";
}
}
break;
case "6":
{
if (i == 0) {
imgwidth = width * 2;
style = "margin-bottom:" + margin + "rem;";
} else if (i == 1) {
style =
"margin-right:" + margin + "rem;margin-top:" + margin + "rem;";
} else {
style =
"margin-left:" + margin + "rem;margin-top:" + margin + "rem;";
}
}
break;
case "7":
{
if (i == 0) {
style = "margin-right:" + margin + "rem;";
} else if (i == 1) {
style =
"margin-right:" + margin + "rem;margin-top:" + margin + "rem;";
} else if (i == 2) {
imgwidth = width / 2 - margin;
style =
"margin-left:" +
margin +
"rem;margin-top:" +
margin +
"rem;margin-right:" +
margin +
"rem";
} else {
imgwidth = width / 2 - margin;
style =
"margin-left:" + margin + "rem;margin-top:" + margin + "rem;";
}
}
break;
}
item.style = style;
item.imgwidth = imgwidth;
imagelist.push(item);
}
this.data.images = imagelist;
},
computed: {}
};
</script>
<template>
<div>
<van-swipe :autoplay="3000" v-if="data.type=='1'" :style="'height:'+height+'px'" >
<van-swipe-item v-for="(image,index) in data.imagelist" :key="index" >
<a :href="image.url">
<img v-lazy="image.src+''" style="width: 100%;" />
</a>
</van-swipe-item>
</van-swipe>
<ul v-if="data.type=='2'">
<li v-for="(image,index) in data.imagelist" :key="index" class="cap-image-ad__content" :style="'margin:'+data.imagegap+'px 0px;'">
<div class="image-wrapper">
<a :href="image.url">
<img alt="" class="cap-image-ad__image" v-lazy="image.src+''" />
</a>
</div>
</li>
</ul>
<div v-if="data.type=='3'||data.type=='4'||data.type=='5'" class='cap-image-ad__image-nav' style='overflow-x:scroll;' >
<div v-for="(item,index) in data.imagelist" :key="index" class="image-wrapper" :style="'width:'+(data.type=='3'?'80':(data.type=='4'?'40':'20'))+'%;margin-right:'+data.imagegap+'px;'">
<a :href="item.link" class="cap-image-ad__link cap-image-ad__link--image-nav" >
<div class="cap-image-ad__image">
<img :src="item.src+'?w=640'" style="width: 100%; " />
</div>
</a>
</div>
</div>
</div>
</template>
<script>
export default {
name:'imageAd',
components:{
},
props:{
data:Object
},
data(){
return{
height:0
}
},
created(){
if(this.data.imagelist.length==0||this.data.type!='1'){
return;
}
var that=this;
var image =this.data.imagelist[0];
let img = new Image()
img.src = image.src;
var width= window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
img.onload = function () {
that.height= Math.ceil(img.height/img.width * width);
}
}
}
</script>
<style>
</style>
<template>
<div :class='(data.type == "1" ? "cap-image-ad__image-nav" : "cap-image-ad__slide cap-image-ad__text-nav")' :style='"overflow-x:"+(data.showtype == "1" ? "hidden" : "scroll")+"; background-color:"+data.backgroundcolor' >
<div v-if="data.type == '1'" v-for="(item,index) in data.imagelist" :key="index" class="image-wrapper" :style="'width:'+ data.width+'%; margin-right: 0px;'">
<a :href="item.link" class="cap-image-ad__link cap-image-ad__link--image-nav" :style="'color:'+data.color">
<div class="cap-image-ad__image">
<img v-lazy="item.src+'?w=320'" style="width: 100%; " />
</div>
<h3 v-if="item.title!=''" class="cap-image-ad__nav-title">{{item.title}}</h3>
</a>
</div>
<a v-if="data.type=='2'" v-for="(item,index) in data.imagelist" :key="index" :href="item.link" class="text-nav-wrapper" :style="'width:'+data.width+'%; color: '+data.color+'; background-color: '+data.backgroundcolor"><h3 class="cap-image-ad__nav-title">{{item.title}}</h3></a>
</div>
</template>
<script>
export default {
name:'imageText',
props:{
data:Object
},
created:function(){
var width = 0;
if (this.data.showtype == "1") {
width = 100 / this.data.imagelist.length;
}
else {
width = (100 * 0.95) / (this.data.shownumber - 1);
}
this.data.width=width;
}
}
</script>
<style>
</style>
<template>
<div :style="divstyle" ><div :style="linestyle"></div></div>
</template>
<script>
export default {
name: 'page-line',
props: {
data: Object,
},
computed:{
divstyle(){
return{
height:"30px",
position:'relative',
margin:'0px '+this.data.margintype+'px'
};
},
linestyle(){
return{
position:'absolute',
top:'14px',
width:'100%',
borderTop:'1px '+(this.data.type==undefined?'solid':this.data.type)+" "+(this.data.color==undefined?'#000':this.data.color),
};
}
}
};
</script>
<template>
<NoticeBar
:text="data.value"
:background="data.background"
:color="data.color"
/>
</template>
<script>
import { NoticeBar } from "vant";
export default {
name:'notice',
components:{
NoticeBar
},
props:{
data:Object
},
computed:{
}
}
</script>
<style>
</style>
<template>
<div>
<ul :class="'cap-goods-list__container cap-goods-list__container--'+data.classname+' cap-goods-list__container--'+data.ParameterDictionary.showtype+' '+(data.ParameterDictionary.type=='6'?'nowrap':'')" >
<li v-if="productlist.length==0" style="width:100%;height:150px;border:0px;">
<div style="width:100%;height:150px;"></div>
</li>
<li v-for="(item,index) in productlist" :key="index" :class="'cap-goods-list__wrapper '+(data.ParameterDictionary.type=='3'?(index%3==0?'cap-goods-list__wrapper--hybrid-big ':'cap-goods-list__wrapper--hybrid-small '):'')">
<router-link :class="'cap-goods-list__item cap-goods-list__item--'+data.classname+' '+data.ParameterDictionary.showtype+' '+data.aclass" :to="'/product/'+item.id">
<div class="cap-goods-list__photo">
<img class="cap-goods-list__img lazy lazyload" v-lazy="item.imageURL+'?w='+((data.ParameterDictionary.type=='1'||data.ParameterDictionary.type=='3')?'750':'375')" />
</div>
<div :class="'cap-goods-list__info has-title has-price '+(data.ParameterDictionary.showtype == 'card'?'has-btn':'')">
<h3 class="title">{{item.title}}</h3>
<p class="sale-info">
<span class="sale-price">¥ {{item.price}}</span>
</p>
</div>
<div v-if="data.ParameterDictionary.showtype == 'card'" class="cap-goods-list__buy-btn-wrapper cap-goods-list__buy-btn-wrapper--4">
<button class="cap-goods-list__buy-btn-4 van-button van-button--default van-button--small">{{data.ParameterDictionary.buttonvalue}}</button>
</div>
</router-link>
</li>
</ul>
<div style="clear:both;"></div>
</div>
</template>
<script>
import {getProduct} from "../../api/page.js";
export default {
name:'product',
data () {
return {
productlist: []
}
},
props:{
data:Object
},
created:function(){
var id=this.data.PageSectionId;
var data=this.data;
var classname = "big";
var aclass = "";
switch (data.ParameterDictionary.type) {
case "1":
aclass = "cap-goods-list__item--btn1 cap-goods-list__item--ratio-3-2 cap-goods-list__item--whitespace";
break;
case "2":
classname = "small";
aclass = "cap-goods-list__item--btn1 cap-goods-list__item--padding";
break;
case "3":
classname = "hybrid";
aclass = "cap-goods-list__item--big cap-goods-list__item--hybrid-big cap-goods-list__item--btn1 cap-goods-list__item--padding";
break;
case "4":
classname = "list";
aclass = "cap-goods-list__item--btn4 cap-goods-list__item--padding";
break;
case "5":
classname = "three";
aclass = "cap-goods-list__item--btn4 cap-goods-list__item--padding";
break;
case "6":
classname = "three";
break;
}
data.classname=classname;
data.aclass=aclass;
getProduct(id).then(response => {
this.productlist=response;
})
}
}
</script>
<style>
</style>
<template>
<div class="search-box" :style="boxstyle" >
<div class="search-box__view" :style="boxviewstyle">
<div class="search">
<div :class="'search__filed search__filed--'+data.textalign+' search__filed--'+(data.boxtype=='2'?'circle':'rect')" :style="'background-color:'+(data.boxcolor==undefined?'#ffffff':data.boxcolor)+';'">
<van-icon name="search" class="icon-search" size="14px" :color="data.color" />
<div class="cell field" :style="data.textalign=='left'?'':'width: 80px;'">
<div class="cell__value cell__value--alone">
<div class="field__body">
<input type="search" :placeholder="data.keyword==''||data.keyword==undefined?'商品搜索':data.keyword" class="field__control" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:'search',
components:{
},
props:{
data:Object
},
created:function(){
if(this.data.position=='fixed'){
this.$emit('settopheight', 50);
}
},
computed:{
boxstyle(){
if(this.data.position=='fixed'){
return{
position:'fixed',
top: 0,
zIndex: 10,
}
}else{
return{}
}
},
boxviewstyle(){
return{
background: (this.data.backgroundcolor==undefined?"#f9f9f9":this.data.backgroundcolor),
paddingRight: '15px',
top:'0px' ,
}
},
}
}
</script>
<style>
</style>
<template>
<div :style="style">{{data.value}}</div>
</template>
<script>
export default {
name:'page-text',
props:{
data:Object
},
computed:{
style(){
return{
position:'relative',
padding: '10px',
fontSize:(this.data.fontsize==undefined?'10':this.data.fontsize)+'px',
color:(this.data.color==undefined?'#000':this.data.color),
background:this.data.backgroundcolor,
textAlign:this.data.textalign,
}
}
}
}
</script>
<template>
<a :href="data.link">
<div v-if="data.type == '1'" class="cap-title cap-title--normal" :style="'background-color:'+data.backgroundcolor+'; text-align:'+data.textalign+';color:'+data.color">
<h2 class="cap-title__main">{{data.title}}</h2>
<p v-if="data.subtitle!=undefined&&data.subtitle!=''" class="cap-title__sub"><span class="cap-title__sub-title">{{data.subtitle}}</span></p>
</div>
<div v-if="data.type == '2'" class="title" :style="'background:'+data.backgroundcolor+';text-align:'+data.textalign">
<span :style="data.color==''?'':'border-bottom: 1px solid '+data.color+';color:'+data.color+';'">{{data.title}}</span>
</div>
</a>
</template>
<script>
export default {
name:'page-title',
props:{
data:Object
},
computed:{
}
}
</script>
<style>
</style>
<template>
<div :style="style"></div>
</template>
<script>
export default {
name: 'whitespace',
props: {
data: Object,
},
computed: {
style() {
return {
height: (this.data.height==undefined?'30':this.data.height)+"px",
};
}
}
};
</script>
<template>
<div>
<van-nav-bar left-arrow class="product-serach"
@click-left="onBack"
>
<van-search
v-model="value"
placeholder="请输入搜索关键词"
background="#fff"
show-action
@search="onSearch"
slot="title"
>
<div slot="action" @click="onSearch">搜索</div>
</van-search>
</van-nav-bar>
</div>
</template>
<script>
import { Search } from "vant";
export default {
name:'searchtop',
components:{
[Search.name]:Search,
},
data(){
return{
value:'',
}
},
methods:{
onSearch() {
console.log(this.value);
},
onBack() {
history.back();
},
}
}
</script>
<style lang="less">
.product-serach{
.van-search{
padding: 7px 0;
background: #fff;
.van-cell{
background: rgb(242, 242, 242);
margin-right: 10px;
}
.van-search__action{
background: #e93b3d;
color: #fff;
}
}
.van-nav-bar__title{
margin: 0;
max-width: 100%;
padding-left: 40px;
padding-right: 20px;
}
}
</style>
import headerNav from '../components/header/nav';
import navigate from '../components/footer/navigate.vue'
import productcard from '../components/common/productcard.vue'
import {
Tag,
Col,
Icon,
Cell,
CellGroup,
Swipe,
Toast,
SwipeItem,
GoodsAction,
GoodsActionBigBtn,
GoodsActionMiniBtn,
Actionsheet,
Sku,
Card,Button,SwipeCell,Dialog,Tab, Tabs,Row,Checkbox, CheckboxGroup, SubmitBar,NavBar,Tabbar, TabbarItem,Panel,List,Step, Steps,Field ,
Badge, BadgeGroup,Popup,Stepper,RadioGroup, Radio,Picker,Uploader,Info
} from 'vant';
const components=[
Tag,
Col,
Icon,
Cell,
CellGroup,
Swipe,
SwipeItem,
GoodsAction,
GoodsActionBigBtn,
GoodsActionMiniBtn,
Actionsheet,
Sku,
Card,
Button,
SwipeCell ,
Dialog ,
headerNav,
Tab, Tabs,Toast,Row,Checkbox, CheckboxGroup, SubmitBar,NavBar ,Tabbar, TabbarItem,navigate,Panel,List ,Step, Steps,Field ,
Badge, BadgeGroup,Popup,productcard,Stepper,RadioGroup, Radio,Picker,Uploader,Info
]
export default (Vue)=>{
components.forEach(Component => {
Vue.component(Component.name, Component)
});
}
/**
* 配置编译环境和线上环境之间的切换
*
* baseUrl: 域名地址
* routerMode: 路由模式
* dataSources:数据源
*/
let baseUrl = '';
let routerMode = 'hash';
let dataSources='local';//local=本地,其他值代表非本地
if (process.env.NODE_ENV == 'development') {
baseUrl='';
}else if(process.env.NODE_ENV == 'production'){
baseUrl = '';
}
export {
baseUrl,
routerMode,
dataSources,
}
\ No newline at end of file
(function(d, w) {
const doc = d.documentElement;
function rem() {
const width = Math.min(doc.getBoundingClientRect().width, 768);
doc.style.fontSize = width / 7.5 + 'px';
}
rem();
w.addEventListener('resize', rem);
})(document, window);
\ No newline at end of file
import axios from 'axios'
import {baseUrl,dataSources} from './env';
import datas from '../data/data';
const service =axios.create({
baseURL: baseUrl, // api 的 base_url
timeout: 5000, // request timeout
});
const servicef =function(parameter){
if(dataSources=='local'){
//定义回调函数和axios一致
const promist = new Promise(function(resolve,reject){
var data=datas[parameter.url];
if(typeof data=='string'){
data= JSON.parse(data);
}
resolve(data);
})
return promist;
}
return service(parameter);
}
service.interceptors.request.use(
config => {
// Do something before request is sent
// if (store.getters.token) {
// // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
// config.headers['X-Token'] = getToken()
// }
return config
},
error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
//response => response,
/**
* 下面的注释为通过在response里,自定义code来标示请求状态
* 当code返回如下情况则说明权限有问题,登出并返回到登录页
* 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
* 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
*/
response => {
const res = response.data;
if (res.ResultCode !== 200) {
// Message({
// message: res.message,
// type: 'error',
// duration: 5 * 1000
// })
// // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
// if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// // 请自行在引入 MessageBox
// // import { Message, MessageBox } from 'element-ui'
// MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
// confirmButtonText: '重新登录',
// cancelButtonText: '取消',
// type: 'warning'
// }).then(() => {
// store.dispatch('FedLogOut').then(() => {
// location.reload() // 为了重新实例化vue-router对象 避免bug
// })
// })
// }
console.log(1);
return Promise.reject('error')
} else {
if(typeof response.data.Tag=='string'){
return JSON.parse(response.data.Tag);
}else{
return response.data.Tag;
}
}
},
error => {
return Promise.reject(error)
}
)
export default servicef
\ No newline at end of file
import Vue from 'vue';
import Router from 'vue-router';
Vue.use(Router);
const routes = [
{
path: '*',
redirect: '/home'
},
{
name: 'home',
component: () => import('../page/index'),
meta: {
title: '首页'
}
},
{
path: '/login',
component: () => import('../page/account/login'),
meta: {
title: '登录'
}
},
{
path: '/login/password',
component: () => import('../page/account/password'),
meta: {
title: '登录'
}
},
{
path: '/login/phone',
component: () => import('../page/account/phonelogin'),
meta: {
title: '手机号登录'
}
},
{
path: '/login/register',
component: () => import('../page/account/register'),
meta: {
title: '注册'
}
},
{
path: '/user/index',
component: () => import('../page/user/index'),
name: 'user',
meta: {
title: '会员中心'
}
},
{
path: '/user/info',
component: () => import('../page/user/info/detail'),
name: 'user',
meta: {
title: '账号管理'
}
},
{
path: '/user/address',
component: () => import('../page/user/address/list'),
meta: {
title: '我的地址'
}
},
{
path: '/user/address/edit',
component: () => import('../page/user/address/edit'),
meta: {
title: '修改地址'
}
},
{
path: '/user/favorite',
component: () => import('../page/user/favorite/list'),
meta: {
title: '我的收藏'
}
},
{
path: '/user/coupon',
component: () => import('../page/user/coupon/list'),
meta: {
title: '我的优惠券'
}
},
{
path: '/user/order',
component: () => import('../page/user/order/list'),
meta: {
title: '我的订单'
}
},
{
path: '/user/order/:id',
component: () => import('../page/user/order/list'),
meta: {
title: '我的订单'
}
},
{
path: '/user/order/info/:id',
component: () => import('../page/user/order/info'),
meta: {
title: '我的订单'
}
},
{
path: '/user/order/logistics/:id',
component: () => import('../page/user/order/logistics'),
meta: {
title: '订单追踪'
}
},
{
path: '/user/aftersale',
component: () => import('../page/user/aftersale/list'),
meta: {
title: '售后'
}
},
{
path: '/user/aftersale/apply',
component: () => import('../page/user/aftersale/apply'),
meta: {
title: '申请售后'
}
},
{
path: '/user/aftersale/detail',
component: () => import('../page/user/aftersale/detail'),
meta: {
title: '服务单详情'
}
},
{
path: '/user/aftersale/track/:id',
component: () => import('../page/user/aftersale/track'),
meta: {
title: '进度详情'
}
},
{
path: '/product/:id',
component: () => import('../page/product/detail'),
meta: {
title: '商品详情'
}
},
{
path: '/search',
component: () => import('../page/product/list'),
meta: {
title: '商品列表'
}
},
{
name: 'cart',
component: () => import('../page/cart/index'),
meta: {
title: '购物车'
}
},
{
path: '/order',
component: () => import('../page/shipping/order'),
meta: {
title: '确认订单'
}
},
{
name: 'category',
component: () => import('../page/category/index'),
meta: {
title: '分类'
}
},
];
// add route path
routes.forEach(route => {
route.path = route.path || '/' + (route.name || '');
});
const router = new Router({ routes });
router.beforeEach((to, from, next) => {
const title = to.meta && to.meta.title;
if (title) {
document.title = title;
}
next();
});
export {
router
};
This source diff could not be displayed because it is too large. You can view the blob instead.
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论