4 | */
5 | const DEFAULT = {
6 | speed: 50,
7 | distance: 10,
8 | time: 700
9 | };
10 | const eventName = 'wmapptap';
11 |
12 | export default function tap(Vue, options) {
13 | let option = Object.assign({}, DEFAULT, options);
14 | let startState = null;
15 | window.addEventListener('touchstart', function ontouchstart(e) {
16 | startState = {
17 | x: e.changedTouches[0].clientX,
18 | y: e.changedTouches[0].clientY,
19 | time: Date.now()
20 | };
21 | });
22 |
23 | window.addEventListener('touchend', function ontouchend(e) {
24 | if (e.changedTouches.length !== 1 || !startState) {
25 | startState = null;
26 | return;
27 | }
28 | let endState = {
29 | x: e.changedTouches[0].clientX,
30 | y: e.changedTouches[0].clientY,
31 | time: Date.now()
32 | };
33 | let distance = Math.sqrt(Math.pow(endState.x - startState.x, 2) + Math.pow(endState.y - startState.y, 2));
34 | let time = endState.time - startState.time;
35 | let speed = distance / time * 1000;
36 | if (distance <= option.distance && time <= option.time && speed <= option.speed) {
37 | let ev = document.createEvent('Event');
38 | ev.initEvent(eventName, true, true);
39 | ev.pageX = e.changedTouches[0].pageX;
40 | ev.pageY = e.changedTouches[0].pageY;
41 | e.target.dispatchEvent(ev);
42 | }
43 | });
44 | Vue.directive('tap', {
45 | bind: function (el, binding, vnode) {
46 | el.addEventListener(eventName, function ontap(e) {
47 | if (binding.modifiers.self && e.target !== el) {
48 | return;
49 | }
50 | if (binding.modifiers.stop) {
51 | e.stopPropagation();
52 | }
53 | if (binding.modifiers.prevent) {
54 | e.preventDefault();
55 | }
56 | if (typeof binding.value.callback !== 'function') {
57 | return;
58 | }
59 | let argus = binding.value.argus || [];
60 | argus.push(e);
61 | binding.value.callback.apply(vnode.context, argus);
62 | });
63 | }
64 | });
65 | }
66 |
--------------------------------------------------------------------------------
/src/utils/fetch.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /*
3 | * use method
4 | * fetch().get(url, data)
5 | *.then()
6 | * .catch()
7 | */
8 |
9 | const param = require('jquery-param'); // for 深度解析
10 |
11 | function isObject(data) {
12 | return Object.prototype.toString.call(data) === '[object Object]' ||
13 | Object.prototype.toString.call(data) === '[object Array]';
14 | }
15 |
16 | function hasContentType(headers) {
17 | return Object.keys(headers).some(function (name) {
18 | return name.toLowerCase() === 'content-type';
19 | });
20 | }
21 |
22 | function setHeaders(xhr, headers) {
23 | headers = headers || {};
24 |
25 | if (!hasContentType(headers)) {
26 | headers['Content-Type'] = 'application/x-www-form-urlencoded';
27 | }
28 |
29 | Object.keys(headers).forEach(function (name) {
30 | xhr.setRequestHeader(name, headers[name]);
31 | });
32 | }
33 |
34 | function xhrConnection(type, url, data, options) {
35 | if (isObject(data)) {
36 | data = param(data);
37 | }
38 | return new Promise(function (resolve, reject) {
39 | let xhr = new XMLHttpRequest();
40 | if (type === 'get') {
41 | url = url.replace(/#.*$/, '');
42 | let divider = url.indexOf('?') !== -1 ? '&' : '?';
43 | url = [url, data].join(divider);
44 | data = null;
45 | }
46 |
47 | xhr.open(type, url || '', true);
48 | setHeaders(xhr, options.headers);
49 | xhr.onload = function () {
50 | if (xhr.status >= 200 && xhr.status < 300) {
51 | let result;
52 | try {
53 | result = JSON.parse(xhr.responseText);
54 | } catch (e) {
55 | window.wmErrorReport && window.wmErrorReport(e);
56 | result = xhr.responseText;
57 | }
58 | resolve(result);
59 | } else {
60 | reject(Error(xhr.statusText));
61 | }
62 | };
63 | xhr.onerror = function () {
64 | reject(Error('Network Error'));
65 | };
66 | xhr.send(data);
67 | });
68 | }
69 |
70 | export default function Ajax(options) {
71 | options = options || {};
72 |
73 | let ajax = {};
74 |
75 | let httpMethods = ['get', 'post', 'put', 'delete'];
76 |
77 | httpMethods.forEach(function (method) {
78 | ajax[method] = function (url, data) {
79 | return xhrConnection(method, url, data, options);
80 | };
81 | });
82 | return ajax;
83 | }
84 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-shop-cli",
3 | "version": "1.0.0",
4 | "description": "a vue project for e-commerce",
5 | "author": "ppya
",
6 | "private": true,
7 | "scripts": {
8 | "dev": "node build/dev-server.js",
9 | "build": "node build/build.js",
10 | "lint": "eslint --ext .js,.vue src"
11 | },
12 | "dependencies": {
13 | "jquery-param": "^0.2.0",
14 | "object-assign": "^4.1.1",
15 | "vue": "^2.2.1",
16 | "vue-router": "^2.2.0",
17 | "vuex": "^2.0.0"
18 | },
19 | "devDependencies": {
20 | "autoprefixer": "^6.7.2",
21 | "babel-core": "^6.22.1",
22 | "babel-eslint": "^7.1.1",
23 | "babel-helper-vue-jsx-merge-props": "^2.0.2",
24 | "babel-loader": "^6.2.10",
25 | "babel-plugin-istanbul": "^3.1.2",
26 | "babel-plugin-syntax-jsx": "^6.18.0",
27 | "babel-plugin-transform-runtime": "^6.22.0",
28 | "babel-plugin-transform-vue-jsx": "^3.3.0",
29 | "babel-preset-latest": "^6.22.0",
30 | "babel-preset-stage-2": "^6.22.0",
31 | "babel-register": "^6.22.0",
32 | "chalk": "^1.1.3",
33 | "chromedriver": "^2.27.2",
34 | "connect-history-api-fallback": "^1.3.0",
35 | "copy-webpack-plugin": "^4.0.1",
36 | "cross-env": "^3.1.4",
37 | "cross-spawn": "^5.0.1",
38 | "css-loader": "^0.26.1",
39 | "eslint": "^3.14.1",
40 | "eslint-config-standard": "^6.2.1",
41 | "eslint-friendly-formatter": "^2.0.7",
42 | "eslint-loader": "^1.6.1",
43 | "eslint-plugin-html": "^2.0.0",
44 | "eslint-plugin-promise": "^3.4.0",
45 | "eslint-plugin-standard": "^2.0.1",
46 | "eventsource-polyfill": "^0.9.6",
47 | "express": "^4.14.1",
48 | "extract-text-webpack-plugin": "^2.0.0",
49 | "file-loader": "^0.10.0",
50 | "friendly-errors-webpack-plugin": "^1.1.3",
51 | "function-bind": "^1.1.0",
52 | "html-webpack-plugin": "^2.28.0",
53 | "http-proxy-middleware": "^0.17.3",
54 | "inject-loader": "^2.0.1",
55 | "node-gyp": "^3.4.0",
56 | "node-sass": "^4.5.0",
57 | "opn": "^4.0.2",
58 | "optimize-css-assets-webpack-plugin": "^1.3.0",
59 | "ora": "^1.1.0",
60 | "phantomjs-prebuilt": "^2.1.14",
61 | "rimraf": "^2.6.0",
62 | "sass": "^0.5.0",
63 | "sass-loader": "^4.1.1",
64 | "scss": "^0.2.4",
65 | "scss-loader": "0.0.1",
66 | "selenium-server": "^3.0.1",
67 | "semver": "^5.3.0",
68 | "url-loader": "^0.5.7",
69 | "vue-loader": "^11.0.0",
70 | "vue-style-loader": "^2.0.0",
71 | "vue-template-compiler": "^2.2.1",
72 | "webpack": "^3.0.0",
73 | "webpack-bundle-analyzer": "^2.2.1",
74 | "webpack-dev-middleware": "^1.10.0",
75 | "webpack-hot-middleware": "^2.16.1",
76 | "webpack-merge": "^2.6.1"
77 | },
78 | "engines": {
79 | "node": ">= 4.0.0",
80 | "npm": ">= 3.0.0"
81 | },
82 | "browserlist": [
83 | "> 1%",
84 | "last 2 versions",
85 | "not ie <= 8"
86 | ]
87 | }
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-shop-cli
2 |
3 | 这是一款基于vue实现的,适用于电商平台的架手架,移动、轻便、可扩展性强。
4 |
5 | ## 技术栈
6 |
7 | vue2 + vue-rotuer2 + vuex2 + webpack + ES6/7 + fetch + sass + svg. (支持反向代理)
8 |
9 | ## 项目布局
10 |
11 | ```
12 | |-- build // webpack配置文件
13 | |-- config // 项目打包路径
14 | |-- dist // 上线项目文件,放在服务器即可正常访问
15 | |
16 | |-- src // 源码目录
17 | | |-- assets // 公共资源(eg.图片)
18 | | |-- components // 组件
19 | | |-- common // 公共组件
20 | | |-- loading.js // 页面初始化加载数据的动画组件
21 | | |-- mixin.js // 组件混合(包括:指令-下拉加载更多,处理图片地址)
22 | | |-- footer // 底部公共组件
23 | | |-- header // 头部公共组件
24 | |
25 | | |-- pages // 页面组件
26 | | |-- home // 首页
27 | | |-- myshop // 购物页
28 | | |-- my // 我的
29 | |
30 | | |-- plugins // 引用的插件
31 | |
32 | | |-- router // 路由配置
33 | |
34 | | |-- service // 数据交互统一调配
35 | | |-- template // 开发阶段的临时数据
36 | | |-- getData.js // 获取数据的统一调配文件,对接口进行统一管理
37 | |
38 | | |-- store // vuex的状态管理
39 | | |-- modules // store模块
40 | | |-- action.js // 配置actions
41 | | |-- getters.js // 配置getters
42 | | |-- index.js // 引用vuex,创建store
43 | | |-- mutation-types.js // 定义常量muations名
44 | | |-- mutations.js // 配置mutations
45 | |
46 | | |-- utils // 工具函数 && 全局配置
47 | | |-- env.js // 环境切换配置
48 | | |-- fetch.js // 获取数据
49 | | |-- mUtils.js // 常用的js方法
50 | | |-- rem.js // px转换rem
51 | |
52 | | |-- style // 各种样式文件
53 | | |-- common.scss // 公共样式文件
54 | | |-- mixin.scss // 样式配置文件
55 | |
56 | | |-- App.vue // 页面入口文件
57 | |
58 | | |-- main.js // 程序入口文件,加载各种公共组件
59 | |
60 | |-- .babelrc // ES6语法编译配置
61 | |-- .editorconfig // 代码编写规格
62 | |-- .gitignore // 忽略的文件
63 | |-- favicon.ico // 页面左上角小图标
64 | |-- index.html // 入口html文件
65 | |-- package.json // 项目及工具的依赖配置文件
66 | |-- README.md // 说明
67 | ```
68 |
69 | ## 项目运行
70 |
71 | ```
72 | 克隆,或者直接下载
73 | git clone https://github.com/ppya0812/vue-shop-cli
74 |
75 | 进入文件夹
76 | cd vue-shop-cli
77 |
78 | 安装依赖
79 | npm install
80 | ```
81 |
82 | ## 编译环境
83 |
84 | ```
85 | 开启本地服务器
86 | npm run dev
87 |
88 | 访问 http://localhost:8088
89 | ```
90 |
91 | ## 线上版本
92 |
93 | ```
94 | npm run build
95 |
96 | 生成的dist文件夹放在服务器即可正常访问
97 | ```
98 |
--------------------------------------------------------------------------------
/src/assets/error.svg:
--------------------------------------------------------------------------------
1 |
2 |
31 |
--------------------------------------------------------------------------------
/src/utils/mUtils.js:
--------------------------------------------------------------------------------
1 | // export const json2url = json => {
2 | // let arr = [];
3 | // for (let i in json) {
4 | // arr.push(i + '=' + json[i]);
5 | // }
6 | // return arr.join('&');
7 | // }
8 |
9 | /**
10 | * 存储localStorage
11 | */
12 | export const setStore = (name, content) => {
13 | if (!name) {
14 | return;
15 | }
16 | if (typeof content !== 'string') {
17 | content = JSON.stringify(content);
18 | }
19 | window.localStorage.setItem(name, content);
20 | }
21 |
22 | /**
23 | * 获取localStorage
24 | */
25 | export const getStore = name => {
26 | if (!name) {
27 | return;
28 | }
29 | return window.localStorage.getItem(name);
30 | }
31 |
32 | /**
33 | * 删除localStorage
34 | */
35 | export const removeStore = name => {
36 | if (!name) {
37 | return;
38 | }
39 | window.localStorage.removeItem(name);
40 | }
41 |
42 | /**
43 | * 获取style样式
44 | */
45 | export const getStyle = (element, attr, NumberMode = 'int') => {
46 | let target;
47 | // scrollTop 获取方式不同,没有它不属于style,而且只有document.body才能用
48 | if (attr === 'scrollTop') {
49 | target = element.scrollTop;
50 | } else if (element.currentStyle) {
51 | target = element.currentStyle[attr];
52 | } else {
53 | target = document.defaultView.getComputedStyle(element, null)[attr];
54 | }
55 | // 在获取 opactiy 时需要获取小数 parseFloat
56 | return NumberMode === 'float'
57 | ? parseFloat(target)
58 | : parseInt(target);
59 | }
60 |
61 | /**
62 | * 页面到达底部,加载更多
63 | */
64 | export const loadMore = (element, callback) => {
65 | let windowHeight = window.screen.height;
66 | let height;
67 | let setTop;
68 | let paddingBottom;
69 | let marginBottom;
70 | let requestFram;
71 | let oldScrollTop;
72 |
73 | element.addEventListener('scroll', () => {
74 | loadMore();
75 | }, false)
76 | // 运动开始时获取元素 高度 和 offseTop, pading, margin
77 | element.addEventListener('touchstart', () => {
78 | height = element.offsetHeight;
79 | setTop = element.offsetTop;
80 | paddingBottom = getStyle(element, 'paddingBottom');
81 | marginBottom = getStyle(element, 'marginBottom');
82 | }, {passive: true})
83 |
84 | // 运动过程中保持监听 scrollTop 的值判断是否到达底部
85 | element.addEventListener('touchmove', () => {
86 | loadMore();
87 | }, {passive: true})
88 |
89 | // 运动结束时判断是否有惯性运动,惯性运动结束判断是非到达底部
90 | element.addEventListener('touchend', () => {
91 | oldScrollTop = document.body.scrollTop;
92 | moveEnd();
93 | }, {passive: true})
94 |
95 | const moveEnd = () => {
96 | requestFram = requestAnimationFrame(() => {
97 | if (document.body.scrollTop !== oldScrollTop) {
98 | oldScrollTop = document.body.scrollTop;
99 | loadMore();
100 | moveEnd();
101 | } else {
102 | cancelAnimationFrame(requestFram);
103 | // 为了防止鼠标抬起时已经渲染好数据从而导致重获取数据,应该重新获取dom高度
104 | height = element.offsetHeight;
105 | loadMore();
106 | }
107 | })
108 | }
109 |
110 | const loadMore = () => {
111 | if (document.body.scrollTop + windowHeight >= height + setTop + paddingBottom + marginBottom) {
112 | callback();
113 | }
114 | }
115 | }
116 |
117 | /**
118 | * 显示返回顶部按钮,开始、结束、运动 三个过程中调用函数判断是否达到目标点
119 | */
120 | export const showBack = callback => {
121 | let requestFram;
122 | let oldScrollTop;
123 |
124 | document.addEventListener('scroll', () => {
125 | showBackFun();
126 | }, false)
127 | document.addEventListener('touchstart', () => {
128 | showBackFun();
129 | }, {passive: true})
130 |
131 | document.addEventListener('touchmove', () => {
132 | showBackFun();
133 | }, {passive: true})
134 |
135 | document.addEventListener('touchend', () => {
136 | oldScrollTop = document.body.scrollTop;
137 | moveEnd();
138 | }, {passive: true})
139 |
140 | const moveEnd = () => {
141 | requestFram = requestAnimationFrame(() => {
142 | if (document.body.scrollTop !== oldScrollTop) {
143 | oldScrollTop = document.body.scrollTop;
144 | moveEnd();
145 | } else {
146 | cancelAnimationFrame(requestFram);
147 | }
148 | showBackFun();
149 | })
150 | }
151 |
152 | // 判断是否达到目标点
153 | const showBackFun = () => {
154 | if (document.body.scrollTop > 500) {
155 | callback(true);
156 | } else {
157 | callback(false);
158 | }
159 | }
160 | }
161 |
162 | /**
163 | * 运动效果
164 | * @param {HTMLElement} element 运动对象,必选
165 | * @param {JSON} target 属性:目标值,必选
166 | * @param {number} duration 运动时间,可选
167 | * @param {string} mode 运动模式,可选
168 | * @param {function} callback 可选,回调函数,链式动画
169 | */
170 | export const animate = (element, target, duration = 400, mode = 'ease-out', callback) => {
171 | clearInterval(element.timer);
172 |
173 | // 判断不同参数的情况
174 | if (duration instanceof Function) {
175 | callback = duration;
176 | duration = 400;
177 | } else if (duration instanceof String) {
178 | mode = duration;
179 | duration = 400;
180 | }
181 |
182 | // 判断不同参数的情况
183 | if (mode instanceof Function) {
184 | callback = mode;
185 | mode = 'ease-out';
186 | }
187 |
188 | // 获取dom样式
189 | const attrStyle = attr => {
190 | if (attr === 'opacity') {
191 | return Math.round(getStyle(element, attr, 'float') * 100);
192 | } else {
193 | return getStyle(element, attr);
194 | }
195 | }
196 | // 根字体大小,需要从此将 rem 改成 px 进行运算
197 | const rootSize = parseFloat(document.documentElement.style.fontSize);
198 |
199 | const unit = {};
200 | const initState = {};
201 |
202 | // 获取目标属性单位和初始样式值
203 | Object.keys(target).forEach(attr => {
204 | if (/[^\d^.]+/gi.test(target[attr])) {
205 | unit[attr] = target[attr].match(/[^\d^.]+/gi)[0] || 'px';
206 | } else {
207 | unit[attr] = 'px';
208 | }
209 | initState[attr] = attrStyle(attr);
210 | });
211 |
212 | // 去掉传入的后缀单位
213 | Object.keys(target).forEach(attr => {
214 | if (unit[attr] === 'rem') {
215 | target[attr] = Math.ceil(parseInt(target[attr]) * rootSize);
216 | } else {
217 | target[attr] = parseInt(target[attr]);
218 | }
219 | });
220 |
221 | let flag = true; // 假设所有运动到达终点
222 | const remberSpeed = {}; // 记录上一个速度值,在ease-in模式下需要用到
223 | element.timer = setInterval(() => {
224 | Object.keys(target).forEach(attr => {
225 | let iSpeed = 0; // 步长
226 | let status = false; // 是否仍需运动
227 | let iCurrent = attrStyle(attr) || 0; // 当前元素属性址
228 | let speedBase = 0; // 目标点需要减去的基础值,三种运动状态的值都不同
229 | let intervalTime; // 将目标值分为多少步执行,数值越大,步长越小,运动时间越长
230 | switch (mode) {
231 | case 'ease-out':
232 | speedBase = iCurrent;
233 | intervalTime = duration * 5 / 400;
234 | break;
235 | case 'linear':
236 | speedBase = initState[attr];
237 | intervalTime = duration * 20 / 400;
238 | break;
239 | case 'ease-in':
240 | let oldspeed = remberSpeed[attr] || 0;
241 | iSpeed = oldspeed + (target[attr] - initState[attr]) / duration;
242 | remberSpeed[attr] = iSpeed
243 | break;
244 | default:
245 | speedBase = iCurrent;
246 | intervalTime = duration * 5 / 400;
247 | }
248 | if (mode !== 'ease-in') {
249 | iSpeed = (target[attr] - speedBase) / intervalTime;
250 | iSpeed = iSpeed > 0
251 | ? Math.ceil(iSpeed)
252 | : Math.floor(iSpeed);
253 | }
254 | // 判断是否达步长之内的误差距离,如果到达说明到达目标点
255 | switch (mode) {
256 | case 'ease-out':
257 | status = iCurrent !== target[attr];
258 | break;
259 | case 'linear':
260 | status = Math.abs(Math.abs(iCurrent) - Math.abs(target[attr])) > Math.abs(iSpeed);
261 | break;
262 | case 'ease-in':
263 | status = Math.abs(Math.abs(iCurrent) - Math.abs(target[attr])) > Math.abs(iSpeed);
264 | break;
265 | default:
266 | status = iCurrent !== target[attr];
267 | }
268 |
269 | if (status) {
270 | flag = false;
271 | // opacity 和 scrollTop 需要特殊处理
272 | if (attr === 'opacity') {
273 | element.style.filter = 'alpha(opacity:' + (iCurrent + iSpeed) + ')';
274 | element.style.opacity = (iCurrent + iSpeed) / 100;
275 | } else if (attr === 'scrollTop') {
276 | element.scrollTop = iCurrent + iSpeed;
277 | } else {
278 | element.style[attr] = iCurrent + iSpeed + 'px';
279 | }
280 | } else {
281 | flag = true;
282 | }
283 |
284 | if (flag) {
285 | clearInterval(element.timer);
286 | if (callback) {
287 | callback();
288 | }
289 | }
290 | })
291 | }, 20);
292 | }
293 |
--------------------------------------------------------------------------------
/src/test.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([23], {
2 | 0: function(t, e, a) {
3 | t.exports = a(176)
4 | },
5 | 113: function(t, e) {
6 | "use strict";
7 | Object.defineProperty(e, "__esModule", {
8 | value: !0
9 | });
10 | var a = function(t) {
11 | var e = document.createElement("a");
12 | e.href = t;
13 | var a = ["http:", "https:", "eleme:"];
14 | return a.indexOf(e.protocol) !== -1 && !(e.hostname && !e.hostname.match(/(^|\.)ele(net)?\.me$/))
15 | };
16 | e.default = {
17 | post: function(t, e) {
18 | var a = {
19 | method: "POST",
20 | credentials: "include",
21 | body: JSON.stringify(e)
22 | };
23 | return window.fetch(t, a).then(function(t) {
24 | var e = t.json();
25 | return t.ok ? e : e.then(Promise.reject.bind(Promise))
26 | })
27 | },
28 | redirect: function() {
29 | var t = (new window.UParams).redirect;
30 | t && a(t) || (t = "/msite/"),
31 | location.href = t
32 | }
33 | }
34 | },
35 | 140: function(t, e, a) {
36 | var s, o, i = {};
37 | a(559),
38 | s = a(329),
39 | o = a(878),
40 | t.exports = s || {},
41 | t.exports.__esModule && (t.exports = t.exports.default);
42 | var c = "function" == typeof t.exports ? t.exports.options || (t.exports.options = {}) : t.exports;
43 | o && (c.template = o),
44 | c.computed || (c.computed = {}),
45 | Object.keys(i).forEach(function(t) {
46 | var e = i[t];
47 | c.computed[t] = function() {
48 | return e
49 | }
50 | })
51 | },
52 | 176: function(t, e, a) {
53 | "use strict";
54 | var s = a(1006)
55 | , o = babelHelpers.interopRequireDefault(s);
56 | new Vue({
57 | el: "body",
58 | components: {
59 | App: o.default
60 | }
61 | })
62 | },
63 | 328: function(t, e, a) {
64 | "use strict";
65 | Object.defineProperty(e, "__esModule", {
66 | value: !0
67 | });
68 | var s = a(1007)
69 | , o = babelHelpers.interopRequireDefault(s)
70 | , i = a(1008)
71 | , c = babelHelpers.interopRequireDefault(i)
72 | , n = a(4);
73 | e.default = {
74 | components: {
75 | ElemeHeader: n.ElemeHeader,
76 | Message: o.default,
77 | Password: c.default
78 | },
79 | data: function() {
80 | return {
81 | apihost: "//mainsite-restapi.ele.me",
82 | current: "message",
83 | toast: "",
84 | timer: null,
85 | showToast: !1,
86 | isApp: /Eleme/.test(navigator.userAgent)
87 | }
88 | },
89 | computed: {
90 | headerOpt: function() {
91 | return {
92 | message: {
93 | title: "登录",
94 | switchName: "密码登录",
95 | switchTarget: "password"
96 | },
97 | password: {
98 | title: "密码登录",
99 | switchName: "短信登录",
100 | switchTarget: "message"
101 | }
102 | }[this.current]
103 | }
104 | },
105 | methods: {
106 | switchTo: function(t) {
107 | this.current = t
108 | }
109 | },
110 | events: {
111 | setToast: function(t) {
112 | var e = this;
113 | clearTimeout(this.timer),
114 | this.toast = t,
115 | this.showToast = !0,
116 | this.timer = setTimeout(function() {
117 | e.showToast = !1
118 | }, 2e3)
119 | }
120 | }
121 | }
122 | },
123 | 329: function(t, e) {
124 | "use strict";
125 | Object.defineProperty(e, "__esModule", {
126 | value: !0
127 | }),
128 | e.default = {
129 | props: {
130 | apihost: {
131 | type: String,
132 | default: "//mainsite-restapi.ele.me"
133 | },
134 | confirmButton: {
135 | type: Function,
136 | default: function() {}
137 | },
138 | cancelButton: {
139 | type: Function,
140 | default: function() {}
141 | }
142 | },
143 | data: function() {
144 | return {
145 | captchaCode: "",
146 | userCaptcha: ""
147 | }
148 | },
149 | computed: {
150 | captchaImage: function() {
151 | if (this.captchaCode)
152 | return this.apihost + "/v1/captchas/" + this.captchaCode
153 | }
154 | },
155 | methods: {
156 | $fetch: function(t, e) {
157 | return window.fetch(t, e).then(function(t) {
158 | var e = t.json();
159 | return t.status >= 200 && t.status < 300 ? e : e.then(Promise.reject.bind(Promise))
160 | })
161 | },
162 | reloadCaptcha: function() {
163 | this.$emit("getCaptcha")
164 | },
165 | submitCaptcha: function() {
166 | return this.userCaptcha ? void this.confirmButton(this.userCaptcha, this.captchaCode) : this.$dispatch("setToast", "请填写验证码")
167 | }
168 | },
169 | events: {
170 | getCaptcha: function() {
171 | var t = this;
172 | this.userCaptcha = "",
173 | this.$fetch(this.apihost + "/v1/captchas", {
174 | method: "POST",
175 | credentials: "include"
176 | }).then(function(e) {
177 | t.captchaCode = e.code
178 | }).catch(function() {
179 | return {}
180 | })
181 | }
182 | }
183 | }
184 | },
185 | 330: function(t, e, a) {
186 | "use strict";
187 | Object.defineProperty(e, "__esModule", {
188 | value: !0
189 | });
190 | var s = a(140)
191 | , o = babelHelpers.interopRequireDefault(s)
192 | , i = a(113)
193 | , c = babelHelpers.interopRequireDefault(i);
194 | e.default = {
195 | components: {
196 | Captcha: o.default
197 | },
198 | props: ["apihost", "current", "is-app"],
199 | data: function() {
200 | return {
201 | isShowLayer: void 0,
202 | interval: null,
203 | countdown: 0,
204 | mobilePhone: "",
205 | msgCaptcha: "",
206 | msgToken: ""
207 | }
208 | },
209 | computed: {
210 | isMobile: function t() {
211 | var t = /(^(13\d|15[^4,\D]|17[13678]|18\d)\d{8}|170[^346,\D]\d{7})$/;
212 | return t.test(this.mobilePhone)
213 | },
214 | enableShowLayer: function() {
215 | return !this.isShowLayer && this.isMobile
216 | },
217 | buttonText: function() {
218 | return "undefined" == typeof this.isShowLayer ? "获取验证码" : this.isShowLayer ? "发送中..." : "重新获取"
219 | }
220 | },
221 | methods: {
222 | showLayer: function() {
223 | this.enableShowLayer && (this.$broadcast("getCaptcha"),
224 | this.isShowLayer = !0)
225 | },
226 | hideLayer: function() {
227 | this.isShowLayer = !1
228 | },
229 | getMsgCaptcha: function(t) {
230 | var e = this
231 | , a = {
232 | mobile: this.mobilePhone,
233 | scene: "login",
234 | type: "sms"
235 | };
236 | t && (this.isShowLayer = !1,
237 | a.captcha_code = t),
238 | c.default.post(this.apihost + "/v4/mobile/verify_code/send", a).then(function(t) {
239 | e.setCountdown(),
240 | e.msgToken = t.validate_token,
241 | e.isShowLayer = !1
242 | }).catch(function(t) {
243 | "NEED_CAPTCHA" === t.name ? e.showLayer() : e.$dispatch("setToast", t.message)
244 | })
245 | },
246 | setCountdown: function() {
247 | var t = this
248 | , e = function() {
249 | if (t.countdown--,
250 | t.countdown <= 0)
251 | return clearInterval(t.interval)
252 | };
253 | this.countdown = 30,
254 | this.interval = setInterval(e, 1e3)
255 | },
256 | loginByMsg: function() {
257 | var t = this;
258 | return this.mobilePhone ? this.isMobile ? this.msgToken ? this.msgCaptcha ? void c.default.post(this.apihost + "/v1/login/app_mobile", {
259 | validate_token: this.msgToken,
260 | code: this.msgCaptcha,
261 | mobile: this.mobilePhone
262 | }).then(function() {
263 | c.default.redirect()
264 | }).catch(function(e) {
265 | t.msgCaptcha = "",
266 | t.$dispatch("setToast", e.message)
267 | }) : this.$dispatch("setToast", "请填写验证码") : this.$dispatch("setToast", "请获取验证码") : this.$dispatch("setToast", "请填写合法的手机号") : this.$dispatch("setToast", "请填写手机号")
268 | }
269 | }
270 | }
271 | },
272 | 331: function(t, e, a) {
273 | "use strict";
274 | Object.defineProperty(e, "__esModule", {
275 | value: !0
276 | });
277 | var s = a(140)
278 | , o = babelHelpers.interopRequireDefault(s)
279 | , i = a(1009)
280 | , c = babelHelpers.interopRequireDefault(i)
281 | , n = a(113)
282 | , r = babelHelpers.interopRequireDefault(n);
283 | e.default = {
284 | components: {
285 | Captcha: o.default,
286 | Switch: c.default
287 | },
288 | props: ["apihost", "current", "is-app"],
289 | data: function() {
290 | return {
291 | captchaCode: "",
292 | userId: "",
293 | userPw: "",
294 | userCaptcha: "",
295 | showPwText: !1
296 | }
297 | },
298 | computed: {
299 | captchaImage: function() {
300 | return this.captchaCode ? this.apihost + "/v1/captchas/" + this.captchaCode : void 0
301 | }
302 | },
303 | methods: {
304 | getCaptchaCode: function() {
305 | var t = this;
306 | this.userCaptcha = "",
307 | r.default.post(this.apihost + "/v1/captchas").then(function(e) {
308 | t.captchaCode = e.code
309 | }).catch(function() {
310 | return {}
311 | })
312 | },
313 | loginByUserId: function() {
314 | var t = this
315 | , e = this.captchaCode && this.userCaptcha || !this.captchaCode;
316 | return this.userId ? this.userPw ? e ? void r.default.post(this.apihost + "/v2/login", {
317 | username: this.userId,
318 | password: this.userPw,
319 | captcha_code: this.userCaptcha
320 | }).then(function() {
321 | r.default.redirect()
322 | }).catch(function(e) {
323 | t.getCaptchaCode(),
324 | t.$dispatch("setToast", e.message)
325 | }) : this.$dispatch("setToast", "请填写验证码") : this.$dispatch("setToast", "密码不能为空") : this.$dispatch("setToast", "手机/邮箱/用户名 不能为空")
326 | }
327 | }
328 | }
329 | },
330 | 332: function(t, e) {
331 | "use strict";
332 | Object.defineProperty(e, "__esModule", {
333 | value: !0
334 | }),
335 | e.default = {
336 | props: {
337 | value: {
338 | type: Boolean,
339 | twoWay: !0
340 | }
341 | },
342 | methods: {
343 | switchValue: function() {
344 | this.value = !this.value
345 | }
346 | }
347 | }
348 | },
349 | 448: function(t, e) {},
350 | 449: function(t, e) {},
351 | 450: function(t, e) {},
352 | 559: function(t, e) {},
353 | 581: function(t, e) {},
354 | 788: function(t, e) {
355 | t.exports = " "
356 | },
357 | 789: function(t, e) {
358 | t.exports = " 温馨提示:未注册饿了么帐号的手机号,登录时将自动注册,且代表您已同意
《用户服务协议》 登录
"
359 | },
360 | 790: function(t, e) {
361 | t.exports = " "
362 | },
363 | 878: function(t, e) {
364 | t.exports = ' '
365 | },
366 | 900: function(t, e) {
367 | t.exports = ' '
368 | },
369 | 1006: function(t, e, a) {
370 | var s, o, i = {};
371 | a(450),
372 | s = a(328),
373 | o = a(788),
374 | t.exports = s || {},
375 | t.exports.__esModule && (t.exports = t.exports.default);
376 | var c = "function" == typeof t.exports ? t.exports.options || (t.exports.options = {}) : t.exports;
377 | o && (c.template = o),
378 | c.computed || (c.computed = {}),
379 | Object.keys(i).forEach(function(t) {
380 | var e = i[t];
381 | c.computed[t] = function() {
382 | return e
383 | }
384 | })
385 | },
386 | 1007: function(t, e, a) {
387 | var s, o, i = {};
388 | a(448),
389 | s = a(330),
390 | o = a(789),
391 | t.exports = s || {},
392 | t.exports.__esModule && (t.exports = t.exports.default);
393 | var c = "function" == typeof t.exports ? t.exports.options || (t.exports.options = {}) : t.exports;
394 | o && (c.template = o),
395 | c.computed || (c.computed = {}),
396 | Object.keys(i).forEach(function(t) {
397 | var e = i[t];
398 | c.computed[t] = function() {
399 | return e
400 | }
401 | })
402 | },
403 | 1008: function(t, e, a) {
404 | var s, o, i = {};
405 | a(449),
406 | s = a(331),
407 | o = a(790),
408 | t.exports = s || {},
409 | t.exports.__esModule && (t.exports = t.exports.default);
410 | var c = "function" == typeof t.exports ? t.exports.options || (t.exports.options = {}) : t.exports;
411 | o && (c.template = o),
412 | c.computed || (c.computed = {}),
413 | Object.keys(i).forEach(function(t) {
414 | var e = i[t];
415 | c.computed[t] = function() {
416 | return e
417 | }
418 | })
419 | },
420 | 1009: function(t, e, a) {
421 | var s, o, i = {};
422 | a(581),
423 | s = a(332),
424 | o = a(900),
425 | t.exports = s || {},
426 | t.exports.__esModule && (t.exports = t.exports.default);
427 | var c = "function" == typeof t.exports ? t.exports.options || (t.exports.options = {}) : t.exports;
428 | o && (c.template = o),
429 | c.computed || (c.computed = {}),
430 | Object.keys(i).forEach(function(t) {
431 | var e = i[t];
432 | c.computed[t] = function() {
433 | return e
434 | }
435 | })
436 | }
437 | });
438 |
--------------------------------------------------------------------------------