lihai 2 years ago
parent
commit
1c8699551c
59 changed files with 19720 additions and 2 deletions
  1. 33 2
      README.md
  2. 10 0
      babel.config.js
  3. 39 0
      commitlint.config.js
  4. 16233 0
      package-lock.json
  5. 105 0
      package.json
  6. 18 0
      public/index.html
  7. 27 0
      src/App.vue
  8. 34 0
      src/assets/font/iconfont.css
  9. BIN
      src/assets/font/iconfont.eot
  10. 60 0
      src/assets/font/iconfont.svg
  11. BIN
      src/assets/font/iconfont.ttf
  12. 32 0
      src/common/auth.js
  13. 38 0
      src/common/errorHandler.js
  14. 135 0
      src/common/http.js
  15. 10 0
      src/common/index.js
  16. 6 0
      src/common/login.js
  17. 44 0
      src/common/matchMenu.js
  18. 7 0
      src/common/reg.js
  19. 210 0
      src/common/tool.js
  20. 114 0
      src/common/validHelper.js
  21. 172 0
      src/components/common/layout/layout.vue
  22. 139 0
      src/components/common/layout/leftMenu.vue
  23. 40 0
      src/components/modules/helloWorld.vue
  24. 26 0
      src/config/env.js
  25. 48 0
      src/directives/drag.js
  26. 90 0
      src/filters/filter.js
  27. 30 0
      src/main.js
  28. 31 0
      src/pages/confirmOrder/index.vue
  29. 31 0
      src/pages/coupon/index.vue
  30. 31 0
      src/pages/customerMan/index.vue
  31. 31 0
      src/pages/historicalOrder/index.vue
  32. 295 0
      src/pages/home/index.vue
  33. 117 0
      src/pages/login/login.vue
  34. 31 0
      src/pages/storeDetection/index.vue
  35. 31 0
      src/pages/testSkin/details/index.vue
  36. 248 0
      src/pages/testSkin/index.vue
  37. 615 0
      src/plugins/qrcode.min.js
  38. 9 0
      src/plugins/rsa_password.js
  39. 16 0
      src/router/index.js
  40. 28 0
      src/router/map/home.js
  41. 8 0
      src/router/map/login.js
  42. 16 0
      src/server/home.js
  43. 5 0
      src/server/urls.js
  44. 11 0
      src/store/index.js
  45. 23 0
      src/store/modules/comVal.js
  46. 25 0
      src/style/common.less
  47. 32 0
      src/style/index.less
  48. 15 0
      src/style/reset.less
  49. 51 0
      src/style/root.less
  50. 19 0
      tests/e2e/custom-assertions/elementCount.js
  51. 26 0
      tests/e2e/reports/CHROME_71.0.3578.80_Windows NT_test.xml
  52. 26 0
      tests/e2e/reports/CHROME_74.0.3729.108_Windows NT_test.xml
  53. 14 0
      tests/e2e/specs/test.js
  54. 5 0
      tests/unit/.eslintrc.js
  55. 12 0
      tests/unit/components/hello.spec.js
  56. 11 0
      tests/unit/pages/loan.spec.js
  57. 42 0
      vue.config.js
  58. 1 0
      安装插件.bat
  59. 164 0
      规范说明

+ 33 - 2
README.md

@@ -1,3 +1,34 @@
1
-# pad_spa
1
+# web
2 2
 
3
-玖哩仪器操作平台
3
+## Project setup
4
+```
5
+npm install
6
+```
7
+
8
+### Compiles and hot-reloads for development
9
+```
10
+npm run dev
11
+```
12
+
13
+### Compiles and minifies for production
14
+```
15
+npm run build
16
+```
17
+
18
+### Run your tests
19
+```
20
+e2e test(端到端测试)
21
+npm run test1     
22
+
23
+unit test(单元测试)
24
+npm run unit  
25
+```
26
+
27
+### Lints and fixes files
28
+```
29
+npm run lint
30
+```
31
+eslint详细规则:https://eslint.org/docs/rules/
32
+
33
+### Customize configuration
34
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 10 - 0
babel.config.js

@@ -0,0 +1,10 @@
1
+module.exports = {
2
+  presets: [
3
+    [
4
+        '@vue/app',
5
+        {
6
+            "useBuiltIns": "entry"
7
+        }
8
+    ]
9
+  ]
10
+}

+ 39 - 0
commitlint.config.js

@@ -0,0 +1,39 @@
1
+const types = [
2
+    'build',    // 修改项目的的构建系统(xcodebuild、webpack、glup等)的提交
3
+    'ci',       // 修改项目的持续集成流程(Kenkins、Travis等)的提交
4
+    'chore',    // 构建过程或辅助工具的变化,翻译为日常琐事
5
+    'docs',     // 文档提交(documents)
6
+    'feat',     // 新功能(feature)
7
+    'fix',      // bug已经修复。 适合于一次提交直接修复问题
8
+    'to',       // bug还未修复。适合于多次提交。最终修复问题提交时使用fix
9
+    'pref',     // 优化相关,比如提升性能、体验(performance)
10
+    'refactor', // 重构(即不是新增功能,也不是修改bug的代码变动)
11
+    'revert',   // 回滚到上一个版本
12
+    'style',    // 不影响程序逻辑的代码修改、主要是样式方面的优化、修改
13
+    'test',     // 测试相关的开发
14
+    'sync'      // 同步主线或分支的Bug
15
+  ];
16
+  
17
+  typeEnum = {
18
+    rules: {
19
+      'type-enum': [2, 'always', types]
20
+    },
21
+    value: () => types
22
+  }
23
+  
24
+  module.exports = {
25
+      extends: [
26
+        "@commitlint/config-conventional"
27
+      ],
28
+      rules: {
29
+        'type-case': [0],
30
+        'type-empty': [2, 'never'],
31
+        'scope-empty': [0],
32
+        'scope-case': [0],
33
+        'subject-full-stop': [0, 'never'],
34
+        'subject-case': [0, 'never'],
35
+        'header-max-length': [0, 'always', 72],
36
+        'type-enum': typeEnum.rules['type-enum']
37
+      }
38
+    };
39
+  

File diff suppressed because it is too large
+ 16233 - 0
package-lock.json


+ 105 - 0
package.json

@@ -0,0 +1,105 @@
1
+{
2
+  "name": "web",
3
+  "version": "0.1.0",
4
+  "private": true,
5
+  "scripts": {
6
+    "dev": "cross-env env_config=dev vue-cli-service serve --open",
7
+    "build": "cross-env env_config=prod vue-cli-service build",
8
+    "build:t": "cross-env env_config=test vue-cli-service build",
9
+    "lint": "vue-cli-service lint",
10
+    "test1": "vue-cli-service test:e2e",
11
+    "test2": "vue-cli-service test:unit"
12
+  },
13
+  "dependencies": {
14
+    "axios": "^0.18.0",
15
+    "crypto-js": "^3.1.9-1",
16
+    "element-ui": "^2.8.2",
17
+    "vue": "^2.6.6",
18
+    "vue-router": "^3.0.1",
19
+    "vuex": "^3.0.1"
20
+  },
21
+  "devDependencies": {
22
+    "@commitlint/cli": "^11.0.0",
23
+    "@commitlint/config-conventional": "^11.0.0",
24
+    "@vue/cli-plugin-babel": "^3.5.0",
25
+    "@vue/cli-plugin-eslint": "^3.5.0",
26
+    "@vue/cli-plugin-unit-jest": "^3.5.0",
27
+    "@vue/cli-service": "^3.5.0",
28
+    "@vue/test-utils": "1.0.0-beta.29",
29
+    "babel-core": "7.0.0-bridge.0",
30
+    "babel-eslint": "^10.0.1",
31
+    "babel-jest": "^23.6.0",
32
+    "cross-env": "^5.2.1",
33
+    "eslint": "^5.8.0",
34
+    "eslint-plugin-vue": "^5.0.0",
35
+    "husky": "^4.3.0",
36
+    "less": "^3.0.4",
37
+    "less-loader": "^4.1.0",
38
+    "vue-template-compiler": "^2.5.21"
39
+  },
40
+  "eslintConfig": {
41
+    "root": true,
42
+    "env": {
43
+      "node": true
44
+    },
45
+    "extends": [
46
+      "plugin:vue/essential",
47
+      "eslint:recommended"
48
+    ],
49
+    "rules": {
50
+      "no-undef": 0,
51
+      "no-console": 0,
52
+      "no-unused-vars": 0,
53
+      "no-useless-escape": 0,
54
+      "indent": "off",
55
+      "vue/script-indent": [
56
+        "error",
57
+        4
58
+      ]
59
+    },
60
+    "parserOptions": {
61
+      "parser": "babel-eslint"
62
+    }
63
+  },
64
+  "postcss": {
65
+    "plugins": {
66
+      "autoprefixer": {}
67
+    }
68
+  },
69
+  "browserslist": [
70
+    "> 1%",
71
+    "last 2 versions",
72
+    "not ie <= 8"
73
+  ],
74
+  "jest": {
75
+    "moduleFileExtensions": [
76
+      "js",
77
+      "jsx",
78
+      "json",
79
+      "vue"
80
+    ],
81
+    "transform": {
82
+      "^.+\\.vue$": "vue-jest",
83
+      ".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$": "jest-transform-stub",
84
+      "^.+\\.jsx?$": "babel-jest"
85
+    },
86
+    "transformIgnorePatterns": [
87
+      "/node_modules/"
88
+    ],
89
+    "moduleNameMapper": {
90
+      "^@/(.*)$": "<rootDir>/src/$1"
91
+    },
92
+    "snapshotSerializers": [
93
+      "jest-serializer-vue"
94
+    ],
95
+    "testMatch": [
96
+      "**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"
97
+    ],
98
+    "testURL": "http://localhost/"
99
+  },
100
+  "husky": {
101
+    "hooks": {
102
+      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
103
+    }
104
+  }
105
+}

+ 18 - 0
public/index.html

@@ -0,0 +1,18 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+  <head>
4
+    <meta charset="utf-8">
5
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
7
+    <title>玖哩仪器操作平台</title>
8
+  </head>
9
+  <body>
10
+    <noscript>
11
+      <strong>您的浏览器版本较低,请升级最新版浏览器</strong>
12
+    </noscript>
13
+    <div id="app"></div>
14
+    <script src="https://ydcommon.51yund.com/vue/axios.min.js"></script>
15
+    <script src="https://ydcommon.51yund.com/vue/yd_collect2.js"></script>
16
+    <!-- built files will be auto injected -->
17
+  </body>
18
+</html>

+ 27 - 0
src/App.vue

@@ -0,0 +1,27 @@
1
+<template>
2
+    <div id="app">
3
+        <router-view></router-view>
4
+    </div>
5
+</template>
6
+
7
+<script>
8
+export default {
9
+    data() {
10
+        return {
11
+            list:[]
12
+        }
13
+    },
14
+    mounted: function () {
15
+        
16
+    },
17
+    created: function () {
18
+        
19
+    },
20
+    methods: {
21
+        
22
+    }
23
+}
24
+</script>
25
+<style scoped>
26
+	
27
+</style>

File diff suppressed because it is too large
+ 34 - 0
src/assets/font/iconfont.css


BIN
src/assets/font/iconfont.eot


File diff suppressed because it is too large
+ 60 - 0
src/assets/font/iconfont.svg


BIN
src/assets/font/iconfont.ttf


+ 32 - 0
src/common/auth.js

