黄何裕
2024-07-26 e3c2f393e6080b5e34c5eb22fb6ed6271e1317bd
登录页面接口封装
11个文件已修改
4个文件已添加
5个文件已删除
1139 ■■■■■ 已修改文件
.env.development 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
mock/index.js 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mock/mock-server.js 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mock/table.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mock/user.js 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
mock/utils.js 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/student.js 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/user.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/permission.js 84 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/graphql.js 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/development/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/home/index.vue 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/integral/index.vue 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.vue 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/rollCall/index.vue 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/student/index.vue 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 147 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -2,4 +2,4 @@
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'
VUE_APP_BASE_API = 'http://192.168.3.88:18080/dream_test'
mock/index.js
File was deleted
mock/mock-server.js
File was deleted
mock/table.js
File was deleted
mock/user.js
File was deleted
mock/utils.js
File was deleted
package.json
@@ -14,15 +14,26 @@
    "test:ci": "npm run lint && npm run test:unit"
  },
  "dependencies": {
    "apollo-boost": "^0.4.9",
    "apollo-cache-inmemory": "^1.6.6",
    "apollo-client": "^2.6.10",
    "apollo-link": "^1.2.14",
    "apollo-link-context": "^1.0.20",
    "apollo-link-http": "^1.5.17",
    "axios": "0.18.1",
    "core-js": "3.6.5",
    "cors": "^2.8.5",
    "element-ui": "2.13.2",
    "graphql": "^16.9.0",
    "graphql-tag": "^2.12.6",
    "js-cookie": "2.2.0",
    "normalize.css": "7.0.0",
    "nprogress": "0.2.0",
    "path-to-regexp": "2.4.0",
    "vue": "2.6.10",
    "vue-apollo": "^3.1.2",
    "vue-router": "3.0.6",
    "vue-wechat-login": "0.0.1",
    "vuex": "3.1.0"
  },
  "devDependencies": {
@@ -48,7 +59,8 @@
    "serve-static": "1.13.2",
    "svg-sprite-loader": "4.1.3",
    "svgo": "1.2.2",
    "vue-template-compiler": "2.6.10"
    "vue-template-compiler": "2.6.10",
    "vue-wxlogin": "^1.0.5"
  },
  "browserslist": [
    "> 1%",
src/api/student.js
New file
@@ -0,0 +1,48 @@
import apolloClient from "@/utils/graphql";
import gql from "graphql-tag";
export function getData(params) {
  return apolloClient.query({
    query: gql`
      query vars($staffId: Int!, $keyword: String, $pageIn: PageIn!) {
        findPlayerByStaff(
          staffId: $staffId
          keyword: $keyword
          pageIn: $pageIn
        ) {
          ls {
            id
            name
            gender
            mobile
            user {
              id
              name
              wxOaOpenId
            }
            accs {
              id
              voucher {
                id
                voucherType
                name
              }
              qty
              freezeQty
              amt
              beginDate
              endDate
              modifyTime
            }
          }
          pageOut {
            total
            index
            size
          }
        }
      }
    `,
    variables: params,
  });
}
src/api/user.js
@@ -2,12 +2,11 @@
export function login(data) {
  return request({
    url: '/vue-admin-template/user/login',
    url: '/wx/web/login',
    method: 'post',
    data
  })
}
export function getInfo(token) {
  return request({
    url: '/vue-admin-template/user/info',
src/main.js
@@ -1,20 +1,26 @@
import Vue from 'vue'
import Vue from "vue";
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import "normalize.css/normalize.css"; // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
// import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import locale from 'element-ui/lib/locale/lang/zh-CN';
import '@/styles/index.scss' // global css
import locale from "element-ui/lib/locale/lang/zh-CN";
import "@/styles/index.scss"; // global css
import App from './App'
import store from './store'
import router from './router'
import App from "./App";
import store from "./store";
import router from "./router";
import '@/icons' // icon
import '@/permission' // permission control
import "@/icons"; // icon
import "@/permission"; // permission control
// const cors = require('cors');
// // 处理跨域请求
// App.use(cors());
// // 处理请求
// App.use(express.json());//express.json=bodyParser.json
// App.use(express.urlencoded({ extended: true }));
/**
 * If you don't want to use mock-server
 * you want to use MockJs for mock api
@@ -23,21 +29,17 @@
 * Currently MockJs will be used in the production environment,
 * please remove it before going online ! ! !
 */
if (process.env.NODE_ENV === 'production') {
  const { mockXHR } = require('../mock')
  mockXHR()
}
// if (process.env.NODE_ENV === 'production') {
//   const { mockXHR } = require('../mock')
//   mockXHR()
// }
Vue.use(ElementUI, { locale });
// set ElementUI lang to EN
Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui,按如下方式声明
// Vue.use(ElementUI,{ locale: zhCn })
Vue.config.productionTip = false
Vue.config.productionTip = false;
new Vue({
  el: '#app',
  el: "#app",
  router,
  store,
  render: h => h(App)
})
  render: (h) => h(App),
});
src/permission.js
@@ -10,53 +10,53 @@
const whiteList = ['/login'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()
// router.beforeEach(async(to, from, next) => {
//   // start progress bar
//   NProgress.start()
  // set page title
  document.title = getPageTitle(to.meta.title)
//   // set page title
//   document.title = getPageTitle(to.meta.title)
  // determine whether the user has logged in
  const hasToken = getToken()
//   // determine whether the user has logged in
//   const hasToken = getToken()
  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // get user info
          await store.dispatch('user/getInfo')
//   if (hasToken) {
//     if (to.path === '/login') {
//       // if is logged in, redirect to the home page
//       next({ path: '/' })
//       NProgress.done()
//     } else {
//       const hasGetUserInfo = store.getters.name
//       if (hasGetUserInfo) {
//         next()
//       } else {
//         try {
//           // get user info
//           await store.dispatch('user/getInfo')
          next()
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* has no token*/
//           next()
//         } catch (error) {
//           // remove token and go to login page to re-login
//           await store.dispatch('user/resetToken')
//           Message.error(error || 'Has Error')
//           next(`/login?redirect=${to.path}`)
//           NProgress.done()
//         }
//       }
//     }
//   } else {
//     /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})
//     if (whiteList.indexOf(to.path) !== -1) {
//       // in the free login whitelist, go directly
//       next()
//     } else {
//       // other pages that do not have permission to access are redirected to the login page.
//       next(`/login?redirect=${to.path}`)
//       NProgress.done()
//     }
//   }
// })
router.afterEach(() => {
  // finish progress bar
src/router/index.js
@@ -109,6 +109,18 @@
        name: 'Development',
        component: () => import('@/views/development/index'),
        meta: { title: '成长', icon: 'tree' }
      },
      {
        path: 'integral',
        name: 'Integral',
        component: () => import('@/views/integral/index'),
        meta: { title: '积分', icon: 'tree' }
      },
      {
        path: 'rollCall',
        name: 'RollCall',
        component: () => import('@/views/rollCall/index'),
        meta: { title: '点评', icon: 'tree' }
      }
    ]
  },
src/utils/graphql.js
New file
@@ -0,0 +1,63 @@
// import ApolloClient from 'apollo-boost';
// const apolloClient = new ApolloClient({
//   uri: 'http://127.0.0.1:7001/graphql'
// })
// export default apolloClient;
// 定义不同请求地址
const EFORMURI = "http://192.168.3.88:18080/dream_test/graphql";
const IOTURI = "https://www.9village.cn/dream_test" + "/graphql";
// import ApolloClient from 'apollo-boost' //引入apollo-boost插件
import { ApolloClient } from "apollo-client";
import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloLink } from "apollo-link";
const httpLink = createHttpLink({
  uri: EFORMURI, //配置api调用连接
});
const middlewareLink = new ApolloLink((operation, forward) => {
  operation.setContext({
    headers: {
      Authorization: 'eyJhbGciOiJIUzI1NiJ9.eyJleHBUaW1lIjoiMjAyNC8wNy8yNSAxMTozOSIsInVzZXJJZCI6MSwianRpIjoiZGVkZWRlMWQtYTU4MC00NDkxLWI0YzAtMjA5ODRjYTk3NmE3IiwiaWF0IjoxNzIxODcxNTYyLCJzdWIiOiJ5Y2wiLCJleHAiOjE3MjE4Nzg3NjJ9.gvEk8RHvJD7QQjr83XVwPe9msqEeVITXg3hIJRaNubI',
      staffId: "1680",
      playerId: '3350',
    },
  }); //request拦截器
  return forward(operation).map((response) => {
    return response;
  }); //response拦截器,但是此处并不能对错误响应进行拦截
});
const authLink = middlewareLink.concat(httpLink);
const defaultOptions = {
  watchQuery: {
    fetchPolicy: "network-only",
    errorPolicy: "ignore",
  },
  query: {
    fetchPolicy: "network-only",
    errorPolicy: "all",
  },
};
const apolloClient = new ApolloClient({
  link: authLink,
  cache: new InMemoryCache(),
  connectToDevTools: true,
  defaultOptions: defaultOptions,
});
// const apolloClient = new ApolloClient({
//   uri: 'https://countries.trevorblades.com/',
//   headers:{
//     Authorization: 'eyJhbGciOiJIUzI1NiJ9.eyJleHBUaW1lIjoiMjAyNC8wNy8yNSAxMTozOSIsInVzZXJJZCI6MSwianRpIjoiZGVkZWRlMWQtYTU4MC00NDkxLWI0YzAtMjA5ODRjYTk3NmE3IiwiaWF0IjoxNzIxODcxNTYyLCJzdWIiOiJ5Y2wiLCJleHAiOjE3MjE4Nzg3NjJ9.gvEk8RHvJD7QQjr83XVwPe9msqEeVITXg3hIJRaNubI',
//     staffId: "1680",
//     playerId: '3350',
//   }
// })
//导出实例
export default apolloClient;
src/views/development/index.vue
@@ -65,20 +65,20 @@
            element-loading-text="Loading"
            fit
          >
            <el-table-column label="学员">
            <el-table-column label="课程">
              <template slot-scope=""> xxxxx </template>
            </el-table-column>
            <el-table-column label="时间" width="80">
              <template slot-scope=""> 男 </template>
            </el-table-column>
            <el-table-column label="标题" width="200">
            <el-table-column label="学员数" width="200">
              <template slot-scope=""> 10086 </template>
            </el-table-column>
            <el-table-column label="点评老师" width="200">
            <el-table-column label="已记录数" width="200">
              <template slot-scope=""> asfiaf </template>
            </el-table-column>
            <el-table-column label="操作" width="">
              <template slot-scope=""> 查看 </template>
              <template slot-scope=""> 记录 </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
src/views/home/index.vue
@@ -5,16 +5,28 @@
</template>
<script>
import { mapGetters } from 'vuex'
import { mapGetters } from "vuex";
import { login } from "@/api/user";
export default {
  name: 'Dashboard',
  name: "Dashboard",
  computed: {
    ...mapGetters([
      'name'
    ])
  }
}
    ...mapGetters(["name"]),
  },
  created() {
    this.getUserDate();
  },
  methods: {
    getUserDate() {
      console.log(123);
      login({
        code: "031xHA00064oxS1Es0200cRzRF2xHA0t",
      }).then((res) => {
       console.log(res);
      });
    },
  },
};
</script>
<style lang="scss" scoped>
src/views/integral/index.vue
New file
@@ -0,0 +1,106 @@
<template>
    <div class="app-container">
      <el-tabs v-model="activeName" @tab-click="handleClick">
        <el-tab-pane label="按学员" name="first">
          <div style="display: flex; flex-direction: row-reverse">
            <div style="width: 300px">
              <el-input
                placeholder="按标题搜索"
                v-model="input3"
                class="input-with-select"
                size="small"
              >
                <el-button slot="append" icon="el-icon-search"></el-button>
              </el-input>
            </div>
          </div>
          <el-table
            v-loading="listLoading"
            :data="list"
            element-loading-text="Loading"
            fit
          >
            <el-table-column label="姓名">
              <template slot-scope=""> xxxxx </template>
            </el-table-column>
            <el-table-column label="积分" width="80">
              <template slot-scope=""> 男 </template>
            </el-table-column>
            <el-table-column label="更新时间" width="200">
              <template slot-scope=""> 10086 </template>
            </el-table-column>
            <el-table-column label="操作" width="">
              <template slot-scope=""> 兑换 发放 </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
        <el-tab-pane label="按班级" name="fourth">
          <div style="display: flex; flex-direction: row-reverse">
            <div style="width: 300px">
              <el-input
                placeholder="按学员名称搜索"
                v-model="input3"
                class="input-with-select"
                size="small"
              >
                <el-button slot="append" icon="el-icon-search"></el-button>
              </el-input>
            </div>
          </div>
          <el-table
            v-loading="listLoading"
            :data="list"
            element-loading-text="Loading"
            fit
          >
            <el-table-column label="班级">
              <template slot-scope=""> xxxxx </template>
            </el-table-column>
            <el-table-column label="学员人数" width="80">
              <template slot-scope=""> 男 </template>
            </el-table-column>
            <el-table-column label="操作" width="">
              <template slot-scope=""> 发放 </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>
    </div>
  </template>
  <script>
  import { getList } from "@/api/table";
  export default {
    filters: {
      statusFilter(status) {
        const statusMap = {
          published: "success",
          draft: "gray",
          deleted: "danger",
        };
        return statusMap[status];
      },
    },
    data() {
      return {
        list: null,
        listLoading: true,
        activeName: "first",
      };
    },
    created() {
      this.fetchData();
    },
    methods: {
      fetchData() {
        this.listLoading = true;
        getList().then((response) => {
          this.list = response.data.items;
          this.listLoading = false;
        });
      },
    },
  };
  </script>
