├── .browserslistrc
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
└── index.html
├── screenshot
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
└── 6.png
├── src
├── App.vue
├── config
│ ├── area.js
│ ├── filters.js
│ ├── global.js
│ └── rem.js
├── images
│ └── tabbar
│ │ ├── category_default.png
│ │ ├── category_selected.png
│ │ ├── home_default.png
│ │ ├── home_selected.png
│ │ ├── mine_default.png
│ │ ├── mine_selected.png
│ │ ├── shoppingcart_default.png
│ │ └── shoppingcart_selected.png
├── main.js
├── plugins
│ └── vant.js
├── router
│ └── index.js
├── service
│ └── api
│ │ ├── ajax.js
│ │ └── index.js
├── store
│ ├── actions.js
│ ├── index.js
│ ├── mutations-type.js
│ ├── mutations.js
│ └── state.js
├── style
│ └── common.less
└── views
│ ├── cart
│ ├── Cart.vue
│ └── images
│ │ ├── detail1.jpg
│ │ └── shop-icon.png
│ ├── category
│ ├── Category.vue
│ └── components
│ │ ├── ContentView.vue
│ │ ├── Header.vue
│ │ └── ProductItem.vue
│ ├── dashboard
│ └── DashBoard.vue
│ ├── home
│ ├── Home.vue
│ └── components
│ │ ├── flashSale
│ │ ├── FlashSale.vue
│ │ └── FlashSaleItem.vue
│ │ ├── header
│ │ └── Header.vue
│ │ ├── markPage
│ │ └── MarkPage.vue
│ │ ├── nav
│ │ └── Nav.vue
│ │ ├── sowing
│ │ └── Sowing.vue
│ │ └── youLike
│ │ ├── YouLike.vue
│ │ └── YouLikeItem.vue
│ ├── login
│ ├── Login.vue
│ ├── SelectLogin.vue
│ └── images
│ │ ├── captcha.svg
│ │ ├── hide_pwd.png
│ │ ├── logo_bg.png
│ │ └── show_pwd.png
│ ├── mine
│ ├── Mine.vue
│ ├── children
│ │ ├── MineOrder.vue
│ │ ├── UserCenter.vue
│ │ └── components
│ │ │ └── MineOrderItem.vue
│ └── images
│ │ └── avator.jpg
│ └── order
│ ├── Order.vue
│ ├── children
│ ├── MyAddress.vue
│ ├── OrderDetail.vue
│ └── children
│ │ ├── AddAddress.vue
│ │ └── EditAddress.vue
│ └── images
│ ├── detail1.jpg
│ └── shop-icon.png
├── tests
└── unit
│ └── example.spec.js
└── vue.config.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-shop
2 | 基于Vue + VantUI 做的生鲜商城demo 线上体验地址: http://www.lrboy.live
3 |
4 | # 技术栈
5 | ***
6 | ### vue2.6 + vue-router + vuex + axios + vantUI + ES6 + less
7 |
8 | ## 预览
9 | ***
10 | 
11 | 
12 | 
13 | 
14 | 
15 | 
16 |
17 | ## 经验
18 | ***
19 | ##### 1.用一个Pubsub-js发布订阅模式插件,可以在任意组件中通信,无需关注父子子孙等组件的通信问题
20 | ##### 2.页面中的返回顶部以及轮播图插件其实可以用其他插件更方便,本项目用的swiper以及scroll配置有点麻烦
21 |
22 | ## Build Setup
23 | ***
24 | ```
25 | # install dependencies
26 | npm install
27 |
28 | # serve with hot reload at localhost:1322
29 | npm run dev
30 |
31 | # build for production with minification
32 | npm run build
33 | ```
34 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/app'
4 | ],
5 | plugins: [
6 | ['import', {
7 | libraryName: 'vant',
8 | libraryDirectory: 'es',
9 | style: true
10 | }, 'vant']
11 | ]
12 | };
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lk-shop",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "test:unit": "vue-cli-service test:unit"
9 | },
10 | "dependencies": {
11 | "axios": "^0.19.0",
12 | "better-scroll": "^1.15.2",
13 | "core-js": "^2.6.5",
14 | "fastclick": "^1.0.6",
15 | "moment": "^2.24.0",
16 | "pubsub-js": "^1.7.0",
17 | "vant": "^2.1.1",
18 | "vue": "^2.6.10",
19 | "vue-awesome-swiper": "^3.1.3",
20 | "vue-qriously": "^1.1.1",
21 | "vue-router": "^3.0.3",
22 | "vuex": "^3.0.1"
23 | },
24 | "devDependencies": {
25 | "@vue/cli-plugin-babel": "^3.9.0",
26 | "@vue/cli-plugin-unit-mocha": "^3.9.0",
27 | "@vue/cli-service": "^3.9.0",
28 | "@vue/test-utils": "1.0.0-beta.29",
29 | "babel-plugin-import": "^1.12.0",
30 | "chai": "^4.1.2",
31 | "less": "^3.0.4",
32 | "less-loader": "^4.1.0",
33 | "vue-template-compiler": "^2.6.10"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 生鲜商城
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/screenshot/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/screenshot/1.png
--------------------------------------------------------------------------------
/screenshot/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/screenshot/2.png
--------------------------------------------------------------------------------
/screenshot/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/screenshot/3.png
--------------------------------------------------------------------------------
/screenshot/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/screenshot/4.png
--------------------------------------------------------------------------------
/screenshot/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/screenshot/5.png
--------------------------------------------------------------------------------
/screenshot/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/screenshot/6.png
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
--------------------------------------------------------------------------------
/src/config/filters.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | // 人民币过滤器
4 | Vue.filter('moneyFormat', (value)=>{
5 | return '¥' + Number(value).toFixed(2);
6 | });
--------------------------------------------------------------------------------
/src/config/global.js:
--------------------------------------------------------------------------------
1 |
2 | export const showBack = (callback)=>{
3 | // 1. 变量
4 | let docB = document.documentElement || document.body;
5 | let oldScrollTop, requestFrame;
6 |
7 | // 2. 监听滚动
8 | document.addEventListener('scroll', ()=>{
9 | showBackFunc();
10 | }, false);
11 |
12 | // 3. 监听触摸
13 | document.addEventListener('touchstart', ()=>{
14 | showBackFunc();
15 | },{passive:true});
16 |
17 | document.addEventListener('touchmove', ()=>{
18 | showBackFunc();
19 | },{passive:true});
20 |
21 | document.addEventListener('touchend', ()=>{
22 | oldScrollTop = docB.scrollTop;
23 | moveEnd();
24 | },{passive:true});
25 |
26 | const moveEnd = ()=>{
27 | /*
28 | 屏幕刷新率 60HZ 1000 / 60 = 16.7ms
29 | 屏幕刷新率 75HZ 1000 / 75 = 13.3ms
30 |
31 | 1) 函数节流
32 | */
33 | requestFrame = requestAnimationFrame(()=>{
34 | if(docB.scrollTop !== oldScrollTop){
35 | oldScrollTop = docB.scrollTop;
36 | moveEnd();
37 | }else {
38 | cancelAnimationFrame(requestFrame);
39 | }
40 | showBackFunc();
41 | });
42 | };
43 |
44 |
45 | // 判断是否到达目标点
46 | const showBackFunc = ()=>{
47 | // console.log(docB.scrollTop);
48 | if(docB.scrollTop >= 200){
49 | callback(true);
50 | }else {
51 | callback(false);
52 | }
53 | }
54 | };
55 |
56 | /**
57 | * 获取style样式
58 | */
59 | export const getStyle = (element, attr, NumberMode = 'int') => {
60 | let target;
61 | // scrollTop 获取方式不同,没有它不属于style,而且只有document.body才能用
62 | if (attr === 'scrollTop') {
63 | target = element.scrollTop;
64 | }else if(element.currentStyle){
65 | target = element.currentStyle[attr];
66 | }else{
67 | target = document.defaultView.getComputedStyle(element,null)[attr];
68 | }
69 | //在获取 opactiy 时需要获取小数 parseFloat
70 | return NumberMode === 'float' ? parseFloat(target) : parseInt(target);
71 | };
72 |
73 |
74 | /**
75 | * 运动效果
76 | * @param {HTMLElement} element 运动对象,必选
77 | * @param {JSON} target 属性:目标值,必选
78 | * @param {number} duration 运动时间,可选
79 | * @param {string} mode 运动模式,可选
80 | * @param {function} callback 可选,回调函数,链式动画
81 | */
82 | export const animate = (element, target, duration = 400, mode = 'ease-out', callback) => {
83 | clearInterval(element.timer);
84 | //判断不同参数的情况
85 | if (duration instanceof Function) {
86 | callback = duration;
87 | duration = 400;
88 | }else if(duration instanceof String){
89 | mode = duration;
90 | duration = 400;
91 | }
92 |
93 | //判断不同参数的情况
94 | if (mode instanceof Function) {
95 | callback = mode;
96 | mode = 'ease-out';
97 | }
98 |
99 | //获取dom样式
100 | const attrStyle = attr => {
101 | if (attr === "opacity") {
102 | return Math.round(getStyle(element, attr, 'float') * 100);
103 | } else {
104 | return getStyle(element, attr);
105 | }
106 | };
107 | //根字体大小,需要从此将 rem 改成 px 进行运算
108 | const rootSize = parseFloat(document.documentElement.style.fontSize);
109 |
110 | const unit = {};
111 | const initState = {};
112 |
113 | //获取目标属性单位和初始样式值
114 | Object.keys(target).forEach(attr => {
115 | if (/[^\d^\.]+/gi.test(target[attr])) {
116 | unit[attr] = target[attr].match(/[^\d^\.]+/gi)[0] || 'px';
117 | }else{
118 | unit[attr] = 'px';
119 | }
120 | initState[attr] = attrStyle(attr);
121 | });
122 |
123 | //去掉传入的后缀单位
124 | Object.keys(target).forEach(attr => {
125 | if (unit[attr] === 'rem') {
126 | target[attr] = Math.ceil(parseInt(target[attr])*rootSize);
127 | }else{
128 | target[attr] = parseInt(target[attr]);
129 | }
130 | });
131 |
132 |
133 | let flag = true; //假设所有运动到达终点
134 | const remberSpeed = {};//记录上一个速度值,在ease-in模式下需要用到
135 | element.timer = setInterval(() => {
136 | Object.keys(target).forEach(attr => {
137 | let iSpeed = 0; //步长
138 | let status = false; //是否仍需运动
139 | let iCurrent = attrStyle(attr) || 0; //当前元素属性址
140 | let speedBase = 0; //目标点需要减去的基础值,三种运动状态的值都不同
141 | let intervalTime; //将目标值分为多少步执行,数值越大,步长越小,运动时间越长
142 | switch(mode){
143 | case 'ease-out':
144 | speedBase = iCurrent;
145 | intervalTime = duration*5/400;
146 | break;
147 | case 'linear':
148 | speedBase = initState[attr];
149 | intervalTime = duration*20/400;
150 | break;
151 | case 'ease-in':
152 | let oldspeed = remberSpeed[attr] || 0;
153 | iSpeed = oldspeed + (target[attr] - initState[attr])/duration;
154 | remberSpeed[attr] = iSpeed;
155 | break;
156 | default:
157 | speedBase = iCurrent;
158 | intervalTime = duration*5/400;
159 | }
160 | if (mode !== 'ease-in') {
161 | iSpeed = (target[attr] - speedBase) / intervalTime;
162 | iSpeed = iSpeed > 0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
163 | }
164 | //判断是否达步长之内的误差距离,如果到达说明到达目标点
165 | switch(mode){
166 | case 'ease-out':
167 | status = iCurrent !== target[attr];
168 | break;
169 | case 'linear':
170 | status = Math.abs(Math.abs(iCurrent) - Math.abs(target[attr])) > Math.abs(iSpeed);
171 | break;
172 | case 'ease-in':
173 | status = Math.abs(Math.abs(iCurrent) - Math.abs(target[attr])) > Math.abs(iSpeed);
174 | break;
175 | default:
176 | status = iCurrent !== target[attr];
177 | }
178 |
179 | if (status) {
180 | flag = false;
181 | //opacity 和 scrollTop 需要特殊处理
182 | if (attr === "opacity") {
183 | element.style.filter = "alpha(opacity:" + (iCurrent + iSpeed) + ")";
184 | element.style.opacity = (iCurrent + iSpeed) / 100;
185 | } else if (attr === 'scrollTop') {
186 | element.scrollTop = iCurrent + iSpeed;
187 | }else{
188 | element.style[attr] = iCurrent + iSpeed + 'px';
189 | }
190 | } else {
191 | flag = true;
192 | }
193 |
194 | if (flag) {
195 | clearInterval(element.timer);
196 | if (callback) {
197 | callback();
198 | }
199 | }
200 | })
201 | }, 20);
202 | };
203 |
204 | /*
205 | 本地化存储
206 | */
207 | export const setStore = (name, content) =>{
208 | if(!name) return;
209 | if(typeof content !== 'string'){
210 | content = JSON.stringify(content);
211 | }
212 | window.localStorage.setItem(name, content);
213 | };
214 |
215 | /*
216 | 本地化获取
217 | */
218 | export const getStore = (name)=>{
219 | if(!name) return;
220 | return window.localStorage.getItem(name);
221 | };
222 |
223 | /*
224 | 本地化删除
225 | */
226 | export const removeStore = (name)=>{
227 | if(!name) return;
228 | return window.localStorage.removeItem(name);
229 | };
--------------------------------------------------------------------------------
/src/config/rem.js:
--------------------------------------------------------------------------------
1 | (function (doc, win) {
2 | var docEl = doc.documentElement,
3 | resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
4 | recalc = function() {
5 | var clientWidth = docEl.clientWidth;
6 | if (!clientWidth) return;
7 | docEl.style.fontSize = 15 * (clientWidth / 320) + 'px';
8 | };
9 | if (!doc.addEventListener) return;
10 | win.addEventListener(resizeEvt, recalc, false);
11 | doc.addEventListener('DOMContentLoaded', recalc, false);
12 | })(document, window);
--------------------------------------------------------------------------------
/src/images/tabbar/category_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/images/tabbar/category_default.png
--------------------------------------------------------------------------------
/src/images/tabbar/category_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/images/tabbar/category_selected.png
--------------------------------------------------------------------------------
/src/images/tabbar/home_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/images/tabbar/home_default.png
--------------------------------------------------------------------------------
/src/images/tabbar/home_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/images/tabbar/home_selected.png
--------------------------------------------------------------------------------
/src/images/tabbar/mine_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/images/tabbar/mine_default.png
--------------------------------------------------------------------------------
/src/images/tabbar/mine_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/images/tabbar/mine_selected.png
--------------------------------------------------------------------------------
/src/images/tabbar/shoppingcart_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/images/tabbar/shoppingcart_default.png
--------------------------------------------------------------------------------
/src/images/tabbar/shoppingcart_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/images/tabbar/shoppingcart_selected.png
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router/index'
4 | import store from './store/index'
5 |
6 | // 1. 引入fastClick
7 | import FastClick from 'fastclick'
8 | if ('addEventListener' in document) {
9 | document.addEventListener('DOMContentLoaded', function() {
10 | FastClick.attach(document.body);
11 | }, false);
12 | }
13 |
14 | // 2. 引入全局的样式
15 | import '@/style/common.less'
16 |
17 | // 3. 引入全局UI组件库-vant
18 | import '@/plugins/vant'
19 |
20 | // 4. 引入rem
21 | import '@/config/rem.js'
22 |
23 | // 5. 引入全局过滤器
24 | import '@/config/filters'
25 |
26 | // 6. 配置二维码插件
27 | import VueQriously from 'vue-qriously'
28 | Vue.use(VueQriously);
29 |
30 | new Vue({
31 | router,
32 | store,
33 | render: h => h(App)
34 | }).$mount('#app');
35 |
--------------------------------------------------------------------------------
/src/plugins/vant.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | // 1. 底部的导航
4 | import { Tabbar, TabbarItem } from 'vant';
5 | Vue.use(Tabbar).use(TabbarItem);
6 |
7 | // 2. Loading
8 | import { Loading } from 'vant';
9 | Vue.use(Loading);
10 |
11 | //3. 图片懒加载
12 | import { Image } from 'vant';
13 | Vue.use(Image);
14 |
15 | // 4. 提示
16 | import { Toast } from 'vant';
17 | Vue.use(Toast);
18 |
19 | // 5. 蒙版提示
20 | import { Dialog } from 'vant';
21 | Vue.use(Dialog);
22 |
23 | // 6. 导航栏
24 | import { NavBar } from 'vant';
25 | Vue.use(NavBar);
26 |
27 | // 7. 地址
28 | import { ContactCard, ContactList, ContactEdit } from 'vant';
29 | Vue.use(ContactCard).use(ContactList).use(ContactEdit);
30 |
31 | import { AddressList } from 'vant';
32 | Vue.use(AddressList);
33 |
34 | import { AddressEdit } from 'vant';
35 | Vue.use(AddressEdit);
36 |
37 | // 8. 单元格
38 | import { Cell, CellGroup } from 'vant';
39 | Vue.use(Cell).use(CellGroup);
40 |
41 | // 9. 提交订单
42 | import { SubmitBar } from 'vant';
43 | Vue.use(SubmitBar);
44 |
45 | // 10. 宫格
46 | import { Grid, GridItem } from 'vant';
47 | Vue.use(Grid).use(GridItem);
48 |
49 | // 11. 弹出层
50 | import { Popup } from 'vant';
51 | Vue.use(Popup);
52 |
53 | // 12. 日期组件
54 | import { DatetimePicker } from 'vant';
55 | Vue.use(DatetimePicker);
56 |
57 | // 13. 卡片选项
58 | import { Card } from 'vant';
59 | Vue.use(Card);
60 |
61 | // 14. 选项卡
62 | import { Tab, Tabs } from 'vant';
63 | Vue.use(Tab).use(Tabs);
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 |
4 | // 引入一级组件
5 | import DashBoard from './../views/dashboard/DashBoard'
6 | const Home = ()=> import('./../views/home/Home.vue');
7 | const Category = ()=> import('./../views/category/Category.vue');
8 | const Cart = ()=> import('./../views/cart/Cart.vue');
9 |
10 | // 用户中心
11 | const Mine = ()=> import('./../views/mine/Mine.vue');
12 | const UserCenter = ()=> import('./../views/mine/children/UserCenter');
13 | const MineOrder = ()=> import('./../views/mine/children/MineOrder');
14 |
15 | // 引入组件相关
16 | const Order = ()=> import('./../views/order/Order.vue');
17 | const OrderDetail = ()=> import('./../views/order/children/OrderDetail.vue');
18 | const MyAddress = ()=> import('./../views/order/children/MyAddress.vue');
19 | const AddAddress = ()=> import('./../views/order/children/children/AddAddress.vue');
20 | const EditAddress = ()=> import('./../views/order/children/children/EditAddress.vue');
21 |
22 | // 引入登录
23 | const Login = ()=> import('./../views/login/Login.vue');
24 |
25 |
26 | Vue.use(Router);
27 |
28 | export default new Router({
29 | routes: [
30 | {path: '/', redirect: '/dashboard'},
31 | {
32 | path: '/dashboard',
33 | name: 'dashboard',
34 | component: DashBoard,
35 | children: [
36 | {path: '/dashboard', redirect: '/dashboard/home'},
37 | {path: 'home', name:'home', component: Home, meta: { keepAlive: true}},
38 | {path: 'category', name:'category', component: Category, meta: { keepAlive: true}},
39 | {path: 'cart', name:'cart', component: Cart},
40 | {
41 | path: 'mine',
42 | name:'mine',
43 | component: Mine,
44 | children: [
45 | {path: 'userCenter', component: UserCenter}, // 用户中心
46 | {path: 'mineOrder', component: MineOrder} // 我的订单
47 | ]
48 | }
49 | ]
50 | },
51 | {
52 | path: '/confirmOrder',
53 | name: 'order',
54 | component: Order,
55 | children: [
56 | {
57 | path:'myAddress',
58 | name: 'myAddress',
59 | component: MyAddress,
60 | children: [
61 | // 添加地址
62 | {path: 'addAddress', name:'addAddress', component: AddAddress},
63 | {path: 'editAddress', name:'editAddress', component: EditAddress},
64 | ]
65 | },
66 | {
67 | path: 'orderDetail',
68 | name: 'orderDetail',
69 | component: OrderDetail
70 | }
71 | ]
72 | },
73 | {path: '/login', name: 'login', component: Login}
74 | ]
75 | });
--------------------------------------------------------------------------------
/src/service/api/ajax.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | export default function ajax(url = '', params = {}, type = 'GET') {
4 | // 1. 变量
5 | let promise;
6 |
7 | // 2. 返回一个promise对象
8 | return new Promise((resolve, reject) => {
9 | // 2.1 判断请求的类型
10 | if (type.toUpperCase() === 'GET') { // get请求
11 | // 2.2 拼接字符串
12 | let paramsStr = '';
13 | // 2.3 遍历
14 | Object.keys(params).forEach(key => {
15 | paramsStr += key + '=' + params[key] + '&';
16 | });
17 | // 2.4 过滤最后的&
18 | /*
19 | 注意:为了防止请求缓存,在尾部加了时间戳
20 | */
21 | if (paramsStr) {
22 | paramsStr = paramsStr.substr(0, paramsStr.lastIndexOf('&'));
23 | // 2.5 拼接完整路径
24 | if(url.indexOf('47.98.157.152') === -1) {
25 | url += '?' + paramsStr + '&itlike=' + randomCode(20);
26 | }else {
27 | url += '?' + paramsStr;
28 | }
29 | }else {
30 | if(url.indexOf('47.98.157.152') === -1){
31 | url += '?itlike=' + randomCode(20)
32 | }
33 | }
34 | // 2.6 发起get请求
35 | promise = axios.get(url);
36 | } else if (type.toUpperCase() === 'POST') { // post请求
37 | // 2.7 发起post请求
38 | promise = axios.post(url, params);
39 | }
40 | // 2.8 处理结果并返回
41 | promise.then((response) => {
42 | resolve(response.data);
43 | }).catch(error => {
44 | reject(error);
45 | })
46 | });
47 |
48 | }
49 |
50 | /*生成指定长度的随机数*/
51 | function randomCode(length) {
52 | let chars = ['0','1','2','3','4','5','6','7','8','9'];
53 | let result = "";
54 | for(let i = 0; i < length ; i ++) {
55 | let index = Math.ceil(Math.random()*9);
56 | result += chars[index];
57 | }
58 | return result;
59 | }
--------------------------------------------------------------------------------
/src/service/api/index.js:
--------------------------------------------------------------------------------
1 | import ajax from './ajax'
2 |
3 |
4 | // 1. 定义基础路径
5 | const BASE_URL = 'http://demo.itlike.com/web/xlmc';
6 |
7 | export const getHomeData = () => ajax(BASE_URL + '/api/homeApi');
8 | export const getCategories = () => ajax(BASE_URL + '/api/homeApi/categories');
9 | export const getCategoriesDetail = (preParams) => ajax(BASE_URL + '/api/homeApi/categoriesdetail' + preParams);
10 |
11 |
12 |
13 |
14 |
15 | // 2. 用户中心接口
16 | // http://localhost:3000/web/xlmc/api/send_code
17 | const LOCAL_BASE_URL = 'http://demo.itlike.com/web/xlmc';
18 | // const LOCAL_BASE_URL = '/api';
19 |
20 | // 2.1 获取短信验证码(GET)
21 | export const getPhoneCode = (phone) => ajax(LOCAL_BASE_URL + '/api/send_code', { phone });
22 | // 2.2 手机验证码登录(POST)
23 | export const phoneCodeLogin = (phone, code) => ajax(LOCAL_BASE_URL + '/api/login_code', { phone, code }, 'POST');
24 | // 2.3 用户名和密码登录(POST)
25 | export const pwdLogin = (user_name, user_pwd, captcha) => ajax(LOCAL_BASE_URL + '/api/login_pwd', { user_name, user_pwd, captcha }, 'POST');
26 | // 2.4 自动登录
27 | export const getUserInfo = () => ajax(LOCAL_BASE_URL + '/api/userinfo');
28 | // 2.5 退出登录
29 | export const getLogOut = () => ajax(LOCAL_BASE_URL + '/api/logout');
30 |
31 |
32 |
33 |
34 | // 3. 购物车接口
35 | /*
36 | 3.1 添加商品
37 | 请求方式:POST
38 | 参数:{goods_id: String, goods_name: String, goods_price: Number, small_image: String}
39 | */
40 | export const addGoodsToCart = (user_id, goods_id, goods_name, goods_price, small_image) => ajax(LOCAL_BASE_URL + '/api/cart/add', { user_id, goods_id, goods_name, goods_price, small_image }, 'POST');
41 |
42 | // 3.2 获取当前用户购物车中的商品
43 | export const getGoodsCart = (user_id) => ajax(LOCAL_BASE_URL + '/api/cart/search/' + user_id);
44 |
45 | // 3.3 修改购物车商品数量
46 | export const changeCartNum = (user_id, goods_id, type) => ajax(LOCAL_BASE_URL + '/api/cart/num', { user_id, goods_id, type }, 'POST');
47 |
48 | // 3.4 删除当前用户购物车中所有的商品
49 | export const clearAllCart = (user_id) => ajax(LOCAL_BASE_URL + '/api/cart/clear/' + user_id);
50 |
51 | // 3.5 单个商品的选中和取消选中
52 | export const singerGoodsSelect = (user_id, goods_id) => ajax(LOCAL_BASE_URL + '/api/cart/singer_select', { user_id, goods_id }, 'POST');
53 |
54 | // 3.6 所有商品的选中和取消选中
55 | export const allGoodsSelect = (user_id, flag) => ajax(LOCAL_BASE_URL + '/api/cart/all_select', { user_id, flag }, 'POST');
56 |
57 | // 3.7 查询所有已经被选中的商品
58 | export const getAllSelectedGoods = (user_id) => ajax(LOCAL_BASE_URL + '/api/cart/selected/' + user_id);
59 |
60 | // 3.8 删除已经生成订单的商品
61 | export const delAllSelectedGoods = (user_id) => ajax(LOCAL_BASE_URL + '/api/cart/del_checked/' + user_id);
62 |
63 |
64 | // 4. 地址接口
65 |
66 | // 4.1 获取当前用户的地址
67 | export const getUserAddress = (user_id) => ajax(LOCAL_BASE_URL + '/api/address/search/' + user_id);
68 |
69 | // 4.2 添加新的地址
70 | export const addUserAddress = (user_id, address_name, address_phone, address_area, address_area_detail, address_post_code, address_tag, province, city, county, areaCode) => ajax(LOCAL_BASE_URL + '/api/address/add', { user_id, address_name, address_phone, address_area, address_area_detail, address_post_code, address_tag, province, city, county, areaCode }, 'POST');
71 |
72 | // 4.3 编辑用户的地址
73 | export const changeUserAddress = (address_id, user_id, address_name, address_phone, address_area, address_area_detail, address_post_code, address_tag, province, city, county, areaCode) => ajax(LOCAL_BASE_URL + '/api/address/edit', { address_id, user_id, address_name, address_phone, address_area, address_area_detail, address_post_code, address_tag, province, city, county, areaCode }, 'POST');
74 |
75 | // 4.4 删除用户的地址
76 | export const delUserAddress = (address_id) => ajax(LOCAL_BASE_URL + '/api/address/del/' + address_id);
77 |
78 | // 4.5 获取单条地址
79 | export const getCurrentUserAddress = (user_id, address_id) => ajax(LOCAL_BASE_URL + '/api/address/one', { user_id, address_id }, 'POST');
80 |
81 | // 5. 订单接口
82 | // 5.1 提交订单
83 | export const postOrder = (user_id, address_id, arrive_time, cart_shop, notice, shop_price, dis_price) => ajax(LOCAL_BASE_URL + '/api/order/post', { user_id, address_id, arrive_time, cart_shop, notice, shop_price, dis_price }, 'POST');
84 |
85 | // 5.2 订单支付成功
86 | export const orderPaySuccess = (user_id, order_id) => ajax(LOCAL_BASE_URL + '/api/order/change_status', { user_id, order_id }, 'POST');
87 |
88 | // 5.3 查询订单
89 | export const getOrder = (user_id, status) => ajax(LOCAL_BASE_URL + '/api/order/get', { user_id, status }, 'POST'); // pay will
90 |
91 |
92 | // 6. 微信支付接口部署
93 |
94 | const PAY_URL = 'http://47.98.157.152/WXPayProject/pay';
95 | // const PAY_URL = '/pay';
96 | // 6.1 获取支付的URL
97 | export const getWXCode = (outTradeNo, totalFee) => ajax(PAY_URL + '/createNative.do', { outTradeNo, totalFee });
98 | // 6.2 查询是否支付成功
99 | export const queryPayStatus = (out_trade_no) => ajax(PAY_URL + '/queryPayStatus.do', { out_trade_no });
--------------------------------------------------------------------------------
/src/store/actions.js:
--------------------------------------------------------------------------------
1 | import {USER_INFO} from './mutations-type'
2 | import {getStore} from './../config/global'
3 | import {getUserInfo} from './../service/api/index'
4 |
5 | export default {
6 | // 1. 同步用户信息
7 | syncUserInfo({commit}, userInfo) {
8 | commit(USER_INFO, {userInfo})
9 | },
10 |
11 | // 2. 自动登录
12 | async reqUserInfo({commit}){
13 | // 2.1 从本地获取数据
14 | let userInfo = JSON.parse(getStore('userInfo'));
15 | if(userInfo){
16 | commit(USER_INFO, {userInfo});
17 | }else {
18 | // 2.2 从服务器端验证
19 | let result = await getUserInfo();
20 | // console.log(result);
21 | if(200 === result.success_code){
22 | commit(USER_INFO, {userInfo: result.data});
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import state from './state'
5 | import mutations from './mutations'
6 | import actions from './actions'
7 |
8 | Vue.use(Vuex);
9 |
10 | export default new Vuex.Store({
11 | state,
12 | mutations,
13 | actions
14 | })
--------------------------------------------------------------------------------
/src/store/mutations-type.js:
--------------------------------------------------------------------------------
1 | export const ADD_GOODS = 'ADD_GOODS'; // 添加商品到购物车
2 | export const INIT_SHOP_CART = 'INIT_SHOP_CART'; //初始化购物车
3 | export const REDUCE_CART = 'REDUCE_CART'; // 把商品移出购物车
4 | export const SELECTED_SINGER_GOODS = 'SELECTED_SINGER_GOODS'; // 单个商品的选中和取消选中
5 | export const SELECTED_All_GOODS = 'SELECTED_All_GOODS'; // 全选和取消全选
6 | export const CLEAR_CART = 'CLEAR_CART'; // 清空购物车
7 |
8 | export const USER_INFO = 'USER_INFO'; // 保存用户信息
9 | export const INIT_USER_INFO = 'INIT_USER_INFO'; // 初始化用户数据
10 | export const RESET_USER_INFO = 'RESET_USER_INFO'; // 重置用户数据
11 |
12 |
--------------------------------------------------------------------------------
/src/store/mutations.js:
--------------------------------------------------------------------------------
1 | import {
2 | ADD_GOODS,
3 | INIT_SHOP_CART,
4 | REDUCE_CART,
5 | SELECTED_SINGER_GOODS,
6 | SELECTED_All_GOODS,
7 | CLEAR_CART,
8 | USER_INFO,
9 | INIT_USER_INFO,
10 | RESET_USER_INFO
11 | } from './mutations-type'
12 |
13 | import { getStore, removeStore, setStore } from './../config/global'
14 | import Vue from 'vue'
15 |
16 | export default {
17 | // 1. 往购物车中添加数据
18 | [ADD_GOODS](state, { goodsId, goodsName, smallImage, goodsPrice }) {
19 | let shopCart = state.shopCart;
20 | // 1.1 判断商品是否存在
21 | if (shopCart[goodsId]) { // 存在
22 | shopCart[goodsId]['num']++;
23 | } else { // 不存在
24 | shopCart[goodsId] = {
25 | "num": 1,
26 | "id": goodsId,
27 | "name": goodsName,
28 | "small_image": smallImage,
29 | "price": goodsPrice,
30 | "checked": true
31 | }
32 | }
33 | // 1.2 产生新对象
34 | state.shopCart = {...shopCart };
35 | // 1.3 存入本地
36 | setStore('shopCart', state.shopCart);
37 | },
38 |
39 | // 2. 页面初始化,获取购物车的数据(本地)
40 | [INIT_SHOP_CART](state) {
41 | let initCart = getStore('shopCart');
42 | if (initCart) {
43 | state.shopCart = JSON.parse(initCart);
44 | }
45 | },
46 |
47 | // 3. 把商品移出购物车
48 | [REDUCE_CART](state, { goodsId }) {
49 | let shopCart = state.shopCart;
50 | let goods = shopCart[goodsId];
51 | if (goods) { // 找到该商品
52 | if (goods['num'] > 0) {
53 | goods['num']--;
54 | // 3.1 判断是否只有0个
55 | if (goods['num'] === 0) {
56 | delete shopCart[goodsId];
57 | }
58 | } else {
59 | goods = null;
60 | }
61 | // 3.2 同时数据
62 | state.shopCart = {...shopCart };
63 | setStore('shopCart', state.shopCart);
64 | }
65 | },
66 |
67 | // 4. 单个商品选中和取消选中
68 | [SELECTED_SINGER_GOODS](state, { goodsId }) {
69 | let shopCart = state.shopCart;
70 | let goods = shopCart[goodsId];
71 | if (goods) {
72 | if (goods.checked) { // 存在该属性
73 | goods.checked = !goods.checked;
74 | } else {
75 | Vue.set(goods, 'checked', true);
76 | // goods.checked = true;
77 | }
78 | // 4.1 同时数据
79 | state.shopCart = {...shopCart };
80 | setStore('shopCart', state.shopCart);
81 | }
82 | },
83 |
84 | // 5. 所有商品选中和取消选中
85 | [SELECTED_All_GOODS](state, { isSelected }) {
86 | let shopCart = state.shopCart;
87 | Object.values(shopCart).forEach((goods, index) => {
88 | if (goods.checked) { // 存在该属性
89 | goods.checked = !isSelected;
90 | } else {
91 | Vue.set(goods, 'checked', !isSelected);
92 | }
93 | });
94 | state.shopCart = {...shopCart };
95 | },
96 |
97 | // 6. 清空购物车
98 | [CLEAR_CART](state) {
99 | state.shopCart = null;
100 | state.shopCart = {...state.shopCart };
101 | setStore('shopCart', state.shopCart);
102 | },
103 |
104 | // 7. 保存用户信息报本地
105 | [USER_INFO](state, { userInfo }) {
106 | state.userInfo = userInfo;
107 | setStore('userInfo', state.userInfo);
108 | },
109 |
110 | // 8. 获取用户信息
111 | [INIT_USER_INFO](state) {
112 | // 8.1 获取用户信息
113 | let userInfo = getStore('userInfo');
114 | // 8.2 判断
115 | if (userInfo) {
116 | state.userInfo = JSON.parse(userInfo);
117 | }
118 | },
119 |
120 | // 9. 退出登录
121 | [RESET_USER_INFO](state) {
122 | state.userInfo = {};
123 | removeStore('userInfo');
124 | }
125 | }
--------------------------------------------------------------------------------
/src/store/state.js:
--------------------------------------------------------------------------------
1 | export default {
2 | // 购物车的商品
3 | shopCart: {},
4 | // 用户信息
5 | userInfo: {}
6 | }
--------------------------------------------------------------------------------
/src/style/common.less:
--------------------------------------------------------------------------------
1 | body, div, span, header, footer, nav, section, aside, article, ul, dl, dt, dd, li, a, p, h1, h2, h3, h4,h5, h6, i, b, textarea, button, input, select, figure, figcaption{
2 | padding: 0;
3 | margin: 0;
4 | list-style: none;
5 | font-style: normal;
6 | text-decoration: none;
7 | border: none;
8 | font-weight: normal;
9 | font-family: "Microsoft Yahei", serif;
10 | box-sizing: border-box;
11 | -webkit-tap-highlight-color:transparent;
12 | -webkit-font-smoothing: antialiased;
13 | &:hover{
14 | outline: none;
15 | }
16 | }
17 |
18 | html,body{
19 | height: 100%;
20 | width: 100%;
21 | background-color: #F5F5F5;
22 | }
23 |
24 | /* 根据dpr显示2x图/3x图 */
25 | .bg-image(@url){
26 | background-image:~"url('@{url}@2x.png')";
27 | @media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3){
28 | background-image:~"url('@{url}@3x.png')";
29 | }
30 | }
31 |
32 | input,textarea {
33 | border: 0;
34 | -webkit-appearance: none;
35 | }
--------------------------------------------------------------------------------
/src/views/cart/Cart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
22 |
23 |
![]()
24 |
25 |
26 |
{{goods.name}}
27 |
28 |
{{goods.price | moneyFormat}}
29 |
30 | -
31 |
32 | +
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
48 |
49 |
全选
50 |
51 | 合计:{{totalPrice | moneyFormat}}
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
209 |
210 |
--------------------------------------------------------------------------------
/src/views/cart/images/detail1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/views/cart/images/detail1.jpg
--------------------------------------------------------------------------------
/src/views/cart/images/shop-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/views/cart/images/shop-icon.png
--------------------------------------------------------------------------------
/src/views/category/Category.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | -
18 | {{cate.name}}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
31 | 正在拼命加载中,请稍后…
32 |
33 |
34 |
35 |
36 |
126 |
127 |
--------------------------------------------------------------------------------
/src/views/category/components/ContentView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
{{categoriesDetail.name}}
8 |
9 |
10 |
11 |
12 |
13 |
25 |
26 |
--------------------------------------------------------------------------------
/src/views/category/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
17 |
18 |
--------------------------------------------------------------------------------
/src/views/category/components/ProductItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
![]()
7 |
8 |
9 |
10 | {{product.product_name}}
11 |
12 |
13 | {{product.spec}}
14 |
15 |
18 |
19 |
20 |
21 | {{product.price | moneyFormat}}
22 |
23 |
24 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
93 |
94 |
--------------------------------------------------------------------------------
/src/views/dashboard/DashBoard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 首页
6 |
7 |
8 |
9 | 分类
10 |
11 |
12 |
13 | 购物车
14 |
15 |
16 |
17 | 我的
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
119 |
120 |
--------------------------------------------------------------------------------
/src/views/home/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 | 正在拼命加载中…
23 |
24 |
25 |
26 |
27 |
150 |
151 |
--------------------------------------------------------------------------------
/src/views/home/components/flashSale/FlashSale.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
限时抢购
5 |
07:00场
6 |
已结束
7 |
更多
8 |
9 |
10 |
15 |
16 |
17 |
18 |
19 |
31 |
32 |
--------------------------------------------------------------------------------
/src/views/home/components/flashSale/FlashSaleItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
![]()
6 |
7 |
8 |
{{product.name}}
9 |
{{product.origin_price | moneyFormat}}
10 |
11 |
{{product.price | moneyFormat}}
12 |
13 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
48 |
49 |
--------------------------------------------------------------------------------
/src/views/home/components/header/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
{{city || '上海撩课大厦'}}
9 |
13 |
14 |
25 |
26 |
27 |
28 |
60 |
61 |
--------------------------------------------------------------------------------
/src/views/home/components/markPage/MarkPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
21 |
22 |
--------------------------------------------------------------------------------
/src/views/home/components/nav/Nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
![]()
6 |
7 |
10 |
11 |
12 |
13 |
14 |
22 |
23 |
--------------------------------------------------------------------------------
/src/views/home/components/sowing/Sowing.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
61 |
62 |
--------------------------------------------------------------------------------
/src/views/home/components/youLike/YouLike.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
29 |
30 |
--------------------------------------------------------------------------------
/src/views/home/components/youLike/YouLikeItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {{product.name}}
16 |
17 |
20 |
21 |
22 |
23 |
24 | {{product.price | moneyFormat}}
25 |
26 |
{{product.origin_price | moneyFormat}}
27 |
28 |
29 |
30 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
65 |
66 |
--------------------------------------------------------------------------------
/src/views/login/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
68 |
69 |
70 |
218 |
219 |
--------------------------------------------------------------------------------
/src/views/login/SelectLogin.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |

5 |
6 |
选择登录方式
7 |
手机登录
8 |
9 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/src/views/login/images/captcha.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/views/login/images/hide_pwd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/views/login/images/hide_pwd.png
--------------------------------------------------------------------------------
/src/views/login/images/logo_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/views/login/images/logo_bg.png
--------------------------------------------------------------------------------
/src/views/login/images/show_pwd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/views/login/images/show_pwd.png
--------------------------------------------------------------------------------
/src/views/mine/Mine.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
17 |
18 |
19 |

20 |
21 | LRboy
22 | 手机号:{{userInfo.phone}}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
96 |
97 |
--------------------------------------------------------------------------------
/src/views/mine/children/MineOrder.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
95 |
96 |
--------------------------------------------------------------------------------
/src/views/mine/children/UserCenter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
41 |
42 |
--------------------------------------------------------------------------------
/src/views/mine/children/components/MineOrderItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
![]()
9 |
10 |
{{order.cart_shop.length > 6 ? '…' : ''}}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
26 |
27 |
--------------------------------------------------------------------------------
/src/views/mine/images/avator.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/views/mine/images/avator.jpg
--------------------------------------------------------------------------------
/src/views/order/Order.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
53 |
54 |
55 |
56 |
57 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
283 |
284 |
--------------------------------------------------------------------------------
/src/views/order/children/MyAddress.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
121 |
122 |
--------------------------------------------------------------------------------
/src/views/order/children/OrderDetail.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
50 |
51 |
--------------------------------------------------------------------------------
/src/views/order/children/children/AddAddress.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
20 |
21 |
22 |
23 |
24 |
84 |
85 |
--------------------------------------------------------------------------------
/src/views/order/children/children/EditAddress.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
21 |
22 |
23 |
24 |
25 |
121 |
122 |
--------------------------------------------------------------------------------
/src/views/order/images/detail1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/views/order/images/detail1.jpg
--------------------------------------------------------------------------------
/src/views/order/images/shop-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LRboyz/vue-shop/c3a1fdfa9c47b23587072d160ce752102c7fc743/src/views/order/images/shop-icon.png
--------------------------------------------------------------------------------
/tests/unit/example.spec.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai'
2 | import { shallowMount } from '@vue/test-utils'
3 | import HelloWorld from '@/components/HelloWorld.vue'
4 |
5 | describe('HelloWorld.vue', () => {
6 | it('renders props.msg when passed', () => {
7 | const msg = 'new message'
8 | const wrapper = shallowMount(HelloWorld, {
9 | propsData: { msg }
10 | })
11 | expect(wrapper.text()).to.include(msg)
12 | })
13 | })
14 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | publicPath: '/',
3 | devServer: {
4 | proxy: {
5 | // '/api': {
6 | // target: 'http://lrboy.live',
7 | // changeOrigin: true,
8 | // pathRewrite: {
9 | // '^/api': ''
10 | // }
11 | // },
12 | }
13 | }
14 | };
--------------------------------------------------------------------------------