@@ -0,0 +1,32 @@
1
+import {logFlag, logPath} from '@/config/env'
2
+let isFirst = false;
3
+export default (router, hasLogin) => {
4
+    router.beforeEach((to, from, next)=>{
5
+        if (to.meta.title) {
6
+            document.title = to.meta.title;
7
+        }
8
+        isFirst = globalVue ? false : true;
9
+        if(to.meta.auth && !hasLogin){ //需要登录而未登录
10
+            let backUrl = _getTargetUrl(to, from);
11
+            tool.toLogin(backUrl);//如果不加backUrl则登录回调会跳转到前一个页面
12
+        } else{
13
+            next()
14
+        }
15
+    })
16
+}
17
+
18
+function _getTargetUrl(to, from){
19
+    let backUrl = location.href.split("?")[0];
20
+    if(!isFirst){ //只有非首次进入才做处理
21
+        if(from.path === '/' && to.path != '/'){ //首页到其它页
22
+            backUrl += to.path.slice(1);
23
+        } else{ //其它页互相跳(包括跳到首页)
24
+            backUrl = backUrl.replace(from.path, to.path);
25
+        }
26
+    }
27
+
28
+    if(location.search){
29
+        backUrl += location.search;
30
+    }
31
+    return backUrl;
32
+}

+ 38 - 0
src/common/errorHandler.js

@@ -0,0 +1,38 @@
1
+import Vue from 'vue'
2
+import {logFlag} from '@/config/env'
3
+export default () =>{
4
+    const errorHandler = (err, vm, info) => {
5
+        // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
6
+        let compName = "";
7
+        if (vm) {
8
+            compName = _formatComponentName(vm);
9
+            compName = compName.replace(/\\/g, "/");
10
+        }
11
+        let obj = {
12
+            component: compName, 
13
+            hook: info, 
14
+            err_msg: err + ''
15
+        }
16
+        let hosts = location.host;
17
+        if((hosts.indexOf("localhost") > -1 || hosts.indexOf("test") > -1)){
18
+            console.table(obj);
19
+        }
20
+        tool.$throwJS(obj);
21
+    }
22
+    Vue.config.errorHandler = errorHandler;
23
+}
24
+
25
+//获取当前组件的路径
26
+function _formatComponentName(vm) {
27
+    if (vm.$root === vm) return 'root';
28
+    let name = vm._isVue
29
+        ? (vm.$options && vm.$options.name) ||
30
+        (vm.$options && vm.$options._componentTag)
31
+        : vm.name;
32
+    return (
33
+        (name ? 'component <' + name + '>' : 'anonymous component') +
34
+        (vm._isVue && vm.$options && vm.$options.__file
35
+            ? ' at ' + (vm.$options && vm.$options.__file)
36
+            : '')
37
+    );
38
+}

+ 135 - 0
src/common/http.js

@@ -0,0 +1,135 @@
1
+// 封装axios请求
2
+/**axios封装
3
+ * 请求拦截、相应拦截、错误统一处理
4
+ */
5
+import axios from 'axios';
6
+import QS from 'qs';
7
+import store from '../store/index'
8
+
9
+// 环境的切换
10
+if (process.env.NODE_ENV == 'development') {
11
+	axios.defaults.baseURL = '/api';
12
+} else if (process.env.NODE_ENV == 'debug') {
13
+	axios.defaults.baseURL = '';
14
+} else if (process.env.NODE_ENV == 'production') {
15
+	axios.defaults.baseURL = 'http://api.123dailu.com/';
16
+}
17
+
18
+// 请求超时时间
19
+axios.defaults.timeout = 10000;
20
+
21
+// post请求头
22
+axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
23
+
24
+// 请求拦截器
25
+axios.interceptors.request.use(
26
+	config => {
27
+		// 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
28
+		// 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断
29
+		const token = store.state.token;
30
+		token && (config.headers.Authorization = token);
31
+		return config;
32
+	},
33
+	error => {
34
+		return Promise.error(error);
35
+	})
36
+
37
+// 响应拦截器
38
+axios.interceptors.response.use(
39
+	response => {
40
+		if (response.status === 200) {
41
+			return Promise.resolve(response);
42
+		} else {
43
+			return Promise.reject(response);
44
+		}
45
+	},
46
+	// 服务器状态码不是200的情况
47
+	error => {
48
+		if (error.response.status) {
49
+			switch (error.response.status) {
50
+				// 401: 未登录
51
+				// 未登录则跳转登录页面,并携带当前页面的路径
52
+				// 在登录成功后返回当前页面,这一步需要在登录页操作。
53
+				case 401:
54
+					router.replace({
55
+						path: '/login',
56
+						query: { redirect: router.currentRoute.fullPath }
57
+					});
58
+					break;
59
+				// 403 token过期
60
+				// 登录过期对用户进行提示
61
+				// 清除本地token和清空vuex中token对象
62
+				// 跳转登录页面
63
+				case 403:
64
+					this.$message.error('登录过期,请重新登录');
65
+					// 清除token
66
+					localStorage.removeItem('token');
67
+					store.commit('loginSuccess', null);
68
+					// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
69
+					setTimeout(() => {
70
+						router.replace({
71
+							path: '/login',
72
+							query: {
73
+								redirect: router.currentRoute.fullPath
74
+							}
75
+						});
76
+					}, 1000);
77
+					break;
78
+				// 404请求不存在
79
+				case 404:
80
+					this.$message.error('网络请求不存在');
81
+					break;
82
+				// 其他错误,直接抛出错误提示
83
+				default:
84
+					this.$message.error(error.response.data.message);
85
+			}
86
+			return Promise.reject(error.response);
87
+		}
88
+	}
89
+)
90
+	/**
91
+	 * get方法,对应get请求
92
+	 * @param {String} url [请求的url地址]
93
+	 * @param {Object} params [请求时携带的参数]
94
+	 */
95
+function get(url, params){
96
+	return new Promise((resolve, reject) =>{
97
+		axios.get(url, {
98
+			params: params
99
+		})
100
+			.then(res => {
101
+				resolve(res.data);
102
+			})
103
+			.catch(err => {
104
+				reject(err.data)
105
+			})
106
+	});
107
+}
108
+/**
109
+ * post方法,对应post请求
110
+ * @param {String} url [请求的url地址]
111
+ * @param {Object} params [请求时携带的参数]
112
+ */
113
+function post(url, params) {
114
+	return new Promise((resolve, reject) => {
115
+		axios.post(url, QS.stringify(params))
116
+			.then(res => {
117
+				resolve(res.data);
118
+			})
119
+			.catch(err => {
120
+				reject(err.data)
121
+			})
122
+	});
123
+}
124
+
125
+
126
+
127
+export default () => {
128
+	if (typeof window.$http == 'undefined') {
129
+		window.$http = {
130
+			post: post,
131
+			get: get
132
+		}
133
+	}
134
+}
135
+

+ 10 - 0
src/common/index.js

@@ -0,0 +1,10 @@
1
+// 全局注入 
2
+import {injectTool} from './tool'
3
+import injectHttp from './http'
4
+import errorLog from './errorHandler.js'
5
+
6
+export const injectGlobal = () => {
7
+	injectTool();
8
+	injectHttp();
9
+	errorLog();
10
+}

+ 6 - 0
src/common/login.js

@@ -0,0 +1,6 @@
1
+export default (cb) => {
2
+    let userId, xyy;
3
+    userId = localStorage.getItem('user_id'); 
4
+    xyy = localStorage.getItem('xyy');
5
+
6
+}

+ 44 - 0
src/common/matchMenu.js

@@ -0,0 +1,44 @@
1
+export default class menuMethod {	
2
+	static matchMenu(menu,path) {
3
+		if(path=='/'){
4
+			jumpUrl(menu);
5
+		} else{
6
+			let permission=find(menu,path);
7
+			if(!permission){
8
+				globalVue.$router.push({path:'/'});
9
+				globalVue.$alert('抱歉,找不到该页面', '标题名称', {
10
+					confirmButtonText: '确定',
11
+					callback: () => {
12
+						jumpUrl(menu);
13
+					}
14
+				});
15
+			}
16
+		}
17
+	}
18
+}
19
+
20
+// 匹配查找,看是否有访问当前url的权限
21
+function find(menu,path) {
22
+	for(let i=0;i<menu.length;i++){
23
+		if(menu[i].children){
24
+		let result=find(menu[i].children,path);
25
+			if(result) return true;
26
+		} else if(menu[i].path==path){
27
+			return true;
28
+		}
29
+	}
30
+}
31
+// 路由跳转
32
+function jumpUrl(menu){
33
+	if(menu[0].path){
34
+		globalVue.$router.push({path:menu[0].path});
35
+	} else {
36
+		if(menu[0].children[0].children){
37
+			globalVue.$router.push({path:menu[0].children[0].children[0].path});
38
+		} else {
39
+			globalVue.$router.push({path:menu[0].children[0].path});
40
+		}
41
+	}
42
+}
43
+
44
+ 

+ 7 - 0
src/common/reg.js

@@ -0,0 +1,7 @@
1
+export default { 
2
+    idCard: /^\d{6}((?:19|20)((?:\d{2}(?:0[13578]|1[02])(?:0[1-9]|[12]\d|3[01]))|(?:\d{2}(?:0[13456789]|1[012])(?:0[1-9]|[12]\d|30))|(?:\d{2}02(?:0[1-9]|1\d|2[0-8]))|(?:(?:0[48]|[2468][048]|[13579][26])0229)))\d{2}(\d)[xX\d]$/,
3
+	name:  /^[\u4e00-\u9fa5]{2,4}$/,
4
+	email: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
5
+	phone: /^1[3456789]\d{9}$/,
6
+	vfCode: /^\d{6}$/,
7
+}

+ 210 - 0
src/common/tool.js

