提交 74d05557 authored 作者: YunaiV's avatar YunaiV

移除 user-mobile 项目,迁移到单独的工程

上级 6d1a47af
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
.DS_Store
node_modules
/dist
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 商城
> TODO
\ No newline at end of file
## 基于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": "npm run serve",
"serve": "vue-cli-service serve",
"build": "NODE_ENV=production vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.18.0",
"moment": "^2.24.0",
"pingpp-js": "^2.2.13",
"vant": "^1.3.1",
"vue": "^2.5.17",
"vue-router": "^3.0.1",
"vuex": "^3.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.4.1",
"@vue/cli-plugin-eslint": "^3.4.1",
"@vue/cli-service": "^3.6.0",
"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>
# 使用说明
### 第一步
```
npm install
```
### 第二步
复制文件到 server 目录
```
cp -rf dist server
```
### 第三步
```
node server.prod
```
//
// 粉笔:
// 输出不同颜色的提示信息
const chalk = require('chalk');
module.exports = {
chalkError: chalk.red,
chalkSuccess: chalk.green,
chalkWarning: chalk.yellow,
chalkProcessing: chalk.blue,
};
module.exports = {
'/admin-api -> http://180.167.213.26:18083/': {
changeOrigin: true,
pathRewrite: {},
},
'/server/api -> https://preview.pro.ant.design/': {
changeOrigin: true,
pathRewrite: { '^/server': '' },
},
};
{
"name": "browser-work-server",
"description": "node server",
"dependencies": {
"express": "^4.16.3",
"object-assign": "4.1.1",
"chalk": "2.4.1",
"http-proxy-middleware": "^0.18.0"
}
}
{
"name": "mobile-web",
"script": "./server.prod.js",
"instances": "1",
"env": {
"NODE_ENV": "development"
},
"env_production": {
"NODE_ENV": "production"
}
}
const path = require('path');
const express = require('express');
const { chalkSuccess } = require('./config/chalk.config');
const proxyConfig = require('./config/proxy.prod.config');
const proxyBuild = require('./utils/proxy.build');
// create app server
const app = express();
const port = 3100;
// host proxy
app.use(proxyBuild(proxyConfig));
// use index.html
app.use(express.static(path.join(__dirname, 'dist/css')));
app.use(express.static(path.join(__dirname, 'dist/js')));
app.use(express.static(path.join(__dirname, 'dist')));
app.use((req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});
app.listen(port, error => {
if (error) {
console.error(error);
} else {
console.info(
chalkSuccess(
'==> 🌎 Listening on port %s. ' + 'Open up http://localhost:%s/ in your browser.'
),
port,
port
);
}
});
# 安装依赖包
cd mobile-web
npm install
# 开始构建
#npm run build
# 创建 app 运行目录
rm -rf app
mkdir app
# 复制配置文件
cp -rf server app/
# npm 构建项目
npm run build
# 复制文件到 server 努力
cp -rf dist app/server
# 复制文件到 project 目录执行
if [ ! -d "/work2/project/mobile-web/server/dist" ]; then
mkdir -pv /work2/project/mobile-web/server/dist
else
rm -rf /work2/project/mobile-web/server/dist
fi
cp -rf app/server /work2/project/mobile-web
# 安装 server 依赖项
cd /work2/project/mobile-web/server
npm install
# 启动服务
pm2 restart pm2.json
const proxy = require('http-proxy-middleware');
const ObjectAssign = require('object-assign');
const { chalkError, chalkSuccess } = require('../config/chalk.config');
/**
*
* key :
* [0]: /api
* [1]: target url
*
* 预计写法:
* 1、 /api -> baidu.com : { }
* 2、 /user : function() { return {} }
*
* @param config
*/
module.exports = function(config) {
console.info(chalkSuccess('build proxy.%s.config 配置!'), process.env.NODE_ENV);
const proxys = [];
if (!config) {
console.log(chalkError('proxy.%s.config 没有配置!'), process.env.NODE_ENV);
}
for (const key in config) {
if (/->/.test(key)) {
const keys = key.toString().split('->');
const source = keys[0].trim();
const target = keys[1].trim();
if (typeof config !== 'object') {
console.log(
chalkError('%s: proxy.%s.config 初始化失败 config 类型为 object!'),
key,
process.env.NODE_ENV
);
break;
}
proxys.push(proxy(source, ObjectAssign({ target }, config[key])));
}
}
return proxys;
};
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
import './assets/style/common.css';
export default {
name: 'app'
}
</script>
import request from "../config/request";
// order
export function createOrder(params) {
return request({
headers: {
'Content-Type': 'application/json',
},
url: '/order-api/users/order/create_order',
method: 'post',
data: {
...params,
},
});
}
export function getOrderPage(params) {
return request({
url: '/order-api/users/order/order_page',
method: 'get',
params: {
...params,
}
});
}
export function confirmReceiving(orderId) {
return request({
url: '/order-api/users/order/confirm_receiving',
method: 'post',
params: {
orderId,
}
});
}
export function getOrderConfirmCreateOrder(skuId, quantity, couponCardId) {
return request({
url: '/order-api/users/order/confirm_create_order',
method: 'get',
params: {
skuId,
quantity,
couponCardId,
}
});
}
export function getOrderInfo(orderId) {
return request({
url: '/order-api/users/order/info',
method: 'get',
params: {
orderId,
}
});
}
// Cart
export function createOrderFromCart(userAddressId, couponCardId, remark) {
return request({
url: '/order-api/users/order/create_order_from_cart',
method: 'post',
params: {
userAddressId,
remark,
couponCardId,
}
});
}
export function addCart(skuId, quantity) {
return request({
url: '/order-api/users/cart/add',
method: 'post',
params: {
skuId,
quantity,
}
});
}
export function countCart() {
return request({
url: '/order-api/users/cart/count',
method: 'get',
params: {
}
});
}
export function listCart() {
return request({
url: '/order-api/users/cart/list',
method: 'get',
params: {
}
});
}
export function updateCartSelected(skuIds, selected) {
return request({
url: '/order-api/users/cart/update_selected',
method: 'post',
params: {
skuIds: skuIds.join(','),
selected,
}
});
}
export function getCartConfirmCreateOrder(couponCardId) {
return request({
url: '/order-api/users/cart/confirm_create_order',
method: 'get',
params: {
couponCardId
}
});
}
export function getCartCalcSkuPrice(skuId) {
return request({
url: '/order-api/users/cart/calc_sku_price',
method: 'get',
params: {
skuId,
}
});
}
// 物流信息
export function getOrderLogisticsInfo(params) {
return request({
url: '/order-api/users/order_logistics/info_order',
method: 'get',
params: {
...params,
}
});
}
export function getLogisticsInfo(logisticsId) {
return request({
url: '/order-api/users/order_logistics/info',
method: 'GET',
params: {
logisticsId,
},
});
}
// 退货信息
export function getOrderReturnReason() {
return request({
url: '/order-api/users/order_return/reason',
method: 'GET',
});
}
export function orderReturnApply(params) {
return request({
headers: {
'Content-Type': 'application/json',
},
url: '/order-api/users/order_return/apply',
method: 'POST',
data: {
...params,
},
});
}
export function getOrderReturnInfo(orderId) {
return request({
url: '/order-api/users/order_return/info',
method: 'GET',
params: {
orderId,
},
});
}
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 getTransaction(appId, orderId) {
return request({
url: '/pay-api/users/transaction/get',
method: 'get',
params: {
appId,
orderId
}
});
}
export function submitTransaction(appId, orderId, payChannel) {
return request({
url: '/pay-api/users/transaction/submit',
method: 'post',
params: {
appId,
orderId,
payChannel
}
});
}
import request from "../config/request";
export function getProductCategoryList(pid) {
return request({
url: '/product-api/users/category/list',
method: 'get',
params: {
pid
}
});
}
export function getProductSpuPage(cid, pageNo, pageSize) {
return request({
url: '/product-api/users/spu/page',
method: 'get',
params: {
cid,
pageNo: pageNo || 1,
pageSize: pageSize || 10,
}
});
}
export function getProductSpuInfo(id) {
return request({
url: '/product-api/users/spu/info',
method: 'get',
params: {
id,
}
});
}
export function collectionSpu(spuId,hasCollectionType) {
return request({
url: '/product-api/users/spu/collection/'+spuId+'/' + hasCollectionType,
method: 'post'
});
}
import request from "../config/request";
// Banner
export function getBannerList() {
return request({
url: '/promotion-api/users/banner/list',
method: 'get',
});
}
// Product Recommend
export function getProductRecommendList() {
return request({
url: '/promotion-api/users/product_recommend/list',
method: 'get',
params: {
}
});
}
// Coupon Template
export function getCouponTemplate(id) {
return request({
url: '/promotion-api/users/coupon/template/get',
method: 'get',
params: {
id,
}
});
}
export function doAddCouponCard(templateId) {
return request({
url: '/promotion-api/users/coupon/card/add',
method: 'post',
params: {
templateId,
}
});
}
// Coupon Card
export function getCouponPage(status, pageNo, pageSize) {
return request({
url: '/promotion-api/users/coupon/card/page',
method: 'get',
params: {
status,
pageNo,
pageSize
}
});
}
import request from "../config/request";
export function getProductPage({cid, keyword, pageNo, pageSize, sortField, sortOrder}) {
return request({
url: '/search-api/users/product/page',
method: 'get',
params: {
cid,
keyword,
pageNo: pageNo || 1,
pageSize: pageSize || 10,
sortField: sortField,
sortOrder: sortOrder,
}
});
}
export function getProductCondition({keyword}) {
return request({
url: '/search-api/users/product/condition',
method: 'get',
params: {
keyword,
}
});
}
import request from "../config/request";
export function GetFavoritePage(pageNo,pageSize){
return request({
url: '/user-api/users/favorite/page',
method: 'get',
params: { pageNo,pageSize }
})
}
export function DelFavorite(spuId){
return request({
url: '/user-api/users/favorite/remove',
method: 'DELETE',
params: { spuId }
})
}
export function hasUserSpuFavorite(spuId){
return request({
url: '/user-api/users/favorite/hasUserFavorite',
method: 'get',
params: {spuId}
})
}
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 }
})
}
export function getUserInfo() {
return request({
url: '/user-api/users/user/info',
method: 'get',
});
}
export function doUserUpdateNickname(nickname) {
return request({
url: '/user-api/users/user/update_nickname',
method: 'post',
params: {
nickname,
}
});
}
export function doPassportMobileRegister(mobile, code) {
return request({
url: '/user-api/users/passport/mobile/register',
method: 'post',
params: {
mobile,
code,
}
});
}
export function doPassportMobileSendRegisterCode(mobile) {
return request({
url: '/user-api/users/passport/mobile/send_register_code',
method: 'post',
params: {
mobile,
}
});
}
// -------------------------- address
export function GetAddressList(){
return request({
url: '/user-api/users/address/list',
method: 'get',
})
}
export function GetAddressById(id){
return request({
url: '/user-api/users/address/address',
method: 'get',
params: { id }
})
}
export function GetDefaultAddress(){
return request({
url: '/user-api/users/address/default_address',
method: 'get',
})
}
export function UpdateAddress(data){
return request({
url: '/user-api/users/address/update',
method: 'PUT',
params: data
})
}
export function SaveAddress(data){
return request({
url: '/user-api/users/address/add',
method: 'POST',
params: data
})
}
export function DelAddress(data){
return request({
url: '/user-api/users/address/remove',
method: 'DELETE',
params: data
})
}
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;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
background-color: #ffffff;
}
/* 处理 pc 最大尺寸 */
#app {
/*border-left: 1px solid #ccc2bf;*/
/*border-right: 1px solid #ccc2bf;*/
}
@media screen and (min-width: 769px) {
#app, .van-goods-action, .van-overflow-hidden {
max-width: 600px!important;
margin: 0 auto;
}
.van-tabbar, .van-submit-bar {
max-width: 600px!important;
position:fixed;
margin:auto;
left:0;
right:0;
}
}
.wap-wrap {
font-size: 0.32rem;
width: 100%;
}
#maxWidth {
display: flex;
flex: 1;
}
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;
}
差异被折叠。
<template>
<router-link :to="'/product/' + product.id">
<van-cell-group class="additional">
<van-card
:title="product.name"
:desc="product.sellPoint"
:num="(iscard?null:product.quantity)"
style="background:#fff"
>
<template slot="thumb">
<img :src="product.picUrls && product.picUrls ? product.picUrls[0] : ''"/>
</template>
<template slot="tags">
<p class="price" v-if="product.buyPrice || product.price">
<span>{{product.buyPrice ? product.buyPrice / 100.00 : product.price / 100.00}}</span>
<van-tag v-if="product.promotionActivityTitle" plain type="danger">
{{ product.promotionActivityTitle }}
</van-tag>
</p>
<!-- TODO 芋艿 暂时去掉 -->
<!-- <van-stepper v-if="iscard" v-model="product.quantity" :max="product.max" :min="product.min"/>-->
</template>
</van-card>
<!-- TODO 芋艿,暂时去掉赠品 -->
<!--<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>
</router-link>
</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 v-model="active">
<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,
},
data() {
return {
active: 0,
};
},
created() {
// TODO 芋艿,可能不太优雅
let path = this.$route.path;
switch (path) {
case '/home':
this.active = 0;
break;
case '/category':
this.active = 1;
break;
case '/cart':
this.active = 2;
break;
case '/user/index':
this.active = 3;
break;
}
}
}
</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>
// TODO 芋艿,准备废弃。
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="onSearchClick"
slot="title"
>
<div slot="action" @click="onSearchClick">搜索</div>
</van-search>
</van-nav-bar>
</div>
</template>
<script>
import { Search } from "vant";
export default {
name:'searchtop',
components:{
[Search.name]:Search,
},
props: {
keyword: String,
// onSearch: Function,
},
data(){
return{
value: this.keyword,
}
},
methods:{
onSearchClick() {
// this.props.onSearch(this.keyword);
this.$emit('onSearch', 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 || process.env.NODE_ENV == 'development') {
baseUrl='http://127.0.0.1';
}else if(process.env.NODE_ENV == 'production'){
baseUrl = 'http://180.167.213.26:18099';
dataSources='production';
}
// baseUrl = 'http://127.0.0.1';
// baseUrl = 'http://180.167.213.26:18099';
dataSources = 'remote';
// dataSources = 'local';
export {
baseUrl,
routerMode,
dataSources,
}
(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';
import { getAccessToken, getRefreshToken } from '../utils/cache.js';
import { Dialog } from 'vant';
import {setLoginToken} from "../utils/cache";
const serviceRouter = function(requestUrl) {
function getConfig() {
const configDev = {
'/order-api': {
prefix: '/order-api',
target: 'http://127.0.0.1:18088/order-api',
},
'/user-api': {
prefix: '/user-api',
target: 'http://127.0.0.1:18082/user-api',
},
'/product-api': {
prefix: '/product-api',
target: 'http://127.0.0.1:18081/product-api',
},
'/promotion-api': {
prefix: '/promotion-api',
target: 'http://127.0.0.1:18085/promotion-api',
},
'/pay-api': {
prefix: '/pay-api',
target: 'http://127.0.0.1:18084/pay-api',
},
'/search-api': {
prefix: '/search-api',
target: 'http://127.0.0.1:18086/search-api',
},
};
const configProd = {
'/order-api': {
prefix: '/order-api',
target: 'http://api.shop.iocoder.cn/order-api',
},
'/user-api': {
prefix: '/user-api',
target: 'http://api.shop.iocoder.cn/user-api',
},
'/product-api': {
prefix: '/product-api',
target: 'http://api.shop.iocoder.cn/product-api',
},
'/promotion-api': {
prefix: '/promotion-api',
target: 'http://api.shop.iocoder.cn/promotion-api',
},
'/pay-api': {
prefix: '/pay-api',
target: 'http://api.shop.iocoder.cn/pay-api',
},
'/search-api': {
prefix: '/search-api',
target: 'http://api.shop.iocoder.cn/search-api',
},
};
if (process.env.NODE_ENV == 'development') {
return configDev;
} else {
return configProd
}
}
// function doCreateServer(config) {
// // 获取请求配置文件
// const createServer = {};
// for (const configKey in config) {
// const serverPrefix = configKey;
// const {target} = config[configKey];
// // 创建服务
// createServer[serverPrefix] = axios.create({
// baseURL: target, // api 的 base_url
// timeout: 5000, // request timeout
// headers: {
// 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
// }
// });
// }
// }
const config = getConfig();
// TODO 芋艿,临时加下。
// const createServer = doCreateServer(config);
const indexOf = requestUrl.indexOf("/", 1);
const _urlPrefix = requestUrl.substring(0, indexOf);
if (!config[_urlPrefix]) {
// throw new Error(`服务路由,未找到可用服务! ${requestUrl}`);
console.error(`服务路由,未找到可用服务! ${requestUrl}`)
return ''
}
// if (!createServer[_urlPrefix]) {
// throw new Error("服务路由,未找到可用服务!");
// }
// const { target } = config[_urlPrefix];
// const requestServer = createServer[_urlPrefix];
// const targetRequestUrl = _requestUrl.replace(_urlPrefix, target)
// return createServer;
return config[_urlPrefix];
};
const service = axios.create({
// baseURL: baseUrl, // api 的 base_url
timeout: 30000, // request timeout
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
});
const servicef = function (parameter) {
// debugger;
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;
}
// 设置 access token
// debugger;
// if (getAccessToken()) {
// parameter.headers = {
// ...parameter.headers,
// 'Authorization': `Bearer ${getAccessToken()}`,
// };
// }
// debugger;
return service(parameter);
};
service.interceptors.request.use(
config => {
// 记录下原始请求的地址
config.originUrl = config.url;
// Do something before request is sent
// if (store.getters.token) {
// // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
// config.headers['X-Token'] = getToken()
// }
// 切换地址
const { target, prefix } = serviceRouter(config.url)
let url = config.url = config.url.replace(`${prefix}`, target);
// TODO 芋艿,这些 url 不用增加认证 token 。可能这么写,有点脏,后面看看咋优化下。
if (url.indexOf('user-api/users/passport/mobile/send_register_code') !== -1
|| url.indexOf('user-api/users/passport/mobile/register') !== -1
|| url.indexOf('user-api/users/passport/refresh_token') !== -1) {
return config;
}
// debugger;
if (getAccessToken()) {
config.headers['Authorization'] = `Bearer ${getAccessToken()}`;
}
return config
},
error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
);
function refreshToken(lastResponse) {
// TODO 芋艿,可能会存在多个异步 callback 的情况。
let refreshToken = getRefreshToken();
return servicef({
url: '/user-api/users/passport/refresh_token',
method: 'post',
params: {
refreshToken
}
}).then(data => {
// 设置新的 accessToken
setLoginToken(data.accessToken, data.refreshToken);
// 重新发起请求
let config = lastResponse.config;
return servicef({
url: config.originUrl,
method: config.method,
params: {
...config.params,
}
});
});
}
// response interceptor
service.interceptors.response.use(
//response => response,
/**
* 下面的注释为通过在response里,自定义code来标示请求状态
* 当code返回如下情况则说明权限有问题,登出并返回到登录页
* 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
* 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
*/
response => {
// debugger;
const res = response.data;
const code = res.code;
if (code !== 0) {
// // 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
// })
// })
// }
// TODO token 过期
// TODO 需要拿 refresh token 置换
if (code === 1002001011 // 访问令牌不存在
|| code === 1002001013 // 访问令牌已失效
|| code === 1002001017 // 刷新令牌不存在
|| code === 1002001018 // 刷新令牌已过期
|| code === 1002001019) { // 刷新令牌已失效
Dialog.confirm({
title: '系统提示',
message: res.message,
confirmButtonText: '重新登陆',
beforeClose: function (action, done) {
done();
if (action === 'confirm') {
// debugger;
// this.$router.push({ path: '/login' })
// TODO 跳转到登陆页.不是很优雅
location.replace('/#login');
location.reload();
}
}
});
} else if (code === 1002001012) { // 访问令牌已过期
return refreshToken(response);
} else {
Dialog.alert({
title: '系统提示',
message: res.message,
});
}
return Promise.reject('error')
} else {
// if (typeof response.data.Tag == 'string') {
// return JSON.parse(response.data.Tag);
// } else {
// return response.data.Tag;
// }
// debugger;
return res.data;
}
},
error => {
Dialog.alert({
title: '系统提示',
message: error,
});
console.error(`请求失败`, error);
throw new Error(error);
// return Promise.reject(error)
}
);
export default servicef
import Vue from 'vue';
import Router from 'vue-router';
import { getAccessToken } from '../utils/cache';
Vue.use(Router);
const routes = [
{
path: '*',
redirect: '/home'
},
{
name: 'home',
component: () => import('../page/index'),
meta: {
title: '首页'
}
},
{
path: '/login',
component: () => import('../page/account/phonelogin'),
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: '个人信息',
requireAuth: true,
}
},
{
path: '/user/address',
component: () => import('../page/user/address/list'),
meta: {
title: '我的地址',
requireAuth: true,
}
},
{
path: '/user/address/edit',
component: () => import('../page/user/address/edit'),
meta: {
title: '修改地址',
requireAuth: true,
}
},
{
path: '/user/favorite',
component: () => import('../page/user/favorite/list'),
meta: {
title: '我的收藏',
requireAuth: true,
}
},
{
path: '/user/coupon',
component: () => import('../page/coupon/list'),
meta: {
title: '我的优惠券',
requireAuth: true,
}
},
{
path: '/user/order',
component: () => import('../page/user/order/list'),
meta: {
title: '我的订单'
},
},
{
path: '/user/order/:id',
component: () => import('../page/user/order/list'),
meta: {
title: '我的订单',
requireAuth: true,
}
},
{
path: '/user/order/info/:id',
component: () => import('../page/user/order/info'),
meta: {
title: '我的订单',
requireAuth: true,
}
},
{
path: '/user/order/logistics/:id',
component: () => import('../page/user/order/logistics'),
meta: {
title: '订单追踪',
requireAuth: true,
}
},
{
path: '/user/aftersale',
component: () => import('../page/user/aftersale/list'),
meta: {
title: '售后'
}
},
{
path: '/user/aftersale/apply/:orderId',
component: () => import('../page/user/aftersale/apply'),
meta: {
title: '申请售后'
}
},
{
path: '/user/aftersale/detail/:orderId',
component: () => import('../page/user/aftersale/detail'),
meta: {
title: '服务单详情'
}
},
{
path: '/user/aftersale/track/:id/:serviceNumber',
component: () => import('../page/user/aftersale/track'),
meta: {
title: '进度详情'
}
},
{
name: '/product/search',
path: '/product/search',
component: () => import('../page/product/search'),
meta: {
title: '商品搜索'
}
},
{
path: '/product/:id',
component: () => import('../page/product/detail'),
meta: {
title: '商品详情'
}
},
{
path: '/products/list',
component: () => import('../page/product/list'),
meta: {
title: '商品列表'
}
},
{
name: 'cart',
component: () => import('../page/cart/index'),
meta: {
title: '购物车',
requireAuth: true,
}
},
{
path: '/order',
component: () => import('../page/shipping/order'),
meta: {
title: '确认订单',
requireAuth: true,
}
},
{
name: 'category',
component: () => import('../page/category/index'),
meta: {
title: '分类'
}
},
{
path: '/coupon/fetch',
component: () => import('../page/coupon/fetch'),
meta: {
title: '优惠劵领取'
}
},
{
path: '/pay',
component: () => import('../page/pay/index'),
meta: {
title: '收银台',
requireAuth: true,
}
}
];
// add route path
routes.forEach(route => {
route.path = route.path || '/' + (route.name || '');
});
const router = new Router({ routes });
router.beforeEach((to, from, next) => {
// 判断是否需要认证
const requireAuth = to.meta && to.meta.requireAuth;
if (requireAuth) {
if (!getAccessToken()) { // 未登陆
next({
path: '/login',
query: {redirect: to.fullPath} // 将跳转的路由path作为参数,登录成功后跳转到该路由
});
return;
}
}
// 处理标题
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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论