mk 1 year ago
commit
59c644956b
  1. 2
      .browserslistrc
  2. 14
      .editorconfig
  3. 6
      .env.development
  4. 5
      .env.production
  5. 4
      .env.staging
  6. 4
      .eslintignore
  7. 54
      .eslintrc.js
  8. 24
      .gitignore
  9. 13
      .postcssrc.js
  10. 1
      .prettierignore
  11. 24
      .prettierrc
  12. 1212
      README.md
  13. 22
      babel.config.js
  14. 17
      jsconfig.json
  15. 60
      package.json
  16. BIN
      public/favicon.ico
  17. 27
      public/index.html
  18. 14
      src/App.vue
  19. 6
      src/api/home.js
  20. 7
      src/api/index.js
  21. 32
      src/api/user.js
  22. 70
      src/assets/css/common.less
  23. 35
      src/assets/css/index.less
  24. 36
      src/assets/css/mixin.scss
  25. 688
      src/assets/css/vant-theme.less
  26. 3
      src/assets/css/variables.scss
  27. BIN
      src/assets/logo.png
  28. 54
      src/components/TabBar.vue
  29. 9
      src/config/env.development.js
  30. 8
      src/config/env.production.js
  31. 8
      src/config/env.staging.js
  32. 3
      src/config/index.js
  33. 0
      src/const/index.js
  34. 37
      src/filters/filter.js
  35. 7
      src/filters/index.js
  36. 39
      src/main.js
  37. 53
      src/plugins/vant.js
  38. 30
      src/router/index.js
  39. 11
      src/router/router.config.js
  40. 4
      src/store/getters.js
  41. 15
      src/store/index.js
  42. 19
      src/store/modules/app.js
  43. 110
      src/utils/index.js
  44. 7
      src/utils/jsApiList.js
  45. 58
      src/utils/request.js
  46. 35
      src/utils/storage.js
  47. 20
      src/utils/validate.js
  48. 3
      src/utils/vconsole.js
  49. 12
      src/utils/wechatPlugin.js
  50. 46
      src/views/login/index.vue
  51. BIN
      static/image/demo.png
  52. BIN
      static/image/secret.png
  53. 171
      vue.config.js

2
.browserslistrc

@ -0,0 +1,2 @@
> 1%
last 2 versions

14
.editorconfig

@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

6
.env.development

@ -0,0 +1,6 @@
NODE_ENV='development'
# must start with VUE_APP_
VUE_APP_ENV = 'development'
outputDir = 'epmet-work-h5-dev'

5
.env.production

@ -0,0 +1,5 @@
NODE_ENV='production'
# must start with VUE_APP_
VUE_APP_ENV = 'production'
outputDir = 'epmet-work-h5-prod'

4
.env.staging

@ -0,0 +1,4 @@
NODE_ENV='production'
# must start with VUE_APP_
VUE_APP_ENV = 'staging'

4
.eslintignore

@ -0,0 +1,4 @@
build/*.js
src/assets
public
dist

54
.eslintrc.js

@ -0,0 +1,54 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true,
'vue/setup-compiler-macros': true
},
globals: {
defineProps: 'readonly',
defineEmits: 'readonly'
},
extends: ['plugin:vue/essential', 'eslint:recommended', 'plugin:prettier/recommended'],
parserOptions: {
parser: '@babel/eslint-parser'
},
rules: {
'no-console': 'warn',
'no-debugger': 'warn',
'vue/script-setup-uses-vars': 'error',
'vue/custom-event-name-casing': 'off',
'no-use-before-define': 'off',
'no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_'
}
],
'space-before-function-paren': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/require-default-prop': 'off',
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'never',
component: 'always'
},
svg: 'always',
math: 'always'
}
],
'vue/v-on-event-hyphenation': 'off',
'vue/multi-word-component-names': 'off'
}
}

24
.gitignore

@ -0,0 +1,24 @@
.DS_Store
node_modules
/dist
/docs
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
package-lock.json
yarn.lock

13
.postcssrc.js

@ -0,0 +1,13 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
plugins: {
autoprefixer: {
overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8']
},
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*'],
//selectorBlackList: ['van-']
}
}
}

1
.prettierignore

@ -0,0 +1 @@
README.md

24
.prettierrc

@ -0,0 +1,24 @@
{
"printWidth": 120,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "none",
"semi": false,
"wrap_line_length": 120,
"wrap_attributes": "auto",
"proseWrap": "always",
"arrowParens": "avoid",
"bracketSpacing": true,
"jsxBracketSameLine": true,
"useTabs": false,
"eslintIntegration":true,
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}
],
"endOfLine": "auto"
}

1212
README.md

File diff suppressed because it is too large

22
babel.config.js

@ -0,0 +1,22 @@
// 获取 VUE_APP_ENV 非 NODE_ENV,测试环境依然 console
const IS_PROD = ['production', 'prod'].includes(process.env.VUE_APP_ENV)
const plugins = [
[
'import',
{
libraryName: 'vant',
libraryDirectory: 'es',
style: true
},
'vant'
]
]
// 去除 console.log
if (IS_PROD) {
plugins.push('transform-remove-console')
}
module.exports = {
presets: [['@vue/cli-plugin-babel/preset', {useBuiltIns: 'usage', corejs: 3}]],
plugins
}

17
jsconfig.json

@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"allowSyntheticDefaultImports": true,
"baseUrl": "./",
"paths": {
//
"@/*": ["src/*"]
}
},
"exclude": [
//
"node_modules"
],
"include": ["./src/**/*"] //VueJs
}

60
package.json