@@ -0,0 +1,210 @@
1
+import * as config from '@/config/env'
2
+import store from '@/store/index'
3
+import urls from '@/server/urls'
4
+const tool = {
5
+    timeSpace: 0, //本地和服务器的时间间隔
6
+    fetchSKtime:0, //获取sessionkey超时的重试次数
7
+    getUrlParam: function(name){
8
+        const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
9
+        if(location.href.indexOf("?") < 0) return "";
10
+        let r = location.href.split("?")[1].match(reg);
11
+        if (r != null){
12
+            let d = decodeURIComponent(r[2]);
13
+            return tool.getIntValue(d);
14
+        }
15
+        return '';
16
+    },
17
+    getCookieValue: function(name){
18
+        let nameEQ = name + "=";
19
+        let ca = document.cookie.split(';');
20
+        for (let i = 0; i < ca.length; i++) {
21
+            let c = ca[i];
22
+            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
23
+            if (c.indexOf(nameEQ) == 0) {
24
+                return c.substring(nameEQ.length, c.length);
25
+            }
26
+        }
27
+        return "";
28
+    },
29
+    getIntValue(value){
30
+        if(value === 'null' || value === 'undefined' || value === null || value === undefined){
31
+            return ''
32
+        } else if(value === '0'){
33
+            return 0
34
+        }
35
+        return value
36
+    },
37
+    createCookie(name, value, days) {
38
+        let expires = "";
39
+        if (days) {
40
+            var date = new Date();
41
+            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
42
+            expires = "; expires=" + date.toGMTString();
43
+        }
44
+        let cookieDomain = "";
45
+        if(name == "user_id" || name == "xyy"){
46
+            cookieDomain = "; domain=51yund.com";
47
+        }
48
+        document.cookie = name + "=" + encodeURIComponent(value) + expires + cookieDomain + "; path=/";
49
+    },
50
+    getYdUserKey: function (key) {
51
+        // 取值的时候先取store,再取storage
52
+        let storeVal = store.state.comVal;
53
+        let val = "";
54
+        if(storeVal[key]){
55
+            val = storeVal[key];
56
+        } else {
57
+            val = _getLocalStorage(key) || sessionStorage.getItem(key);
58
+            val = tool.getIntValue(val);
59
+            if(!val){
60
+                val = tool.getUrlParam(key);
61
+            }
62
+            if(val){
63
+                store.dispatch('saveCommonValue', {key:key, value: val})
64
+            }
65
+        }
66
+        return val;
67
+    },
68
+    // 本地持久化存储
69
+    setStorage(name, value, expires){
70
+        if(window.ydStorage){
71
+            ydStorage.setItem(name, value, expires)
72
+        } else {
73
+            localStorage.setItem(name, value);
74
+        }
75
+    },
76
+    getSessionKey: function(userId, xyy, cb) {
77
+        var param = {"user_id":userId, "xyy":xyy};
78
+        return $http.post(urls.getsskey, param, true).then(function(res){
79
+            if(res.code === 0){
80
+                let sessionkey = res.session_key;
81
+                if(sessionkey){
82
+                    tool.fetchSKtime = 0; //获取成功之后把fetchSKtime还原
83
+                    //存值的时候先存store,再存localStorage,存store为了取值更快,存storage为了看方便
84
+                    store.dispatch('saveCommonValue', {key:'session_key', value: sessionkey});
85
+                    tool.setStorage("session_key", sessionkey, res.session_ttl);
86
+                    store.dispatch('saveCommonValue', { 'key': 'user_id', 'value': userId });
87
+                    localStorage.setItem("user_id", userId);
88
+                    store.dispatch('saveCommonValue', { 'key': 'xyy', 'value': xyy });
89
+                    localStorage.setItem("xyy", xyy);
90
+                }
91
+                let hasLogin = userId == 0? false : true;
92
+                if(cb) cb(hasLogin);
93
+                return sessionkey;
94
+            } else if(res.code !== 7007) { //userId和xyy不匹配或其它异常情况,最常见的场景是首次进来时,用户之前本地存储的xyy过期,7007的情况在http层统一处理
95
+                tool.toLogin();
96
+            }
97
+        }).catch(res=>{
98
+            location.href = 'https://ydcommon.51yund.com/circle_html/error_index/errIndex.html';
99
+        });
100
+    },
101
+    //简化版js节流,默认2s内只能点击一次
102
+    throttle: function(callback, duration = 2000){
103
+        let lastTime = tool.lastTime || 0;
104
+        let now = new Date().getTime();
105
+        if(now - lastTime > duration){
106
+            callback();
107
+            tool.lastTime = now;
108
+        }
109
+    },
110
+    //记录上报(访问来源上报、错误上报)
111
+    reportCmd: function (data) {
112
+        $http.postOnly(config.logPath + '/sport/report', data)
113
+    },
114
+    // 上报错误信息
115
+    postErrLog(data, cmdName) {
116
+        let hosts = location.host;
117
+        if((hosts.indexOf("localhost") > -1 || hosts.indexOf("test") > -1) && !config.logFlag.dev){
118
+            return ;
119
+        }
120
+        let param = {
121
+            user_id: tool.getYdUserKey('user_id') || 0,
122
+            cmd: cmdName,
123
+            device_id: 'yuedongweb',
124
+            data: JSON.stringify(data)
125
+        }
126
+        tool.reportCmd(param);
127
+    },
128
+    $throwJS(data){ //抛出js异常
129
+         let obj = {  //公共部分
130
+            platform: "web",
131
+            local_path: location.pathname,
132
+            local_url: location.href,
133
+            package_name: config.logFlag.packageName
134
+        }
135
+        Object.assign(obj, data);
136
+        let filterJsErr = [];
137
+        if(config.filterErr && config.filterErr.length > 0){
138
+            filterJsErr.push(...config.filterErr);
139
+        }
140
+        if(filterJsErr.indexOf(obj.err_msg) > -1) return;
141
+        let cmd_name = 'vue_jserr';
142
+        if(obj.err_msg && obj.err_msg.indexOf('http') > -1){
143
+            cmd_name = 'vue_reserr';  //reserr表示资源加载异常(resource error)
144
+        }
145
+        tool.postErrLog(obj, cmd_name);
146
+    },
147
+    // 抛出请求异常
148
+    $throw(err, info, uri, response){
149
+        let obj = {
150
+            local_url: location.href,
151
+            local_path: location.pathname,
152
+            err_msg: err + '',
153
+            req_params: info,
154
+            req_uri: uri
155
+        }
156
+        if(response){ //返回值结构体异常
157
+            obj.response = response
158
+        }
159
+        let filterErr = config.filterErr;
160
+        if(filterErr && filterErr.indexOf(obj.err_msg) > -1) return;
161
+        tool.postErrLog(obj, 'vue_reqerr');
162
+    },
163
+    //去登录
164
+    toLogin: function(backUrl) {
165
+        localStorage.removeItem('session_key');
166
+        localStorage.removeItem('xyy');
167
+        let cbUrl = backUrl? backUrl : location.href;
168
+        cbUrl = encodeURIComponent(cbUrl);
169
+        // cbUrl = _clearUlrData(cbUrl);
170
+        // if(config.appId){ //如果配置了appid就走新的sso登录,否则还是走老的
171
+        //     location.href = `${config.ssoPath}/v${config.appVersion || 1}/user/login?appid=${config.appId}&cburl=${cbUrl}`;
172
+        // } else {
173
+        //     location.href= config.ssoPath + "/get_tickets?cburl="+cbUrl+"&lg_way=wx"
174
+        // }
175
+
176
+    },
177
+}
178
+
179
+export const injectTool= () => {
180
+    if (typeof window.tool == 'undefined') {
181
+        window.tool = tool;
182
+    }
183
+}
184
+//跳转登录时去掉url上的user_id、xyy和is_login
185
+function _clearUlrData(cbUrl) {
186
+    if(cbUrl.indexOf("?") == -1) return encodeURIComponent(cbUrl);
187
+    let [url, query] = cbUrl.split("?");
188
+    let arr = ['user_id', 'xyy', 'is_login'];
189
+    for(let i = 0; i<arr.length; i++){
190
+        if(query.indexOf(arr[i]) > -1){
191
+            let reg = new RegExp('(^|&)' + arr[i] +'=[^&]*', 'g');
192
+            query = query.replace(reg, '')
193
+        }
194
+    }
195
+    if(query){
196
+        if(query.indexOf('&') === 0){  //最开始一位是&时去掉
197
+             query = query.slice(1);
198
+        }
199
+        url += '?' + query
200
+    }
201
+    return encodeURIComponent(url)
202
+}
203
+
204
+function _getLocalStorage(name) {
205
+    if(window.ydStorage){
206
+        return ydStorage.getItem(name)
207
+    } else {
208
+        return localStorage.getItem(name);
209
+    }
210
+}

+ 114 - 0
src/common/validHelper.js

@@ -0,0 +1,114 @@
1
+/**
2
+ * @描述     表单校验
3
+ * @开发     Zach he
4
+ * @时间     2019-05-05
5
+ * @param  {object}   
6
+ *         options: {
7
+ *         		container:'className', 父容器class name 
8
+ *         }
9
+ * 
10
+ * @result {pass:false, msg:validObj.msg, dom:tempDom};
11
+ *         
12
+ * type枚举值与reg.js一致
13
+ */
14
+import reg from '@/common/reg.js'   //引入正则表达式
15
+
16
+const ValidHelper = (options) => {
17
+	let doms = document.querySelectorAll('.' + options.container);
18
+	if (doms == null || doms.length == 0) return {pass:true,msg:'未能查找到容器'};
19
+
20
+	for (var i = 0; i < doms.length; i++) {
21
+		let dom = doms[i];
22
+		let validDomArray = dom.querySelectorAll('.valid');
23
+
24
+		for (var j = 0; j < validDomArray.length; j++) {
25
+			let d = validDomArray[j];
26
+			let validStr = d.dataset['valid'];
27
+			if(d.className.indexOf('el-input')>-1){
28
+				validStr = d.querySelector('.el-input__inner').dataset['valid'];
29
+			}
30
+			if (validStr) {
31
+				let validStrArray = validStr.split(',');
32
+				let obj = {};
33
+
34
+				validStrArray.forEach((line)=>{
35
+					let attrArray = line.split(':');
36
+					obj[attrArray[0]] = attrArray[1];
37
+				}); 
38
+                 
39
+				let result = check(d, obj); 
40
+				if (!result.pass) { 
41
+					return result;
42
+				}
43
+			} else{       //只是纯input输入框校验空值
44
+				if (d.attributes.type == undefined) {
45
+					d = d.querySelector("input");
46
+				}
47
+                let val = d.value;
48
+				if(!val){
49
+					return {pass: false, msg: '请' + d.getAttribute('placeholder'), dom: d};
50
+				}
51
+			}
52
+		}
53
+	}
54
+	return {pass:true};
55
+}
56
+
57
+
58
+function check(tempDom,validObj) {
59
+	let tipWord="";
60
+	let val = "";
61
+	if (validObj.type.indexOf('select') != -1) {  //下拉框
62
+		tempDom=tempDom.querySelectorAll('.el-input__inner')[0];
63
+		tipWord=validObj.msg;
64
+		val = tempDom.value;
65
+	} else {
66
+		tipWord=tempDom.tagName == 'DIV' ? tempDom.querySelector('input').getAttribute('placeholder') : tempDom.getAttribute('placeholder');
67
+		tipWord = '请' + tipWord;
68
+		val = tempDom.className.indexOf('el-input') != -1 ?  tempDom.querySelector('input').value : tempDom.value;
69
+	} 
70
+	if(!val){
71
+        return {pass:false,msg:tipWord,dom:tempDom};
72
+	}
73
+	if (validObj.type.indexOf('phone') != -1) {   //校验手机
74
+		if (reg.phone.test(val)) return {pass:true}
75
+		else return {pass:false, msg:validObj.msg, dom:tempDom};
76
+	}
77
+	if (validObj.type.indexOf('vfCode') != -1) {  //校验验证码
78
+		if (reg.vfCode.test(val)) return {pass:true}
79
+		else return {pass:false, msg:validObj.msg, dom:tempDom};
80
+	} 
81
+	return {pass:true}
82
+}
83
+
84
+const handle = (validResult,isHandle) => {	 
85
+	if(isHandle){                     //校验不通过时添加class
86
+		let d = validResult.dom.tagName == "DIV" ? validResult.dom.querySelector('input') : validResult.dom;
87
+		let classVal=d.getAttribute('class');
88
+		if(classVal.indexOf('valid-red')=='-1'){
89
+			classVal=classVal.concat(' valid-red');
90
+			d.setAttribute('class',classVal);
91
+		}
92
+		globalVue.$message({type:'info',message:validResult.msg,duration: 1500});	
93
+	} else{                          //输入框获取焦点时移除class
94
+		let classVal=validResult.getAttribute('class');
95
+		classVal=classVal.replace('valid-red',"");
96
+		validResult.setAttribute('class',classVal);
97
+	}
98
+
99
+	// 添加事件 
100
+	if (validResult.dom) {
101
+		let d = validResult.dom.tagName == "DIV" ? validResult.dom.querySelector('input') : validResult.dom;
102
+		d.addEventListener('focus',(e)=>{ 
103
+			let target = e.srcElement || e.target;
104
+			handle(target);
105
+		}); 
106
+	}
107
+}
108
+
109
+if (typeof window.$ValidHelper == "undefined"){
110
+	window.$ValidHelper = {};
111
+	window.$ValidHelper.check = ValidHelper;
112
+	window.$ValidHelper.handle = handle;
113
+} 
114
+	

+ 172 - 0
src/components/common/layout/layout.vue

