zhanghua
2024-09-18 fd989d2af98e1ba50d82bbe9db6ce0a24a074bbf
学员导入功能
6个文件已修改
3个文件已添加
368 ■■■■ 已修改文件
public/static/学员导入模板.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/login_backgroup.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/drag-upload.vue 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Navbar.vue 57 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/cache.js 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/student/components/upload-student.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/student/index.vue 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/static/ѧԱµ¼ÈëÄ£°å.xlsx
Binary files differ
src/assets/login_backgroup.png

src/components/drag-upload.vue
New file
@@ -0,0 +1,90 @@
<template>
  <div class="center">
    <el-upload
      class="upload-demo"
      :action="action"
      :headers="headers"
      :data="{ staffId: staffId, orgId: orgId }"
      :on-exceed="handleExceed"
      :on-success="fileSuccess"
      :on-error="fileSuccess"
      :file-list="fileList"
      :show-file-list="true"
      multiple
      :limit="limit"
      accept=".xls,.xlsx"
      :before-upload="beforeAvatarUpload"
    >
      <slot></slot>
      <slot name="tip"></slot>
    </el-upload>
  </div>
</template>
<script>
export default {
  data() {
    return {
      msg: "拖动上传",
      fileList: [],
      headers: {
        token: localStorage.getItem("token"),
      },
    };
  },
  props: {
    limit: {
      type: Number,
    },
    action: {
      type: String,
    },
    type: {
      type: String,
    },
    orgId: {
      type: Number,
    },
    staffId: {
      type: Number,
    },
  },
  methods: {
    // è¶…出文件上传个数回调
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 1 ä¸ªæ–‡ä»¶`);
    },
    // ç§»é™¤æ–‡ä»¶å¼¹å‡ºå±‚
    beforeRemove(file, fileList) {
      return this.$confirm(`确定移除 ${file.name}?`);
    },
    // ä¸Šä¼ æˆåŠŸå›žè°ƒ
    fileSuccess(res, f, fl) {
      this.$emit("fileSuccess", res, this.type);
    },
    // è¿‡æ»¤æ–‡ä»¶
    beforeAvatarUpload(file) {
      let fileName = file.name.substring(file.name.lastIndexOf(".") + 1);
      const extension = fileName === "xls";
      const extension2 = fileName === "xlsx";
      if (!extension && !extension2) {
        this.$message({
          message: "上传文件只能是 xls、xlsx格式!",
          type: "warning",
        });
        return false;
      }
    },
  },
  mounted() {},
};
</script>
<style lang="scss" scoped>
.center {
  float: left;
}
</style>
src/layout/components/Navbar.vue
@@ -11,11 +11,7 @@
        <!-- <h3 style="position: fixed; top: 0; font-size: 16px; color: #5a5e66; " :style="'right:' + orgCss() ">{{ getOrgName() }}</h3> -->
        <div class="right-menu">
            <el-dropdown
                trigger="click"
                ref="eldrop"
                style="margin-right: 20px"
            >
      <el-dropdown trigger="click" ref="eldrop" style="margin-right: 20px">
                <div class="avatar-wrapper" style="font-size: 20px">
                    {{ selectStaff.org.name }}
                    <i class="el-icon-caret-bottom"></i>
@@ -32,7 +28,7 @@
            </el-dropdown>
            <el-dropdown class="avatar-container" trigger="click">
                <div class="avatar-wrapper">
                    {{ '您好,' + getUserName() }}
          {{ "您好," + getUserName() }}
                    <i class="el-icon-caret-bottom"></i>
                </div>
                <el-dropdown-menu slot="dropdown" class="user-dropdown">
@@ -46,53 +42,62 @@
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'
import { mapGetters } from "vuex";
import Breadcrumb from "@/components/Breadcrumb";
import Hamburger from "@/components/Hamburger";
export default {
    inject: ['reload'], // ä¾èµ–注入
  inject: ["reload"], // ä¾èµ–注入
    data() {
        return {
            selectStaff: JSON.parse(localStorage.getItem("selectStaff")),
            staffs: JSON.parse(localStorage.getItem("staffs"))
        }
      selectStaff: { org: {} },
      staffs: [],
    };
    },
    components: {
        Breadcrumb,
        Hamburger
    Hamburger,
    },
    computed: {
        ...mapGetters([
            'sidebar',
            'avatar'
        ])
    ...mapGetters(["sidebar", "avatar"]),
    },
    methods: {
        changeStaff(item) {
            this.selectStaff = item
            localStorage.setItem("selectStaff", JSON.stringify(item))
      this.selectStaff = item;
      localStorage.setItem("selectStaff", JSON.stringify(item));
            // this.$router.go(0)
            this.reload()
      this.reload();
        },
        orgCss() {
            return JSON.parse(localStorage.getItem("user")).name.length * 20 + 100 + 'px';
      return (
        JSON.parse(localStorage.getItem("user")).name.length * 20 + 100 + "px"
      );
        },
        getOrgName() {
            return JSON.parse(localStorage.getItem("user")).staffs[0].org.name;
      return JSON.parse(localStorage.getItem("selectStaff")).org.name;
        },
        getUserName() {
            return JSON.parse(localStorage.getItem("user")).name;
        },
        toggleSideBar() {
            this.$store.dispatch('app/toggleSideBar')
      this.$store.dispatch("app/toggleSideBar");
        },
        async logout() {
            // await this.$store.dispatch('user/logout')
            this.$router.push(`/login`)
      this.$router.push(`/login`);
    },
  },
  created() {
    const selectStaff = JSON.parse(localStorage.getItem("selectStaff"));
    if (selectStaff) {
      this.selectStaff = selectStaff;
        }
    const staffs = JSON.parse(localStorage.getItem("staffs"));
    if (staffs) {
      this.staffs = staffs;
    }
}
  },
};
</script>
<style lang="scss" scoped>
src/utils/cache.js
@@ -1,20 +1,20 @@
const sessionCache = {
  set (key, value) {
    if (!sessionStorage) {
    if (!localStorage) {
      return
    }
    if (key != null && value != null) {
      sessionStorage.setItem(key, value)
      localStorage.setItem(key, value)
    }
  },
  get (key) {
    if (!sessionStorage) {
    if (!localStorage) {
      return null
    }
    if (key == null) {
      return null
    }
    return sessionStorage.getItem(key)
    return localStorage.getItem(key)
  },
  setJSON (key, jsonValue) {
    if (jsonValue != null) {
@@ -28,7 +28,7 @@
    }
  },
  remove (key) {
    sessionStorage.removeItem(key);
    localStorage.removeItem(key);
  }
}
const localCache = {
src/views/login/index.vue
@@ -88,9 +88,9 @@
            login({
                code: code,
            }).then((res) => {
                sessionStorage.setItem("user", JSON.stringify(res));
                sessionStorage.setItem("staffs", JSON.stringify(res.staffs));
                sessionStorage.setItem("selectStaff", JSON.stringify(res.staffs[0]));
                localStorage.setItem("user", JSON.stringify(res));
                localStorage.setItem("staffs", JSON.stringify(res.staffs));
                localStorage.setItem("selectStaff", JSON.stringify(res.staffs[0]));
                this.$router.push("/student");
            });
        },
src/views/student/components/upload-student.vue
New file
@@ -0,0 +1,140 @@
<template>
  <el-form class="demo-ruleForm">
    <el-form-item label="" style="display: inline-block">
      <div class="uploading-center">
        <div class="uploading">
          <dragUpload
            :limit="1"
            :orgId="parseInt(orgId)"
            :staffId="parseInt(staffId)"
            @fileSuccess="fatherMethod"
            :type="'AUDIENCE'"
            :action="'/dream_test/player/importPlayer'"
          >
            <div class="uploading-btn-to">
              <i class="iconfont iconAdd"></i> ä¸Šä¼ 
            </div>
            <div class="el-upload__tip" slot="tip">只能上传.xls,.xlsx文件</div>
          </dragUpload>
        </div>
        <div class="download-file">
          <i class="iconfont iconFile"></i>
          <a href="/static/学员导入模板.xlsx" download>下载学员模板</a>
        </div>
      </div>
      <div style="font-size: 12px; color: #6993ff" v-if="hasAudience">
        å·²ä¸Šä¼ ,如需修改直接点击上传
        <i class="el-icon-close" title="删除" @click="clearaudience"></i>
      </div>
    </el-form-item>
  </el-form>
</template>
<script>
import dragUpload from "@/components/drag-upload";
export default {
  inject: ["reload"],
  name: "Creation",
  data() {
    return {
      orgId: 0,
      staffId: 0,
      hasAudience: false,
    };
  },
  components: { dragUpload },
  methods: {
    downloadlist() {
      window.open("../../../assets/学员导入模板.xlsx", "_blank");
      // this.download('downPlayerTemplate', '学员导入模板.xlsx')
    },
    clearaudience() {
      this.hasAudience = false;
    },
    fatherMethod(res, type) {
      if (res.falseLst === null) {
        this.$message.success("上传数据成功");
        this.$emit("load-success");
      } else if (res.falseLst.length >= 1) {
        let errortips = "";
        res.falseLst.map((item) => {
          errortips += `${item.cause} \r\n`;
        });
        this.$message({
          message: `导入数据成功导入${res.successNum}条,错误信息:${errortips}`,
          type: "error",
          duration: 6000,
        });
      }
    },
  },
  created() {
    const selectStaff = JSON.parse(localStorage.getItem("selectStaff"));
    this.orgId = selectStaff.org.id;
    this.staffId = selectStaff.id;
  },
};
</script>
<style lang="scss" scoped>
.demo-ruleForm {
  text-align: center;
}
.creation-center {
  padding: 40px 40px 40px 40px;
}
.uploading-center {
  display: flex;
  flex-direction: row;
  > .uploading {
    min-height: 40px;
    line-height: 40px;
    box-sizing: border-box;
    border-radius: 4px;
  }
  .uploading-btn-to {
    width: 100px;
    line-height: 38px;
    height: 38px;
    border-radius: 3px;
    text-align: center;
    padding: 0 0px;
    cursor: pointer;
    user-select: none;
    margin-left: 0;
    color: #ffa800;
    font-size: 14px;
    border: 1px solid #ffbe41;
    > i {
      color: #ffbe41;
      font-size: 12px;
      margin-right: 5px;
    }
  }
  > .download-file {
    float: left;
    display: flex;
    flex-direction: row;
    margin-left: 20px;
    color: #6993ff;
    font-size: 14px;
    cursor: pointer;
    user-select: none;
    height: 40px;
    > div {
      width: 117px;
      margin-left: 5px;
    }
  }
}
.uploading-center-style {
  ::v-deep .upload-demo {
    ::v-deep .el-upload {
      line-height: 38px;
    }
  }
}
::v-deep .uploading-center > .uploading {
  line-height: 37px;
}
</style>
src/views/student/index.vue
@@ -8,9 +8,14 @@
        </el-tabs>
        <div style="display: flex; justify-content: space-between">
            <!-- <el-button type="primary" size="small" @click="showCreate">新建学员</el-button> -->
      <div>
            <el-button type="primary" size="small" @click="handleExport"
                >导出学员</el-button
            >
        <el-button type="primary" size="small" @click="handleImport"
          >导入学员</el-button
        >
      </div>
            <div style="width: 500px">
                <!-- <el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
        end-placeholder="结束日期" value-format="yyyy-MM-dd" style="margin-right: 10px">
@@ -59,7 +64,7 @@
                    v-if="activeName !== 'deactivated'"
                >
                    <template slot-scope="scope">
                        {{ scope.row.gender == 'FEMALE' ? '女' : '男' }}
            {{ scope.row.gender == "FEMALE" ? "女" : "男" }}
                    </template>
                </el-table-column>
                <el-table-column
@@ -69,7 +74,7 @@
                    v-if="activeName !== 'deactivated'"
                >
                    <template slot-scope="scope">
                        {{ scope.row.mobile ? scope.row.mobile : '--' }}
            {{ scope.row.mobile ? scope.row.mobile : "--" }}
                    </template>
                </el-table-column>
                <el-table-column
@@ -78,7 +83,7 @@
                    v-if="activeName !== 'deactivated'"
                >
                    <template slot-scope="scope">
                        {{ scope.row.user ? '是' : '否' }}
            {{ scope.row.user ? "是" : "否" }}
                    </template>
                </el-table-column>
                <el-table-column
@@ -87,13 +92,9 @@
                    v-if="activeName == 'deactivated'"
                >
                    <template slot-scope="">
                        <el-link type="primary" :underline="false"
                            >删除</el-link
                        >
            <el-link type="primary" :underline="false">删除</el-link>
                        &nbsp;&nbsp;&nbsp;&nbsp;
                        <el-link type="primary" :underline="false"
                            >恢复</el-link
                        >
            <el-link type="primary" :underline="false">恢复</el-link>
                    </template>
                </el-table-column>
                <el-table-column
@@ -119,14 +120,18 @@
            >
            </el-pagination>
        </div>
        <StudentCreate ref="studentCreate" />
    <el-dialog :visible.sync="dialogVisible" width="560px" title="导入学员">
      <UploadStudent
        v-if="dialogVisible"
        @load-success="reloadData"
      ></UploadStudent>
    </el-dialog>
    </div>
</template>
<script>
import { getData, getRenew, getExpire, getDeleted, handleExport } from "@/api/student";
import StudentCreate from "./components/create.vue";
import { getData, getRenew, getExpire, getDeleted } from "@/api/student";
import UploadStudent from "./components/upload-student.vue";
export default {
    filters: {
@@ -140,7 +145,7 @@
        },
    },
    components: {
        StudentCreate,
    UploadStudent,
    },
    data() {
        return {
@@ -162,6 +167,7 @@
                    },
                },
            },
      dialogVisible: false,
        };
    },
    created() {
@@ -188,16 +194,33 @@
    },
    methods: {
        handleExport() {
            this.download('exportPlayer?orgId=' + JSON.parse(localStorage.getItem("user")).staffs[0].org.id, {
            }, `导出_${new Date().getTime()}.xlsx`)
      this.download(
        "exportPlayer?orgId=" +
          JSON.parse(localStorage.getItem("selectStaff")).org.id,
        {},
        `导出_${new Date().getTime()}.xlsx`
      );
        },
        handleExport2() {
            if (this.dateRange.length == 0) {
                this.$message.warning("请选择日期范围");
                return;
            }
            this.download('exportReport?startDate=' + this.dateRange[0] + '&endDate=' + this.dateRange[1], {
            }, `导出_${new Date().getTime()}.xlsx`)
      this.download(
        "exportReport?startDate=" +
          this.dateRange[0] +
          "&endDate=" +
          this.dateRange[1],
        {},
        `导出_${new Date().getTime()}.xlsx`
      );
    },
    handleImport() {
      this.dialogVisible = true;
    },
    reloadData() {
      this.dialogVisible = false;
      this.fetchData();
        },
        fetchData() {
            this.listLoading = true;
@@ -205,7 +228,7 @@
                this.list = response.data.findPlayerByStaff.ls;
                this.total = response.data.findPlayerByStaff.pageOut.total;
                this.listLoading = false;
            })
      });
        },
        handleSizeChange(val) {
            this.data.pageIn.size = val;
@@ -216,7 +239,7 @@
            this.handleClick();
        },
        handleClick(tab, event) {
            this.data.staffId = JSON.parse(localStorage.getItem("selectStaff")).id
      this.data.staffId = JSON.parse(localStorage.getItem("selectStaff")).id;
            if (this.activeName == "pendingFees") {
                this.listLoading = true;
                getRenew(this.data).then((response) => {
vue.config.js
@@ -39,7 +39,7 @@
    proxy: {
      [process.env.VUE_APP_BASE_API]: {
        // åŒ¹é…æ‰€æœ‰ä»¥ '/dev-api'开头的请求路径
        target: "http://localhost:18081/dream_test", //类似于Nginx反向代理
        target: "http://localhost:18080/dream_test", //类似于Nginx反向代理
        changeOrigin: true, // æ”¯æŒè·¨åŸŸ
        pathRewrite: {
          // é‡å†™è·¯å¾„: åŽ»æŽ‰è·¯å¾„ä¸­å¼€å¤´çš„'/dev-api'