@ -0,0 +1,60 @@
{
"name": "epmet-work-h5",
"version": "1.0.0",
"description": "",
"author": "",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --host 0.0.0.0",
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"build:dev": "vue-cli-service build --mode development",
"build:prod": "vue-cli-service build --mode production",
"build:stage": "vue-cli-service build --mode staging",
"lint": "vue-cli-service lint",
"deps": "yarn upgrade-interactive --latest"
},
"dependencies": {
"@vue-office/docx": "^1.0.0",
"@vue-office/excel": "^1.0.0",
"@vue-office/pdf": "^1.0.0",
"amfe-flexible": "^2.2.1",
"axios": "^0.27.2",
"core-js": "^3.23.3",
"dayjs": "^1.11.7",
"eslint": "^8.12.0",
"eslint-plugin-vue": "^8.4.0",
"filemanager-webpack-plugin": "^8.0.0",
"html-webpack-plugin": "^5.5.3",
"less-loader": "^11.1.0",
"postcss-pxtorem": "^6.0.0",
"regenerator-runtime": "^0.13.5",
"vant": "^2.12.48",
"vconsole": "^3.15.0",
"vue": "^2.7.8",
"vue-demi": "^0.14.0",
"vue-router": "^3.5.4",
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/core": "^7.18.10",
"@babel/eslint-parser": "^7.18.2",
"@vue/cli-plugin-babel": "~5.0.8",
"@vue/cli-plugin-eslint": "~5.0.8",
"@vue/cli-plugin-router": "~5.0.8",
"@vue/cli-plugin-vuex": "~5.0.8",
"@vue/cli-service": "~5.0.8",
"ajv": "^7.2.4",
"babel-eslint": "^10.1.0",
"babel-plugin-import": "^1.13.5",
"babel-plugin-transform-remove-console": "^6.9.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"less": "^4.1.2",
"postcss": "^8.4.12",
"prettier": "2.6.2",
"script-ext-html-webpack-plugin": "2.1.4",
"svg-sprite-loader": "5.1.1",
"webpack-bundle-analyzer": "^4.5.0"
}
}

BIN
public/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

27
public/index.html

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- <% for (var i in
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
<link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
<% } %> -->
<title><%= webpackConfig.name %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- 使用CDN加速的JS文件,配置在vue.config.js下 -->
<!-- <% for (var i in
htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %> -->
<!-- built files will be auto injected -->
</body>
</html>

14
src/App.vue

@ -0,0 +1,14 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {}
}
}
</script>
<style lang="less"></style>

6
src/api/home.js

@ -0,0 +1,6 @@
// import qs from 'qs'
// axios
// import request from '@/utils/request'
//home api

7
src/api/index.js

@ -0,0 +1,7 @@
const api = {
Login: '/user/login',
UserInfo: '/user/userinfo',
UserName: '/user/name'
}
export default api

32
src/api/user.js

@ -0,0 +1,32 @@
import api from './index'
// axios
import request from '@/utils/request'
// 登录
export function login(data) {
return request({
url: api.Login,
method: 'post',
data
})
}
// 用户信息 post 方法
export function getUserInfo(data) {
return request({
url: api.UserInfo,
method: 'post',
data,
hideloading: true
})
}
// 用户名称 get 方法
export function getUserName(params) {
return request({
url: api.UserName,
method: 'get',
params,
hideloading: true
})
}

70
src/assets/css/common.less

@ -0,0 +1,70 @@
html,
body #app {
color: @black;
background-color: @background-color;
}
#app {
font-size: 16px;
background-size: 100% auto;
}
.flex {
display: flex;
}
.mr10 {
margin-right: 10px;
}
.primary-color {
color: @blue;
}
.jcsb {
justify-content: space-between;
}
.aic {
align-items: center;
}
.container {
padding: 10px;
}
.card{
background-color: #fff;
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0,0,0,.3);
box-sizing: border-box;
width: 100%;
}
.flex{
display: flex;
.flex1{
flex: 1;
}
&-y{
flex-direction: column;
}
&-center1{
justify-content: center;
}
&-center2{
align-items: center;
}
&-mean{
justify-content: space-around;
}
&-end{
justify-content: space-between;
}
}
.m-top12{
margin-top: 12px;
}

35
src/assets/css/index.less

@ -0,0 +1,35 @@
html,
body #app {
color: @black;
background-color: @background-color;
}
#app {
font-size: 16px;
background-size: 100% auto;
}
.flex {
display: flex;
}
.mr10 {
margin-right: 10px;
}
.primary-color {
color: @blue;
}
.jcsb {
justify-content: space-between;
}
.aic {
align-items: center;
}
.container {
padding: 10px;
}

36
src/assets/css/mixin.scss

@ -0,0 +1,36 @@
// mixin
// 清除浮动
@mixin clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
// 多行隐藏
@mixin textoverflow($clamp:1) {
display: block;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: $clamp;
/*! autoprefixer: ignore next */
-webkit-box-orient: vertical;
}
//flex box
@mixin flexbox($jc:space-between, $ai:center, $fd:row, $fw:nowrap) {
display: flex;
display: -webkit-flex;
flex: 1;
justify-content: $jc;
-webkit-justify-content: $jc;
align-items: $ai;
-webkit-align-items: $ai;
flex-direction: $fd;
-webkit-flex-direction: $fd;
flex-wrap: $fw;
-webkit-flex-wrap: $fw;
}

688
src/assets/css/vant-theme.less