@@ -0,0 +1,172 @@
1
+<template>
2
+  <div class="layout">
3
+    <div class="menu-wrapper">
4
+      <left-menu :isCollapse='isFold' @changeMenu="changeMenu"></left-menu>
5
+    </div>
6
+    <div class="content">
7
+      <header :style="menuIndex==0?'justify-content: space-between;':''">
8
+        <div class="left" v-if="menuIndex==0">
9
+          <div class="address">JOLIJOLI(西安)</div>
10
+        </div>
11
+        <div class="right">
12
+          <div class="news"><img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/news.png"></div>
13
+          <div class="head-img"><img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/cancelOrder.png"></div>
14
+        </div>
15
+      </header>
16
+      <div class="main-wrapper">
17
+        <router-view></router-view>
18
+      </div>
19
+    </div>
20
+  </div>
21
+</template>
22
+
23
+<script type="text/javascript">
24
+import leftMenu from './leftMenu'
25
+import api from '@/server/home'
26
+import {mapState} from 'vuex'
27
+
28
+export default {
29
+  data() {
30
+    return {
31
+      isFold: false,    //导航菜单面板是否折叠
32
+      userId: 0,
33
+      menuIndex:0,
34
+    }
35
+  },
36
+  created() {
37
+    this.initData();
38
+  },
39
+  components: {
40
+    leftMenu,
41
+  },
42
+  methods: {
43
+    initData() {
44
+      let sskey = tool.getYdUserKey("session_key");
45
+      let userId = tool.getYdUserKey('user_id');
46
+      let enterprise_id = tool.getYdUserKey('enterprise_id');
47
+      if (!userId || !sskey) {
48
+        tool.toLogin();
49
+        return;
50
+      }
51
+      this.userId = userId;
52
+      this.$router.replace('/home');
53
+    },
54
+    loginOut() {
55
+      let keys = document.cookie.match(/[^ =;]+(?=\=)/g);
56
+      if (keys) {
57
+        for (let i = keys.length; i--;)
58
+          document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString()
59
+      }
60
+      tool.toLogin();
61
+    },
62
+    changeMenu(index){
63
+      this.menuIndex = index
64
+    }
65
+  },
66
+  computed: {
67
+    ...mapState(['user']),
68
+    routerItems() {
69
+      let resultArr = [];
70
+      let routeNow = this.$route;
71
+      let RootName = routeNow.matched[0].name; //当前路由的根路由name
72
+      resultArr.push({
73
+        name: RootName,
74
+        path: ''
75
+      })
76
+      if (routeNow.matched[0].path !== '' && RootName !== routeNow.name) {
77
+        if (RootName !== routeNow.name) {
78
+          resultArr.push({
79
+            name: routeNow.matched[1].name,
80
+            path: routeNow.matched[1].path
81
+          })
82
+        }
83
+      }
84
+      return resultArr;
85
+    }
86
+  },
87
+}
88
+
89
+</script>
90
+
91
+<style lang="less" scoped>
92
+@import url(../../../style/root.less);
93
+
94
+.layout {
95
+  height: 100vh;
96
+  display: flex;
97
+}
98
+
99
+.menu-wrapper {
100
+  height: 100%;
101
+  text-align: center;
102
+  overflow: auto;
103
+  background-color: #FA7D22;
104
+
105
+  .el-menu {
106
+    background-color: #FA7D22;
107
+
108
+    .el-menu-item {
109
+      color: #eee
110
+    }
111
+  }
112
+}
113
+
114
+.content {
115
+  background-color: #fff;
116
+  flex: 1;
117
+  overflow: hidden;
118
+
119
+  header {
120
+    line-height: 50px;
121
+    font-size: 16px;
122
+    color: #409EFF;
123
+    padding: 0 28px 0 13px;
124
+    border-bottom: 1px solid #e5e5e5;
125
+    height: 60px;
126
+    display: flex;
127
+    align-items: center;
128
+    justify-content: right;
129
+
130
+    position: relative;
131
+    .left{
132
+      font-size: 14px;
133
+      font-family: SourceHanSansCN-Regular, SourceHanSansCN;
134
+      font-weight: 400;
135
+      color: #333333;
136
+      line-height: 21px;
137
+    }
138
+    .right {
139
+      float: right;
140
+      display: flex;
141
+
142
+      .news {
143
+        width: 24px;
144
+        height: 24px;
145
+
146
+        img {
147
+          width: 100%;
148
+          display: block;
149
+        }
150
+      }
151
+      .head-img{
152
+        margin-left: 19px;
153
+        width: 28px;
154
+        height: 28px;
155
+        border-radius: 50%;
156
+        img{
157
+          width: 100%;
158
+          display: block;
159
+        }
160
+      }
161
+    }
162
+  }
163
+
164
+  .main-wrapper {
165
+    height: calc(100% - 51px);
166
+    width: 100%;
167
+    overflow: auto;
168
+    padding: 20px;
169
+    background-color: #F7F8FA;
170
+  }
171
+}
172
+</style>

+ 139 - 0
src/components/common/layout/leftMenu.vue

@@ -0,0 +1,139 @@
1
+<template>
2
+  <el-menu :collapse="isCollapse"
3
+           background-color="#FA7D22"
4
+           text-color="#FFFFFF"
5
+           active-text-color="#FA7D22"
6
+           :default-active="$route.path"
7
+           style="width: 115px;"
8
+           router>
9
+    <div class="logo">
10
+      <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/logo.png" alt="">
11
+    </div>
12
+    <div v-for="(item,index1) in menu" :key="index1">
13
+      <!--      <el-submenu :index="index1+'a'" v-if="item.children && item.children.length > 0">-->
14
+      <!--        <template slot="title">-->
15
+      <!--          <i :class="item.icon"></i>-->
16
+      <!--          <span v-show="!isCollapse" slot="title">{{ item.name }}</span>-->
17
+      <!--        </template>-->
18
+      <!--        <div v-for="(child,index2) in item.children" :key="'second'+index2">-->
19
+      <!--          <el-menu-item :index="child.path">-->
20
+      <!--            <i :class="child.icon"></i>-->
21
+      <!--            <span slot="title">{{ child.name }}</span>-->
22
+      <!--          </el-menu-item>-->
23
+      <!--        </div>-->
24
+      <!--      </el-submenu>-->
25
+      <div class="el-menu-item" @click="handleSelect(index1,item)" :index="item.path" :class="index1==nowIndex?'active':''"
26
+           :style="index1+1==nowIndex?'padding-bottom:0px':index1-1==nowIndex?'padding-top:0px':''">
27
+        <img :src="index1==nowIndex?item.icon:item.unicon"><span slot="title">{{ item.name }}</span>
28
+      </div>
29
+    </div>
30
+  </el-menu>
31
+</template>
32
+
33
+<script>
34
+// import memberLogic from '@/server/memberLogic.js'
35
+export default {
36
+  props: ['isCollapse'],
37
+  data() {
38
+    return {
39
+      menu: [
40
+        {
41
+          name: "首页",
42
+          path: "/home",
43
+          unicon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/unhome.png',
44
+          icon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/home.png'
45
+
46
+        }, {
47
+          name: "测肤记录",
48
+          path: "/testSkin",
49
+          unicon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/unskin.png',
50
+          icon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/Skin.png',
51
+        }, {
52
+          name: "发券中心",
53
+          path: "/coupon",
54
+          unicon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/uncoupon.png',
55
+          icon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/coupon.png',
56
+        }, {
57
+          name: "客户管理",
58
+          path: "/customerMan",
59
+          unicon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/unskin.png',
60
+          icon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/Skin.png',
61
+        }, {
62
+          name: "历史订单",
63
+          path: "/historicalOrder",
64
+          unicon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/unhistory.png',
65
+          icon:'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/history.png',
66
+        }, {
67
+          name: "确定订单",
68
+          path: "/confirmOrder",
69
+          unicon:'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/unconfirmOrder.png',
70
+          icon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/confirmOrder.png'
71
+        }, {
72
+          name: "门店检测",
73
+          path: "/storeDetection",
74
+          icon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/testing.png',
75
+          unicon: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/icon/slices/untesting.png'
76
+        }
77
+      ],
78
+      nowIndex: 0
79
+    }
80
+  },
81
+  mounted() {
82
+
83
+  },
84
+  methods: {
85
+    handleSelect(index,item) {
86
+      this.nowIndex = index
87
+      this.$router.push({
88
+        path:item.path
89
+      })
90
+      this.$emit('changeMenu',index)
91
+    }
92
+  }
93
+}
94
+</script>
95
+
96
+<style lang="less" scoped>
97
+.logo {
98
+  margin-top: 22px;
99
+  text-align: center;
100
+
101
+  img {
102
+    width: 60px;
103
+    height: 60px;
104
+
105
+  }
106
+}
107
+
108
+.active {
109
+  line-height: 46px !important;
110
+  background: url("https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/select_icon.png") no-repeat;
111
+  background-size: 100% 100%;
112
+  background-color: #FA7D22 !important;
113
+  color: #FA7D22 !important;
114
+}
115
+
116
+.el-menu-item {
117
+  margin-left: 8px;
118
+  padding: 0;
119
+  padding-left: 9px !important;
120
+  height: auto;
121
+  line-height: initial;
122
+  padding: 13px 0;
123
+  cursor: none;
124
+  color: #FFFFFF;
125
+
126
+  img {
127
+    width: 20px;
128
+    height: 20px;
129
+  }
130
+}
131
+
132
+/deep/ .el-menu-item:focus {
133
+  background-color: transparent;
134
+}
135
+
136
+/deep/ .el-menu-item:hover {
137
+  background-color: transparent;
138
+}
139
+</style>

+ 40 - 0
src/components/modules/helloWorld.vue

@@ -0,0 +1,40 @@
1
+<template>
2
+    <div class="hello">
3
+        <h1>{{ msg }},样式由less书写</h1>
4
+        <input type="text" class="common">
5
+        <button @click="test()">点击</button>
6
+    </div>
7
+</template>
8
+
9
+<script>
10
+export default {
11
+    name: 'HelloWorld',
12
+    props: {
13
+        msg: String
14
+    },
15
+    data() {
16
+        return {
17
+            
18
+        }
19
+    },
20
+    mounted: function () {
21
+    },
22
+    created: function () {
23
+    },
24
+    methods: {
25
+        test(){
26
+            console.log("点击了")
27
+        }
28
+    }
29
+}
30
+</script>
31
+
32
+<style lang='less' scoped>
33
+    @import url(../../style/root.less);
34
+    h1 {
35
+        .hei(60px);
36
+        &:hover {
37
+            color: #696;
38
+        }
39
+    }
40
+</style>

+ 26 - 0
src/config/env.js

@@ -0,0 +1,26 @@
1
+// 环境配置
2
+let appId = 102;       //sso登录服务的appid,传0表示走老的授权登录
3
+let appVersion = 1;    //sso登录服务的版本,默认为第一版
4
+let logFlag = {
5
+	dev: false,    			// 开发和测试环境是否上报log
6
+	from: false,   			// 是否上传页面来源
7
+	packageName: 'web-init'
8
+}; 
9
+let basePath = 'https://api.51yund.com'; 	// api请求地址
10
+let ssoPath = 'https://sso.51yund.com';		// 授权登录地址
11
+let localPath = 'https://51yund.com';       // 获取定位地址
12
+let logPath = 'https://api.51yund.com';     // 上传日志地址
13
+let jumpPath = 'https://d.51yund.com';		// 跳转登录地址
14
+let filterErr = ['sskey过期'];  //过滤掉某些错不上报
15
+
16
+export {
17
+	basePath,
18
+	ssoPath,
19
+	localPath,
20
+	jumpPath,
21
+	logPath,
22
+	logFlag,
23
+	appId,
24
+	appVersion,
25
+	filterErr
26
+}

+ 48 - 0
src/directives/drag.js

@@ -0,0 +1,48 @@
1
+import Vue from 'vue'
2
+Vue.directive('drag', {  //自定义指令                                      JS
3
+    bind:function (el, binding) {
4
+        let oDiv = el;   //当前元素
5
+        oDiv.onmousedown = function (e) {
6
+         //鼠标按下,计算当前元素距离可视区的距离
7
+            let disX = e.clientX - oDiv.offsetLeft;
8
+            let disY = e.clientY - oDiv.offsetTop;
9
+
10
+            document.onmousemove = function (e) {
11
+              //通过事件委托,计算移动的距离 
12
+                let l = e.clientX - disX;
13
+                let t = e.clientY - disY;
14
+              //移动当前元素  
15
+                oDiv.style.left = l + 'px';
16
+                oDiv.style.top = t + 'px';
17
+            };
18
+            document.onmouseup = function () {               
19
+                document.onmousemove = null;
20
+                document.onmouseup = null;
21
+            };
22
+        };
23
+
24
+        function onMouseWheel(ev) {/*当鼠标滚轮事件发生时,执行一些操作*/
25
+            ev = ev || window.event;
26
+            var down = true; // 定义一个标志,当滚轮向下滚时,执行一些操作
27
+                down = ev.wheelDelta?ev.wheelDelta<0:ev.detail>0;
28
+            if(down){
29
+                oDiv.style.width = oDiv.offsetWidth-20+'px';
30
+            }else{
31
+                oDiv.style.width = oDiv.offsetWidth+20+'px';
32
+            }
33
+            if(ev.preventDefault){/*FF 和 Chrome*/
34
+                ev.preventDefault();// 阻止默认事件
35
+            }
36
+            return false;
37
+        }
38
+        addEvent(oDiv,'mousewheel',onMouseWheel);
39
+        addEvent(oDiv,'DOMMouseScroll',onMouseWheel);
40
+        function addEvent(obj,xEvent,fn) {
41
+            if(obj.attachEvent){
42
+                obj.attachEvent('on'+xEvent,fn);
43
+            }else{
44
+                obj.addEventListener(xEvent,fn,false);
45
+            }
46
+        }
47
+    }
48
+});