src/views/login/index.vue
@@ -1,7 +1,13 @@
<template>
  <div class="login-container">
    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
    <!-- <el-form
      ref="loginForm"
      :model="loginForm"
      :rules="loginRules"
      class="login-form"
      auto-complete="on"
      label-position="left"
    >
      <div class="title-container">
        <h3 class="title">Login Form</h3>
      </div>
@@ -37,100 +43,144 @@
          @keyup.enter.native="handleLogin"
        />
        <span class="show-pwd" @click="showPwd">
          <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
          <svg-icon
            :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
          />
        </span>
      </el-form-item>
      <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>
      <el-button
        :loading="loading"
        type="primary"
        style="width: 100%; margin-bottom: 30px"
        @click.native.prevent="handleLogin"
        >Login</el-button
      >
      <div class="tips">
        <span style="margin-right:20px;">username: admin</span>
        <span style="margin-right: 20px">username: admin</span>
        <span> password: any</span>
      </div>
    </el-form>
    </el-form> -->
    <div class="wxLogin">
      <el-card class="main_wx">
        <wxlogin
          :appid="appid"
          :redirect_uri="redirect_uri"
          scope="snsapi_login"
          :href="href"
          :state="state"
        ></wxlogin>
        <el-button @click="handleLogin">开发环境专用偷渡按钮</el-button>
      </el-card>
    </div>
  </div>