@ -0,0 +1,688 @@
// Color Palette
@black: #000;
@white: #fff;
@gray-1: #f7f8fa;
@gray-2: #f2f3f5;
@gray-3: #ebedf0;
@gray-4: #dcdee0;
@gray-5: #c8c9cc;
@gray-6: #969799;
@gray-7: #646566;
@gray-8: #323233;
@red: #ee0a24;
@blue: #1989fa;
@orange: #ff976a;
@orange-dark: #ed6a0c;
@orange-light: #fffbe8;
@green: #07c160;
// Gradient Colors
@gradient-red: linear-gradient(to right, #ff6034, #ee0a24);
@gradient-orange: linear-gradient(to right, #ffd01e, #ff8917);
// Component Colors
@text-color: @gray-8;
@active-color: @gray-2;
@active-opacity: 0.7;
@disabled-opacity: 0.5;
@background-color: @gray-1;
@background-color-light: #fafafa;
@text-link-color: #576b95;
// Padding
@padding-base: 4px;
@padding-xs: @padding-base * 2;
@padding-sm: @padding-base * 3;
@padding-md: @padding-base * 4;
@padding-lg: @padding-base * 6;
@padding-xl: @padding-base * 8;
// Font
@font-size-xs: 10px;
@font-size-sm: 12px;
@font-size-md: 14px;
@font-size-lg: 16px;
@font-weight-bold: 500;
@line-height-xs: 14px;
@line-height-sm: 18px;
@line-height-md: 20px;
@line-height-lg: 22px;
@base-font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB',
'Microsoft Yahei', sans-serif;
@price-integer-font-family: Avenir-Heavy, PingFang SC, Helvetica Neue, Arial,
sans-serif;
// Animation
@animation-duration-base: 0.3s;
@animation-duration-fast: 0.2s;
// Border
@border-color: @gray-3;
@border-width-base: 1px;
@border-radius-sm: 2px;
@border-radius-md: 4px;
@border-radius-lg: 8px;
@border-radius-max: 999px;
//ActionSheet
@action-sheet-max-height: 90%;
@action-sheet-header-height: 48px;
@action-sheet-header-font-size: @font-size-lg;
@action-sheet-description-color: @gray-6;
@action-sheet-description-font-size: @font-size-md;
@action-sheet-description-line-height: 20px;
@action-sheet-item-background: @white;
@action-sheet-item-font-size: @font-size-lg;
@action-sheet-item-line-height: 22px;
@action-sheet-item-text-color: @text-color;
@action-sheet-item-disabled-text-color: @gray-5;
@action-sheet-subname-color: @gray-6;
@action-sheet-subname-font-size: @font-size-sm;
@action-sheet-subname-line-height: 20px;
@action-sheet-close-icon-size: 22px;
@action-sheet-close-icon-color: @gray-5;
@action-sheet-close-icon-padding: 0 @padding-md;
@action-sheet-cancel-text-color: @gray-7;
@action-sheet-cancel-padding-top: @padding-xs;
@action-sheet-cancel-padding-color: @background-color;
// Button
@button-mini-height: 22px;
@button-mini-min-width: 50px;
@button-mini-font-size: @font-size-xs;
@button-small-height: 30px;
@button-small-font-size: @font-size-sm;
@button-small-min-width: 60px;
@button-normal-font-size: @font-size-md;
@button-large-height: 50px;
@button-default-color: @text-color;
@button-default-height: 44px;
@button-default-font-size: @font-size-lg;
@button-default-background-color: @white;
@button-default-border-color: @border-color;
@button-primary-color: @white;
@button-primary-background-color: @blue;
@button-primary-border-color: @blue;
@button-info-color: @white;
@button-info-background-color: @blue;
@button-info-border-color: @blue;
@button-danger-color: @white;
@button-danger-background-color: @red;
@button-danger-border-color: @red;
@button-warning-color: @white;
@button-warning-background-color: @orange;
@button-warning-border-color: @orange;
@button-line-height: 20px;
@button-border-width: 1px;
@button-border-radius: @border-radius-sm;
@button-round-border-radius: @border-radius-max;
@button-plain-background-color: @white;
@button-disabled-opacity: @disabled-opacity;
// Calendar
@calendar-height: 100%;
@calendar-background-color: @white;
@calendar-popup-height: 90%;
@calendar-header-box-shadow: 0 2px 10px rgba(125, 126, 128, 0.16);
@calendar-header-title-height: 44px;
@calendar-header-title-font-size: @font-size-lg;
@calendar-header-subtitle-font-size: @font-size-md;
@calendar-weekdays-height: 30px;
@calendar-weekdays-font-size: @font-size-sm;
@calendar-month-title-font-size: @font-size-md;
@calendar-month-mark-color: fade(@gray-2, 80%);
@calendar-month-mark-font-size: 160px;
@calendar-day-height: 64px;
@calendar-day-font-size: @font-size-lg;
@calendar-range-edge-color: @white;
@calendar-range-edge-background-color: @red;
@calendar-range-middle-color: @red;
@calendar-range-middle-background-opacity: 0.1;
@calendar-selected-day-size: 54px;
@calendar-selected-day-color: @white;
@calendar-info-font-size: @font-size-xs;
@calendar-info-line-height: 14px;
@calendar-selected-day-background-color: @red;
@calendar-day-disabled-color: @gray-5;
@calendar-confirm-button-height: 36px;
@calendar-confirm-button-margin: 7px 0;
@calendar-confirm-button-line-height: 34px;
// Card
@card-padding: @padding-xs @padding-md;
@card-font-size: @font-size-sm;
@card-text-color: @text-color;
@card-background-color: @background-color-light;
@card-thumb-size: 88px;
@card-title-line-height: 16px;
@card-desc-color: @gray-7;
@card-desc-line-height: 20px;
@card-price-color: @red;
@card-origin-price-color: @gray-7;
@card-origin-price-font-size: @font-size-xs;
@card-price-font-size: @font-size-sm;
@card-price-integer-font-size: @font-size-lg;
@card-price-font-family: @price-integer-font-family;
// Cell
@cell-font-size: @font-size-md;
@cell-line-height: 24px;
@cell-vertical-padding: 10px;
@cell-horizontal-padding: @padding-md;
@cell-text-color: @text-color;
@cell-background-color: @white;
@cell-border-color: @border-color;
@cell-active-color: @active-color;
@cell-required-color: @red;
@cell-label-color: @gray-6;
@cell-label-font-size: @font-size-sm;
@cell-label-line-height: 18px;
@cell-label-margin-top: 3px;
@cell-value-color: @gray-6;
@cell-icon-size: 16px;
@cell-right-icon-color: @gray-6;
@cell-large-vertical-padding: @padding-sm;
@cell-large-title-font-size: @font-size-lg;
@cell-large-value-font-size: @font-size-lg;
@cell-large-label-font-size: @font-size-md;
// CellGroup
@cell-group-background-color: @white;
@cell-group-title-color: @gray-6;
@cell-group-title-padding: @padding-md @padding-md @padding-xs;
@cell-group-title-font-size: @font-size-md;
@cell-group-title-line-height: 16px;
@cell-group-inset-padding: 0 @padding-md;
@cell-group-inset-border-radius: @border-radius-lg;
@cell-group-inset-title-padding: @padding-md @padding-md @padding-xs @padding-xl;
// Checkbox
@checkbox-size: 20px;
@checkbox-border-color: @gray-5;
@checkbox-transition-duration: 0.2s;
@checkbox-label-margin: 10px;
@checkbox-label-color: @text-color;
@checkbox-checked-icon-color: @blue;
@checkbox-disabled-icon-color: @gray-5;
@checkbox-disabled-label-color: @gray-5;
@checkbox-disabled-background-color: @border-color;
// Circle
@circle-text-color: @text-color;
// Collapse
@collapse-item-transition-duration: 0.3s;
@collapse-item-content-padding: 15px;
@collapse-item-content-font-size: 13px;
@collapse-item-content-line-height: 1.5;
@collapse-item-content-text-color: @gray-6;
@collapse-item-content-background-color: @white;
@collapse-item-title-disabled-color: @gray-5;
// CountDown
@count-down-text-color: @text-color;
@count-down-font-size: @font-size-md;
@count-down-line-height: 20px;
// Dialog
@dialog-width: 320px;
@dialog-small-screen-width: 90%;
@dialog-font-size: @font-size-lg;
@dialog-border-radius: 16px;
@dialog-background-color: @white;
@dialog-header-font-weight: @font-weight-bold;
@dialog-header-line-height: 24px;
@dialog-header-padding-top: @padding-lg;
@dialog-header-isolated-padding: @padding-lg 0;
@dialog-message-padding: @padding-lg;
@dialog-message-font-size: @font-size-md;
@dialog-message-line-height: 20px;
@dialog-message-max-height: 60vh;
@dialog-has-title-message-text-color: @gray-7;
@dialog-has-title-message-padding-top: @padding-xs;
// Field
@field-label-color: @gray-7;
@field-input-text-color: @text-color;
@field-input-error-text-color: @red;
@field-input-disabled-text-color: @gray-5;
@field-placeholder-text-color: @gray-5;
@field-icon-size: 16px;
@field-clear-icon-size: 16px;
@field-clear-icon-color: @gray-5;
@field-icon-container-color: @gray-6;
@field-error-message-color: @red;
@field-error-message-text-font-size: @font-size-sm;
@field-text-area-min-height: 18px;
@field-word-limit-color: @gray-7;
@field-word-limit-font-size: @font-size-sm;
@field-word-limit-line-height: 16px;
@field-word-num-full-color: @red;
@field-disabled-text-color: @gray-5;
// GoodsAction
@goods-action-background-color: @white;
@goods-action-height: 50px;
@goods-action-icon-width: 48px;
@goods-action-icon-height: @goods-action-height;
@goods-action-icon-color: @text-color;
@goods-action-icon-size: 18px;
@goods-action-icon-font-size: @font-size-xs;
@goods-action-icon-text-color: @gray-7;
@goods-action-button-height: 40px;
@goods-action-button-line-height: @button-line-height;
@goods-action-button-border-radius: @border-radius-max;
@goods-action-button-warning-color: @gradient-orange;
@goods-action-button-danger-color: @gradient-red;
@goods-action-button-plain-color: @white;
// Image
@image-placeholder-text-color: @gray-6;
@image-placeholder-font-size: @font-size-md;
@image-placeholder-background-color: @background-color;
@image-loading-icon-size: 32px;
@image-loading-icon-color: @gray-4;
@image-error-icon-size: 32px;
@image-error-icon-color: @gray-4;
// Info
@info-size: 16px;
@info-color: @white;
@info-padding: 0 3px;
@info-font-size: 12px;
@info-font-weight: 500;
@info-border-width: 1px;
@info-background-color: @red;
@info-dot-color: @red;
@info-dot-size: 8px;
@info-font-family: -apple-system-font, Helvetica Neue, Arial, sans-serif;
// Loading
@loading-text-color: @gray-6;
@loading-text-font-size: @font-size-md;
@loading-text-line-height: 20px;
@loading-spinner-color: @gray-5;
@loading-spinner-size: 30px;
@loading-spinner-animation-duration: 0.8s;
// NavBar
@nav-bar-height: 46px;
@nav-bar-background-color: @white;
@nav-bar-arrow-size: 16px;
@nav-bar-icon-color: @blue;
@nav-bar-text-color: @blue;
@nav-bar-title-font-size: @font-size-lg;
@nav-bar-title-text-color: @text-color;
// NoticeBar
@notice-bar-height: 40px;
@notice-bar-padding: 0 @padding-md;
@notice-bar-wrapable-padding: @padding-xs @padding-md;
@notice-bar-font-size: @font-size-md;
@notice-bar-text-color: @orange-dark;
@notice-bar-line-height: 24px;
@notice-bar-background-color: @orange-light;
@notice-bar-icon-size: 16px;
@notice-bar-icon-min-width: 22px;
// Notify
@notify-padding: 6px 15px;
@notify-font-size: 14px;
@notify-line-height: 20px;
@notify-primary-background-color: @blue;
@notify-success-background-color: @blue;
@notify-danger-background-color: @red;
@notify-warning-background-color: @orange;
// Overlay
@overlay-background-color: rgba(0, 0, 0, 0.7);
// Panel
@panel-background-color: @white;
@panel-header-value-color: @red;
@panel-footer-padding: @padding-xs @padding-md;
// Picker
@picker-background-color: @white;
@picker-toolbar-height: 44px;
@picker-title-font-size: @font-size-lg;
@picker-action-padding: 0 @padding-md;
@picker-action-font-size: @font-size-md;
@picker-confirm-action-color: @text-link-color;
@picker-cancel-action-color: @gray-6;
@picker-option-font-size: @font-size-lg;
@picker-option-text-color: @black;
@picker-loading-icon-color: @blue;
@picker-loading-mask-color: rgba(255, 255, 255, 0.9);
@picker-option-disabled-opacity: 0.3;
@picker-option-selected-text-color: @text-color;
// Popup
@popup-background-color: @white;
@popup-round-border-radius: 16px;
@popup-close-icon-size: 18px;
@popup-close-icon-color: @gray-6;
@popup-close-icon-margin: 16px;
@popup-close-icon-z-index: 1;
// Progress
@progress-height: 4px;
@progress-background-color: @gray-3;
@progress-pivot-padding: 0 5px;
@progress-color: @blue;
@progress-pivot-font-size: @font-size-xs;
@progress-pivot-line-height: 1.6;
@progress-pivot-background-color: @blue;
@progress-pivot-text-color: @white;
// Radio
@radio-size: 20px;
@radio-border-color: @gray-5;
@radio-transition-duration: 0.2s;
@radio-label-margin: 10px;
@radio-label-color: @text-color;
@radio-checked-icon-color: @blue;
@radio-disabled-icon-color: @gray-5;
@radio-disabled-label-color: @gray-5;
@radio-disabled-background-color: @border-color;
// Rate
@rate-horizontal-padding: 2px;
@rate-icon-size: 20px;
@rate-icon-void-color: @gray-5;
@rate-icon-full-color: @red;
@rate-icon-disabled-color: @gray-5;
@rate-icon-gutter: @padding-base;
// Switch
@switch-width: 2em;
@switch-height: 1em;
@switch-node-size: 1em;
@switch-node-z-index: 1;
@switch-node-background-color: @white;
@switch-node-box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05),
0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 3px 3px 0 rgba(0, 0, 0, 0.05);
@switch-background-color: @white;
@switch-on-background-color: @blue;
@switch-transition-duration: 0.3s;
@switch-disabled-opacity: 0.4;
@switch-border: 1px solid rgba(0, 0, 0, 0.1);
// ShareSheet
@share-sheet-header-padding: @padding-sm @padding-md @padding-base;
@share-sheet-title-color: @text-color;
@share-sheet-title-font-size: @font-size-md;
@share-sheet-title-line-height: @line-height-md;
@share-sheet-description-color: @gray-6;
@share-sheet-description-font-size: @font-size-sm;
@share-sheet-description-line-height: 16px;
@share-sheet-icon-size: 48px;
@share-sheet-option-name-color: @gray-7;
@share-sheet-option-name-font-size: @font-size-sm;
@share-sheet-option-description-color: @gray-5;
@share-sheet-option-description-font-size: @font-size-sm;
@share-sheet-cancel-button-font-size: @font-size-lg;
@share-sheet-cancel-button-height: 48px;
@share-sheet-cancel-button-background: @white;
// Search
@search-background-color: @gray-1;
@search-padding: 10px @padding-sm;
@search-input-height: 34px;
@search-label-padding: 0 5px;
@search-label-color: @text-color;
@search-label-font-size: @font-size-md;
@search-left-icon-color: @gray-6;
@search-action-padding: 0 @padding-xs;
@search-action-text-color: @text-color;
@search-action-font-size: @font-size-md;
// Sidebar
@sidebar-width: 80px;
// SidebarItem
@sidebar-font-size: @font-size-md;
@sidebar-line-height: 20px;
@sidebar-text-color: @text-color;
@sidebar-disabled-text-color: @gray-5;
@sidebar-padding: 20px @padding-sm 20px @padding-xs;
@sidebar-active-color: @active-color;
@sidebar-background-color: @background-color;
@sidebar-selected-font-weight: @font-weight-bold;
@sidebar-selected-text-color: @text-color;
@sidebar-selected-border-color: @red;
@sidebar-selected-background-color: @white;
// Slider
@slider-active-background-color: @blue;
@slider-inactive-background-color: @gray-3;
@slider-disabled-opacity: @disabled-opacity;
@slider-bar-height: 2px;
@slider-button-width: 24px;
@slider-button-height: 24px;
@slider-button-border-radius: 50%;
@slider-button-background-color: @white;
@slider-button-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
// Step
@step-text-color: @gray-6;
@step-process-text-color: @text-color;
@step-font-size: @font-size-md;
@step-line-color: @border-color;
@step-finish-line-color: @blue;
@step-finish-text-color: @text-color;
@step-icon-size: 12px;
@step-circle-size: 5px;
@step-circle-color: @gray-6;
@step-horizontal-title-font-size: @font-size-sm;
// Steps
@steps-background-color: @white;
// Stepper
@stepper-active-color: #e8e8e8;
@stepper-background-color: @active-color;
@stepper-button-icon-color: @text-color;
@stepper-button-disabled-color: @background-color;
@stepper-button-disabled-icon-color: @gray-5;
@stepper-button-round-theme-color: @red;
@stepper-input-width: 32px;
@stepper-input-height: 28px;
@stepper-input-font-size: @font-size-md;
@stepper-input-line-height: normal;
@stepper-input-text-color: @text-color;
@stepper-input-disabled-text-color: @gray-5;
@stepper-input-disabled-background-color: @active-color;
@stepper-border-radius: @border-radius-md;
// SubmitBar
@submit-bar-height: 50px;
@submit-bar-z-index: 100;
@submit-bar-background-color: @white;
@submit-bar-button-width: 110px;
@submit-bar-price-color: @red;
@submit-bar-price-font-size: @font-size-sm;
@submit-bar-currency-font-size: @font-size-sm;
@submit-bar-text-color: @text-color;
@submit-bar-text-font-size: 14px;
@submit-bar-tip-padding: 10px;
@submit-bar-tip-font-size: 12px;
@submit-bar-tip-line-height: 1.5;
@submit-bar-tip-color: #f56723;
@submit-bar-tip-background-color: #fff7cc;
@submit-bar-tip-icon-size: 12px;
@submit-bar-button-height: 40px;
@submit-bar-padding: 0 @padding-md;
@submit-bar-price-integer-font-size: 20px;
@submit-bar-price-font-family: @price-integer-font-family;
// Tabbar
@tabbar-height: 50px;
@tabbar-background-color: @white;
// TabbarItem
@tabbar-item-font-size: @font-size-sm;
@tabbar-item-text-color: @gray-7;
@tabbar-item-active-color: @blue;
@tabbar-item-line-height: 1;
@tabbar-item-icon-size: 22px;
@tabbar-item-margin-bottom: 4px;
// Tab
@tab-text-color: @gray-7;
@tab-active-text-color: @text-color;
@tab-disabled-text-color: @gray-5;
@tab-font-size: @font-size-md;
// Tabs
@tabs-default-color: @red;
@tabs-line-height: 44px;
@tabs-card-height: 30px;
@tabs-nav-background-color: @white;
@tabs-bottom-bar-height: 3px;
@tabs-bottom-bar-color: @tabs-default-color;
// Tag
@tag-padding: 0 @padding-base;
@tag-text-color: @white;
@tag-font-size: @font-size-sm;
@tag-border-radius: 2px;
@tag-line-height: 16px;
@tag-medium-padding: 2px 6px;
@tag-large-padding: @padding-base @padding-xs;
@tag-large-border-radius: @border-radius-md;
@tag-large-font-size: @font-size-md;
@tag-round-border-radius: @border-radius-max;
@tag-danger-color: @red;
@tag-primary-color: @blue;
@tag-success-color: @blue;
@tag-warning-color: @orange;
@tag-default-color: @gray-6;
@tag-plain-background-color: @white;
// Toast
@toast-max-width: 70%;
@toast-font-size: 14px;
@toast-text-color: @white;
@toast-line-height: 20px;
@toast-border-radius: @border-radius-lg;
@toast-background-color: fade(@black, 70%);
@toast-icon-size: 36px;
@toast-text-min-width: 96px;
@toast-text-padding: @padding-xs @padding-sm;
@toast-default-padding: @padding-md;
@toast-default-width: 88px;
@toast-default-min-height: 88px;
// GridItem
@grid-item-content-padding: @padding-md @padding-xs;
@grid-item-content-background-color: @white;
@grid-item-content-active-color: @active-color;
@grid-item-icon-size: 26px;
@grid-item-text-color: @gray-7;
@grid-item-text-font-size: @font-size-sm;
// Divider
@divider-margin: @padding-md 0;
@divider-text-color: @gray-6;
@divider-font-size: @font-size-md;
@divider-line-height: 24px;
@divider-border-color: @border-color;
@divider-content-padding: @padding-md;
@divider-content-left-width: 10%;
@divider-content-right-width: 10%;
// Empty
@empty-padding: @padding-xl 0;
@empty-image-size: 160px;
@empty-description-margin-top: @padding-md;
@empty-description-padding: 0 60px;
@empty-description-color: @gray-6;
@empty-description-font-size: 14px;
@empty-description-line-height: 20px;
@empty-bottom-margin-top: 24px;
// TreeSelect
@tree-select-font-size: @font-size-md;
@tree-select-nav-background-color: @background-color;
@tree-select-content-background-color: @white;
@tree-select-nav-item-padding: @padding-sm @padding-xs @padding-sm @padding-sm;
@tree-select-item-height: 44px;
@tree-select-item-active-color: @red;
@tree-select-item-disabled-color: @gray-5;
// Uploader
@uploader-size: 80px;
@uploader-icon-size: 24px;
@uploader-icon-color: @gray-4;
@uploader-text-color: @gray-6;
@uploader-text-font-size: @font-size-sm;
@uploader-upload-background-color: @gray-1;
@uploader-upload-active-color: @active-color;
@uploader-delete-color: @white;
@uploader-delete-icon-size: 14px;
@uploader-delete-background-color: rgba(0, 0, 0, 0.7);
@uploader-file-background-color: @background-color;
@uploader-file-icon-size: 20px;
@uploader-file-icon-color: @gray-7;
@uploader-file-name-padding: 0 @padding-base;
@uploader-file-name-margin-top: @padding-xs;
@uploader-file-name-font-size: @font-size-sm;
@uploader-file-name-text-color: @gray-7;
@uploader-mask-background-color: fade(@gray-8, 88%);
@uploader-mask-icon-size: 22px;
@uploader-mask-message-font-size: @font-size-sm;
@uploader-mask-message-line-height: 14px;
@uploader-loading-icon-size: 22px;
@uploader-loading-icon-color: @white;
@uploader-disabled-opacity: @disabled-opacity;
// DropdownMenu
@dropdown-menu-height: 50px;
@dropdown-menu-background-color: @white;
@dropdown-menu-title-font-size: 15px;
@dropdown-menu-title-text-color: @text-color;
@dropdown-menu-title-active-text-color: @red;
@dropdown-menu-title-disabled-text-color: @gray-6;
@dropdown-menu-title-padding: 0 @padding-lg 0 @padding-xs;
@dropdown-menu-title-line-height: 18px;
@dropdown-menu-option-active-color: @red;
@dropdown-menu-box-shadow: 0 2px 12px fade(@gray-7, 12);
// IndexAnchor
@index-anchor-padding: 0 @padding-md;
@index-anchor-text-color: @text-color;
@index-anchor-font-weight: 500;
@index-anchor-font-size: @font-size-md;
@index-anchor-line-height: 32px;
@index-anchor-background-color: transparent;
@index-anchor-active-background-color: @white;
@index-anchor-active-text-color: @blue;
// IndexBar
@index-bar-index-font-size: @font-size-xs;
@index-bar-index-line-height: 14px;
// skeleton
@skeleton-padding: 0 @padding-md;
@skeleton-row-height: 16px;
@skeleton-row-background-color: @gray-2;
@skeleton-row-margin-top: @padding-sm;
@skeleton-avatar-background-color: @gray-2;
@skeleton-animation-duration: 1.2s;
// Cascader
@cascader-header-height: 48px;
@cascader-header-padding: 0 16px;
@cascader-title-font-size: 16px;
@cascader-title-line-height: 20px;
@cascader-close-icon-size: 22px;
@cascader-close-icon-color: #c8c9cc;
@cascader-selected-icon-size: 18px;
@cascader-tabs-height: 48px;
@cascader-active-color: @blue;
@cascader-options-height: 384px;
@cascader-option-disabled-color: #c8c9cc;
@cascader-tab-color: #323233;
@cascader-unselected-tab-color: #969799;

3
src/assets/css/variables.scss

@ -0,0 +1,3 @@
// variables
$background-color: #f8f8f8;
$theme-color: #07b0b8;

BIN
src/assets/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

54
src/components/TabBar.vue

@ -0,0 +1,54 @@
<template>
<div>
<van-tabbar fixed route v-model="active" @change="handleChange">
<van-tabbar-item v-for="(item, index) in data" :to="item.to" :icon="item.icon" :key="index">
{{ item.title }}
</van-tabbar-item>
</van-tabbar>
</div>
</template>
<script>
export default {
name: 'TabBar',
props: {
defaultActive: {
type: Number,
default: 0
},
data: {
type: Array,
default: () => {
return []
}
}
},
data() {
return {
active: this.defaultActive
}
},
methods: {
handleChange(value) {
this.$emit('change', value)
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

9
src/config/env.development.js

@ -0,0 +1,9 @@
// 本地环境配置
module.exports = {
env: 'development',
title: 'e联社区',
baseUrl: 'http://192.168.1.144/', // 项目地址
baseApi: 'http://192.168.1.144/api', // 本地api请求地址,注意:如果你使用了代理,请设置成'/'
APPID: 'xxx',
APPSECRET: 'xxx',
}

8
src/config/env.production.js

@ -0,0 +1,8 @@
// 正式
module.exports = {
env: 'production',
title: 'e联社区',
baseUrl: 'https://epmet-preview.elinkservice.cn/', // 正式项目地址
baseApi: 'https://epmet-preview.elinkservice.cn/api', // 正式api请求地址
APPSECRET: 'xxx',
}

8
src/config/env.staging.js

@ -0,0 +1,8 @@
module.exports = {
env: 'staging',
title: 'e联社区',
baseUrl: 'https://test.xxx.com', // 测试项目地址
baseApi: 'https://test.xxx.com/api', // 测试api请求地址
APPID: 'xxx',
APPSECRET: 'xxx',
}

3
src/config/index.js

@ -0,0 +1,3 @@
// 根据环境引入不同配置 process.env.NODE_ENV
const config = require('./env.' + process.env.VUE_APP_ENV)
module.exports = config

0
src/const/index.js

37
src/filters/filter.js

@ -0,0 +1,37 @@
/**
*格式化时间
*yyyy-MM-dd hh:mm:ss
*/
export function formatDate(time, fmt) {
if (time === undefined || '') {
return
}
const date = new Date(time)
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
}
const o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds()
}
for (const k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
const str = o[k] + ''
fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str))
}
}
return fmt
}
function padLeftZero(str) {
return ('00' + str).substr(str.length)
}
/*
* 隐藏用户手机号中间四位
*/
export function hidePhone(phone) {
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}