+ 90 - 0
src/filters/filter.js

@@ -0,0 +1,90 @@
1
+import Vue from 'vue'
2
+/**
3
+   * 取小数位的精度   页面用法:{{'13232.1' | doubleNum}} 返回值:13232.10
4
+   * @param {Object} value     //需要匹配小数位的原始值
5
+   * @param {Object} d         //小数位的位数(可不传,不传默认保留两位小数)  
6
+   */
7
+Vue.filter("doubleNum", function(value,d) {
8
+	if(value=='--'){
9
+		return value;
10
+	}
11
+	d=d?d:'2';
12
+	if(value){
13
+		return parseFloat(value).toFixed(d);
14
+	} else{
15
+		// return '--'
16
+		return (0).toFixed(d);
17
+	}
18
+});
19
+
20
+/**
21
+   * 千分位符   页面用法:{{'13232.1' | thousand}}  返回值:13,232.1
22
+   * @param {Object} value     //需要匹配的原始值
23
+   * @param {Object} d         //需要保留的小数位的位数(可不传,不传保留原始小数位)  
24
+   */
25
+Vue.filter("thousand", function(value,d) {
26
+	if(value){
27
+		if(d) value=parseFloat(value).toFixed(d);
28
+		value=value.toString();
29
+		var re=/\d{1,3}(?=(\d{3})+$)/g;
30
+		var n1=value.replace(/^(\d+)((\.\d+)?)$/,function(s,s1,s2){return s1.replace(re,"$&,")+s2;});
31
+		return n1;
32
+	}
33
+});
34
+
35
+/**
36
+   * 日期格式重置   页面用法:{{'2017-08-22 18:30:26','yyyy-mm-dd hhmm' | formatDate}}  返回值:'2017-08-22 18:30'
37
+   * @param {Object} value     //需要匹配的原始值
38
+   * @param {Object} value2    //需要得到的日期格式(页面不区分大小写,可不传,不传默认返回年月日) 
39
+   */
40
+Vue.filter("formatDate", function(value,value2) {
41
+	if(value){ 
42
+		if(value2) {
43
+			if(value2.toLowerCase()=='yyyy-mm-dd hhmm'){
44
+				let str=value.slice(11,19);
45
+				if(str=='23:59:59'){
46
+					return value.slice(0,10)+' 24:00';
47
+				} else{
48
+					return value.slice(0,16);
49
+				}
50
+			} else if(value2.toLowerCase()=='yyyy-mm-dd hh'){
51
+				return value.slice(0,13);
52
+			}else if(value2.toLowerCase()=='hhmm'){
53
+				if(value.slice(11,19)=='23:59:59'){
54
+					return '24:00';
55
+				}
56
+				return value.slice(11,16);
57
+			} else{
58
+				return value.slice(0,10);
59
+			}
60
+		}else{
61
+			return value.slice(0,10);
62
+		}
63
+	}
64
+});
65
+
66
+/**
67
+   * 时间格式重置   页面用法:{{'18:30:26' | formatTime}}  返回值:'18:30'
68
+   * @param {Object} value     //需要匹配的原始值
69
+   */
70
+Vue.filter("formatTime", function(value) {
71
+	if(value){ 
72
+		if(value=='23:59:59'){
73
+			return "24:00";
74
+		} else{
75
+			return value.slice(0,5);
76
+		}
77
+	}
78
+});
79
+
80
+/**
81
+   * 格式重置   返回百分比
82
+   * @param {Object} value     //需要匹配的原始值
83
+   */
84
+Vue.filter("percent", function(value) {
85
+	if(value){
86
+		return parseFloat(value).toFixed(2)+ '%';
87
+	} else{
88
+		return (0).toFixed(2) + '%';
89
+	}
90
+});

+ 30 - 0
src/main.js

@@ -0,0 +1,30 @@
1
+import Vue from 'vue'
2
+import App from './App.vue'
3
+import router from './router/index'
4
+import store from './store/index'
5
+import login from './common/login'
6
+import auth from './common/auth'
7
+import {injectGlobal} from './common/'
8
+import ElementUI from 'element-ui'
9
+import 'element-ui/lib/theme-chalk/index.css'
10
+import './style/reset.less'
11
+import './style/common.less'
12
+import './assets/font/iconfont.css'
13
+import './style/index.less'
14
+import './filters/filter'
15
+//全局注入
16
+injectGlobal()
17
+Vue.use(ElementUI)
18
+
19
+window.globalVue = "";
20
+// login((hasLogin)=>{
21
+	auth(router);
22
+	Vue.config.productionTip = false
23
+	const globalVue = new Vue({
24
+		router,
25
+		store,
26
+		render: h => h(App)
27
+	}).$mount('#app')
28
+	window.globalVue = globalVue;
29
+	window.ydStorage && ydStorage.postItem();
30
+// });

+ 31 - 0
src/pages/confirmOrder/index.vue

@@ -0,0 +1,31 @@
1
+<template>
2
+  <div>
3
+    ConfirmOrder
4
+  </div>
5
+</template>
6
+
7
+<script>
8
+export default {
9
+  components: {},
10
+  data() {
11
+    return {};
12
+  },
13
+  computed: {},
14
+  watch: {},
15
+
16
+  methods: {},
17
+
18
+  created() {
19
+
20
+  },
21
+
22
+  mounted() {
23
+
24
+  },
25
+}
26
+
27
+</script>
28
+
29
+<style lang='less' scoped>
30
+
31
+</style>

+ 31 - 0
src/pages/coupon/index.vue

@@ -0,0 +1,31 @@
1
+<template>
2
+  <div>
3
+    coupon
4
+  </div>
5
+</template>
6
+
7
+<script>
8
+export default {
9
+  components: {},
10
+  data() {
11
+    return {};
12
+  },
13
+  computed: {},
14
+  watch: {},
15
+
16
+  methods: {},
17
+
18
+  created() {
19
+
20
+  },
21
+
22
+  mounted() {
23
+
24
+  },
25
+}
26
+
27
+</script>
28
+
29
+<style lang='less' scoped>
30
+
31
+</style>

+ 31 - 0
src/pages/customerMan/index.vue

@@ -0,0 +1,31 @@
1
+<template>
2
+  <div>
3
+客户管理
4
+  </div>
5
+</template>
6
+
7
+<script>
8
+export default {
9
+  components: {},
10
+  data() {
11
+    return {};
12
+  },
13
+  computed: {},
14
+  watch: {},
15
+
16
+  methods: {},
17
+
18
+  created() {
19
+
20
+  },
21
+
22
+  mounted() {
23
+
24
+  },
25
+}
26
+
27
+</script>
28
+
29
+<style lang='less' scoped>
30
+
31
+</style>

+ 31 - 0
src/pages/historicalOrder/index.vue

@@ -0,0 +1,31 @@
1
+<template>
2
+  <div>
3
+    historicalOrder
4
+  </div>
5
+</template>
6
+
7
+<script>
8
+export default {
9
+  components: {},
10
+  data() {
11
+    return {};
12
+  },
13
+  computed: {},
14
+  watch: {},
15
+
16
+  methods: {},
17
+
18
+  created() {
19
+
20
+  },
21
+
22
+  mounted() {
23
+
24
+  },
25
+}
26
+
27
+</script>
28
+
29
+<style lang='less' scoped>
30
+
31
+</style>

+ 295 - 0
src/pages/home/index.vue

@@ -0,0 +1,295 @@
1
+<template>
2
+  <div class="home">
3
+    <div class="tab">
4
+      <div class="make-order" v-for="item in tabList">
5
+        <div class="make-icon">
6
+          <img :src="item.image">
7
+        </div>
8
+        <div class="make-tips">
9
+          <div class="make-num">{{ item.num }}</div>
10
+          <div class="make-name">{{ item.name }}</div>
11
+        </div>
12
+      </div>
13
+    </div>
14
+    <div class="order-list">
15
+      <div class="title">预约订单列表</div>
16
+      <div class="list-info">
17
+        <div class="user-info" v-for="(item,index) in orderList" :style="index==orderList.length-1?'border-bottom:0px':''">
18
+          <div class="head-img"> <div class="new">新</div><img :src="item.img" alt=""></div>
19
+          <div class="user-information">
20
+            <div class="name">客户昵称:<span>{{ item.name }}</span></div>
21
+            <div class="name">预约项目时间:<span>{{ item.ts }}</span></div>
22
+            <div class="name">预约项目数量:<span>{{ item.num }}</span></div>
23
+          </div>
24
+          <ul class="product-list">
25
+            <li class="product-image" v-for="value in item.imgList"><img :src="value" alt=""></li>
26
+          </ul>
27
+          <div class="status">
28
+            {{ item.status }}
29
+          </div>
30
+        </div>
31
+      </div>
32
+    </div>
33
+  </div>
34
+</template>
35
+
36
+<script>
37
+import api from '@/server/home'
38
+
39
+export default {
40
+  name: 'home',
41
+  data() {
42
+    return {
43
+      tabList: [
44
+        {
45
+          image: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
46
+          num: 0,
47
+          name: '预约订单'
48
+        },
49
+        {
50
+          image: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/unpaid.png',
51
+          num: 0,
52
+          name: '未支付订单'
53
+        },
54
+        {
55
+          image: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/cancelOrder.png',
56
+          num: 0,
57
+          name: '取消订单'
58
+        },
59
+      ],
60
+      orderList: [
61
+        {
62
+          img: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
63
+          name: '滴滴滴',
64
+          ts: '2022.04.25  14:30-16:30',
65
+          num: '5',
66
+          imgList: [
67
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
68
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
69
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
70
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
71
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
72
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
73
+          ],
74
+          status: '未支付'
75
+        },
76
+        {
77
+          img: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
78
+          name: '滴滴滴',
79
+          ts: '2022.04.25  14:30-16:30',
80
+          num: '5',
81
+          imgList: [
82
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
83
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
84
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
85
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
86
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
87
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
88
+          ],
89
+          status: '未支付'
90
+        },
91
+        {
92
+          img: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
93
+          name: '滴滴滴',
94
+          ts: '2022.04.25  14:30-16:30',
95
+          num: '5',
96
+          imgList: [
97
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
98
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
99
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
100
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
101
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
102
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
103
+          ],
104
+          status: '未支付'
105
+        },
106
+        {
107
+          img: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
108
+          name: '滴滴滴',
109
+          ts: '2022.04.25  14:30-16:30',
110
+          num: '5',
111
+          imgList: [
112
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
113
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
114
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
115
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
116
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
117
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
118
+          ],
119
+          status: '未支付'
120
+        },
121
+      ],
122
+
123
+    }
124
+  },
125
+  mounted: function () {
126
+
127
+  },
128
+  created: function () {
129
+
130
+  },
131
+  methods: {
132
+    initData() {
133
+
134
+    },
135
+  },
136
+  computed: {},
137
+  watch: {}
138
+}
139
+</script>
140
+<style lang='less' scoped>
141
+@import url(../../style/root.less);
142
+
143
+.home {
144
+  text-align: center;
145
+
146
+  .tab {
147
+    display: flex;
148
+    justify-content: space-between;
149
+    align-items: center;
150
+
151
+    .make-order {
152
+      width: 274px;
153
+      padding: 14px 30px;
154
+      background: #FFFFFF;
155
+      box-shadow: 0px 2px 4px 0px rgba(184, 191, 198, 0.2);
156
+      border-radius: 8px;
157
+      display: flex;
158
+      align-items: center;
159
+
160
+      .make-icon {
161
+        img {
162
+          width: 68px;
163
+        }
164
+      }
165
+
166
+      .make-tips {
167
+        margin-left: 20px;
168
+
169
+        .make-num {
170
+          font-size: 34px;
171
+          font-family: OPPOSans-B, OPPOSans;
172
+          font-weight: normal;
173
+          color: #333333;
174
+          line-height: 40px;
175
+          text-align: left;
176
+        }
177
+
178
+        .make-name {
179
+          font-size: 14px;
180
+          font-family: PingFangSC-Regular, PingFang SC;
181
+          font-weight: 400;
182
+          color: #333333;
183
+          line-height: 20px;
184
+        }
185
+      }
186
+    }
187
+  }
188
+
189
+  .order-list {
190
+    margin-top: 18px;
191
+    width: 100%;
192
+    background: #FFFFFF;
193
+    box-shadow: 0px 2px 4px 0px rgba(184, 191, 198, 0.2);
194
+    border-radius: 8px;
195
+    padding: 14px 12px;
196
+
197
+    .title {
198
+      font-size: 14px;
199
+      font-family: PingFangSC-Medium, PingFang SC;
200
+      font-weight: 500;
201
+      color: #333333;
202
+      line-height: 20px;
203
+      text-align: left;
204
+      padding-bottom: 5px;
205
+    }
206
+
207
+    .list-info {
208
+      height: 300px;
209
+      overflow: auto;
210
+
211
+      .user-info {
212
+        padding: 14px 0;
213
+        border-bottom: 1px solid #E6E6E6;
214
+        display: flex;
215
+        align-items: center;
216
+
217
+        .head-img {
218
+          position: relative;
219
+          width: 72px;
220
+          .new{
221
+            position: absolute;
222
+            top: -2px;
223
+            right: -2px;
224
+            width: 21px;
225
+            height: 21px;
226
+            line-height: 21px;
227
+            text-align: center;
228
+            font-size: 12px;
229
+            font-family: PingFangSC-Regular, PingFang SC;
230
+            font-weight: 400;
231
+            color: #FFFFFF;
232
+            line-height: 17px;
233
+            background: #FF6945;
234
+            border-radius: 50%;
235
+          }
236
+
237
+          img {
238
+            width: 100%;
239
+            border-radius: 50%;
240
+          }
241
+        }
242
+
243
+        .user-information {
244
+          margin-left: 16px;
245
+          text-align: left;
246
+          font-size: 14px;
247
+          font-family: SourceHanSansCN-Regular, SourceHanSansCN;
248
+          font-weight: 400;
249
+          color: #999999;
250
+          line-height: 21px;
251
+
252
+          .name {
253
+            span {
254
+              color: #333333;
255
+            }
256
+          }
257
+        }
258
+
259
+        .product-list {
260
+          width: 322px;
261
+          margin-left: 22px;
262
+          white-space: nowrap;
263
+          overflow-x: scroll;
264
+          overflow-y: hidden;
265
+          padding-left: 8px;
266
+
267
+
268
+          .product-image {
269
+            display: inline-block;
270
+            margin-left: 16px;
271
+            width: 72px;
272
+            img{
273
+              border-radius: 8px;
274
+              width: 100%;
275
+              display: block;
276
+            }
277
+
278
+          }
279
+
280
+        }
281
+        .status{
282
+          margin-left: 56px;
283
+          font-size: 16px;
284
+          font-family: SourceHanSansCN-Regular, SourceHanSansCN;
285
+          font-weight: 400;
286
+          color: #FC3019;
287
+          line-height: 24px;
288
+        }
289
+      }
290
+    }
291
+
292
+  }
293
+}
294
+
295
+</style>

+ 117 - 0
src/pages/login/login.vue

@@ -0,0 +1,117 @@
1
+<template>
2
+  <div class="mine">
3
+    <div class="login-info">
4
+      <div class="logo">
5
+        <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/logo%402x.png" alt="">
6
+      </div>
7
+      <div class="login-title">JOLIJOLI店员端</div>
8
+      <div class="content">
9
+        <div class="value-inp">
10
+          <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/num_icon.png" alt="">
11
+          <el-input placeholder="请输入账号名" v-model="account"></el-input>
12
+        </div>
13
+        <div class="value-inp">
14
+          <img src="https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/password_icon.png" alt="">
15
+          <el-input placeholder="请输入密码" v-model="password" show-password></el-input>
16
+        </div>
17
+      </div>
18
+    </div>
19
+  </div>
20
+</template>
21
+
22
+<script>
23
+export default {
24
+  components: {},
25
+  data() {
26
+    return {
27
+      account:"",
28
+      password:""
29
+
30
+    };
31
+  },
32
+  computed: {},
33
+  watch: {},
34
+
35
+  methods: {},
36
+
37
+  created() {
38
+
39
+  },
40
+
41
+  mounted() {
42
+
43
+  },
44
+}
45
+
46
+</script>
47
+
48
+<style lang='less' scoped>
49
+.mine {
50
+  width: 100%;
51
+  min-height: 100vh;
52
+  background: linear-gradient(315deg, #FF9F7E 0%, #FF926C 0%, #FF9D55 100%);
53
+  position: relative;
54
+  .login-info{
55
+    position: absolute;
56
+    left: 50%;
57
+    top: 15%;
58
+    transform: translateX(-50%);
59
+    width: 460px;
60
+    height: 460px;
61
+    background: url("https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/login_bg.png") no-repeat;
62
+    background-size: 100% 100%;
63
+    .logo{
64
+      width: 100px;
65
+      height: 100px;
66
+      position: relative;
67
+      left: 50%;
68
+      transform: translateX(-50%);
69
+      top: -17px;
70
+      img{
71
+        width: 100%;
72
+        display: block;
73
+      }
74
+    }
75
+    .login-title{
76
+      margin-top: 7px;
77
+      font-size: 28px;
78
+      font-family: PingFangSC-Medium, PingFang SC;
79
+      font-weight: 500;
80
+      text-align: center;
81
+      color: #EB5C21;
82
+      line-height: 40px;
83
+    }
84
+    .content{
85
+      padding-top: 15px;
86
+      position: relative;
87
+      .value-inp{
88
+        position: relative;
89
+        margin-top: 20px;
90
+        left: 50%;
91
+        transform: translateX(-50%);
92
+        width: 336px;
93
+        height: 53px;
94
+        background: url("https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/input_bg.png") no-repeat;
95
+        background-size: 100% 100%;
96
+        display: flex;
97
+        padding: 0 24px;
98
+        justify-content: space-between;
99
+        align-items: center;
100
+        img{
101
+          width: 32px;
102
+          height: 32px;
103
+        }
104
+       /deep/ .el-input__inner{
105
+          background-color:transparent;
106
+         border: 0px solid #DCDFE6;
107
+         height: 53px;
108
+         line-height: 53px;
109
+         font-size: 18px;
110
+         font-family: PingFangSC-Regular, PingFang SC;
111
+         font-weight: 400;
112
+        }
113
+      }
114
+    }
115
+  }
116
+}
117
+</style>

+ 31 - 0
src/pages/storeDetection/index.vue

@@ -0,0 +1,31 @@
1
+<template>
2
+  <div>
3
+    storeDetection
4
+  </div>
5
+</template>
6
+
7
+<script>
8
+export default {
9
+  components: {},
10
+  data() {
11
+    return {};
12
+  },
13
+  computed: {},
14
+  watch: {},
15
+
16
+  methods: {},
17
+
18
+  created() {
19
+
20
+  },
21
+
22
+  mounted() {
23
+
24
+  },
25
+}
26
+
27
+</script>
28
+
29
+<style lang='less' scoped>
30
+
31
+</style>

+ 31 - 0
src/pages/testSkin/details/index.vue

@@ -0,0 +1,31 @@
1
+<template>
2
+  <div class="mine">
3
+    <div class=""></div>
4
+  </div>
5
+</template>
6
+
7
+<script>
8
+export default {
9
+  components: {},
10
+  data() {
11
+    return {};
12
+  },
13
+  computed: {},
14
+  watch: {},
15
+
16
+  methods: {},
17
+
18
+  created() {
19
+
20
+  },
21
+
22
+  mounted() {
23
+
24
+  },
25
+}
26
+
27
+</script>
28
+
29
+<style lang='less' scoped>
30
+
31
+</style>

+ 248 - 0
src/pages/testSkin/index.vue

@@ -0,0 +1,248 @@
1
+<template>
2
+  <div class="mine">
3
+    <div class="condition">
4
+      <el-date-picker v-model="dates"
5
+                      type="daterange"
6
+                      range-separator="->"
7
+                      start-placeholder="开始日期"
8
+                      end-placeholder="结束日期">
9
+      </el-date-picker>
10
+
11
+      <el-input placeholder="请输入内容"
12
+                class="search"
13
+                v-model="searchText">
14
+        <i slot="prefix"
15
+           class="el-input__icon el-icon-search"></i>
16
+      </el-input>
17
+      <el-button type="primary"
18
+                 class="searchButton">搜索</el-button>
19
+    </div>
20
+    <div class="list">
21
+      <div class="tab">
22
+        <div class="head-img">头像</div>
23
+        <div class="head-name">昵称</div>
24
+        <div class="head-phone">联系电话</div>
25
+        <div class="head-ts">预约时间</div>
26
+        <div class="head-status">状态</div>
27
+      </div>
28
+      <div class="content">
29
+        <div class="tab user-info"
30
+             v-for="(item,index) in userList"
31
+             :key="index"
32
+             @click="onDetails">
33
+          <div class="head-img"><img :src="item.img"
34
+                 alt=""></div>
35
+          <div class="head-name">{{ item.name }}</div>
36
+          <div class="head-phone">{{ item.phone }}</div>
37
+          <div class="head-ts">{{ item.ts }}</div>
38
+          <div class="head-status">{{ item.status }}</div>
39
+        </div>
40
+      </div>
41
+      <div class="pagin">
42
+        <el-pagination background
43
+                       layout="prev, pager, next"
44
+                       @size-change="handleSizeChange"
45
+                       @current-change="handleCurrentChange"
46
+                       :current-page.sync="currentPage1"
47
+                       :total="1000">
48
+        </el-pagination>
49
+      </div>
50
+    </div>
51
+  </div>
52
+</template>
53
+
54
+<script>
55
+export default {
56
+  components: {},
57
+  data () {
58
+    return {
59
+      dates: '',
60
+      searchText: '',
61
+      userList: [
62
+        {
63
+          img:
64
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
65
+          name: '张三',
66
+          phone: 4556455645,
67
+          ts: '2022.04.15  14:30-16:30',
68
+          status: '标签信息未填写'
69
+        },
70
+        {
71
+          img:
72
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
73
+          name: '张三',
74
+          phone: 4556455645,
75
+          ts: '2022.04.15  14:30-16:30',
76
+          status: '标签信息未填写'
77
+        },
78
+        {
79
+          img:
80
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
81
+          name: '张三',
82
+          phone: 4556455645,
83
+          ts: '2022.04.15  14:30-16:30',
84
+          status: '标签信息未填写'
85
+        },
86
+        {
87
+          img:
88
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
89
+          name: '张三',
90
+          phone: 4556455645,
91
+          ts: '2022.04.15  14:30-16:30',
92
+          status: '标签信息未填写'
93
+        },
94
+        {
95
+          img:
96
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
97
+          name: '张三',
98
+          phone: 4556455645,
99
+          ts: '2022.04.15  14:30-16:30',
100
+          status: '标签信息未填写'
101
+        },
102
+        {
103
+          img:
104
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
105
+          name: '张三',
106
+          phone: 4556455645,
107
+          ts: '2022.04.15  14:30-16:30',
108
+          status: '标签信息未填写'
109
+        },
110
+        {
111
+          img:
112
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
113
+          name: '张三',
114
+          phone: 4556455645,
115
+          ts: '2022.04.15  14:30-16:30',
116
+          status: '标签信息未填写'
117
+        },
118
+        {
119
+          img:
120
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
121
+          name: '张三',
122
+          phone: 4556455645,
123
+          ts: '2022.04.15  14:30-16:30',
124
+          status: '标签信息未填写'
125
+        },
126
+        {
127
+          img:
128
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
129
+          name: '张三',
130
+          phone: 4556455645,
131
+          ts: '2022.04.15  14:30-16:30',
132
+          status: '标签信息未填写'
133
+        },
134
+        {
135
+          img:
136
+            'https://we-spa.oss-cn-shenzhen.aliyuncs.com/pad_clerk/home/make.png',
137
+          name: '张三',
138
+          phone: 4556455645,
139
+          ts: '2022.04.15  14:30-16:30',
140
+          status: '标签信息未填写'
141
+        }
142
+      ],
143
+      currentPage1: 2
144
+    }
145
+  },
146
+  computed: {},
147
+  watch: {},
148
+
149
+  methods: {
150
+    onDetails () {
151
+      this.$router.push({
152
+        path: '/testSkin/details'
153
+      })
154
+    },
155
+    handleCurrentChange () { },
156
+    handleSizeChange () { }
157
+  },
158
+
159
+  created () { },
160
+
161
+  mounted () { }
162
+}
163
+</script>
164
+
165
+<style lang='less' scoped>
166
+.mine {
167
+  .condition {
168
+    display: flex;
169
+
170
+    .search {
171
+      width: 152px;
172
+      margin-left: 18px;
173
+    }
174
+
175
+    .searchButton {
176
+      margin-left: 18px;
177
+      width: 68px;
178
+      background: #fa7d22;
179
+      border-radius: 2px;
180
+      border-color: #fa7d22;
181
+    }
182
+  }
183
+
184
+  .list {
185
+    margin-top: 18px;
186
+    padding: 14px 12px;
187
+    background: #ffffff;
188
+    box-shadow: 0px 2px 4px 0px rgba(184, 191, 198, 0.2);
189
+    border-radius: 8px;
190
+
191
+    .tab {
192
+      padding-bottom: 9px;
193
+      border-bottom: 1px solid #e6e6e6;
194
+      display: flex;
195
+      align-items: center;
196
+      font-size: 14px;
197
+      font-family: PingFangSC-Regular, PingFang SC;
198
+      font-weight: 400;
199
+      color: #999999;
200
+      line-height: 20px;
201
+
202
+      .head-img {
203
+        width: 84px;
204
+
205
+        img {
206
+          width: 36px;
207
+        }
208
+      }
209
+
210
+      .head-name {
211
+        width: 144px;
212
+      }
213
+
214
+      .head-phone {
215
+        width: 192px;
216
+      }
217
+
218
+      .head-ts {
219
+        width: 288px;
220
+      }
221
+
222
+      .head-status {
223
+      }
224
+    }
225
+
226
+    .content {
227
+      border-bottom: 0px;
228
+      padding-top: 14px;
229
+      max-height: 300px;
230
+      overflow: auto;
231
+
232
+      .user-info {
233
+        border-bottom: 18px;
234
+        font-size: 14px;
235
+        font-family: PingFangSC-Regular, PingFang SC;
236
+        font-weight: 400;
237
+        color: #333333;
238
+        line-height: 22px;
239
+      }
240
+    }
241
+
242
+    .el-pagination {
243
+      text-align: center;
244
+      margin-top: 50px;
245
+    }
246
+  }
247
+}
248
+</style>

File diff suppressed because it is too large
+ 615 - 0
src/plugins/qrcode.min.js


+ 9 - 0
src/plugins/rsa_password.js

@@ -0,0 +1,9 @@
1
+/* eslint-disable */
2
+function rsa(a) {
3
+	var rsa = new RSAKey();
4
+	var key="B2B41708916608F05AD96EBB26512E9700151348F13167BFDC79825F39FE68F867252275AD3476A3F36DAC7D2B370A15A2FAEFCA7C08980996A163984450642CD8B9A5788BB2D0F3940F8F7A41A0FCD2AFD823FDD3762729B2F4A56F8C4BFBDCD51EA314792527151D32EC6765B073756409C9BB2187278EFAD6DC0C167E0B33";
5
+	rsa.setPublic(key,"10001");
6
+	var res = rsa.encrypt(a);
7
+	res=linebrk(hex2b64(res), 64);
8
+	return res;
9
+}

+ 16 - 0
src/router/index.js

@@ -0,0 +1,16 @@
1
+import Vue from 'vue'
2
+import Router from 'vue-router'
3
+
4
+import home from './map/home'
5
+import login from "./map/login";
6
+
7
+Vue.use(Router)
8
+
9
+export default new Router({
10
+    mode: 'history',
11
+    base: process.env.BASE_URL,
12
+    routes: [
13
+        home,
14
+        ...login
15
+    ]
16
+})

+ 28 - 0
src/router/map/home.js

@@ -0,0 +1,28 @@
1
+/**
2
+ * Created by ZhongquanHe on 2019/04/29.
3
+ */
4
+import layout from '@/components/common/layout/layout' 
5
+import Home from '@/pages/home/index.vue'
6
+import TestSkin from '@/pages/testSkin/index'
7
+import TestSkinDetails from '@/pages/testSkin/details'
8
+import CustomerMan from '@/pages/customerMan/index'
9
+import HistoricalOrder from '@/pages/historicalOrder/index'
10
+import ConfirmOrder from '@/pages/confirmOrder/index'
11
+import StoreDetection from '@/pages/storeDetection/index'
12
+import Coupon from '@/pages/coupon/index'
13
+export default {
14
+	path: '/',
15
+	name: '首页',
16
+	component:layout,
17
+	children:[
18
+		{path:'/home', component:Home},
19
+		{path:'/testSkin',component:TestSkin },
20
+		{path:'/testSkin/details',component: TestSkinDetails},
21
+		{path:'/customerMan',component:CustomerMan },
22
+		{path: '/historicalOrder',component: HistoricalOrder},
23
+		{path: '/confirmOrder',component: ConfirmOrder},
24
+		{path: '/storeDetection',component: StoreDetection},
25
+		{path:'/coupon',component: Coupon},
26
+
27
+    ]
28
+}

+ 8 - 0
src/router/map/login.js

@@ -0,0 +1,8 @@
1
+// 登录
2
+export default [
3
+	{	
4
+		path: '/login',
5
+		name: 'login',
6
+		component: () => import('@/pages/login/login.vue') 
7
+	}
8
+]

+ 16 - 0
src/server/home.js

@@ -0,0 +1,16 @@
1
+// created by zach He on 2019-04-29
2
+// 企业概况
3
+import url from './urls'
4
+
5
+export default class Home {
6
+	/**
7
+	 * @描述  1.1	获取用户信息
8
+	 */
9
+	static getUserMess(parms) {
10
+		return $http.post(url.getUserMess,parms);
11
+    }
12
+}
13
+
14
+ 
15
+ 
16
+

+ 5 - 0
src/server/urls.js

@@ -0,0 +1,5 @@
1
+export default {
2
+	//登录
3
+	getsskey: '/sport/get_session_key',
4
+	getUserMess: '/enterprise/check_user_auth'
5
+}

+ 11 - 0
src/store/index.js

@@ -0,0 +1,11 @@
1
+import Vue from 'vue'
2
+import Vuex from 'vuex'
3
+import comVal from './modules/comVal'
4
+
5
+Vue.use(Vuex)
6
+
7
+export default new Vuex.Store({
8
+	modules: {
9
+        comVal
10
+    }
11
+})

+ 23 - 0
src/store/modules/comVal.js

@@ -0,0 +1,23 @@
1
+const state = {
2
+    name:666,
3
+    isBack:false
4
+}
5
+
6
+const actions = {
7
+    saveCommonValue({commit},value) {
8
+        commit('SAVE_COMMON_VALUE', value);
9
+	}
10
+}
11
+
12
+const mutations = {
13
+    SAVE_COMMON_VALUE(state, obj) {
14
+        state[obj.key] = obj.value;
15
+        // state.data = data;
16
+    },
17
+}
18
+
19
+export default {
20
+    state,
21
+    actions,
22
+    mutations
23
+}

+ 25 - 0
src/style/common.less

@@ -0,0 +1,25 @@
1
+.valid-red{
2
+    border: 1px solid #ea1717;
3
+}
4
+.search-wrapper{
5
+    >div{
6
+        margin:0 10px 10px 0;
7
+        display: inline-block;
8
+    }
9
+    margin-bottom: 20px;
10
+    color: #666
11
+}
12
+.login{
13
+    .el-dialog{
14
+        width: 400px;
15
+        .dialog-footer{
16
+            text-align: center;
17
+            .el-button{
18
+                width: 217px;
19
+            }
20
+        }
21
+
22
+    }
23
+}
24
+
25
+

+ 32 - 0
src/style/index.less

@@ -0,0 +1,32 @@
1
+
2
+//elementUI 组件样式覆盖
3
+
4
+.el-date-table td.in-range div, .el-date-table td.in-range div:hover, .el-date-table.is-week-mode .el-date-table__row.current div, .el-date-table.is-week-mode .el-date-table__row:hover div {
5
+  background-color: #FFF0E6;
6
+}
7
+.el-date-table td.end-date span, .el-date-table td.start-date span {
8
+  background-color:  #FA7D22 !important;
9
+  border-radius: 2px;
10
+}
11
+.el-date-table td.today span{
12
+  border-radius: 2px;
13
+  border: 1px solid #FA7D22;
14
+  color: #FA7D22;
15
+}
16
+ .el-date-table td.start-date div{
17
+  border-top-left-radius: 2px;
18
+  border-bottom-left-radius: 2px;
19
+}
20
+.el-date-table td.end-date div{
21
+  border-top-right-radius: 2px;
22
+  border-bottom-right-radius: 2px;
23
+}
24
+.el-date-editor.el-input, .el-date-editor.el-input__inner{
25
+  width: 280px;
26
+}
27
+.el-date-editor .el-range-separator{
28
+  width: 20px;
29
+}
30
+.el-pagination.is-background .el-pager li:not(.disabled).active{
31
+  background-color: #FA7D22;
32
+}

+ 15 - 0
src/style/reset.less

@@ -0,0 +1,15 @@
1
+/*样式重置*/
2
+body,html{margin:0; font:normal normal normal 14px/20px sans-serif;line-height: 1;}
3
+html *{margin:0; padding:0; box-sizing: border-box;}
4
+.clearfix:after { content: "\0020"; display: block; height: 0; clear: both; }
5
+.clearfix { _zoom: 1; }
6
+ul{list-style:none;}
7
+li,i,em{font-style:normal;}
8
+input{outline:medium;border:none;}
9
+a:focus,select{outline:none;}
10
+a{ text-decoration:none;}
11
+a:hover{ text-decoration:none;}
12
+.el-pagination{margin-top: 30px;}
13
+.el-menu{border: none; width: 200px; text-align: left};
14
+.el-menu--collapse{width: 64px;}
15
+.el-date-editor .el-range-separator{padding:0}

+ 51 - 0
src/style/root.less

@@ -0,0 +1,51 @@
1
+@mainColor: #999;  //全局主色调
2
+@width: 300px;
3
+.widh(@w: 100px, @h: 200px){
4
+	width: @w;
5
+	height: @h;
6
+}
7
+.lett(@l: 100px, @t: 100px){
8
+	left: @l;
9
+	top: @t;
10
+}
11
+.bg(@color: #696){
12
+	background-color: @color;
13
+	cursor: pointer;
14
+}
15
+.hei(@height: 30px){
16
+	height: @height;
17
+	line-height: @height;
18
+}
19
+@box:{
20
+	width: @width - 100;
21
+	height: 200px;
22
+	border: solid 1px red;
23
+	margin: 0 auto;
24
+	color: @mainColor;
25
+};
26
+@absolute:{
27
+	position: absolute;
28
+    .widh(200px);
29
+    .lett(100px, 100px);
30
+    z-index: 10;
31
+}
32
+.btnBg(@bgColor: #696){
33
+	transition: all 0.2s;
34
+	&:hover{
35
+		background-color: @bgColor
36
+	}
37
+}
38
+.btn(@color: #696){
39
+	transition: all 0.2s;
40
+	&:hover{
41
+		color: @color
42
+	}
43
+}
44
+.abso(@l: 0, @t: 0, @w: 100%){
45
+	position: absolute;
46
+	z-index: 10;
47
+	left: @l;
48
+	top: @t;
49
+	width: @w;
50
+}
51
+

+ 19 - 0
tests/e2e/custom-assertions/elementCount.js

@@ -0,0 +1,19 @@
1
+// A custom Nightwatch assertion.
2
+// The assertion name is the filename.
3
+// Example usage:
4
+//
5
+//   browser.assert.elementCount(selector, count)
6
+//
7
+// For more information on custom assertions see:
8
+// http://nightwatchjs.org/guide#writing-custom-assertions
9
+
10
+exports.assertion = function elementCount (selector, count) {
11
+  this.message = `Testing if element <${selector}> has count: ${count}`
12
+  this.expected = count
13
+  this.pass = val => val === count
14
+  this.value = res => res.value
15
+  function evaluator (_selector) {
16
+    return document.querySelectorAll(_selector).length
17
+  }
18
+  this.command = cb => this.api.execute(evaluator, [selector], cb)
19
+}

+ 26 - 0
tests/e2e/reports/CHROME_71.0.3578.80_Windows NT_test.xml

@@ -0,0 +1,26 @@
1
+<?xml version="1.0" encoding="UTF-8" ?>
2
+<testsuites errors="0"
3
+            failures="0"
4
+            tests="1">
5
+
6
+  <testsuite name="test"
7
+    errors="0" failures="0" hostname="" id="" package="test" skipped="0"
8
+    tests="1" time="3.642" timestamp="Fri, 15 Mar 2019 05:44:11 GMT">
9
+  
10
+    <testcase name="default e2e tests" classname="test" time="3.642" assertions="4">
11
+
12
+    
13
+
14
+    
15
+
16
+    
17
+
18
+    
19
+    </testcase>
20
+  
21
+
22
+  
23
+
24
+  
25
+  </testsuite>
26
+</testsuites>

+ 26 - 0
tests/e2e/reports/CHROME_74.0.3729.108_Windows NT_test.xml

@@ -0,0 +1,26 @@
1
+<?xml version="1.0" encoding="UTF-8" ?>
2
+<testsuites errors="0"
3
+            failures="0"
4
+            tests="1">
5
+
6
+  <testsuite name="test"
7
+    errors="0" failures="0" hostname="" id="" package="test" skipped="0"
8
+    tests="1" time="7.874" timestamp="Mon, 29 Apr 2019 12:25:44 GMT">
9
+  
10
+    <testcase name="default e2e tests" classname="test" time="7.874" assertions="4">
11
+
12
+    
13
+
14
+    
15
+
16
+    
17
+
18
+    
19
+    </testcase>
20
+  
21
+
22
+  
23
+
24
+  
25
+  </testsuite>
26
+</testsuites>

+ 14 - 0
tests/e2e/specs/test.js

@@ -0,0 +1,14 @@
1
+// For authoring Nightwatch tests, see
2
+// http://nightwatchjs.org/guide#usage
3
+
4
+module.exports = {
5
+  'default e2e tests': browser => {
6
+    browser
7
+      .url(process.env.VUE_DEV_SERVER_URL)
8
+      .waitForElementVisible('#app', 5000)
9
+      .assert.elementPresent('.hello')
10
+      .assert.containsText('h1', 'Welcome to Your Vue.js ,样式由less书写')
11
+      .assert.elementCount('img', 1)
12
+      .end()
13
+  }
14
+}

+ 5 - 0
tests/unit/.eslintrc.js

@@ -0,0 +1,5 @@
1
+module.exports = {
2
+  env: {
3
+    jest: true
4
+  }
5
+}

+ 12 - 0
tests/unit/components/hello.spec.js

@@ -0,0 +1,12 @@
1
+import {shallowMount} from '@vue/test-utils'
2
+import HelloWorld from '@/components/modules/helloWorld.vue'
3
+
4
+describe('helloWorld.vue', () => {
5
+    it('renders props.msg when passed', () => {
6
+        const msg = 'new message'
7
+        const wrapper = shallowMount(HelloWorld, {
8
+            propsData: {msg}
9
+        })
10
+        expect(wrapper.text()).toMatch(msg)
11
+    })
12
+})

+ 11 - 0
tests/unit/pages/loan.spec.js

@@ -0,0 +1,11 @@
1
+import {mount} from '@vue/test-utils'
2
+import home from '@/pages/home/index.vue'
3
+import HelloWorld from '@/components/modules/helloWorld.vue'
4
+
5
+describe('HelloWorld.vue', () => {
6
+    it('render img', () => {
7
+        const msg = 'new message'
8
+        const wrapper = mount(home)
9
+        expect(wrapper.contains(HelloWorld)).toBe(true)
10
+    })
11
+})

+ 42 - 0
vue.config.js

@@ -0,0 +1,42 @@
1
+// vue.config.js 配置说明
2
+//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
3
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
4
+
5
+module.exports = {
6
+    publicPath: process.env.env_config === 'prod' ? 'https://ydcommon.51yund.com/' : 
7
+    process.env.env_config === 'test' ? '/vapps/calory/' : '/', 
8
+    // 设置跨域
9
+    crossorigin: 'anonymous',
10
+    /**
11
+       * 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
12
+       *  map文件的作用在于:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。
13
+       *  有了map就可以像未加密的代码一样,准确的输出是哪一行哪一列有错。
14
+       * */
15
+    productionSourceMap: false,
16
+    transpileDependencies: ['swiper', 'dom7'],
17
+ 
18
+    // 它支持webPack-dev-server的所有选项
19
+    devServer: {
20
+        host: "0.0.0.0",
21
+        port: 8083, // 端口号
22
+        https: false, // https:{type:Boolean}
23
+        open: true, //配置自动启动浏览器
24
+        proxy: '' // 配置跨域处理
25
+    },
26
+    configureWebpack: {
27
+        externals: {
28
+            'axios': "axios"
29
+        }
30
+        // 这是七牛找不到资源时的紧急处理方法,通过修改hash位数修改编译后的资源文件名
31
+        // output: { 
32
+        //     filename: `js/[name].[hash:6].js`,
33
+        //     chunkFilename: `js/[name].[hash:6].js`
34
+        // },
35
+        // plugins: [
36
+        //     new MiniCssExtractPlugin({
37
+        //         filename: `css/[name].[hash:6].css`,
38
+        //         chunkFilename: `css/[name].[hash:6].css`
39
+        //     })
40
+        // ]
41
+    }
42
+}

+ 1 - 0
安装插件.bat

@@ -0,0 +1 @@
1
+npm install --registry=https://registry.npm.taobao.org --verbose 

+ 164 - 0
规范说明

@@ -0,0 +1,164 @@
1
+项目结构与规范说明
2
+
3
+一、目录结构说明
4
+src
5
+	assets			静态资源(图片、字体等)
6
+	common 			项目全局公共函数封装
7
+	components		全部组件
8
+		common 		通用组件,不带有任何业务数据,只带有通用样式或特定样式以及事件;以文件夹的形式隔开,如果存在资源则建立子目录存放
9
+		modules		业务组件,带有通用业务数据;
10
+	config			全局配置
11
+	directives		全局指令 按文件名划分
12
+	filters			全局筛选指令
13
+	pages			页面容器
14
+		login		路由为/home的页面,该页面如果涉及子页面,则创建children目录进行存放,多级递归。注意这里多级时路由配置也需要多级配置
15
+			children
16
+				child.vue
17
+			index.vue
18
+	plugins 		js第三方插件
19
+	router			路由配置
20
+		map			各个页面对应的路由配置,注意:这里是按页面来配置
21
+	server			前端领域业务封装,文件名按领域来区分;测试用例针对领域来编写流程
22
+		testData	按领域来存放测试数据
23
+	store			vuex 模块
24
+		modules		细分各个模块
25
+		index		vuex入口
26
+	style			全局样式
27
+		common.less 全局公共样式
28
+		root.less	全局less变量		
29
+tests
30
+	e2e				端到端测试
31
+	unit			单元测试
32
+vue.config.js		工程基本配置文件-端口、编译输出目录...
33
+
34
+
35
+三、js规范
36
+变量
37
+1.当前作用域顶端定义
38
+2.var禁用 在块级作用域下使用let
39
+3.在全局作用域下,函数及变量使用const定义
40
+4.字符串统一使用单引号,标签或者属性的值采用双引号
41
+
42
+函数
43
+1.that=this; 函数内部存在嵌套函数时,必须在最外层定义this指向
44
+2.内部私有方法写在return之后
45
+3.判断是否相等用全等号
46
+
47
+类
48
+1.定义顺序:变量、公开方法、私有方法
49
+
50
+模块
51
+1.export default 写到最底部
52
+2.export 变量写在一起靠底部位置
53
+
54
+命名
55
+1.变量、函数、vue组件名称 小写开头 驼峰规则
56
+2.私有加前缀(下划线)
57
+3.类命名 大写开始 驼峰规则
58
+4.资源文件全部用小写命名(包括文件夹),如backbtn.png、 province_city.json
59
+
60
+四、css规范
61
+每个style标签必去加上scoped
62
+样式规则:
63
+.classname{
64
+	//定位规则
65
+
66
+	//盒子属性
67
+
68
+	//其它
69
+}
70
+
71
+classname:命名规则 小写;多个单词-(中划线)分格
72
+
73
+层级样式减少标签直接使用方式;
74
+层级定义样式规则:
75
+.父级
76
+	.父级-子级
77
+		.父级-子级-子级		
78
+class相隔必须用-(中划线)
79
+id相隔必须用_(下划线)
80
+
81
+样式封装块,重复样式定义继承处理
82
+.commonclassname
83
+
84
+.classname {
85
+	//定位规则
86
+
87
+	//盒子属性
88
+
89
+	//其它
90
+
91
+	&:伪类 {
92
+
93
+	}
94
+
95
+	// 嵌套层级
96
+	.classname {
97
+		
98
+	}
99
+
100
+	.classname {
101
+
102
+	}
103
+}
104
+
105
+五、路由规范
106
+	根据页面来制定路由区域
107
+
108
+六、Vue文件规范
109
+<template>
110
+	// v-on => @
111
+	// v-bind => :
112
+</template>
113
+<script>
114
+	// 模块引入
115
+	// 对象接口
116
+	export default {
117
+		props:{
118
+			// 父级传入属性 
119
+	  	},
120
+		data(){
121
+			return {
122
+				组件相关初始化数据定义
123
+			}
124
+		},	
125
+
126
+		created(){
127
+			// 异步装载初始化数据
128
+			this.methodC();
129
+		},
130
+
131
+		components:{
132
+			// 引用的组件
133
+
134
+		},
135
+		
136
+		methods:{
137
+			// 一些数据交互的问题
138
+			methodA() {
139
+
140
+			},
141
+			methodB() {
142
+
143
+			},
144
+			async methodC() {
145
+
146
+			}
147
+		},
148
+		computed:{
149
+			// 需要属性计算的操作
150
+		},
151
+		watch:{
152
+			// 检控属性变化
153
+		}
154
+	}
155
+</script>
156
+<style lang="less" scoped>
157
+	
158
+</style>
159
+
160
+
161
+
162
+
163
+
164
+