</template>
<script>
import { validUsername } from '@/utils/validate'
import { validUsername } from "@/utils/validate";
import wxlogin from "vue-wxlogin";
export default {
  name: 'Login',
  name: "Login",
  components: { wxlogin },
  data() {
    const validateUsername = (rule, value, callback) => {
      if (!validUsername(value)) {
        callback(new Error('Please enter the correct user name'))
        callback(new Error("Please enter the correct user name"));
      } else {
        callback()
        callback();
      }
    }
    };
    const validatePassword = (rule, value, callback) => {
      if (value.length < 6) {
        callback(new Error('The password can not be less than 6 digits'))
        callback(new Error("The password can not be less than 6 digits"));
      } else {
        callback()
        callback();
      }
    }
    };
    return {
      appid: "wx7103925df6236723",
      redirect_uri: encodeURIComponent("https://www.9village.cn"),
      state: "1",
      href: "data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7CiAgICAgICAgICBib3JkZXI6IG5vbmU7CiAgICAgICAgICB3aWR0aDogMTQwcHg7CiAgICAgICAgICBoZWlnaHQ6IDE0MHB4OwogICAgICAgIH0=", // 自定义样式链接
      loginForm: {
        username: 'admin',
        password: '111111'
        username: "admin",
        password: "111111",
      },
      loginRules: {
        username: [{ required: true, trigger: 'blur', validator: validateUsername }],
        password: [{ required: true, trigger: 'blur', validator: validatePassword }]
        username: [
          { required: true, trigger: "blur", validator: validateUsername },
        ],
        password: [
          { required: true, trigger: "blur", validator: validatePassword },
        ],
      },
      loading: false,
      passwordType: 'password',
      redirect: undefined
    }
      passwordType: "password",
      redirect: undefined,
    };
  },
  watch: {
    $route: {
      handler: function(route) {
        this.redirect = route.query && route.query.redirect
      handler: function (route) {
        this.redirect = route.query && route.query.redirect;
      },
      immediate: true
    }
      immediate: true,
    },
  },
  mounted() {
    this.getWeChatUrl();
  },
  methods: {
    getWeChatUrl() {
      // api.wachatQrUrl().then(res => {
      //   if (res && res.code === '0000') {
      //     const data = res.data
      //     this.appid = data.appId
      //     this.redirect_uri = data.wxCallbackUrl + 'weChatLogin'
      //   }
      // })
    },
    showPwd() {
      if (this.passwordType === 'password') {
        this.passwordType = ''
      if (this.passwordType === "password") {
        this.passwordType = "";
      } else {
        this.passwordType = 'password'
        this.passwordType = "password";
      }
      this.$nextTick(() => {
        this.$refs.password.focus()
      })
        this.$refs.password.focus();
      });
    },
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true
          this.$store.dispatch('user/login', this.loginForm).then(() => {
            this.$router.push({ path: this.redirect || '/' })
            this.loading = false
          }).catch(() => {
            this.loading = false
          })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    }
  }
}
      this.$router.push({ path: "/educational/student" });
      // this.$refs.loginForm.validate((valid) => {
      //   if (valid) {
      //     this.loading = true;
      //     this.$store
      //       .dispatch("user/login", this.loginForm)
      //       .then(() => {
      //         this.$router.push({ path: this.redirect || "/" });
      //         this.loading = false;
      //       })
      //       .catch(() => {
      //         this.loading = false;
      //       });
      //   } else {
      //     console.log("error submit!!");
      //     return false;
      //   }
      // });
    },
  },
};
</script>
<style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg:#283443;
$light_gray:#fff;
$bg: #283443;
$light_gray: #fff;
$cursor: #fff;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
@@ -141,6 +191,9 @@
/* reset element-ui css */
.login-container {
  display: flex;
  align-items: center;
  justify-content: center;
  .el-input {
    display: inline-block;
    height: 47px;
@@ -170,12 +223,18 @@
    color: #454545;
  }
}
#weixin{
    /* background-color: #fcf; */
    display: flex;
    justify-content: center;
    margin-top: -20px;
}
</style>
<style lang="scss" scoped>
$bg:#2d3a4b;
$dark_gray:#889aa4;
$light_gray:#eee;
$bg: #ffffff;
$dark_gray: #889aa4;
$light_gray: #eee;
.login-container {
  min-height: 100%;
src/views/rollCall/index.vue
New file
@@ -0,0 +1,115 @@
<template>
    <div class="app-container">
      <el-tabs v-model="activeName" @tab-click="handleClick">
        <el-tab-pane label="按学员" name="first">
          <div style="display: flex; flex-direction: row-reverse">
            <div style="width: 300px">
              <el-input
                placeholder="按标题搜索"
                v-model="input3"
                class="input-with-select"
                size="small"
              >
                <el-button slot="append" icon="el-icon-search"></el-button>
              </el-input>
            </div>
          </div>
          <el-table
            v-loading="listLoading"
            :data="list"
            element-loading-text="Loading"
            fit
          >
            <el-table-column label="姓名">
              <template slot-scope=""> xxxxx </template>
            </el-table-column>
            <el-table-column label="课包/会员卡" width="80">
              <template slot-scope=""> 男 </template>
            </el-table-column>
            <el-table-column label="上课日期" width="200">
              <template slot-scope=""> 10086 </template>
            </el-table-column>
            <el-table-column label="课程时长" width="200">
              <template slot-scope=""> 10086 </template>
            </el-table-column>
            <el-table-column label="开始时间" width="200">
              <template slot-scope=""> 10086 </template>
            </el-table-column>
            <el-table-column label="课消数量" width="200">
              <template slot-scope=""> 10086 </template>
            </el-table-column>
            <el-table-column label="操作" width="">
              <template slot-scope=""> 兑换 发放 </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
        <el-tab-pane label="按班级" name="fourth">
          <div style="display: flex; flex-direction: row-reverse">
            <div style="width: 300px">
              <el-input
                placeholder="按学员名称搜索"
                v-model="input3"
                class="input-with-select"
                size="small"
              >
                <el-button slot="append" icon="el-icon-search"></el-button>
              </el-input>
            </div>
          </div>
          <el-table
            v-loading="listLoading"
            :data="list"
            element-loading-text="Loading"
            fit
          >
            <el-table-column label="班级">
              <template slot-scope=""> xxxxx </template>
            </el-table-column>
            <el-table-column label="学员人数" width="80">
              <template slot-scope=""> 男 </template>
            </el-table-column>
            <el-table-column label="操作" width="">
              <template slot-scope=""> 发放 </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>
    </div>
  </template>
  <script>
  import { getList } from "@/api/table";
  export default {
    filters: {
      statusFilter(status) {
        const statusMap = {
          published: "success",
          draft: "gray",
          deleted: "danger",
        };
        return statusMap[status];
      },
    },
    data() {
      return {
        list: null,
        listLoading: true,
        activeName: "first",
      };
    },
    created() {
      this.fetchData();
    },
    methods: {
      fetchData() {
        this.listLoading = true;
        getList().then((response) => {
          this.list = response.data.items;
          this.listLoading = false;
        });
      },
    },
  };
  </script>
src/views/student/index.vue
@@ -6,8 +6,8 @@
      <el-tab-pane label="已过期" name="third" />
      <el-tab-pane label="已停用" name="fourth" />
    </el-tabs>
    <div style="display: flex; flex-direction: row-reverse;">
      <div style="width: 300px;">
    <div style="display: flex; flex-direction: row-reverse">
      <div style="width: 300px">
        <el-input
          placeholder="按姓名搜索"
          v-model="input3"
@@ -39,6 +39,7 @@
      <el-table-column label="账户" width="">
        <template slot-scope=""> asfiaf </template>
      </el-table-column>
      {{ accountList }}
      <!-- <el-table-column label="Author" width="110" align="center">
        <template slot-scope="scope">
          <span>{{ scope.row.author }}</span>
@@ -65,7 +66,7 @@
</template>
<script>
import { getList } from "@/api/table";
import { getData } from "@/api/student";
export default {
  filters: {
@@ -83,6 +84,15 @@
      list: null,
      listLoading: true,
      activeName: "first",
      data: {
        staffId: "1680",
        keyword: "",
        pageIn: {
          //可选,如果是分页查询,需要加上。
          index: 1, //必选
          size: 20, //每页的大小。默认20
        },
      },
    };
  },
  created() {
@@ -91,7 +101,7 @@
  methods: {
    fetchData() {
      this.listLoading = true;
      getList().then((response) => {
      getData(this.data).then((response) => {
        this.list = response.data.items;
        this.listLoading = false;
      });
vue.config.js
@@ -1,19 +1,19 @@
'use strict'
const path = require('path')
const defaultSettings = require('./src/settings.js')
"use strict";
const path = require("path");
const defaultSettings = require("./src/settings.js");
function resolve(dir) {
  return path.join(__dirname, dir)
  return path.join(__dirname, dir);
}
const name = defaultSettings.title || 'vue Admin Template' // page title
const name = defaultSettings.title || "vue Admin Template"; // page title
// If your port is set to 80,
// use administrator privileges to execute the command line.
// For example, Mac: sudo npm run
// You can change the port by the following methods:
// port = 9528 npm run dev OR npm run dev --port = 9528
const port = process.env.port || process.env.npm_config_port || 9528 // dev port
const port = process.env.port || process.env.npm_config_port || 9528; // dev port
// All configuration item explanations can be find in https://cli.vuejs.org/config/
module.exports = {
@@ -24,19 +24,29 @@
   * In most cases please use '/' !!!
   * Detail: https://cli.vuejs.org/config/#publicpath
   */
  publicPath: '/',
  outputDir: 'dist',
  assetsDir: 'static',
  lintOnSave: process.env.NODE_ENV === 'development',
  publicPath: "/",
  outputDir: "dist",
  assetsDir: "static",
  lintOnSave: process.env.NODE_ENV === "development",
  productionSourceMap: false,
  devServer: {
    port: port,
    open: true,
    overlay: {
      warnings: false,
      errors: true
      errors: true,
    },
    before: require('./mock/mock-server.js')
    proxy: {
      [process.env.VUE_APP_BASE_API]: {
        // 匹配所有以 '/dev-api'开头的请求路径
        target: "http://192.168.3.88:18080/dream_test", //类似于Nginx反向代理
        changeOrigin: true, // 支持跨域
        pathRewrite: {
          // 重写路径: 去掉路径中开头的'/dev-api'
          ["^" + process.env.VUE_APP_BASE_API]: "",
        },
      },
    },
  },
  configureWebpack: {
    // provide the app's title in webpack's name field, so that
@@ -44,80 +54,75 @@
    name: name,
    resolve: {
      alias: {
        '@': resolve('src')
      }
    }
        "@": resolve("src"),
      },
    },
  },
  chainWebpack(config) {
    // it can improve the speed of the first screen, it is recommended to turn on preload
    config.plugin('preload').tap(() => [
    config.plugin("preload").tap(() => [
      {
        rel: 'preload',
        rel: "preload",
        // to ignore runtime.js
        // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
        include: 'initial'
      }
    ])
        include: "initial",
      },
    ]);
    // when there are many pages, it will cause too many meaningless requests
    config.plugins.delete('prefetch')
    config.plugins.delete("prefetch");
    // set svg-sprite-loader
    config.module.rule("svg").exclude.add(resolve("src/icons")).end();
    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons'))
      .end()
    config.module
      .rule('icons')
      .rule("icons")
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .include.add(resolve("src/icons"))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .use("svg-sprite-loader")
      .loader("svg-sprite-loader")
      .options({
        symbolId: 'icon-[name]'
        symbolId: "icon-[name]",
      })
      .end()
      .end();
    config
      .when(process.env.NODE_ENV !== 'development',
        config => {
          config
            .plugin('ScriptExtHtmlWebpackPlugin')
            .after('html')
            .use('script-ext-html-webpack-plugin', [{
    config.when(process.env.NODE_ENV !== "development", (config) => {
      config
        .plugin("ScriptExtHtmlWebpackPlugin")
        .after("html")
        .use("script-ext-html-webpack-plugin", [
          {
            // `runtime` must same as runtimeChunk name. default is `runtime`
              inline: /runtime\..*\.js$/
            }])
            .end()
          config
            .optimization.splitChunks({
              chunks: 'all',
              cacheGroups: {
                libs: {
                  name: 'chunk-libs',
                  test: /[\\/]node_modules[\\/]/,
                  priority: 10,
                  chunks: 'initial' // only package third parties that are initially dependent
                },
                elementUI: {
                  name: 'chunk-elementUI', // split elementUI into a single package
                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
                },
                commons: {
                  name: 'chunk-commons',
                  test: resolve('src/components'), // can customize your rules
                  minChunks: 3, //  minimum common number
                  priority: 5,
                  reuseExistingChunk: true
                }
              }
            })
          // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
          config.optimization.runtimeChunk('single')
        }
      )
  }
}
            inline: /runtime\..*\.js$/,
          },
        ])
        .end();
      config.optimization.splitChunks({
        chunks: "all",
        cacheGroups: {
          libs: {
            name: "chunk-libs",
            test: /[\\/]node_modules[\\/]/,
            priority: 10,
            chunks: "initial", // only package third parties that are initially dependent
          },
          elementUI: {
            name: "chunk-elementUI", // split elementUI into a single package
            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
            test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
          },
          commons: {
            name: "chunk-commons",
            test: resolve("src/components"), // can customize your rules
            minChunks: 3, //  minimum common number
            priority: 5,
            reuseExistingChunk: true,
          },
        },
      });
      // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
      config.optimization.runtimeChunk("single");
    });
  },
};