7
src/filters/index.js

@ -0,0 +1,7 @@
import Vue from 'vue'
import * as filter from './filter'
Object.keys(filter).forEach(k => Vue.filter(k, filter[k]))
Vue.prototype.$formatDate = Vue.filter('formatDate')
Vue.prototype.$hidePhone = Vue.filter('hidePhone')

39
src/main.js

@ -0,0 +1,39 @@
import 'core-js/stable'
import 'regenerator-runtime/runtime'
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 全局引入按需引入UI库 vant
import '@/plugins/vant'
// 引入全局样式
import '@/assets/css/common.less'
import '@/assets/css/index.less'
// 移动端适配
import 'amfe-flexible'
Vue.config.productionTip = false
// 日期格式化插件
import dayjs from 'dayjs'
Vue.prototype.$dayjs = dayjs
// 提示框封装
// import { Tips } from '@/utils'
// Vue.prototype.$tips = Tips
//开发环境使用,生产环境自动取消
import Vconsole from 'vconsole'
if (process.env.NODE_ENV !== 'production') {
new Vconsole()
}
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})

53
src/plugins/vant.js

@ -0,0 +1,53 @@
// 按需全局引入 @组件
import Vue from 'vue'
import {
Button,
Field,
Cell,
Uploader,
Image,
Picker,
Popup,
Icon,
Toast,
Progress,
NavBar,
RadioGroup,
Radio,
Dialog,
Tabs,
Tab,
Tag,
Steps,
Step,
Divider,
List,
ActionSheet,
Checkbox,
CellGroup
} from 'vant'
Vue.use(Button)
.use(Field)
.use(Cell)
.use(Uploader)
.use(Image)
.use(Picker)
.use(Popup)
.use(Icon)
.use(Toast)
.use(Progress)
.use(NavBar)
.use(RadioGroup)
.use(Radio)
.use(Dialog)
.use(Tabs)
.use(Tab)
.use(Tag)
.use(Steps)
.use(Step)
.use(Divider)
.use(List)
.use(ActionSheet)
.use(Checkbox)
.use(CellGroup)

30
src/router/index.js

@ -0,0 +1,30 @@
import Vue from 'vue'
import Router from 'vue-router'
import { constantRouterMap } from './router.config.js'
// hack router push callback
const originalPush = Router.prototype.push
Router.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
Vue.use(Router)
const createRouter = () =>
new Router({
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
})
const router = createRouter()
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router

11
src/router/router.config.js

@ -0,0 +1,11 @@
/**
* 基础路由
* @type { *[] }
*/
export const constantRouterMap = [
{
path: '/',
component: () => import('@/views/login'),
meta: { title: '登录', keepAlive: false }
}
]

4
src/store/getters.js

@ -0,0 +1,4 @@
const getters = {
userName: state => state.app.userName
}
export default getters

15
src/store/index.js

@ -0,0 +1,15 @@
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import app from './modules/app'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
app
},
getters
})
export default store

19
src/store/modules/app.js

@ -0,0 +1,19 @@
const state = {
userName: ''
}
const mutations = {
SET_USER_NAME(state, name) {
state.userName = name
}
}
const actions = {
// 设置name
setUserName({ commit }, name) {
commit('SET_USER_NAME', name)
}
}
export default {
state,
mutations,
actions
}

110
src/utils/index.js

@ -0,0 +1,110 @@
/**
* Created by PanJiaChen on 16/11/18.
*/
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return null
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (('' + time).length === 10) {
time = parseInt(time) * 1000
} else {
time = +time
}
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前'
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前'
} else if (diff < 3600 * 24 * 2) {
return '1天前'
}
if (option) {
return parseTime(time, option)
} else {
return (
d.getMonth() +
1 +
'月' +
d.getDate() +
'日' +
d.getHours() +
'时' +
d.getMinutes() +
'分'
)
}
}
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) {
const search = url.split('?')[1]
if (!search) {
return {}
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"')
.replace(/\+/g, ' ') +
'"}'
)
}

7
src/utils/jsApiList.js

@ -0,0 +1,7 @@
export const jsApiList = [
'updateAppMessageShareData',
'updateTimelineShareData',
'getLocation',
'openLocation',
'chooseWXPay'
]

58
src/utils/request.js

@ -0,0 +1,58 @@
import axios from 'axios'
import store from '@/store'
import { Toast } from 'vant'
// 根据环境不同引入不同api地址
import { baseApi } from '@/config'
// create an axios instance
const service = axios.create({
baseURL: baseApi, // url = base api url + request url
withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// request拦截器 request interceptor
service.interceptors.request.use(
config => {
// 不传递默认开启loading
if (!config.hideloading) {
// loading
Toast.loading({
forbidClick: true
})
}
if (store.getters.token) {
config.headers['X-Token'] = ''
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
response => {
Toast.clear()
const res = response.data
if (res.status && res.status !== 200) {
// 登录超时,重新登录
if (res.status === 401) {
store.dispatch('FedLogOut').then(() => {
location.reload()
})
}
return Promise.reject(res || 'error')
} else {
return Promise.resolve(res)
}
},
error => {
Toast.clear()
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default service

35
src/utils/storage.js

@ -0,0 +1,35 @@
/**
* 封装操作localstorage本地存储的方法
*/
export const storage = {
//存储
set(key, value) {
localStorage.setItem(key, JSON.stringify(value))
},
//取出数据
get(key) {
return JSON.parse(localStorage.getItem(key))
},
// 删除数据
remove(key) {
localStorage.removeItem(key)
}
}
/**
* 封装操作sessionStorage本地存储的方法
*/
export const sessionStorage = {
//存储
set(key, value) {
window.sessionStorage.setItem(key, JSON.stringify(value))
},
//取出数据
get(key) {
return JSON.parse(window.sessionStorage.getItem(key))
},
// 删除数据
remove(key) {
window.sessionStorage.removeItem(key)
}
}

20
src/utils/validate.js

@ -0,0 +1,20 @@
/**
* Created by Sunnie on 19/06/04.
*/
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUsername(str) {
const valid_map = ['admin', 'editor']
return valid_map.indexOf(str.trim()) >= 0
}

3
src/utils/vconsole.js

@ -0,0 +1,3 @@
import Vconsole from 'vconsole'
const vConsole = new Vconsole()
export default vConsole

12
src/utils/wechatPlugin.js

@ -0,0 +1,12 @@
import wx from 'weixin-js-sdk'
const plugin = {
install(Vue) {
Vue.prototype.$wx = wx
Vue.wx = wx
},
$wx: wx
}
export default plugin
export const install = plugin.install

46
src/views/login/index.vue

@ -0,0 +1,46 @@
<template>
<div class='login'>
<div class="card">
<van-cell-group inset>
<van-field v-model="phone" label="手机号" type="tel" placeholder="请输入手机号" @blur="handelBlurPhone" />
</van-cell-group>
<van-cell-group inset>
<van-field v-model="password" label="密码" type="password" placeholder="请输入密码" />
</van-cell-group>
</div>
<van-button type="info" round block style="margin-top: 35px;">登录</van-button>
<div class="flex flex-end flex-center1 m-top12">
<van-checkbox v-model="checked" shape="square">下次自动登录</van-checkbox>
<span>忘记密码?</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
phone: null,
password: null,
checked:false
};
},
created() { },
methods: {
handelBlurPhone() {
console.log(this.phone);
}
},
components: {},
computed: {},
watch: {}
}
</script>
<style lang='less' scoped>
.login{
box-sizing: border-box;
width: calc(100% - 20px);
margin: 10px auto 0;
}
</style>

BIN
static/image/demo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
static/image/secret.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

171
vue.config.js

@ -0,0 +1,171 @@
const path = require('path')
const defaultSettings = require('./src/config/index.js')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const OUTPUT_FILE_NAME = process.env.outputDir
const FileManagerPlugin = require('filemanager-webpack-plugin')
const resolve = dir => path.join(__dirname, dir)
// page title
const name = defaultSettings.title || 'vue mobile template'
// 生产环境,测试和正式
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
publicPath: process.env.NODE_ENV === 'development' ? '/' : '/epmet-work-h5', // 署应用包时的基本 URL。 vue-router hash 模式使用
// publicPath: process.env.NODE_ENV === 'development' ? '/' : '/h5', //署应用包时的基本 URL。 vue-router history模式使用
outputDir: `dist/${OUTPUT_FILE_NAME}`, // 生产环境构建文件的目录
assetsDir: 'static', // outputDir的静态资源(js、css、img、fonts)目录
lintOnSave: false,
productionSourceMap: false, // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
devServer: {
// host: 'epmet-cloud.elinkservice.cn',
port: 80, // 端口
open: false, // 启动后打开浏览器
client: {
overlay: {
// 当出现编译器错误或警告时,在浏览器中显示全屏覆盖层
warnings: false,
errors: true
}
},
proxy: {
//配置跨域
'/api': {
// target: `http://219.146.91.110:30801`,
target: `http://127.0.0.1:8080`,
changeOrigin: true,
ws: false,
pathRewrite: {
'^api': ''
}
}
}
},
css: {
extract: IS_PROD,
sourceMap: false,
loaderOptions: {
less: {
lessOptions: {
modifyVars: {
hack: `true; @import "assets/css/vant-theme.less";`
}
}
}
}
},
configureWebpack: config => {
config.name = name
config.plugins.push(
new FileManagerPlugin({
events: {
onEnd: {
delete: [`./${OUTPUT_FILE_NAME}.zip`],
archive: [
{
source: `./dist/${OUTPUT_FILE_NAME}`,
destination: `./${OUTPUT_FILE_NAME}.zip`
}
]
}
}
})
)
// 为生产环境修改配置...
// if (IS_PROD) {
// // externals
// config.externals = externals
// }
},
chainWebpack: config => {
config.plugins.delete('preload') // TODO: need test
config.plugins.delete('prefetch') // TODO: need test
// set svg-sprite-loader
config.module.rule('svg').exclude.add(resolve('src/assets/icons')).end()
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/assets/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
.end()
// 别名 alias
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('api', resolve('src/api'))
.set('views', resolve('src/views'))
.set('components', resolve('src/components'))
/**
* 设置保留空格
*/
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap(options => {
options.compilerOptions.preserveWhitespace = true
return options
})
.end()
/**
* 打包分析
*/
if (IS_PROD) {
config.plugin('webpack-report').use(BundleAnalyzerPlugin, [
{
analyzerMode: 'static'
}
])
}
config
// https://webpack.js.org/configuration/devtool/#development
.when(!IS_PROD, config => config.devtool('cheap-source-map'))
config.when(IS_PROD, config => {
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use('script-ext-html-webpack-plugin', [
{
// 将 runtime 作为内联引入不单独存在
inline: /runtime\..*\.js$/
}
])
.end()
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
// cacheGroups 下可以可以配置多个组,每个组根据test设置条件,符合test条件的模块
commons: {
name: 'chunk-commons',
test: resolve('src/components'),
minChunks: 3, // 被至少用三次以上打包分离
priority: 5, // 优先级
reuseExistingChunk: true // 表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。
},
node_vendors: {
name: 'chunk-libs',
chunks: 'initial', // 只打包初始时依赖的第三方
test: /[\\/]node_modules[\\/]/,
priority: 10
},
vantUI: {
name: 'chunk-vantUI', // 单独将 vantUI 拆包
priority: 20, // 数字大权重到,满足多个 cacheGroups 的条件时候分到权重高的
test: /[\\/]node_modules[\\/]_?vant(.*)/
}
}
})
config.optimization.runtimeChunk('single')
})
}
})
Loading…
Cancel
Save