xiongzhu 4 жил өмнө
parent
commit
b5b1cb8d7e

+ 1 - 0
.env.development

@@ -0,0 +1 @@
+VUE_APP_BASE_URL=http://test.jmrh.izouma.com

+ 1 - 0
.env.production

@@ -0,0 +1 @@
+VUE_APP_BASE_URL=http://jmrh.izouma.com/

+ 22 - 12
.eslintrc.js

@@ -1,14 +1,24 @@
 module.exports = {
-  root: true,
-  env: {
-    node: true
-  },
-  extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"],
-  parserOptions: {
-    parser: "babel-eslint"
-  },
-  rules: {
-    "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
-    "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
-  }
+    root: true,
+    env: {
+        node: true
+    },
+    extends: ['plugin:vue/essential', '@vue/prettier'],
+    rules: {
+        'no-console': 'off',
+        'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
+        'no-unused-vars': 'off',
+        'no-empty': ['error', { allowEmptyCatch: true }],
+        'prettier/prettier': ['error']
+    },
+    parserOptions: {
+        parser: 'babel-eslint'
+    },
+    globals: {
+        Chart: true,
+        AMap: true,
+        FontAwesome: true,
+        wx: true,
+        cordova: true
+    }
 };

+ 5 - 0
.prettierrc.js

@@ -0,0 +1,5 @@
+module.exports = {
+    printWidth: 120,
+    singleQuote: true,
+    tabWidth: 4
+};

+ 1 - 1
babel.config.js

@@ -1,3 +1,3 @@
 module.exports = {
-  presets: ["@vue/cli-plugin-babel/preset"]
+    presets: ['@vue/cli-plugin-babel/preset']
 };

+ 13 - 0
capacitor.config.json

@@ -0,0 +1,13 @@
+{
+  "appId": "cn.drewslab.visitor",
+  "appName": "visitor",
+  "bundledWebRuntime": false,
+  "npmClient": "yarn",
+  "webDir": "dist",
+  "plugins": {
+    "SplashScreen": {
+      "launchShowDuration": 0
+    }
+  },
+  "cordova": {}
+}

+ 9 - 1
package.json

@@ -4,11 +4,17 @@
   "private": true,
   "scripts": {
     "serve": "vue-cli-service serve",
-    "build": "vue-cli-service build",
+    "build": "vue-cli-service build && npx cap copy",
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "@capacitor-community/keep-awake": "^1.0.0",
+    "@capacitor/cli": "^2.4.7",
+    "@capacitor/core": "^2.4.7",
+    "axios": "^0.21.1",
     "core-js": "^3.6.5",
+    "vant": "^2.12.9",
+    "vconsole-webpack-plugin": "^1.5.2",
     "vue": "^2.6.11",
     "vue-router": "^3.2.0",
     "vuex": "^3.4.0"
@@ -27,6 +33,8 @@
     "less": "^3.0.4",
     "less-loader": "^5.0.0",
     "prettier": "^1.19.1",
+    "style-resources-loader": "^1.4.1",
+    "vue-cli-plugin-style-resources-loader": "^0.1.5",
     "vue-template-compiler": "^2.6.11"
   }
 }

+ 2 - 27
src/App.vue

@@ -1,32 +1,7 @@
 <template>
-  <div id="app">
-    <div id="nav">
-      <router-link to="/">Home</router-link> |
-      <router-link to="/about">About</router-link>
-    </div>
-    <router-view />
-  </div>
+    <router-view class="router-page" id="root"></router-view>
 </template>
 
 <style lang="less">
-#app {
-  font-family: Avenir, Helvetica, Arial, sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  text-align: center;
-  color: #2c3e50;
-}
-
-#nav {
-  padding: 30px;
-
-  a {
-    font-weight: bold;
-    color: #2c3e50;
-
-    &.router-link-exact-active {
-      color: #42b983;
-    }
-  }
-}
+@import url(./styles/app.less);
 </style>

BIN
src/assets/nav_icon_back_black.png


BIN
src/assets/nav_icon_back_white.png


BIN
src/assets/nav_icon_search.png


BIN
src/assets/nav_icon_search_white.png


BIN
src/assets/nav_icon_share.png


+ 0 - 130
src/components/HelloWorld.vue

@@ -1,130 +0,0 @@
-<template>
-  <div class="hello">
-    <h1>{{ msg }}</h1>
-    <p>
-      For a guide and recipes on how to configure / customize this project,<br />
-      check out the
-      <a href="https://cli.vuejs.org" target="_blank" rel="noopener"
-        >vue-cli documentation</a
-      >.
-    </p>
-    <h3>Installed CLI Plugins</h3>
-    <ul>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
-          target="_blank"
-          rel="noopener"
-          >babel</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router"
-          target="_blank"
-          rel="noopener"
-          >router</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex"
-          target="_blank"
-          rel="noopener"
-          >vuex</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
-          target="_blank"
-          rel="noopener"
-          >eslint</a
-        >
-      </li>
-    </ul>
-    <h3>Essential Links</h3>
-    <ul>
-      <li>
-        <a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
-      </li>
-      <li>
-        <a href="https://forum.vuejs.org" target="_blank" rel="noopener"
-          >Forum</a
-        >
-      </li>
-      <li>
-        <a href="https://chat.vuejs.org" target="_blank" rel="noopener"
-          >Community Chat</a
-        >
-      </li>
-      <li>
-        <a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
-          >Twitter</a
-        >
-      </li>
-      <li>
-        <a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
-      </li>
-    </ul>
-    <h3>Ecosystem</h3>
-    <ul>
-      <li>
-        <a href="https://router.vuejs.org" target="_blank" rel="noopener"
-          >vue-router</a
-        >
-      </li>
-      <li>
-        <a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/vue-devtools#vue-devtools"
-          target="_blank"
-          rel="noopener"
-          >vue-devtools</a
-        >
-      </li>
-      <li>
-        <a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
-          >vue-loader</a
-        >
-      </li>
-      <li>
-        <a
-          href="https://github.com/vuejs/awesome-vue"
-          target="_blank"
-          rel="noopener"
-          >awesome-vue</a
-        >
-      </li>
-    </ul>
-  </div>
-</template>
-
-<script>
-export default {
-  name: "HelloWorld",
-  props: {
-    msg: String
-  }
-};
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="less">
-h3 {
-  margin: 40px 0 0;
-}
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-li {
-  display: inline-block;
-  margin: 0 10px;
-}
-a {
-  color: #42b983;
-}
-</style>

+ 148 - 0
src/components/NavBar.vue

@@ -0,0 +1,148 @@
+<template>
+    <div :style="computedStyle">
+        <div class="app-nav-bar" :style="navBarStyle">
+            <div class="nav-bar-body">
+                <slot name="title">
+                    <div class="nav-bar-title">{{ title }}</div>
+                </slot>
+                <div class="nav-bar-left" @click="clickLeft">
+                    <slot name="left">
+                        <img
+                            class="nav-left-icon"
+                            :src="
+                                theme === 'dark'
+                                    ? require('../assets/nav_icon_back_black.png')
+                                    : require('../assets/nav_icon_back_white.png')
+                            "
+                        />
+                    </slot>
+                </div>
+                <div class="nav-bar-right" @click="clickRight">
+                    <img
+                        v-if="rightIcon === 'share'"
+                        class="nav-right-icon"
+                        :src="
+                            theme === 'dark'
+                                ? require('../assets/nav_icon_share.png')
+                                : require('../assets/nav_icon_share.png')
+                        "
+                    />
+                    <img
+                        v-else-if="rightIcon === 'search'"
+                        class="nav-right-icon"
+                        :src="
+                            theme === 'dark'
+                                ? require('../assets/nav_icon_search.png')
+                                : require('../assets/nav_icon_search_white.png')
+                        "
+                    />
+                    <slot name="right" v-else> </slot>
+                </div>
+            </div>
+            <slot name="append"></slot>
+        </div>
+    </div>
+</template>
+<script>
+import { Capacitor, Plugins, StatusBarStyle } from '@capacitor/core';
+const { StatusBar } = Plugins;
+export default {
+    props: {
+        title: {},
+        placeholder: {
+            default: true
+        },
+        rightIcon: {},
+        theme: {
+            default: 'dark'
+        },
+        transparent: { type: Boolean, default: false }
+    },
+    data() {
+        return {};
+    },
+    computed: {
+        navBarStyle() {
+            return {
+                background: this.transparent ? 'none' : this.theme === 'dark' ? 'white' : 'black'
+            };
+        },
+        computedStyle() {
+            return {
+                height: this.placeholder ? 'calc(44px + var(--safe-top))' : '0px',
+                minHeight: this.placeholder ? 'calc(44px + var(--safe-top))' : '0px'
+            };
+        }
+    },
+    methods: {
+        clickLeft() {
+            this.$emit('click-left');
+        },
+        clickRight() {
+            this.$emit('click-right');
+        }
+    },
+    watch: {
+        theme(val) {
+            if (val === 'dark') {
+                StatusBar.setStyle({
+                    style: StatusBarStyle.Light
+                });
+            } else {
+                StatusBar.setStyle({
+                    style: StatusBarStyle.Dark
+                });
+            }
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.app-nav-bar {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    z-index: 1;
+    padding-top: var(--safe-top);
+    .nav-bar-body {
+        height: 44px;
+        .flex();
+        position: relative;
+        justify-content: center;
+        .nav-bar-left {
+            position: absolute;
+            left: 0;
+            top: 0;
+            height: 100%;
+            padding: 0 16px;
+            .flex();
+            .nav-left-icon {
+                width: 24px;
+                height: 24px;
+            }
+        }
+        .nav-bar-right {
+            position: absolute;
+            right: 0;
+            top: 0;
+            height: 100%;
+            padding: 0 16px;
+            .flex();
+            .nav-right-icon {
+                width: 24px;
+                height: 24px;
+            }
+        }
+        .nav-bar-title {
+            color: black;
+            font-size: 17px;
+            font-weight: bold;
+            font-weight: 500;
+        }
+    }
+}
+.nav-bar-placeholder {
+    height: calc(44px + var(--safe-top));
+}
+</style>

+ 81 - 9
src/main.js

@@ -1,12 +1,84 @@
-import Vue from "vue";
-import App from "./App.vue";
-import router from "./router";
-import store from "./store";
-
+import Vue from 'vue';
+import App from './App.vue';
+import router from './router';
+import store from './store';
+import { Capacitor, Plugins, StatusBarStyle } from '@capacitor/core';
+import Vant from 'vant';
+import 'vant/lib/index.less';
+import NavBar from './components/NavBar';
+import http from './plugins/http';
 Vue.config.productionTip = false;
+Vue.use(Vant);
+Vue.component('nav-bar', NavBar);
+Vue.use(http);
 
 new Vue({
-  router,
-  store,
-  render: h => h(App)
-}).$mount("#app");
+    router,
+    store,
+    render: h => h(App)
+}).$mount('#app');
+
+const style = document.documentElement.style;
+if (/Capacitor/.test(navigator.userAgent)) {
+    style.setProperty('--safe-top', '44px');
+    style.setProperty('--safe-bottom', '36px');
+}
+document.addEventListener(
+    'deviceready',
+    () => {
+        window.AndroidNotch.getInsetTop(
+            px => {
+                style.setProperty('--safe-top', px + 'px');
+            },
+            err => console.error('Failed to get insets top:', err)
+        );
+
+        window.AndroidNotch.getInsetRight(
+            px => {
+                style.setProperty('--safe-right', px + 'px');
+            },
+            err => console.error('Failed to get insets right:', err)
+        );
+
+        window.AndroidNotch.getInsetBottom(
+            px => {
+                style.setProperty('--safe-bottom', px + 'px');
+            },
+            err => console.error('Failed to get insets bottom:', err)
+        );
+
+        window.AndroidNotch.getInsetLeft(
+            px => {
+                style.setProperty('--safe-left', px + 'px');
+            },
+            err => console.error('Failed to get insets left:', err)
+        );
+        if (window.cordova) {
+            console.log('inApp');
+            store.commit('setApp', true);
+            store.commit('setShowNavigationBar', true);
+        }
+
+        let t = 0;
+        document.addEventListener(
+            'backbutton',
+            e => {
+                if (vm.$route.name === 'home') {
+                    let t1 = new Date().getTime();
+                    if (t1 - t < 1000) {
+                        navigator.app.exitApp();
+                    } else {
+                        t = t1;
+                        console.log(vm.$route);
+                        vm.$toast('再按一次退出');
+                    }
+                    e.preventDefault();
+                } else {
+                    vm.$router.go(-1);
+                }
+            },
+            false
+        );
+    },
+    false
+);

+ 91 - 0
src/plugins/http.js

@@ -0,0 +1,91 @@
+import axios from 'axios';
+import router from '../router';
+import qs from 'qs';
+/* eslint-disable */
+let baseUrl = localStorage.getItem('serverUrl') || process.env.VUE_APP_BASE_URL;
+const axiosInstance = axios.create({
+    baseURL: baseUrl
+});
+
+axiosInstance.interceptors.request.use(
+    function(config) {
+        config.headers = config.headers || {};
+        let token = localStorage.getItem('token');
+        if (token) {
+            config.headers['Authorization'] = 'Bearer ' + token;
+        }
+        return config;
+    },
+    function(error) {
+        return Promise.reject(error);
+    }
+);
+
+axiosInstance.interceptors.response.use(
+    function(response) {
+        return response;
+    },
+    function(error) {
+        console.log(error);
+        if (401 === error.response.status) {
+            if (router.currentRoute.name !== 'login') {
+                // router.replace({
+                //     name: 'login',
+                //     params: {
+                //         from: router.currentRoute.name,
+                //     },
+                // });
+            } else {
+            }
+        }
+        return Promise.reject(error.response.data);
+    }
+);
+export default {
+    axios: axiosInstance,
+    install(_Vue, options) {
+        _Vue.prototype.$baseUrl = baseUrl;
+        _Vue.prototype.$axios = axiosInstance;
+        _Vue.prototype.$http = {
+            axios: axiosInstance,
+            get(url, params) {
+                params = params || {};
+                return new Promise((resolve, reject) => {
+                    axiosInstance
+                        .get(
+                            url,
+                            {
+                                params: params
+                            },
+                            { withCredentials: true }
+                        )
+                        .then(res => {
+                            resolve(res.data);
+                        })
+                        .catch(e => {
+                            reject(e);
+                        });
+                });
+            },
+            post(url, body, options) {
+                options = options || {};
+                body = body || {};
+                if (!(body instanceof FormData)) {
+                    if (options.body !== 'json') {
+                        body = qs.stringify(body);
+                    }
+                }
+                return new Promise((resolve, reject) => {
+                    axiosInstance
+                        .post(url, body, { withCredentials: true })
+                        .then(res => {
+                            resolve(res.data);
+                        })
+                        .catch(e => {
+                            reject(e);
+                        });
+                });
+            }
+        };
+    }
+};

+ 32 - 20
src/router/index.js

@@ -1,28 +1,40 @@
-import Vue from "vue";
-import VueRouter from "vue-router";
-import Home from "../views/Home.vue";
-
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+import Home from '../views/Home.vue';
+import settings from '../views/settings';
+import http from '../plugins/http';
+import { Capacitor, Plugins, StatusBarStyle } from '@capacitor/core';
+const { StatusBar } = Plugins;
 Vue.use(VueRouter);
 
 const routes = [
-  {
-    path: "/",
-    name: "Home",
-    component: Home
-  },
-  {
-    path: "/about",
-    name: "About",
-    // route level code-splitting
-    // this generates a separate chunk (about.[hash].js) for this route
-    // which is lazy-loaded when the route is visited.
-    component: () =>
-      import(/* webpackChunkName: "about" */ "../views/About.vue")
-  }
+    {
+        path: '/',
+        name: 'home',
+        component: Home
+    },
+    {
+        path: '/settings',
+        name: 'settings',
+        component: settings
+    }
 ];
 
 const router = new VueRouter({
-  routes
+    routes
+});
+router.afterEach((to, from) => {
+    const statusBarAvailable = Capacitor.isPluginAvailable('StatusBar');
+    if (statusBarAvailable) {
+        if ('dark' === to.meta.statusBar) {
+            StatusBar.setStyle({
+                style: StatusBarStyle.Light
+            });
+        } else {
+            StatusBar.setStyle({
+                style: StatusBarStyle.Dark
+            });
+        }
+    }
 });
-
 export default router;

+ 6 - 6
src/store/index.js

@@ -1,11 +1,11 @@
-import Vue from "vue";
-import Vuex from "vuex";
+import Vue from 'vue';
+import Vuex from 'vuex';
 
 Vue.use(Vuex);
 
 export default new Vuex.Store({
-  state: {},
-  mutations: {},
-  actions: {},
-  modules: {}
+    state: {},
+    mutations: {},
+    actions: {},
+    modules: {}
 });

+ 299 - 0
src/styles/app.less

@@ -0,0 +1,299 @@
+:root {
+    --safe-top: env(safe-area-inset-top);
+    --safe-bottom: env(safe-area-inset-bottom);
+    --safe-left: env(safe-area-inset-left);
+    --safe-right: env(safe-area-inset-right);
+}
+
+.router-page {
+    position: absolute;
+    top: 0;
+    left: 0;
+    height: 100%;
+    width: 100%;
+    overflow-x: hidden;
+    overflow-y: scroll;
+    -webkit-overflow-scrolling: touch;
+}
+
+html {
+    width: 100%;
+    height: 100vh;
+    font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
+        'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    margin: 0;
+    padding: 0;
+}
+
+body {
+    width: 100%;
+    height: 100%;
+    background: white;
+    font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
+        'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    margin: 0;
+    padding: 0;
+}
+
+* {
+    box-sizing: border-box;
+    -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
+    touch-action: manipulation;
+}
+
+input {
+    outline: none;
+    border: none;
+    background: transparent;
+}
+
+.slide-in-left-enter {
+    transform: translateX(-100%);
+}
+.slide-in-left-enter-active,
+.slide-in-left-leave-active {
+    transition: all 0.3s;
+}
+.fade-enter,
+.fade-leave-active {
+    opacity: 0;
+}
+.fade-enter-active,
+.fade-leave-active {
+    transition: all 0.3s;
+}
+.zoom-enter,
+.zoom-leave-active {
+    opacity: 0;
+    transform: scale3d(1.1, 1.1, 1);
+}
+.zoom-enter-active,
+.zoom-leave-active {
+    transition: all 0.3s;
+}
+.loadmore {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+/*!
+ * Load Awesome v1.1.0 (http://github.danielcardoso.net/load-awesome/)
+ * Copyright 2015 Daniel Cardoso <@DanielCardoso>
+ * Licensed under MIT
+ */
+.la-line-spin-clockwise-fade,
+.la-line-spin-clockwise-fade > div {
+    position: relative;
+    -webkit-box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    box-sizing: border-box;
+}
+.la-line-spin-clockwise-fade {
+    display: block;
+    font-size: 0;
+    color: #fff;
+}
+.la-line-spin-clockwise-fade.la-dark {
+    color: #333;
+}
+.la-line-spin-clockwise-fade > div {
+    display: inline-block;
+    float: none;
+    background-color: currentColor;
+    border: 0 solid currentColor;
+}
+.la-line-spin-clockwise-fade {
+    width: 32px;
+    height: 32px;
+}
+.la-line-spin-clockwise-fade > div {
+    position: absolute;
+    width: 2px;
+    height: 10px;
+    margin: 2px;
+    margin-top: -5px;
+    margin-left: -1px;
+    border-radius: 0;
+    -webkit-animation: line-spin-clockwise-fade 1s infinite ease-in-out;
+    -moz-animation: line-spin-clockwise-fade 1s infinite ease-in-out;
+    -o-animation: line-spin-clockwise-fade 1s infinite ease-in-out;
+    animation: line-spin-clockwise-fade 1s infinite ease-in-out;
+}
+.la-line-spin-clockwise-fade > div:nth-child(1) {
+    top: 15%;
+    left: 50%;
+    -webkit-transform: rotate(0deg);
+    -moz-transform: rotate(0deg);
+    -ms-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    transform: rotate(0deg);
+    -webkit-animation-delay: -0.875s;
+    -moz-animation-delay: -0.875s;
+    -o-animation-delay: -0.875s;
+    animation-delay: -0.875s;
+}
+.la-line-spin-clockwise-fade > div:nth-child(2) {
+    top: 25.2512626585%;
+    left: 74.7487373415%;
+    -webkit-transform: rotate(45deg);
+    -moz-transform: rotate(45deg);
+    -ms-transform: rotate(45deg);
+    -o-transform: rotate(45deg);
+    transform: rotate(45deg);
+    -webkit-animation-delay: -0.75s;
+    -moz-animation-delay: -0.75s;
+    -o-animation-delay: -0.75s;
+    animation-delay: -0.75s;
+}
+.la-line-spin-clockwise-fade > div:nth-child(3) {
+    top: 50%;
+    left: 85%;
+    -webkit-transform: rotate(90deg);
+    -moz-transform: rotate(90deg);
+    -ms-transform: rotate(90deg);
+    -o-transform: rotate(90deg);
+    transform: rotate(90deg);
+    -webkit-animation-delay: -0.625s;
+    -moz-animation-delay: -0.625s;
+    -o-animation-delay: -0.625s;
+    animation-delay: -0.625s;
+}
+.la-line-spin-clockwise-fade > div:nth-child(4) {
+    top: 74.7487373415%;
+    left: 74.7487373415%;
+    -webkit-transform: rotate(135deg);
+    -moz-transform: rotate(135deg);
+    -ms-transform: rotate(135deg);
+    -o-transform: rotate(135deg);
+    transform: rotate(135deg);
+    -webkit-animation-delay: -0.5s;
+    -moz-animation-delay: -0.5s;
+    -o-animation-delay: -0.5s;
+    animation-delay: -0.5s;
+}
+.la-line-spin-clockwise-fade > div:nth-child(5) {
+    top: 84.9999999974%;
+    left: 50.0000000004%;
+    -webkit-transform: rotate(180deg);
+    -moz-transform: rotate(180deg);
+    -ms-transform: rotate(180deg);
+    -o-transform: rotate(180deg);
+    transform: rotate(180deg);
+    -webkit-animation-delay: -0.375s;
+    -moz-animation-delay: -0.375s;
+    -o-animation-delay: -0.375s;
+    animation-delay: -0.375s;
+}
+.la-line-spin-clockwise-fade > div:nth-child(6) {
+    top: 74.7487369862%;
+    left: 25.2512627193%;
+    -webkit-transform: rotate(225deg);
+    -moz-transform: rotate(225deg);
+    -ms-transform: rotate(225deg);
+    -o-transform: rotate(225deg);
+    transform: rotate(225deg);
+    -webkit-animation-delay: -0.25s;
+    -moz-animation-delay: -0.25s;
+    -o-animation-delay: -0.25s;
+    animation-delay: -0.25s;
+}
+.la-line-spin-clockwise-fade > div:nth-child(7) {
+    top: 49.9999806189%;
+    left: 15.0000039834%;
+    -webkit-transform: rotate(270deg);
+    -moz-transform: rotate(270deg);
+    -ms-transform: rotate(270deg);
+    -o-transform: rotate(270deg);
+    transform: rotate(270deg);
+    -webkit-animation-delay: -0.125s;
+    -moz-animation-delay: -0.125s;
+    -o-animation-delay: -0.125s;
+    animation-delay: -0.125s;
+}
+.la-line-spin-clockwise-fade > div:nth-child(8) {
+    top: 25.2506949798%;
+    left: 25.2513989292%;
+    -webkit-transform: rotate(315deg);
+    -moz-transform: rotate(315deg);
+    -ms-transform: rotate(315deg);
+    -o-transform: rotate(315deg);
+    transform: rotate(315deg);
+    -webkit-animation-delay: 0s;
+    -moz-animation-delay: 0s;
+    -o-animation-delay: 0s;
+    animation-delay: 0s;
+}
+.la-line-spin-clockwise-fade.la-sm {
+    width: 16px;
+    height: 16px;
+}
+.la-line-spin-clockwise-fade.la-sm > div {
+    width: 1px;
+    height: 4px;
+    margin-top: -2px;
+    margin-left: 0;
+}
+.la-line-spin-clockwise-fade.la-2x {
+    width: 64px;
+    height: 64px;
+}
+.la-line-spin-clockwise-fade.la-2x > div {
+    width: 4px;
+    height: 20px;
+    margin-top: -10px;
+    margin-left: -2px;
+}
+.la-line-spin-clockwise-fade.la-3x {
+    width: 96px;
+    height: 96px;
+}
+.la-line-spin-clockwise-fade.la-3x > div {
+    width: 6px;
+    height: 30px;
+    margin-top: -15px;
+    margin-left: -3px;
+}
+/*
+  * Animation
+  */
+@-webkit-keyframes line-spin-clockwise-fade {
+    50% {
+        opacity: 0.2;
+    }
+    100% {
+        opacity: 1;
+    }
+}
+@-moz-keyframes line-spin-clockwise-fade {
+    50% {
+        opacity: 0.2;
+    }
+    100% {
+        opacity: 1;
+    }
+}
+@-o-keyframes line-spin-clockwise-fade {
+    50% {
+        opacity: 0.2;
+    }
+    100% {
+        opacity: 1;
+    }
+}
+@keyframes line-spin-clockwise-fade {
+    50% {
+        opacity: 0.2;
+    }
+    100% {
+        opacity: 1;
+    }
+}
+
+::-webkit-scrollbar {
+    display: none;
+}

+ 172 - 0
src/styles/common/index.less

@@ -0,0 +1,172 @@
+@divider: #f2f3f5;
+@prim: #bf1616;
+@success: #07c160;
+@danger: #ee0a24;
+@warn: #ff976a;
+@text0: #181818;
+@text1: #323233;
+@text2: #606266;
+@text3: #939599;
+@text4: #c6c8cc;
+@border1: #dcdfe6;
+@border2: #f2f3f5;
+@border3: #dfe1e6;
+@border4: #f2f6fc;
+@bg: #f7f8fa;
+
+@safe-top: env(safe-area-inset-top);
+@safe-bottom: env(safe-area-inset-bottom);
+
+.flex() {
+    display: flex;
+    align-items: center;
+}
+.flex-col() {
+    display: flex;
+    flex-direction: column;
+}
+
+.setTopLine(@c: @divider) {
+    content: ' ';
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    height: 1px;
+    border-top: 1px solid @c;
+    color: @c;
+    transform-origin: 0 0;
+    transform: scaleY(0.5);
+}
+
+.setBottomLine(@c: @divider) {
+    content: ' ';
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    height: 1px;
+    border-bottom: 1px solid @c;
+    color: @c;
+    transform-origin: 0 100%;
+    transform: scaleY(0.5);
+}
+
+.setLeftLine(@c: @divider) {
+    content: ' ';
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 1px;
+    bottom: 0;
+    border-left: 1px solid @c;
+    color: @c;
+    transform-origin: 0 0;
+    transform: scaleX(0.5);
+}
+
+.setRightLine(@c: @divider) {
+    content: ' ';
+    position: absolute;
+    right: 0;
+    top: 0;
+    width: 1px;
+    bottom: 0;
+    border-right: 1px solid @c;
+    color: @c;
+    transform-origin: 100% 0;
+    transform: scaleX(0.5);
+}
+.ellipsis(@w:auto) {
+    width: @w;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    word-wrap: normal;
+}
+
+.ellipsisLn(@line) {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: @line;
+}
+.text_wrap() {
+    word-wrap: break-word;
+    word-break: break-all;
+}
+.hyphens() {
+    word-wrap: break-word;
+    -webkit-hyphens: auto;
+    hyphens: auto;
+}
+.btn-round-large {
+    height: 44px;
+    background: #f7931d;
+    border-radius: 30px;
+    position: absolute;
+    left: 15px;
+    right: 15px;
+    bottom: 15px;
+    bottom: calc(env(safe-area-inset-bottom) + 15px);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 16px;
+    font-weight: bold;
+    color: white;
+    &:active {
+        background: shade(#f7931d, 10%);
+    }
+    &.disabled {
+        background-color: #8f9294;
+    }
+}
+
+.btn-lg {
+    width: 280px;
+    height: 40px;
+    background: @prim;
+    border-radius: 4px;
+    .flex();
+    color: white;
+    font-size: 14px;
+    justify-content: center;
+    user-select: none;
+    &:active {
+        background: shade(@prim, 10%);
+    }
+}
+.btn-lg-o {
+    width: 280px;
+    height: 40px;
+    border-radius: 4px;
+    .flex();
+    color: @prim;
+    border: 1px solid @prim;
+    font-size: 14px;
+    justify-content: center;
+    user-select: none;
+    &:active {
+        background: fade(@prim, 5%);
+    }
+}
+
+.btn-sm {
+    height: 30px;
+    .flex();
+    justify-content: center;
+    padding: 0 12px;
+    background: @prim;
+    border-radius: 4px;
+    color: white;
+    font-size: 13px;
+    user-select: none;
+    &:active {
+        background: shade(@prim, 10%);
+    }
+    &.disabled {
+        background-color: #8f9294;
+    }
+}

+ 1 - 0
src/styles/theme.less

@@ -0,0 +1 @@
+@dialog-confirm-button-text-color: #bf1616;

+ 0 - 5
src/views/About.vue

@@ -1,5 +0,0 @@
-<template>
-  <div class="about">
-    <h1>This is an about page</h1>
-  </div>
-</template>

+ 3 - 11
src/views/Home.vue

@@ -1,18 +1,10 @@
 <template>
-  <div class="home">
-    <img alt="Vue logo" src="../assets/logo.png" />
-    <HelloWorld msg="Welcome to Your Vue.js App" />
-  </div>
+    <div class="home">home</div>
 </template>
 
 <script>
-// @ is an alias to /src
-import HelloWorld from "@/components/HelloWorld.vue";
-
 export default {
-  name: "Home",
-  components: {
-    HelloWorld
-  }
+    name: 'home',
+    components: {}
 };
 </script>

+ 67 - 0
src/views/settings.vue

@@ -0,0 +1,67 @@
+<template>
+    <div class="settings">
+        <nav-bar title="设置" @click-left="$router.go(-1)"></nav-bar>
+        <div class="section">
+            <div class="section-title">服务器地址</div>
+            <van-field v-model="serverUrl" placeholder="请输入服务器地址" />
+        </div>
+        <div class="btn-save">
+            <van-button block type="primary" @click="save">保存</van-button>
+        </div>
+    </div>
+</template>
+<script>
+import axios from 'axios';
+export default {
+    data() {
+        return {
+            serverUrl: ''
+        };
+    },
+    created() {
+        this.serverUrl = localStorage.getItem('serverUrl') || '';
+    },
+    methods: {
+        save() {
+            if (!/^http(s{0,1})\:\/\/.+$/.test(this.serverUrl)) {
+                this.$toast('请输入正确的地址');
+                return;
+            }
+            this.$toast.loading();
+            axios
+                .get('/user/my', { baseURL: this.serverUrl })
+                .then(res => {
+                    localStorage.setItem('serverUrl', this.serverUrl);
+                    this.$toast.clear();
+                    this.$toast.success('保存成功');
+                    this.$http.axios.defaults.baseURL = this.serverUrl;
+                })
+                .catch(e => {
+                    console.log(e.response);
+                    if (e.response.status === 401) {
+                        localStorage.setItem('serverUrl', this.serverUrl);
+                        this.$toast.clear();
+                        this.$toast.success('保存成功');
+                        this.$http.axios.defaults.baseURL = this.serverUrl;
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.settings {
+    background: @bg;
+}
+.section {
+    margin-top: 20px;
+    .section-title {
+        padding: 0 0 10px 16px;
+        font-size: 13px;
+        color: @text3;
+    }
+}
+.btn-save {
+    margin: 40px 16px 0 16px;
+}
+</style>

+ 38 - 0
vue.config.js

@@ -0,0 +1,38 @@
+const path = require('path');
+const vConsolePlugin = require('vconsole-webpack-plugin');
+module.exports = {
+    productionSourceMap: false,
+    publicPath: '/',
+    devServer: {
+        port: 8082
+    },
+    pluginOptions: {
+        'style-resources-loader': {
+            preProcessor: 'less',
+            patterns: [path.resolve(__dirname, './src/styles/common/index.less')]
+        }
+    },
+    chainWebpack: config => {
+        if ('development' === process.env.NODE_ENV) {
+            config.plugins.delete('preload');
+            config.plugins.delete('prefetch');
+        }
+        config.plugin('vConsole').use(vConsolePlugin, [
+            {
+                filter: [], // 需要过滤的入口文件
+                enable: false // 发布代码前记得改回 false
+            }
+        ]);
+    },
+    css: {
+        loaderOptions: {
+            less: {
+                lessOptions: {
+                    modifyVars: {
+                        hack: `true; @import "${path.resolve(__dirname, './src/styles/theme.less')}";`
+                    }
+                }
+            }
+        }
+    }
+};

+ 239 - 15
yarn.lock

@@ -819,7 +819,7 @@
     "@babel/types" "^7.4.4"
     esutils "^2.0.2"
 
-"@babel/runtime@^7.11.0", "@babel/runtime@^7.8.4":
+"@babel/runtime@7.x", "@babel/runtime@^7.11.0", "@babel/runtime@^7.8.4":
   version "7.13.10"
   resolved "https://registry.npm.taobao.org/@babel/runtime/download/@babel/runtime-7.13.10.tgz?cache=0&sync_timestamp=1615243551514&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
   integrity sha1-R9QqV7YJX0Ro2kQDiP262L6/DX0=
@@ -859,6 +859,35 @@
     lodash "^4.17.19"
     to-fast-properties "^2.0.0"
 
+"@capacitor-community/keep-awake@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@capacitor-community/keep-awake/-/keep-awake-1.0.0.tgz#f570e9395f056a546facbadaa592a71a2619d68a"
+  integrity sha512-4CMFpkLRnnQKBk4i0yz9gGAC48XgCqUtSG96g+miCVUzoPhzO4LcrFa5FcNLUahHkcCiaICyf1tnAr6k1cpc5g==
+
+"@capacitor/cli@^2.4.7":
+  version "2.4.7"
+  resolved "https://registry.yarnpkg.com/@capacitor/cli/-/cli-2.4.7.tgz#690089689b25cb22a25eb930b1dd04af757f2f95"
+  integrity sha512-RC5EO3oA2gWniZK0JWRlZa+7MFIoHYiAtt+W4Hqq74nyv1C0z/MvRY3pX2DX7kKy6Uc1Z/25D0uSXRk+erv3RQ==
+  dependencies:
+    chalk "^2.3.0"
+    commander "^4.1.1"
+    compare-versions "^3.1.0"
+    fs-extra "^4.0.3"
+    inquirer "6.3.1"
+    open "^6.1.0"
+    ora "^1.3.0"
+    plist "^3.0.1"
+    semver "^5.4.1"
+    which "^1.3.0"
+    xml2js "^0.4.19"
+
+"@capacitor/core@^2.4.7":
+  version "2.4.7"
+  resolved "https://registry.yarnpkg.com/@capacitor/core/-/core-2.4.7.tgz#f3b4d5728db7e764c1153da5e67d369bda35b772"
+  integrity sha512-ZPzXXQ4EPwR/ZhNDkmlxyzw4FvquIl/ROj8HMMM0MEd4xZfM8ulNGPIL6br9TWdlFLGBKq40eymPZjKaivGnig==
+  dependencies:
+    tslib "^1.9.0"
+
 "@hapi/address@2.x.x":
   version "2.1.4"
   resolved "https://registry.npm.taobao.org/@hapi/address/download/@hapi/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
@@ -913,6 +942,11 @@
   resolved "https://registry.npm.taobao.org/@nodelib/fs.stat/download/@nodelib/fs.stat-1.1.3.tgz?cache=0&sync_timestamp=1609074440744&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40nodelib%2Ffs.stat%2Fdownload%2F%40nodelib%2Ffs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
   integrity sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=
 
+"@popperjs/core@^2.5.4":
+  version "2.9.1"
+  resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.1.tgz#7f554e7368c9ab679a11f4a042ca17149d70cf12"
+  integrity sha512-DvJbbn3dUgMxDnJLH+RZQPnXak1h4ZVYQ7CWiFWjQwBFkVajT4rfw2PdpHLTSTwxrYfnoEXkuBiwkDm6tPMQeA==
+
 "@soda/friendly-errors-webpack-plugin@^1.7.1":
   version "1.8.0"
   resolved "https://registry.npm.taobao.org/@soda/friendly-errors-webpack-plugin/download/@soda/friendly-errors-webpack-plugin-1.8.0.tgz?cache=0&sync_timestamp=1607927401282&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40soda%2Ffriendly-errors-webpack-plugin%2Fdownload%2F%40soda%2Ffriendly-errors-webpack-plugin-1.8.0.tgz#84751d82a93019d5c92c0cf0e45ac59087cd2240"
@@ -990,7 +1024,7 @@
   dependencies:
     "@types/node" "*"
 
-"@types/json-schema@^7.0.5":
+"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6":
   version "7.0.7"
   resolved "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.7.tgz?cache=0&sync_timestamp=1613379017372&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
   integrity sha1-mKmTUWyFnrDVxMjwmDF6nqaNua0=
@@ -1092,7 +1126,19 @@
     "@types/webpack-sources" "*"
     source-map "^0.6.0"
 
-"@vue/babel-helper-vue-jsx-merge-props@^1.2.1":
+"@vant/icons@1.5.2":
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/@vant/icons/-/icons-1.5.2.tgz#3f3ea353a0eacd38c113757bd31836489facb10b"
+  integrity sha512-Gy2mFIgObvCh1azp6LklQYsNFrCjMLxf/mEzHD6WV0pZbMBNjsb7bWvAjPo3Wygo9IVtGqi/36wrtosv3PkyRg==
+
+"@vant/popperjs@^1.0.0":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/@vant/popperjs/-/popperjs-1.0.4.tgz#49c20809a3828e7b036e23d50fb56121e997618f"
+  integrity sha512-bqbmOoX0kYexGw65awNX9wxePR0ZIdTlVP+7JRahrbUjKW0+HxC2T27NE90cCDmqiFL/6+QYazhLvVa436jV0A==
+  dependencies:
+    "@popperjs/core" "^2.5.4"
+
+"@vue/babel-helper-vue-jsx-merge-props@^1.0.0", "@vue/babel-helper-vue-jsx-merge-props@^1.2.1":
   version "1.2.1"
   resolved "https://registry.npm.taobao.org/@vue/babel-helper-vue-jsx-merge-props/download/@vue/babel-helper-vue-jsx-merge-props-1.2.1.tgz#31624a7a505fb14da1d58023725a4c5f270e6a81"
   integrity sha1-MWJKelBfsU2h1YAjclpMXycOaoE=
@@ -1576,7 +1622,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
   resolved "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.5.2.tgz?cache=0&sync_timestamp=1608062556009&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv-keywords%2Fdownload%2Fajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
   integrity sha1-MfKdpatuANHC0yms97WSlhTVAU0=
 
-ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4:
+ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
   version "6.12.6"
   resolved "https://registry.npm.taobao.org/ajv/download/ajv-6.12.6.tgz?cache=0&sync_timestamp=1615144099331&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
   integrity sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=
@@ -1596,6 +1642,11 @@ ansi-colors@^3.0.0:
   resolved "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
   integrity sha1-46PaS/uubIapwoViXeEkojQCb78=
 
+ansi-escapes@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
+  integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
+
 ansi-escapes@^4.2.1:
   version "4.3.1"
   resolved "https://registry.npm.taobao.org/ansi-escapes/download/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61"
@@ -1812,6 +1863,13 @@ aws4@^1.8.0:
   resolved "https://registry.npm.taobao.org/aws4/download/aws4-1.11.0.tgz?cache=0&sync_timestamp=1604101244098&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws4%2Fdownload%2Faws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
   integrity sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=
 
+axios@^0.21.1:
+  version "0.21.1"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
+  integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
+  dependencies:
+    follow-redirects "^1.10.0"
+
 babel-eslint@^10.1.0:
   version "10.1.0"
   resolved "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz?cache=0&sync_timestamp=1611946213770&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-eslint%2Fdownload%2Fbabel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
@@ -1870,7 +1928,7 @@ balanced-match@^1.0.0:
   resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
   integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
 
-base64-js@^1.0.2:
+base64-js@^1.0.2, base64-js@^1.2.3:
   version "1.5.1"
   resolved "https://registry.npm.taobao.org/base64-js/download/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha1-GxtEAWClv3rUC2UPCVljSBkDkwo=
@@ -2423,11 +2481,21 @@ cli-highlight@^2.1.4:
     parse5-htmlparser2-tree-adapter "^6.0.0"
     yargs "^16.0.0"
 
+cli-spinners@^1.0.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a"
+  integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==
+
 cli-spinners@^2.0.0:
   version "2.5.0"
   resolved "https://registry.npm.taobao.org/cli-spinners/download/cli-spinners-2.5.0.tgz#12763e47251bf951cb75c201dfa58ff1bcb2d047"
   integrity sha1-EnY+RyUb+VHLdcIB36WP8byy0Ec=
 
+cli-width@^2.0.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
+  integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
+
 cli-width@^3.0.0:
   version "3.0.0"
   resolved "https://registry.npm.taobao.org/cli-width/download/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
@@ -2558,6 +2626,11 @@ commander@^2.18.0, commander@^2.20.0:
   resolved "https://registry.npm.taobao.org/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1613373913701&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
   integrity sha1-/UhehMA+tIgcIHIrpIA16FMa6zM=
 
+commander@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
+  integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+
 commander@~2.19.0:
   version "2.19.0"
   resolved "https://registry.npm.taobao.org/commander/download/commander-2.19.0.tgz?cache=0&sync_timestamp=1613373913701&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
@@ -2568,6 +2641,11 @@ commondir@^1.0.1:
   resolved "https://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
   integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
 
+compare-versions@^3.1.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62"
+  integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==
+
 component-emitter@^1.2.1:
   version "1.3.0"
   resolved "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
@@ -3766,6 +3844,13 @@ figgy-pudding@^3.5.1:
   resolved "https://registry.npm.taobao.org/figgy-pudding/download/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
   integrity sha1-tO7oFIq7Adzx0aw0Nn1Z4S+mHW4=
 
+figures@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
+  integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+  dependencies:
+    escape-string-regexp "^1.0.5"
+
 figures@^3.0.0:
   version "3.2.0"
   resolved "https://registry.npm.taobao.org/figures/download/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
@@ -3900,7 +3985,7 @@ flush-write-stream@^1.0.0:
     inherits "^2.0.3"
     readable-stream "^2.3.6"
 
-follow-redirects@^1.0.0:
+follow-redirects@^1.0.0, follow-redirects@^1.10.0:
   version "1.13.3"
   resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
   integrity sha1-5VmK1QF0wbxOhyMB6CrCzZf5Amc=
@@ -3949,6 +4034,15 @@ from2@^2.1.0:
     inherits "^2.0.1"
     readable-stream "^2.0.0"
 
+fs-extra@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
+  integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==
+  dependencies:
+    graceful-fs "^4.1.2"
+    jsonfile "^4.0.0"
+    universalify "^0.1.0"
+
 fs-extra@^7.0.1:
   version "7.0.1"
   resolved "https://registry.npm.taobao.org/fs-extra/download/fs-extra-7.0.1.tgz?cache=0&sync_timestamp=1611075656220&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffs-extra%2Fdownload%2Ffs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
@@ -4078,7 +4172,7 @@ glob-to-regexp@^0.3.0:
   resolved "https://registry.npm.taobao.org/glob-to-regexp/download/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
   integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
 
-glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
+glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
   version "7.1.6"
   resolved "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
   integrity sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY=
@@ -4578,6 +4672,25 @@ inherits@2.0.3:
   resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
   integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
 
+inquirer@6.3.1:
+  version "6.3.1"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.3.1.tgz#7a413b5e7950811013a3db491c61d1f3b776e8e7"
+  integrity sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==
+  dependencies:
+    ansi-escapes "^3.2.0"
+    chalk "^2.4.2"
+    cli-cursor "^2.1.0"
+    cli-width "^2.0.0"
+    external-editor "^3.0.3"
+    figures "^2.0.0"
+    lodash "^4.17.11"
+    mute-stream "0.0.7"
+    run-async "^2.2.0"
+    rxjs "^6.4.0"
+    string-width "^2.1.0"
+    strip-ansi "^5.1.0"
+    through "^2.3.6"
+
 inquirer@^7.0.0, inquirer@^7.1.0:
   version "7.3.3"
   resolved "https://registry.npm.taobao.org/inquirer/download/inquirer-7.3.3.tgz?cache=0&sync_timestamp=1614296694538&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Finquirer%2Fdownload%2Finquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
@@ -5267,7 +5380,7 @@ lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17
   resolved "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
   integrity sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=
 
-log-symbols@^2.2.0:
+log-symbols@^2.1.0, log-symbols@^2.2.0:
   version "2.2.0"
   resolved "https://registry.npm.taobao.org/log-symbols/download/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
   integrity sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=
@@ -5596,6 +5709,16 @@ multicast-dns@^6.0.1:
     dns-packet "^1.3.1"
     thunky "^1.0.2"
 
+mutation-observer@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/mutation-observer/-/mutation-observer-1.0.3.tgz#42e9222b101bca82e5ba9d5a7acf4a14c0f263d0"
+  integrity sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==
+
+mute-stream@0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
+  integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
+
 mute-stream@0.0.8:
   version "0.0.8"
   resolved "https://registry.npm.taobao.org/mute-stream/download/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
@@ -5908,7 +6031,7 @@ onetime@^5.1.0:
   dependencies:
     mimic-fn "^2.1.0"
 
-open@^6.3.0:
+open@^6.1.0, open@^6.3.0:
   version "6.4.0"
   resolved "https://registry.npm.taobao.org/open/download/open-6.4.0.tgz?cache=0&sync_timestamp=1614759218873&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fopen%2Fdownload%2Fopen-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9"
   integrity sha1-XBPpbQ3IlGhhZPGJZez+iJ7PyKk=
@@ -5939,6 +6062,16 @@ optionator@^0.8.3:
     type-check "~0.3.2"
     word-wrap "~1.2.3"
 
+ora@^1.3.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ora/-/ora-1.4.0.tgz#884458215b3a5d4097592285f93321bb7a79e2e5"
+  integrity sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw==
+  dependencies:
+    chalk "^2.1.0"
+    cli-cursor "^2.1.0"
+    cli-spinners "^1.0.1"
+    log-symbols "^2.1.0"
+
 ora@^3.4.0:
   version "3.4.0"
   resolved "https://registry.npm.taobao.org/ora/download/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318"
@@ -6240,6 +6373,15 @@ pkg-dir@^4.1.0:
   dependencies:
     find-up "^4.0.0"
 
+plist@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c"
+  integrity sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==
+  dependencies:
+    base64-js "^1.2.3"
+    xmlbuilder "^9.0.7"
+    xmldom "0.1.x"
+
 pnp-webpack-plugin@^1.6.4:
   version "1.6.4"
   resolved "https://registry.npm.taobao.org/pnp-webpack-plugin/download/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149"
@@ -7067,7 +7209,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
     hash-base "^3.0.0"
     inherits "^2.0.1"
 
-run-async@^2.4.0:
+run-async@^2.2.0, run-async@^2.4.0:
   version "2.4.1"
   resolved "https://registry.npm.taobao.org/run-async/download/run-async-2.4.1.tgz?cache=0&sync_timestamp=1587966119578&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frun-async%2Fdownload%2Frun-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
   integrity sha1-hEDsz5nqPnC9QJ1JqriOEMGJpFU=
@@ -7079,7 +7221,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
   dependencies:
     aproba "^1.1.1"
 
-rxjs@^6.6.0:
+rxjs@^6.4.0, rxjs@^6.6.0:
   version "6.6.6"
   resolved "https://registry.npm.taobao.org/rxjs/download/rxjs-6.6.6.tgz?cache=0&sync_timestamp=1614458618256&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frxjs%2Fdownload%2Frxjs-6.6.6.tgz#14d8417aa5a07c5e633995b525e1e3c0dec03b70"
   integrity sha1-FNhBeqWgfF5jOZW1JeHjwN7AO3A=
@@ -7108,7 +7250,7 @@ safe-regex@^1.1.0:
   resolved "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
   integrity sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=
 
-sax@~1.2.4:
+sax@>=0.6.0, sax@~1.2.4:
   version "1.2.4"
   resolved "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
   integrity sha1-KBYjTiN4vdxOU1T6tcqold9xANk=
@@ -7131,6 +7273,15 @@ schema-utils@^2.0.0, schema-utils@^2.5.0, schema-utils@^2.6.5, schema-utils@^2.6
     ajv "^6.12.4"
     ajv-keywords "^3.5.2"
 
+schema-utils@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef"
+  integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==
+  dependencies:
+    "@types/json-schema" "^7.0.6"
+    ajv "^6.12.5"
+    ajv-keywords "^3.5.2"
+
 select-hose@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npm.taobao.org/select-hose/download/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -7143,7 +7294,7 @@ selfsigned@^1.10.8:
   dependencies:
     node-forge "^0.10.0"
 
-"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0:
+"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0:
   version "5.7.1"
   resolved "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz?cache=0&sync_timestamp=1606851912015&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
   integrity sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=
@@ -7558,7 +7709,7 @@ strict-uri-encode@^1.0.0:
   resolved "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
   integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
 
-string-width@^2.0.0:
+string-width@^2.0.0, string-width@^2.1.0:
   version "2.1.1"
   resolved "https://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz?cache=0&sync_timestamp=1614522217971&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring-width%2Fdownload%2Fstring-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
   integrity sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=
@@ -7662,6 +7813,15 @@ strip-json-comments@^3.0.1:
   resolved "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
   integrity sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=
 
+style-resources-loader@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/style-resources-loader/-/style-resources-loader-1.4.1.tgz#87f520e6c8120a71e756726c1c53a78c544ca7db"
+  integrity sha512-UaAoQXq20relw6B633z4QZDxDyW7gevTt1e0y3MZtzdZfnvB90UL658czAgNc609Y7Kn5ErdthK9bSVhnykBUA==
+  dependencies:
+    glob "^7.1.6"
+    loader-utils "^2.0.0"
+    schema-utils "^3.0.0"
+
 stylehacks@^4.0.0:
   version "4.0.3"
   resolved "https://registry.npm.taobao.org/stylehacks/download/stylehacks-4.0.3.tgz?cache=0&sync_timestamp=1614937854652&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstylehacks%2Fdownload%2Fstylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5"
@@ -7895,6 +8055,11 @@ tough-cookie@~2.5.0:
     psl "^1.1.28"
     punycode "^2.1.1"
 
+transitionEnd@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/transitionEnd/-/transitionEnd-1.0.2.tgz#1914db5b45a7efdc34a01af69285a3a693871633"
+  integrity sha1-GRTbW0Wn79w0oBr2koWjppOHFjM=
+
 tryer@^1.0.1:
   version "1.0.1"
   resolved "https://registry.npm.taobao.org/tryer/download/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
@@ -8177,11 +8342,37 @@ validate-npm-package-license@^3.0.1:
     spdx-correct "^3.0.0"
     spdx-expression-parse "^3.0.0"
 
+vant@^2.12.9:
+  version "2.12.9"
+  resolved "https://registry.yarnpkg.com/vant/-/vant-2.12.9.tgz#92c85fad6277ec21277916715b0a0919ef1a64e3"
+  integrity sha512-frvm0FwrE8lz7Qv2Xnp4QRXxbOAb13ouyKK36K43yN+YrnMTJ3fowQV4eg0eKe1A/5p5ziYisi8paOJpXcwfgw==
+  dependencies:
+    "@babel/runtime" "7.x"
+    "@vant/icons" "1.5.2"
+    "@vant/popperjs" "^1.0.0"
+    "@vue/babel-helper-vue-jsx-merge-props" "^1.0.0"
+    vue-lazyload "1.2.3"
+
 vary@~1.1.2:
   version "1.1.2"
   resolved "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
   integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
 
+vconsole-webpack-plugin@^1.5.2:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/vconsole-webpack-plugin/-/vconsole-webpack-plugin-1.5.2.tgz#4c25b6cc51add03bb4e1562c4d3653431c89af60"
+  integrity sha512-v3goAnjsurFUy+qUmJCGjW+tzeKzlkrlbY8YnctSbhbrKiyC40hDeVFdGJvv7Drvd+w4xCQ1hJFZa5ESadmljQ==
+  dependencies:
+    vconsole "^3.3.4"
+
+vconsole@^3.3.4:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/vconsole/-/vconsole-3.4.0.tgz#2cf2ffaa86cd7ab736997a22b63d05627c6ab567"
+  integrity sha512-N9py7Ch9M9nzsigYf8T/WHIOood7jq2MNtUWDqicnrCsPsOZj8Z3NsmFgBmDA3bPKwnzace11HXHxYKPfwV32A==
+  dependencies:
+    mutation-observer "^1.0.3"
+    transitionEnd "^1.0.2"
+
 vendors@^1.0.0:
   version "1.0.4"
   resolved "https://registry.npm.taobao.org/vendors/download/vendors-1.0.4.tgz?cache=0&sync_timestamp=1615203397897&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvendors%2Fdownload%2Fvendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e"
@@ -8201,6 +8392,11 @@ vm-browserify@^1.0.1:
   resolved "https://registry.npm.taobao.org/vm-browserify/download/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
   integrity sha1-eGQcSIuObKkadfUR56OzKobl3aA=
 
+vue-cli-plugin-style-resources-loader@^0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/vue-cli-plugin-style-resources-loader/-/vue-cli-plugin-style-resources-loader-0.1.5.tgz#3e95f4df41f5408e1255664690698c0533648109"
+  integrity sha512-LluhjWTZmpGl3tiXg51EciF+T70IN/9t6UvfmgluJBqxbrb6OV9i7L5lTd+OKtcTeghDkhcBmYhtTxxU4w/8sQ==
+
 vue-eslint-parser@^7.0.0:
   version "7.6.0"
   resolved "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.6.0.tgz?cache=0&sync_timestamp=1614679624052&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-eslint-parser%2Fdownload%2Fvue-eslint-parser-7.6.0.tgz#01ea1a2932f581ff244336565d712801f8f72561"
@@ -8218,6 +8414,11 @@ vue-hot-reload-api@^2.3.0:
   resolved "https://registry.npm.taobao.org/vue-hot-reload-api/download/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
   integrity sha1-UylVzB6yCKPZkLOp+acFdGV+CPI=
 
+vue-lazyload@1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/vue-lazyload/-/vue-lazyload-1.2.3.tgz#901f9ec15c7e6ca78781a2bae4a343686bdedb2c"
+  integrity sha512-DC0ZwxanbRhx79tlA3zY5OYJkH8FYp3WBAnAJbrcuoS8eye1P73rcgAZhyxFSPUluJUTelMB+i/+VkNU/qVm7g==
+
 "vue-loader-v16@npm:vue-loader@^16.1.0":
   version "16.1.2"
   resolved "https://registry.npm.taobao.org/vue-loader/download/vue-loader-16.1.2.tgz#5c03b6c50d2a5f983c7ceba15c50d78ca2b298f4"
@@ -8465,7 +8666,7 @@ which-module@^2.0.0:
   resolved "https://registry.npm.taobao.org/which-module/download/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
   integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
 
-which@^1.2.9:
+which@^1.2.9, which@^1.3.0:
   version "1.3.1"
   resolved "https://registry.npm.taobao.org/which/download/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
   integrity sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=
@@ -8537,6 +8738,29 @@ ws@^6.0.0, ws@^6.2.1:
   dependencies:
     async-limiter "~1.0.0"
 
+xml2js@^0.4.19:
+  version "0.4.23"
+  resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
+  integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
+  dependencies:
+    sax ">=0.6.0"
+    xmlbuilder "~11.0.0"
+
+xmlbuilder@^9.0.7:
+  version "9.0.7"
+  resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
+  integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
+
+xmlbuilder@~11.0.0:
+  version "11.0.1"
+  resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
+  integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
+
+xmldom@0.1.x:
+  version "0.1.31"
+  resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
+  integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
+
 xtend@^4.0.0, xtend@~4.0.1:
   version "4.0.2"
   resolved "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"