Commit aec557e9 authored by Junling Bu's avatar Junling Bu
Browse files

chore[litemall-vue]: 参考litemall-admin结构,重新调整litemall-vue的src结构

parent 8d262f8b
...@@ -23,7 +23,7 @@ litemall轻商城,是商城移动版本。 ...@@ -23,7 +23,7 @@ litemall轻商城,是商城移动版本。
可以阅读3.1 可以阅读3.1
## 3.2 litemall-vue ## 5.2 litemall-vue
这里的代码基于[vant--mobile-mall](https://github.com/qianzhaoy/vant--mobile-mall) 这里的代码基于[vant--mobile-mall](https://github.com/qianzhaoy/vant--mobile-mall)
......
...@@ -74,7 +74,7 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实 ...@@ -74,7 +74,7 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
* 地址列表、地址添加、地址删除 * 地址列表、地址添加、地址删除
* 收藏、足迹、关于 * 收藏、足迹、关于
### 1.2.1 轻商城功能 ### 1.2.2 轻商城功能
**目前还在开发中,不稳定** **目前还在开发中,不稳定**
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
"vant": "^1.4.4", "vant": "^1.4.4",
"vee-validate": "^2.1.4", "vee-validate": "^2.1.4",
"vue": "^2.5.17", "vue": "^2.5.17",
"js-cookie": "2.2.0",
"vuex": "3.0.1",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vuelidation": "^1.1.0" "vuelidation": "^1.1.0"
}, },
......
import request from '@/core/utils/request' import request from '@/utils/request'
// export const GOODS_CATEGORY = '/category'; // export const GOODS_CATEGORY = '/category';
export const GOODS_CATEGORY = '/wx/catalog/index'; export const GOODS_CATEGORY = '/wx/catalog/index';
......
// 登录 // 登录
export const USER_LOGIN = '/wx/auth/login'; export const USER_LOGIN = '/wx/auth/login';
export const USER_LOGOUT = ''; export const USER_LOGOUT = '';
// 用户信息 // 用户信息
export const USER_PROFILE = '/user-profile'; export const USER_PROFILE = '/user-profile';
export const USER_MODIFY_PASSWORD = ''; export const USER_MODIFY_PASSWORD = '';
export const USER_CHANGE_MOBILE = ''; export const USER_CHANGE_MOBILE = '';
// 验证码 // 验证码
export const USER_SENDCODE = ''; export const USER_SENDCODE = '';
// 地址 // 地址
export const ADDRESS = '/address'; export const ADDRESS = '/address';
export const ADDRESS_DEFAULT = '/address-default'; export const ADDRESS_DEFAULT = '/address-default';
// 收藏 // 收藏
export const GOODS_COLLECT_LIST = '/moreGoods'; export const GOODS_COLLECT_LIST = '/moreGoods';
import request from '@/utils/request'
export function loginByUsername(data) {
return request({
url: '/wx/auth/login',
method: 'post',
data
})
}
export function logout() {
return request({
url: '/auth/logout',
method: 'post'
})
}
export function getUserInfo(token) {
return request({
url: '/auth/info',
method: 'get',
params: { token }
})
}
\ No newline at end of file
<template> <template>
<van-tabbar v-model="active" style="z-index: 1999"> <van-tabbar v-model="active" style="z-index: 1999">
<van-tabbar-item <van-tabbar-item
v-for="(tab, index) in tabbar" v-for="(tab, index) in tabbar"
:icon="tab.icon" :icon="tab.icon"
:to="tab.path" :to="tab.path"
:dot="tab.dot" :dot="tab.dot"
:info="tab.info" :info="tab.info"
:key="index"> :key="index">
{{tab.name}} {{tab.name}}
</van-tabbar-item> </van-tabbar-item>
</van-tabbar> </van-tabbar>
</template> </template>
<script> <script>
import { Tabbar, TabbarItem } from 'vant'; import { Tabbar, TabbarItem } from 'vant';
export default { export default {
data() { data() {
return { return {
active: 0, active: 0,
tabbar: [ tabbar: [
{ {
name: '精选', name: '精选',
path: '/', path: '/',
pathName: 'home', pathName: 'home',
icon: 'compass-full', icon: 'compass-full',
dot: false, dot: false,
info: '' info: ''
}, },
{ {
name: '分类', name: '分类',
path: '/items', path: '/items',
pathName: 'class', pathName: 'class',
icon: 'class-full', icon: 'class-full',
dot: false, dot: false,
info: '' info: ''
}, },
{ {
name: '购物车', name: '购物车',
path: '/order', path: '/order',
pathName: 'cart', pathName: 'cart',
icon: 'cart-full', icon: 'cart-full',
dot: false, dot: false,
info: '' info: ''
}, },
{ {
name: '我的', name: '我的',
path: '/user', path: '/user',
pathName: 'user', pathName: 'user',
icon: 'wode', icon: 'wode',
dot: false, dot: false,
info: '' info: ''
} }
] ]
}; };
}, },
watch: { watch: {
$route: 'changeActive' $route: 'changeActive'
}, },
created() { created() {
const toName = this.$route.name; const toName = this.$route.name;
this.setActive(toName); this.setActive(toName);
}, },
methods: { methods: {
changeActive({ name }) { changeActive({ name }) {
this.setActive(name); this.setActive(name);
}, },
setActive(name) { setActive(name) {
this.tabbar.forEach((tab, i) => { this.tabbar.forEach((tab, i) => {
if (tab.pathName == name) { if (tab.pathName == name) {
this.active = i; this.active = i;
return false; return false;
} }
}); });
} }
}, },
components: { components: {
[Tabbar.name]: Tabbar, [Tabbar.name]: Tabbar,
[TabbarItem.name]: TabbarItem [TabbarItem.name]: TabbarItem
} }
}; };
</script> </script>
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import scroll from 'core/utils/scroll'; import scroll from '@/utils/scroll';
const CONTEXT = '$scrollArrow'; const CONTEXT = '$scrollArrow';
const OFFSET = 30; const OFFSET = 30;
// 绑定事件 // 绑定事件
function startBind(el) { function startBind(el) {
const context = el[CONTEXT]; const context = el[CONTEXT];
context.vm.$nextTick(() => { context.vm.$nextTick(() => {
if (scroll.isAttached(el)) { if (scroll.isAttached(el)) {
doBindEvent.call(el[CONTEXT]); doBindEvent.call(el[CONTEXT]);
} }
}); });
} }
// 绑定事件到元素上 // 绑定事件到元素上
// 读取基本的控制变量 // 读取基本的控制变量
function doBindEvent() { function doBindEvent() {
if (this.el[CONTEXT].binded) { if (this.el[CONTEXT].binded) {
return; return;
} }
this.el[CONTEXT].binded = true; this.el[CONTEXT].binded = true;
this.scrollEventListener = debounce(handleScrollEvent.bind(this), 100); this.scrollEventListener = debounce(handleScrollEvent.bind(this), 100);
// this.scrollEventTarget = this.el; // this.scrollEventTarget = this.el;
// var disabledExpr = this.el.getAttribute('waterfall-disabled'); // var disabledExpr = this.el.getAttribute('waterfall-disabled');
// var disabled = false; // var disabled = false;
// if (disabledExpr) { // if (disabledExpr) {
// this.vm.$watch(disabledExpr, (value) => { // this.vm.$watch(disabledExpr, (value) => {
// this.disabled = value; // this.disabled = value;
// this.scrollEventListener(); // this.scrollEventListener();
// }); // });
// disabled = Boolean(this.vm[disabledExpr]); // disabled = Boolean(this.vm[disabledExpr]);
// } // }
// this.disabled = disabled; // this.disabled = disabled;
const offset = this.el.getAttribute('scroll-offset'); const offset = this.el.getAttribute('scroll-offset');
this.offset = Number(offset) || OFFSET; this.offset = Number(offset) || OFFSET;
this.el.addEventListener('scroll', this.scrollEventListener); this.el.addEventListener('scroll', this.scrollEventListener);
// this.scrollEventListener(); // this.scrollEventListener();
} }
// 处理滚动函数 // 处理滚动函数
function handleScrollEvent() { function handleScrollEvent() {
const element = this.el; const element = this.el;
// 已被禁止的滚动处理 // 已被禁止的滚动处理
// if (this.disabled) return; // if (this.disabled) return;
const targetScrollLeft = scroll.getScrollLeft(element); const targetScrollLeft = scroll.getScrollLeft(element);
const targetVisibleWidth = scroll.getVisibleWidth(element); const targetVisibleWidth = scroll.getVisibleWidth(element);
// 滚动元素可视区域下边沿到滚动元素元素最顶上 距离 // 滚动元素可视区域下边沿到滚动元素元素最顶上 距离
const targetRight = targetScrollLeft + targetVisibleWidth; const targetRight = targetScrollLeft + targetVisibleWidth;
// 如果无元素高度,考虑为元素隐藏,直接返回 // 如果无元素高度,考虑为元素隐藏,直接返回
if (!targetVisibleWidth) return; if (!targetVisibleWidth) return;
// 判断是否到了最右边 // 判断是否到了最右边
const isRightOver = element.scrollWidth - targetRight < this.offset; const isRightOver = element.scrollWidth - targetRight < this.offset;
// 判断是否到了最左边 // 判断是否到了最左边
const isLeftOver = targetScrollLeft < this.offset; const isLeftOver = targetScrollLeft < this.offset;
this.cb && this.cb &&
this.cb({ this.cb({
target: element, target: element,
isRightOver, isRightOver,
isLeftOver isLeftOver
}); });
// // 判断是否到了顶 // // 判断是否到了顶
// let needLoadMoreToUpper = targetScrollTop < this.offset; // let needLoadMoreToUpper = targetScrollTop < this.offset;
// if (needLoadMoreToUpper) { // if (needLoadMoreToUpper) {
// this.cb.upper && this.cb.upper({ // this.cb.upper && this.cb.upper({
// target: scrollEventTarget, // target: scrollEventTarget,
// top: targetScrollTop // top: targetScrollTop
// }); // });
// } // }
} }
// 确认何时绑事件监听函数 // 确认何时绑事件监听函数
function doCheckStartBind(el) { function doCheckStartBind(el) {
const context = el[CONTEXT]; const context = el[CONTEXT];
if (context.vm._isMounted) { if (context.vm._isMounted) {
startBind(el); startBind(el);
} else { } else {
context.vm.$on('hook:mounted', () => { context.vm.$on('hook:mounted', () => {
startBind(el); startBind(el);
}); });
} }
} }
export default { export default {
bind(el, binding, vnode) { bind(el, binding, vnode) {
if (!el[CONTEXT]) { if (!el[CONTEXT]) {
el[CONTEXT] = { el[CONTEXT] = {
el, el,
vm: vnode.context, vm: vnode.context,
cb: {} cb: {}
}; };
} }
el[CONTEXT].cb = binding.value; el[CONTEXT].cb = binding.value;
doCheckStartBind(el); doCheckStartBind(el);
}, },
update(el) { update(el) {
const context = el[CONTEXT]; const context = el[CONTEXT];
context.scrollEventListener && context.scrollEventListener(); context.scrollEventListener && context.scrollEventListener();
} }
}; };
<template> <template>
<div class="field_group"> <div class="field_group">
<slot></slot> <slot></slot>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'md-field-group' name: 'md-field-group'
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.field_group { .field_group {
padding-left: 15px; padding-left: 15px;
padding-right: 15px; padding-right: 15px;
> div { > div {
margin-bottom: 15px; margin-bottom: 15px;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
} }
</style> </style>
<template> <template>
<div class="md_field" :class="{md_field_hasIcon: !!icon, md_field_isError: isError}"> <div class="md_field" :class="{md_field_hasIcon: !!icon, md_field_isError: isError}">
<van-icon v-if="icon" :name="icon" class="md_feld_icon"/> <van-icon v-if="icon" :name="icon" class="md_feld_icon"/>
<div class="md_field_control"> <div class="md_field_control">
<input <input
:type="type" :type="type"
v-on="listeners" v-on="listeners"
v-bind="$attrs" v-bind="$attrs"
:value="value"> :value="value">
</div> </div>
<div> <div>
<slot name="rightIcon"> <slot name="rightIcon">
<van-icon :name="rightIcon" @click="rightClick" v-show="value" /> <van-icon :name="rightIcon" @click="rightClick" v-show="value" />
</slot> </slot>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'md-field', name: 'md-field',
props: { props: {
value: {}, value: {},
type: { type: {
type: String, type: String,
default: 'text' default: 'text'
}, },
rightIcon: String, rightIcon: String,
icon: String, icon: String,
isError: Boolean isError: Boolean
}, },
computed: { computed: {
listeners() { listeners() {
return { return {
...this.$listeners, ...this.$listeners,
input: this.onInput input: this.onInput
}; };
} }
}, },
methods: { methods: {
onInput(event) { onInput(event) {
this.$emit('input', event.target.value); this.$emit('input', event.target.value);
}, },
rightClick(event) { rightClick(event) {
this.$emit('right-click', event); this.$emit('right-click', event);
} }
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.md_field { .md_field {
position: relative; position: relative;
border: 1px solid $border-color; border: 1px solid $border-color;
border-radius: 5px; border-radius: 5px;
padding-top: 10px; padding-top: 10px;
padding-bottom: 10px; padding-bottom: 10px;
padding-left: 10px; padding-left: 10px;
display: table; display: table;
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
background-color: #fff; background-color: #fff;
> div { > div {
display: table-cell; display: table-cell;
} }
> .md_field_control { > .md_field_control {
padding-right: 10px; padding-right: 10px;
box-sizing: border-box; box-sizing: border-box;
input { input {
border: 0; border: 0;
line-height: 14px; line-height: 14px;
font-size: 14px; font-size: 14px;
width: 100%; width: 100%;
} }
} }
.md_feld_icon { .md_feld_icon {
position: absolute; position: absolute;
top: 50%; top: 50%;
left: 10px; left: 10px;
transform: translate(0, -50%); transform: translate(0, -50%);
} }
} }
.md_field_hasIcon { .md_field_hasIcon {
padding-left: 40px; padding-left: 40px;
} }
.md_field_isError { .md_field_isError {
color: $red; color: $red;
background-color: #fcf5f5; background-color: #fcf5f5;
border: 1px solid $red; border: 1px solid $red;
input { input {
color: $red; color: $red;
background-color: #fcf5f5; background-color: #fcf5f5;
} }
input:-webkit-autofill { input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px #fcf5f5 inset !important; -webkit-box-shadow: 0 0 0 1000px #fcf5f5 inset !important;
} }
} }
</style> </style>
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
<script> <script>
import { List } from 'vant'; import { List } from 'vant';
import { get } from 'lodash'; import { get } from 'lodash';
import IsEmpty from '@/vue/components/is-empty'; import IsEmpty from '@/components/is-empty';
import loadMore from '@/vue/mixin/load-more'; import loadMore from '@/mixin/load-more';
const DEFAULT_CONFIG = { const DEFAULT_CONFIG = {
params: {}, params: {},
......
<template> <template>
<div class="is_empty"> <div class="is_empty">
<div> <div>
<img src="../../../assets/images/is_empty.png" alt="无商品" width="20%"> <img src="../../assets/images/is_empty.png" alt="无商品" width="20%">
</div> </div>
<div> <div>
<slot></slot> <slot></slot>
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
<script> <script>
import item_mix from '@/vue/mixin/item-card'; import item_mix from '@/mixin/item-card';
export default { export default {
name: 'item-card-hori', name: 'item-card-hori',
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<script> <script>
import item_mix from '@/vue/mixin/item-card'; import item_mix from '@/mixin/item-card';
export default { export default {
name: 'item-card-vert', name: 'item-card-vert',
......
// 使用这个会导致组件内部的 router 导航守卫无法使用, 慎用
/**
* @param { string } chunkPath views 文件夹下的页面路径
* @return { function } 返回 promise<component> 的匿名函数
*/
import spinner from '@/vue/components/spinner';
export default chunkPath => {
const AsyncHandler = () => ({
component: new Promise(resolve => {
setTimeout(() => {
resolve(
import(/* webpackChunkName: "[request]" */ `@/views/${chunkPath}`)
);
}, 1000);
}),
loading: spinner,
error: {
render(h) {
return h('div', {}, ['异步组件加载失败']);
}
},
timeout: 10000
});
return () =>
Promise.resolve({
functional: true,
render(h, { data, children }) {
return h(AsyncHandler, data, children);
}
});
};
// import axios from 'axios'
// import { Message, MessageBox } from 'element-ui'
// import store from '@/store'
// import { getToken } from '@/utils/auth'
// // create an axios instance
// const service = axios.create({
// baseURL: process.env.BASE_API, // api 的 base_url
// timeout: 5000 // request timeout
// })
// // request interceptor
// service.interceptors.request.use(
// config => {
// // Do something before request is sent
// if (store.getters.token) {
// // 让每个请求携带token-- ['X-Litemall-Admin-Token']为自定义key 请根据实际情况自行修改
// config.headers['X-Litemall-Admin-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 => {
// const res = response.data
// if (res.errno === 501) {
// MessageBox.alert('系统未登录,请重新登录', '错误', {
// confirmButtonText: '确定',
// type: 'error'
// }).then(() => {
// store.dispatch('FedLogOut').then(() => {
// location.reload()
// })
// })
// return Promise.reject('error')
// } else if (res.errno === 502) {
// MessageBox.alert('系统内部错误,请联系管理员维护', '错误', {
// confirmButtonText: '确定',
// type: 'error'
// })
// return Promise.reject('error')
// } else if (res.errno === 503) {
// MessageBox.alert('请求业务目前未支持', '警告', {
// confirmButtonText: '确定',
// type: 'error'
// })
// return Promise.reject('error')
// } else if (res.errno === 504) {
// MessageBox.alert('更新数据已经失效,请刷新页面重新操作', '警告', {
// confirmButtonText: '确定',
// type: 'error'
// })
// return Promise.reject('error')
// } else if (res.errno === 505) {
// MessageBox.alert('更新失败,请再尝试一次', '警告', {
// confirmButtonText: '确定',
// type: 'error'
// })
// return Promise.reject('error')
// } else if (res.errno === 506) {
// MessageBox.alert('没有操作权限,请联系管理员授权', '错误', {
// confirmButtonText: '确定',
// type: 'error'
// })
// return Promise.reject('error')
// } else if (res.errno !== 0) {
// // 非5xx的错误属于业务错误,留给具体页面处理
// return Promise.reject(response)
// } else {
// return response
// }
// }, error => {
// console.log('err' + error)// for debug
// Message({
// message: '登录连接超时(后台不能连接,请联系系统管理员)',
// type: 'error',
// duration: 5 * 1000
// })
// return Promise.reject(error)
// })
// export default service
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment