瀏覽代碼

Merge branch 'dev' of http://git.pro.g107.net/guojy/gdy_pc_8 into dev

walter 1 年之前
父節點
當前提交
089320ec8a
共有 44 個文件被更改,包括 4300 次插入150 次删除
  1. 1 0
      build/webpack.dev.conf.js
  2. 1 1
      src/App.vue
  3. 6 0
      src/api/course.js
  4. 5 1
      src/components/UserImage.vue
  5. 11 2
      src/components/upload.vue
  6. 271 0
      src/course/api/index.js
  7. 533 0
      src/course/courseManage/create.vue
  8. 266 0
      src/course/courseManage/freeEdit.vue
  9. 154 0
      src/course/courseManage/home.vue
  10. 336 0
      src/course/dealerManage/edit.vue
  11. 311 0
      src/course/dealerManage/home.vue
  12. 101 0
      src/course/dealerManage/record.vue
  13. 77 0
      src/course/home.vue
  14. 557 0
      src/course/index.vue
  15. 303 0
      src/course/setting/home.vue
  16. 406 0
      src/course/statistics/home.vue
  17. 262 0
      src/course/user/login.vue
  18. 5 0
      src/course/utils/index.js
  19. 0 0
      src/icons/iconfont.js
  20. 5 1
      src/main.js
  21. 8 4
      src/okr/components/project/Milestone.vue
  22. 26 8
      src/okr/components/project/ProjectTj.vue
  23. 1 1
      src/okr/components/public/TaskItem.vue
  24. 4 3
      src/okr/views/project/myProject.vue
  25. 16 5
      src/okr/views/project/projectDetail.vue
  26. 28 6
      src/performance/views/assessManagement/staffAssDet.vue
  27. 30 14
      src/permission.js
  28. 9 9
      src/point/views/attendance/attendance_classnew.vue
  29. 1 0
      src/point/views/pointHome.vue
  30. 4 3
      src/point/views/setting/set_role.vue
  31. 1 0
      src/point/views/statistics/dept_rank.vue
  32. 113 0
      src/router/course.js
  33. 25 4
      src/router/index.js
  34. 5 0
      src/store/getters.js
  35. 3 1
      src/store/index.js
  36. 56 0
      src/store/modules/course.js
  37. 5 1
      src/store/modules/okrStore.js
  38. 2 1
      src/store/modules/user.js
  39. 122 80
      src/utils/auth.js
  40. 187 0
      src/utils/axiosKc.js
  41. 19 2
      src/views/login.vue
  42. 24 3
      src/views/weixin.vue
  43. 二進制
      static/images/tjbmgly.png
  44. 二進制
      static/images/wechat1.png

+ 1 - 0
build/webpack.dev.conf.js

@@ -39,6 +39,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
     compress: true,
     host: HOST || config.dev.host,
     port: PORT || config.dev.port,
+    disableHostCheck: true,
     open: config.dev.autoOpenBrowser,
     overlay: config.dev.errorOverlay
       ? { warnings: false, errors: true }

+ 1 - 1
src/App.vue

@@ -8,7 +8,7 @@
   export default{
     name: 'App',
     created() {
-      this.getVersions();
+      // this.getVersions();
     },
     methods:{
         getVersions() {

+ 6 - 0
src/api/course.js

@@ -0,0 +1,6 @@
+
+import axiosKc from '@/utils/axiosKc'
+// 根据wo_token获取管理员相关信息
+export function getUserInfo() {
+    return axiosKc('post', '/mkt/admin/login')
+}

+ 5 - 1
src/components/UserImage.vue

@@ -1,6 +1,6 @@
 <template>
   <div style="text-align: center;">
-    <el-image v-if="img_url" :src="img_url" :style="{ width: width, height: height }" style="border-radius: 50%;margin: 0 auto;" fit="fill">
+    <el-image v-if="img_url" :src="img_url" :style="{ width: width, height: height ,'border-radius':radius}" style="margin: 0 auto;" fit="fill">
       <div slot="error" class="image-slot"><i class="el-icon-picture"></i></div>
     </el-image>
     <span class="img_round" v-else>
@@ -21,6 +21,10 @@ export default {
       type: String,
       default: '40px'
     },
+    radius:{
+      typoe:String,
+      default:"50%"
+    },
     id: {
       type: Number,
       default: 0

+ 11 - 2
src/components/upload.vue

@@ -46,6 +46,10 @@
         }
       },
       data: Object,
+      coursePath:{
+        type:String,
+        default:null
+      },
       multiple: Boolean,
       list_type:{
         type: String,
@@ -309,9 +313,14 @@
         const url = 'https://integralsys.oss-cn-shenzhen.aliyuncs.com'
         let date = moment().format('YYYY/MM/DD')
         let param = new FormData()
-        let site_id = this.$getCache('site_info').id
+        let site_id
+        if(this.coursePath){
+          site_id = this.coursePath
+        }else{
+          site_id = this.$getCache('site_info').id
+        }
         let randomStr = this.random_string(32)
-        let key = 'intesys/' + site_id+ '/' + date + '/' + randomStr +'/'+ photoName
+        let key = 'intesys/' + site_id + '/' + date + '/' + randomStr +'/'+ photoName
         // let loadingInstance = Loading.service({});
         param.append('Filename', photoName)
         param.append('key', key)

+ 271 - 0
src/course/api/index.js

@@ -0,0 +1,271 @@
+import axiosKc from '@/utils/axiosKc'
+import { getCourseId } from '@/utils/auth'
+import {
+    Message
+} from 'element-ui'
+//wxid获取用户token
+export function getUserToken(wxId) {
+    return new Promise((resolve, reject) => {
+        axiosKc('get', `/mkt/demo/token/wo/${wxId}`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+// 用户token获取管理员id和token
+export function getAdminTokenId(token) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', '/mkt/admin/login', {}, '', '', '', token).then(res => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取免费课程详情
+export function getFreeCourseList(data) {
+    return new Promise((resolve, reject) => {
+        if(getCourseId()){
+            axiosKc('get', `/mkt/admin/${getCourseId()}/subject/free`, data).then(res => {
+                if (res.data.code == 1) {
+                    resolve(res.data.data)
+                } else {
+                    Message(res.data.message)
+                    reject(res.data.message)
+                }
+            })
+        }
+    })
+}
+//修改免费课程
+export function editFreeCourseList(data) {
+    return new Promise((resolve, reject) => {
+        if(getCourseId()){
+            axiosKc('post', `/mkt/admin/${getCourseId()}/subject/free`, data).then(res => {
+                if (res.data.code == 1) {
+                    resolve(res.data.data)
+                } else {
+                    Message(res.data.message)
+                    reject(res.data.message)
+                }
+            })
+        }
+    })
+}
+//获取课程列表
+export function getCourseList(data) {
+    return new Promise((resolve, reject) => {
+        if(getCourseId()){
+            axiosKc('get', `/mkt/admin/${getCourseId()}/subject/list`, data).then(res => {
+                if (res.data.code == 1) {
+                    resolve(res.data.data)
+                } else {
+                    Message(res.data.message)
+                    reject(res.data.message)
+                }
+            })
+        }
+    })
+}
+//删除课程
+export function deleteCourse(id) {
+    return new Promise((resolve, reject) => {
+        axiosKc('post', `/mkt/admin/${getCourseId()}/subject/delete/${id}`).then(res => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取课程详情
+export function getCourseDetail(curId) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get", `/mkt/admin/${getCourseId()}/subject/info/${curId}`).then(res => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//创建课程
+export function createCourse(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("post",`/mkt/admin/${getCourseId()}/subject/create`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//修改课程
+export function updataCourse(id,data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("post",`/mkt/admin/${getCourseId()}/subject/update/${id}`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取经销商/普通看视频用户列表
+export function getDealerList(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get",`/mkt/admin/${getCourseId()}/user/list`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取经销商各课程购买&销售列表
+export function getDealerTransactionList(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get",`/mkt/admin/${getCourseId()}/user/capital/list`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//加减经销商课程名额
+export function editDealerCourseNum(userId,subjectId,data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("post",`/mkt/admin/${getCourseId()}/user/capital/add/${userId}/${subjectId}`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取经销商课程交易明细
+export function getCourseTransationList(userId,subjectId,data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get",`/mkt/admin/${getCourseId()}/user/capital/log/list/${userId}/${subjectId}`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取经销商订购统计列表
+export function getDealerOrderList(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get",`/mkt/admin/${getCourseId()}/statistics/transfer/user`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取课程订购统计列表
+export function getCourseOrderList(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get",`/mkt/admin/${getCourseId()}/statistics/transfer/subject`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取指定经销商/课程订购统计明细
+export function getDealerOrCourseRecode(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get",`/mkt/admin/${getCourseId()}/statistics/transfer/list`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//获取管理员列表
+export function getAdminList(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get",`/mkt/admin/${getCourseId()}/admin/list`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//删除管理员
+export function deleteAdmin(auId) {
+    return new Promise((resolve, reject) => {
+        axiosKc("post",`/mkt/admin/${getCourseId()}/admin/delete/${auId}`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//添加管理员
+export function addAdmin(auId) {
+    return new Promise((resolve, reject) => {
+        axiosKc("post",`/mkt/admin/${getCourseId()}/admin/create/${auId}`).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}
+//精确搜索8.0平台已绑定账号的微信号
+export function getAssignAccount(data) {
+    return new Promise((resolve, reject) => {
+        axiosKc("get",`/mkt/admin/${getCourseId()}/account`,data).then((res) => {
+            if (res.data.code == 1) {
+                resolve(res.data.data)
+            } else {
+                Message(res.data.message)
+                reject(res.data.message)
+            }
+        })
+    })
+}

+ 533 - 0
src/course/courseManage/create.vue

@@ -0,0 +1,533 @@
+<!-- 课程创建/修改 -->
+
+<template>
+  <div class="pjc">
+    <el-page-header @back="$router.go(-1)" :content="title" style="margin-bottom: 30px;"></el-page-header>
+    <!-- <h3>{{ title }}</h3> -->
+    <el-form :model="courseDeail" label-width="110px" :rules="rules">
+      <el-form-item label="课程名称:" prop="name">
+        <el-input :maxlength="30"  show-word-limit v-model.trim="courseDeail.name" style="width: 40%" placeholder="输入课程名称,最多30字符"></el-input>
+      </el-form-item>
+      <el-form-item label="预览图:" prop="thumb">
+        <uploadOss
+          :headers="$xtoken"
+          :action="$action"
+          :limit="1"
+          list_type="picture-card"
+          :accept="$acceptImg"
+          :multiple="true"
+          ref="clearPicture"
+          coursePath="course"
+          :show-file-list="true"
+          :file-list="courseDeail.thumb"
+          :on-success="handleFilesSuccess2"
+          :on-preview="onFilePreView"
+          :before-upload="beforeUpload"
+          :on-remove="onFileRemove2"
+        >
+          <i class="el-icon-plus"></i>
+        </uploadOss>
+        <!-- <div style="display: flex;">
+          <div style="cursor: pointer;margin-right: 10px;" @click="showApm(courseDeail.thumb)">
+            <userImage
+            v-if="courseDeail.thumb"
+            width="100px"
+            height="100px"
+            radius="5px"
+            :img_url="courseDeail.thumb"
+            :user_name="courseDeail.name"
+          ></userImage>
+          </div>
+          <div class="cursor"  @click="showSelectImg(1)">
+            <div><i class="el-icon-plus"></i></div>
+          </div>
+        </div> -->
+      </el-form-item>
+      <el-form-item label="价格:" prop="price">
+        <!-- <el-input-number
+          v-model="courseDeail.price"
+          :min="0"
+          :max="10000000"
+          label="课程价格"
+        ></el-input-number> -->
+        <el-input v-model="courseDeail.price" maxlength="6" style="width: 150px;" placeholder="请输入价格" size="normal" clearable></el-input>
+      </el-form-item>
+      <el-form-item label="浏览量:" prop="price">
+        <el-input-number
+          v-model="courseDeail.baseClick"
+          :min="0"
+          :max="10000000"
+          label="浏览次数"
+        ></el-input-number>
+      </el-form-item>
+      <el-form-item label="是否上架:">
+        <el-switch
+          v-model="courseDeail.enable"
+          active-color="#13ce66"
+          inactive-color="#999"
+        >
+        </el-switch>
+      </el-form-item>
+      <el-form-item label="课程介绍:" prop="images">
+        <uploadOss
+          :headers="$xtoken"
+          :action="$action"
+          :limit="23"
+          list_type="picture-card"
+          :accept="$acceptImg"
+          :multiple="true"
+          ref="clearPicture"
+          coursePath="course"
+          :show-file-list="true"
+          :file-list="courseDeail.images"
+          :on-success="handleFilesSuccess"
+          :on-preview="onFilePreView"
+          :before-upload="beforeUpload"
+          :on-remove="onFileRemove"
+        >
+          <i class="el-icon-plus"></i>
+        </uploadOss>
+      </el-form-item>
+      
+      <el-form-item label="课程章节" size="normal">
+        <div class="sectionout">
+          <div
+            class="sectionInner"
+            v-for="(item, index) in courseDeail.sections"
+            :key="index"
+          >
+            <div class="sectionName">
+              <el-input v-model.trim="item.name" placeholder="请输入章节名..."></el-input>
+            </div>
+            <div class="sectionUrl">
+              <el-input v-model.trim="item.link" placeholder="请输入章节链接..."></el-input>
+            </div>
+            <div class="del">
+              <el-button
+                type="text"
+                size="mini"
+                plain
+                @click="sectionDel(index, item)"
+                style="color: #f89881"
+                >删除</el-button
+              >
+            </div>
+          </div>
+          <div class="addSection">
+            <el-button plain @click="addSection">+</el-button>
+          </div>
+        </div>
+      </el-form-item>
+
+      <el-form-item style="display: flex; flex-direction: row-reverse">
+        <el-button @click="$router.go(-1)">取消</el-button>
+        <el-button @click="iffirm">{{ alterCreate }}</el-button>
+      </el-form-item>
+    </el-form>
+    <el-dialog :visible.sync="dialogVisible">
+      <img width="100%" :src="dialogImageUrl" alt="" />
+    </el-dialog>
+    <image-cropper
+      v-loading="company_img_loading"
+      field="file"
+      :width="imgWidth"
+      :height="imgHeight"
+      :url="'https://integralsys.oss-cn-shenzhen.aliyuncs.com'"
+      @close="company_img_show = false"
+      @crop-upload-success="company_img_success"
+      langType="zh"
+      v-if="company_img_show"
+    ></image-cropper>
+  </div>
+</template>
+<script>
+import ImageCropper from "@/components/ImageCropper";
+import uploadOss from '@/components/upload';
+import { validateURL } from "@/utils/validate";
+import {createCourse,updataCourse,getCourseDetail} from '../api'
+export default {
+  name: "courseEdit",
+  components: { ImageCropper,uploadOss },
+  data() {
+    return {
+      curId: 0,
+      title: "",
+      company_img_show: false,
+      company_img_loading: false,
+      alterCreate: "保存",
+      imgIndex: 1,
+      imgWidth: 300,
+      imgHeight: 300,
+      // 个人信息
+      courseDeail: {
+        name: "",
+        price: 0,
+        baseClick:100,
+        thumb: [],
+        enable: true,
+        images: [],
+        sections: [],
+      },
+      dialogVisible: false,
+      dialogImageUrl: "",
+      rules: {
+          name: [
+            { required: true, message: '请输入课程名称', trigger: 'blur' },
+            { min: 1, max: 30, message: '长度在 1 到 30 个字符', trigger: 'blur' }
+          ],
+          price: [
+            { required: true, message: '请输入课程价格', trigger: 'blur' },
+          ],
+          baseClick: [
+            { required: true, message: '请输入浏览量', trigger: 'blur' },
+          ],
+          thumb: [
+            { required: true, message: '请选择预览图', trigger: 'change' },
+            {type:'array',trigger:'change'}
+          ],
+          images: [
+            { required: true, message: '请选择介绍图', trigger: 'change' },
+            {type:'array',trigger:'change'}
+          ],
+        }
+    };
+  },
+  computed: {
+    courseImages() {
+      if (this.courseDeail.images) {
+        return this.courseDeail.images.split(",");
+      } else {
+        return [];
+      }
+    },
+  },
+  methods: {
+    // 介绍图上传格式
+    beforeUpload(file) {
+      const isJPG = /^image\/(jpeg|png|jpg)$/.test(file.type);
+      const isLt2M = file.size / 1024 / 1024 < 5;
+      if (!isJPG) {
+        this.$message.error('上传图片只能是 JPG,PNG,JPEG 格式!');
+      }
+      if (!isLt2M) {
+        this.$message.error('上传图片大小不能超过 5MB!');
+      }
+      return isJPG && isLt2M;
+    },
+    //介绍图预览
+    onFilePreView(file) {
+      this.showApm(file.url)
+    },
+    // 介绍图删除
+    onFileRemove(file, fileList) {
+      this.courseDeail.images = fileList
+    },
+    // 介绍图上传
+    handleFilesSuccess(response, file, fileList) {
+      let fileListData = fileList.filter(e => {
+        return e.url;
+      });
+      this.courseDeail.images = fileListData
+    },
+    // 预览图删除
+    onFileRemove2(file, fileList) {
+      this.courseDeail.thumb = fileList
+    },
+    // 预览图上传
+    handleFilesSuccess2(response, file, fileList) {
+      let fileListData = fileList.filter(e => {
+        return e.url;
+      });
+      this.courseDeail.thumb = fileListData
+    },
+    //章节信息校验
+    validateURL() {
+      let result = false;
+      result = this.courseDeail.sections.every((item) => {
+        let reg = /^[^\u4e00-\u9fff]*$/
+        return item.link !== "" &&  reg.test(item.link) && item.name !== "";
+        // return validateURL(item.link) && item.name !== "";
+      });
+      return result;
+    },
+    // 获取课程详情
+    getCourseDetail() {
+      getCourseDetail(this.curId).then((res) => {
+          this.courseDeail = this.uploadToData(res);
+      }).catch(err=>{
+        console.error(err)
+      });
+    },
+    //课程详情数据转换展示
+    uploadToData(data) {
+      data.enable = data.enable == 1 ? true : false;
+      // data.price = Number(data.price);
+      let arr = []
+      data.images.forEach(item=>{
+        arr.push({name:item,url:item})
+      })
+      data.images = arr
+      let arr2 = []
+      data.thumb.split(',').forEach(item=>{
+        arr2.push({name:item,url:item})
+      })
+      data.thumb = arr2
+      return data;
+    },
+    //预览图上传成功回调
+    company_img_success(resData) {
+      if (this.imgIndex == 1) {
+        this.courseDeail.thumb = resData.url;
+      } else {
+        if (
+          this.courseDeail.images.split(",").length == 1 &&
+          this.courseDeail.images.split(",")[0] == ""
+        ) {
+          this.courseDeail.images = resData.url;
+        } else {
+          this.courseDeail.images = `${this.courseDeail.images},${resData.url}`;
+        }
+      }
+      this.company_img_show = false;
+    },
+    // 查看预览图
+    showApm(url){
+      this.dialogVisible = true;
+      this.dialogImageUrl = url;
+    },
+    //打开上传预览图片组件
+    showSelectImg(type) {
+      this.imgIndex = type;
+      this.company_img_show = true;
+    },
+    //展示数据转换成上传数据
+    toUpdata() {
+      let data = JSON.parse(JSON.stringify(this.courseDeail));
+      data.enable = data.enable ? 1 : 0;
+      data.sections = JSON.stringify(data.sections);
+      let arr = data.images.map(item=>{
+        return item.url
+      })
+      data.images = arr.join(',')
+      let arr2 = data.thumb.map(item=>{
+        return item.url
+      })
+      data.thumb = arr2.join(',')
+      return data;
+    },
+    // 添加课程
+    addSection() {
+      let section = {
+        name: "",
+        link: "",
+      };
+      this.courseDeail.sections.push(section);
+    },
+    // 删除章节
+    sectionDel(index, item) {
+      this.$confirm("确定删除当前章节?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.courseDeail.sections.splice(index, 1);
+        })
+        .catch((err) => {
+          this.$message({
+            type: "info",
+            message: "已取消",
+          });
+        });
+    },
+    //保存
+    iffirm() {
+      if (
+        !this.courseDeail.name == "" &&
+        this.courseDeail.images.length &&
+        this.courseDeail.thumb.length &&
+        this.courseDeail.price &&
+        this.courseDeail.baseClick != undefined &&
+        this.validateURL()
+      ) {
+        this.$confirm("确定保存当前课程信息?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "info",
+        })
+          .then(() => {
+            if (this.$route.params.id) {
+              this.saveAlter();
+            } else {
+              this.saveCreate();
+            }
+          })
+          .catch(() => {
+            this.$message({
+              type: "info",
+              message: "已取消",
+            });
+          });
+      } else if (!this.validateURL()) {
+        this.$message({
+          type: "warning",
+          message: "章节列表未填写正确",
+        });
+      } else {
+        this.$message({
+          type: "warning",
+          message: "课程信息未填写完整",
+        });
+      }
+    },
+    //修改保存
+    saveAlter() {
+      let data = this.toUpdata();
+      updataCourse(this.curId,data).then(res=>{
+        this.$message({
+            message: "修改成功!",
+            type: "success",
+            showClose: true,
+            duration: 2000,
+          });
+          this.$router.push("/course/courseManage");
+      }).catch(err=>{
+        console.error(err)
+      })
+    },
+    //保存新建课程
+    saveCreate() {
+      let data = this.toUpdata();
+      createCourse(data).then(res=>{
+        this.$message({
+            message: "新建成功!",
+            type: "success",
+            showClose: true,
+            duration: 2000,
+          });
+          this.$router.push("/course/courseManage");
+      }).catch(err=>{
+        console.error(err)
+      })
+    },
+    //判断新建/修改
+    init() {
+      if (this.$route.params.id == undefined) {
+        this.title = "添加课程";
+        this.courseDeail = {
+          name: "",
+          price: 0,
+          thumb: [],
+          enable: true,
+          baseClick:100,
+          images: [],
+          sections: [],
+        };
+      } else {
+        this.curId = this.$route.params.id;
+        this.title = "编辑课程";
+        this.getCourseDetail();
+      }
+    },
+  },
+  created() {
+    this.init();
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.pjc {
+  width: 900px;
+  height: auto;
+  margin: 0 auto;
+  margin-top: 10px;
+  background-color: #fff;
+  border-radius: 5px;
+  padding: 30px 60px;
+  h3 {
+    color: #000;
+    text-align: center;
+    margin: 30px 0;
+  }
+  form {
+    legend {
+      font-size: 20px;
+      color: #000;
+      line-height: 30px;
+      font-weight: bold;
+      margin-bottom: 22px;
+    }
+    .el-form-item {
+      .el-select {
+        width: 380px;
+      }
+    }
+  }
+}
+.sectionout {
+  .sectionInner {
+    display: flex;
+    // justify-content: space-between;
+    align-items: center;
+    margin-bottom: 10px;
+    .sectionName {
+      width: 150px;
+      margin-right: 20px;
+    }
+    .sectionUrl {
+      width: 250px;
+      margin-right: 20px;
+    }
+    .sectionDel {
+    }
+  }
+}
+.img_all {
+  display: flex;
+  flex-wrap: wrap;
+  & > div {
+    margin-right: 10px;
+    margin-bottom: 10px;
+  }
+  .imgout{
+    position: relative;
+    .imgDelete{
+      width: 100%;
+      height: 100%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+      position: absolute;
+      left:0;
+      top:0;
+      background-color: rgba(0,0,0,.3);
+      opacity: 0;
+      transition: opacity 0.3s ease;
+    } 
+    &:hover{
+      .imgDelete{
+        opacity:1;
+      }
+    }
+  }
+}
+.cursor {
+  & > div {
+    height: 100px;
+    width: 100px;
+    background-color: #fbfdff;
+    border: 1px dashed #c0ccda;
+    border-radius: 5px;
+    font-size: 30px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    i{
+      font-size: 28px;
+      color: #8c939d;
+    }
+  }
+}
+</style>

+ 266 - 0
src/course/courseManage/freeEdit.vue

@@ -0,0 +1,266 @@
+<!-- 课程创建/修改 -->
+
+<template>
+  <div class="pjc">
+    <el-page-header @back="$router.go(-1)" :content="title" style="margin-bottom: 30px;"></el-page-header>
+    <el-form :model="courseDeail" label-width="110px" :rules="rules">
+      <el-form-item label="课程免费章节" size="normal">
+        <div class="sectionout">
+          <div
+            class="sectionInner"
+            v-for="(item, index) in courseDeail.sections"
+            :key="index"
+          >
+            <div class="sectionName">
+              <el-input v-model.trim="item.name" placeholder="请输入章节名..."></el-input>
+            </div>
+            <div class="sectionUrl">
+              <el-input v-model.trim="item.link" placeholder="请输入章节链接..."></el-input>
+            </div>
+            <div class="del">
+              <el-button
+                type="text"
+                size="mini"
+                plain
+                @click="sectionDel(index, item)"
+                style="color: #f89881"
+                >删除</el-button
+              >
+            </div>
+          </div>
+          <div class="addSection">
+            <el-button plain @click="addSection">+</el-button>
+          </div>
+        </div>
+      </el-form-item>
+
+      <el-form-item style="display: flex; flex-direction: row-reverse">
+        <el-button @click="$router.go(-1)">取消</el-button>
+        <el-button @click="iffirm">保存</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+<script>
+import {getFreeCourseList,editFreeCourseList} from '../api'
+export default {
+  name: "courseFreeEdit",
+  data() {
+    return {
+      title: "",
+      // 个人信息
+      courseDeail: {
+        sections: [],
+      },
+      rules: {
+          // images: [
+          //   { required: true, message: '请选择介绍图', trigger: 'change' },
+          //   {type:'array',trigger:'change'}
+          // ],
+        }
+    };
+  },
+  methods: {
+    //章节信息校验
+    validateURL() {
+      let result = false;
+      result = this.courseDeail.sections.every((item) => {
+        let reg = /^[^\u4e00-\u9fff]*$/
+        return item.link !== "" && reg.test(item.link) && item.name !== "";
+        // return validateURL(item.link) && item.name !== "";
+      });
+      return result;
+    },
+    // 获取课程详情
+    getCourseDetail() {
+      getFreeCourseList().then((res) => {
+          this.courseDeail.sections = res.sections;
+      }).catch(err=>{
+        console.error(err)
+      });
+    },
+    // 添加章节
+    addSection() {
+      let section = {
+        name: "",
+        link: "",
+      };
+      if(this.courseDeail.sections.length>=5){
+        this.$message.closeAll();
+        this.$message({
+          message: '最多上传数量为5个',
+          type: 'warning',
+          showClose: true,
+          duration: 3000,
+        });
+        return
+      }
+      this.courseDeail.sections.push(section);
+    },
+    // 删除章节
+    sectionDel(index, item) {
+      this.$confirm("确定删除当前章节?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.courseDeail.sections.splice(index, 1);
+        })
+        .catch((err) => {
+          this.$message({
+            type: "info",
+            message: "已取消",
+          });
+        });
+    },
+    //保存
+    iffirm() {
+      if (
+        this.validateURL()
+      ) {
+        this.$confirm("确定保存当前课程信息?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "info",
+        })
+          .then(() => {
+              this.saveAlter();
+          })
+          .catch(() => {
+            this.$message({
+              type: "info",
+              message: "已取消",
+            });
+          });
+      } else {
+        this.$message({
+          type: "warning",
+          message: "章节列表未填写正确",
+        });
+      }
+    },
+    //修改保存
+    saveAlter() {
+      let data = {
+        sections:JSON.stringify(this.courseDeail.sections)
+      };
+      editFreeCourseList(data).then(res=>{
+        this.$message({
+            message: "修改成功!",
+            type: "success",
+            showClose: true,
+            duration: 2000,
+          });
+          this.$router.push("/course/courseManage");
+      }).catch(err=>{
+        console.error(err)
+      })
+    },
+    //判断新建/修改
+    init() {
+      this.title = "编辑免费课程";
+      this.getCourseDetail();
+    },
+  },
+  created() {
+    this.init();
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.pjc {
+  width: 900px;
+  height: auto;
+  margin: 0 auto;
+  margin-top: 10px;
+  background-color: #fff;
+  border-radius: 5px;
+  padding: 30px 60px;
+  h3 {
+    color: #000;
+    text-align: center;
+    margin: 30px 0;
+  }
+  form {
+    legend {
+      font-size: 20px;
+      color: #000;
+      line-height: 30px;
+      font-weight: bold;
+      margin-bottom: 22px;
+    }
+    .el-form-item {
+      .el-select {
+        width: 380px;
+      }
+    }
+  }
+}
+.sectionout {
+  .sectionInner {
+    display: flex;
+    // justify-content: space-between;
+    align-items: center;
+    margin-bottom: 10px;
+    .sectionName {
+      width: 150px;
+      margin-right: 20px;
+    }
+    .sectionUrl {
+      width: 250px;
+      margin-right: 20px;
+    }
+    .sectionDel {
+    }
+  }
+}
+.img_all {
+  display: flex;
+  flex-wrap: wrap;
+  & > div {
+    margin-right: 10px;
+    margin-bottom: 10px;
+  }
+  .imgout{
+    position: relative;
+    .imgDelete{
+      width: 100%;
+      height: 100%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+      position: absolute;
+      left:0;
+      top:0;
+      background-color: rgba(0,0,0,.3);
+      opacity: 0;
+      transition: opacity 0.3s ease;
+    } 
+    &:hover{
+      .imgDelete{
+        opacity:1;
+      }
+    }
+  }
+}
+.cursor {
+  & > div {
+    height: 100px;
+    width: 100px;
+    background-color: #fbfdff;
+    border: 1px dashed #c0ccda;
+    border-radius: 5px;
+    font-size: 30px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    i{
+      font-size: 28px;
+      color: #8c939d;
+    }
+  }
+}
+</style>

+ 154 - 0
src/course/courseManage/home.vue

@@ -0,0 +1,154 @@
+<template>
+  <div class="page">
+    <el-header style="display: flex;justify-content: space-between;" height="">
+      <el-button type="primary" size="default" @click="courseCreate" plain
+        >+ 添加课程</el-button
+      >
+      <el-button type="primary" size="default" @click="courseFreeCreate" plain
+        >编辑免费课程</el-button
+      >
+    </el-header>
+    <el-container class="course_data">
+      <el-table :data="courseList" border stripe highlight-current-row v-loading="loading">
+        <el-table-column prop="name" label="课程名称" align="center">
+        </el-table-column>
+        <el-table-column label="价格" align="center">
+          <template slot-scope="scope"> {{ scope.row.price }} </template>
+        </el-table-column>
+        <el-table-column label="是否上架" align="center">
+          <template slot-scope="scope">
+            {{ scope.row.enable ? "是" : "否" }}
+          </template>
+        </el-table-column>
+        <el-table-column fixed="right" label="操作" width="250" align="center">
+          <template slot-scope="scope">
+            <el-button type="text" @click="courseEdit(scope.row, scope.$index)"
+              >编辑</el-button
+            >
+            <!-- <el-button type="text" @click="courseDel(scope.row, scope.$index)"
+              >删除</el-button
+            > -->
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="proness">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          @current-change="curPageChange()"
+          :current-page.sync="page.cur"
+          :page-size="page.size"
+          :total="page.total"
+          :hide-on-single-page="true"
+        >
+        </el-pagination>
+      </div>
+    </el-container>
+  </div>
+</template>
+
+<script>
+import { deleteCourse, getCourseList } from "../api";
+export default {
+  name: "",
+  components: {},
+  data() {
+    return {
+      loading:true,
+      page: {
+        total: 0,
+        size: 10,
+        cur: 1,
+      },
+      courseList: [],
+    };
+  },
+  created() {
+    this.getCourseList();
+  },
+  methods: {
+    //获取课程列表
+    getCourseList() {
+      let data = {
+        size: this.page.size,
+        page: this.page.cur,
+      };
+      getCourseList(data).then((res) => {
+        this.loading = false
+        this.courseList = res.list;
+        this.page.total = res.total;
+        this.page.size = res.size;
+        this.page.cur = res.current;
+      });
+    },
+    // 当前页切换
+    curPageChange() {
+      this.loading = true
+      this.getCourseList();
+    },
+    // 跳转课程修改
+    courseEdit(row) {
+      this.$router.push({
+        path: `/course/courseEdit/${row.id}`,
+      });
+    },
+    // 跳转创建新课程
+    courseCreate() {
+      this.$router.push("/course/courseCreate");
+    },
+    // 跳转编辑免费课程课程
+    courseFreeCreate(){
+      this.$router.push("/course/freeCourseEdit");
+    },
+    // 删除
+    deleteCourse(id) {
+      deleteCourse(id).then((res) => {
+        this.$message({
+          message: res.message,
+          type: "success",
+          showClose: true,
+          duration: 3000,
+        });
+        this.page.cur = 1;
+        this.loading = true
+        this.getCourseList();
+      });
+    },
+    // 删除课程
+    courseDel(row) {
+      this.$confirm("确定删除当前课程吗?", "提示", {
+        confirmButtonText: "确认",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then((action) => {
+          this.deleteCourse(row.id);
+        })
+        .catch(() => {});
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.page {
+  padding: 15px;
+  background-color: #fff;
+  border-radius: 5px;
+  // width: 900px;
+  // height: auto;
+  // margin: 0 auto;
+  // margin-top: 10px;
+  // background-color: #fff;
+  // border-radius: 5px;
+  // padding: 30px 60px;
+  .course_data {
+    margin-top: 25px;
+    display: block;
+    .proness {
+      margin-top: 20px;
+      display: flex;
+      justify-content: center;
+    }
+  }
+}
+</style>

+ 336 - 0
src/course/dealerManage/edit.vue

@@ -0,0 +1,336 @@
+<template>
+  <div class="page">
+    <el-page-header
+      @back="$router.go(-1)"
+      :content="curName"
+      style="margin-bottom: 20px"
+    ></el-page-header>
+    <el-container class="course_data">
+      <el-button
+        type="primary"
+        plain
+        size="default"
+        style="margin-bottom: 15px"
+        @click="showAllcourseSelect"
+        >增加课程名额</el-button
+      >
+      <el-table :data="courseList" border stripe highlight-current-row v-loading="loading">
+        <el-table-column prop="subjectName" label="课程名称" align="center">
+        </el-table-column>
+        <el-table-column label="卖出" align="center">
+          <template slot-scope="scope">
+            {{ scope.row.statistics.saleAmount }}
+          </template>
+        </el-table-column>
+        <el-table-column label="剩余" align="center">
+          <template slot-scope="scope"> {{ scope.row.amount }} </template>
+        </el-table-column>
+        <el-table-column fixed="right" label="操作" width="250" align="center">
+          <template slot-scope="scope">
+            <el-button
+              type="text"
+              size="mini"
+              @click="courseAdd(scope.row, scope.$index)"
+              >增加</el-button
+            >
+            <el-button
+              size="mini"
+              type="text"
+              @click="courseSurplus(scope.row, scope.$index)"
+              >减少</el-button
+            >
+            <el-button
+              size="mini"
+              type="text"
+              @click="courseRecord(scope.row, scope.$index)"
+              >变动明细</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="proness">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          @current-change="curPageChange()"
+          :current-page.sync="page.cur"
+          :page-size="page.size"
+          :total="page.total"
+          :hide-on-single-page="false"
+        >
+        </el-pagination>
+      </div>
+    </el-container>
+    <el-dialog
+      :title="eldiType ? '增加课程名额' : '减少课程名额'"
+      :visible.sync="changeLimit"
+      width="30%"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      center
+      @close="cancleDi"
+    >
+      <el-form
+        :model="eldiForm"
+        ref="form"
+        label-width="80px"
+        :inline="false"
+        size="normal"
+      >
+        <el-form-item label="选择课程" size="normal" v-if="addAllcourse">
+          <el-select v-model="eldiForm.id" placeholder="请选择所有课程">
+            <el-option
+              v-for="item in courseOptions(addAllcourse)"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="选择课程" size="normal" v-else>
+          <el-select v-model="eldiForm.id" placeholder="请选择课程" disabled>
+            <el-option
+              v-for="item in courseOptions(addAllcourse)"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="交易名额">
+          <el-input-number
+            v-model="eldiForm.num"
+            size="normal"
+            :min="0"
+            :step="1"
+            :controls="true"
+          >
+          </el-input-number>
+        </el-form-item>
+        <el-form-item label="备注" size="normal">
+          <el-input
+            type="textarea"
+            :rows="2"
+            v-model="eldiForm.content"
+            placeholder="请输入备注(限100字以内)"
+            :maxlength="100"
+            show-word-limit
+            :autosize="{ minRows: 2, maxRows: 5 }"
+          >
+          </el-input>
+        </el-form-item>
+      </el-form>
+      <span slot="footer">
+        <el-button @click="cancleDi">取消</el-button>
+        <el-button type="primary" @click="confirmSave">保存</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  getCourseList,
+  getDealerTransactionList,
+  editDealerCourseNum,
+} from "../api";
+export default {
+  name: "dealerManage",
+  data() {
+    return {
+      loading:true,
+      curName: "",
+      addAllcourse: false,
+      page: {
+        total: 1000,
+        size: 10,
+        cur: 1,
+      },
+      teamValue: "",
+      changeLimit: false,
+      eldiType: 0,
+      eldiForm: {
+        id: 0,
+        num: 1,
+        content: "",
+      },
+      courseList: [],
+      courseAllList: [],
+    };
+  },
+  computed: {
+    //添加/减少课程选择列表
+    courseOptions() {
+      return function (type) {
+        if (!type) {
+          let list = [];
+          this.courseList.forEach((item) => {
+            list.push({
+              label: item.subjectName,
+              value: item.subjectId,
+            });
+          });
+          return list;
+        } else {
+          let list = [];
+          this.courseAllList.forEach((item) => {
+            list.push({
+              label: item.name,
+              value: item.id,
+            });
+          });
+          return list;
+        }
+      };
+    },
+  },
+  created() {
+    this.init();
+  },
+  methods: {
+    //添加新的课程名额
+    showAllcourseSelect() {
+      this.eldiForm.id = this.courseAllList[0].id;
+      this.addAllcourse = true;
+      this.changeLimit = true;
+      this.eldiType = 1;
+    },
+    //获取所有课程列表
+    getAllList() {
+      let data = {
+        page: 1,
+        pageSize: 100000,
+        enable:1
+      };
+      getCourseList(data).then((res) => {
+        this.loading = false
+        this.courseAllList = res.list;
+      });
+    },
+    //获取经销商推广课程列表
+    getList() {
+      let data = {
+        userId: this.$route.params.id,
+        page: this.page.cur,
+        pageSize: this.page.size,
+      };
+      getDealerTransactionList(data)
+        .then((res) => {
+          this.loading = false
+          this.courseList = res.list;
+          this.page.cur = res.current;
+          this.page.total = res.total;
+        })
+        .catch((err) => {
+          console.error(err);
+        });
+    },
+    //增加名额
+    courseAdd(row, index) {
+      this.eldiForm.id = row.subjectId;
+      this.eldiType = 1;
+      this.changeLimit = true;
+    },
+    //减少名额
+    courseSurplus(row, index) {
+      this.eldiForm.id = row.subjectId;
+      this.eldiType = 0;
+      this.changeLimit = true;
+    },
+    //查看明细
+    courseRecord(row, index) {
+      this.$router.push({
+        path: `/course/courseRecord/${this.$route.params.id}/${row.subjectId}`,
+        query: {
+          name: row.subjectName,
+        },
+      });
+    },
+    // 提交名额交易
+    confirmSave() {
+      if(this.eldiForm.num && this.eldiForm.num>=1){
+        this.$confirm(`确定要提交名额交易吗?`, "提示", {
+          confirmButtonText: "确认",
+          cancelButtonText: "取消",
+          type: "info",
+        })
+          .then(() => {
+            let amount = Number(
+              `${this.eldiType ? "" : "-"}${this.eldiForm.num}`
+            );
+            let data = {
+              amount: amount,
+              content: this.eldiForm.content,
+            };
+            editDealerCourseNum(
+              this.$route.params.id,
+              this.eldiForm.id,
+              data
+            ).then((res) => {
+              this.$message({
+                message: "交易成功!",
+                type: "success",
+                showClose: true,
+                duration: 1500,
+              });
+              this.cancleDi();
+              this.loading = true
+              this.getList();
+            });
+          })
+          .catch(() => {});
+      }else{
+        this.$message({
+          message: "请输入正确的交易名额",
+          type: "warning",
+          showClose: true,
+          duration: 1500,
+        });
+      }
+    },
+    //取消弹窗
+    cancleDi() {
+      let form = {
+        id: 0,
+        num: 0,
+        content: "",
+      };
+      this.eldiType = 0;
+      this.eldiForm = form;
+      this.changeLimit = false;
+    },
+    //初始化
+    init() {
+      this.curName = `${this.$route.query.name}推广的课程`;
+      this.getList();
+      this.getAllList();
+    },
+    // 页面切换
+    curPageChange() {
+      this.loading = true
+      this.getList();
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.page {
+  padding: 15px;
+  background-color: #fff;
+  border-radius: 5px;
+  .search {
+    margin-left: 15px;
+  }
+  .course_data {
+    margin-top: 25px;
+    display: block;
+    .proness {
+      margin-top: 20px;
+      display: flex;
+      justify-content: center;
+    }
+  }
+}
+</style>

+ 311 - 0
src/course/dealerManage/home.vue

@@ -0,0 +1,311 @@
+<template>
+  <div class="page">
+    <el-page-header
+      @back="$router.go(-1)"
+      :content="curTeamTel"
+      style="margin-bottom: 20px"
+      v-if="!isOuter"
+    ></el-page-header>
+    <el-header height="40px" style="display: flex; align-items: center">
+      <el-button
+        type="primary"
+        size="normal"
+        @click="qropen"
+        plain
+        v-if="isOuter"
+        >经销商邀请二维码</el-button
+      >
+      <div class="search">
+        <!-- @keyup.enter.native="teamSearch" -->
+        <el-input
+          placeholder="请输入用户名"
+          v-model.trim="teamValue"
+          @input="teamSearch"
+        >
+          <i slot="prefix" class="el-input__icon el-icon-search"></i>
+        </el-input>
+      </div>
+    </el-header>
+    <el-container class="course_data">
+      <el-table
+        :data="dealerInfo"
+        border
+        stripe
+        highlight-current-row
+        v-loading="loading"
+      >
+        <el-table-column prop="name" label="用户名" align="center">
+        </el-table-column>
+        <!-- <el-table-column label="微信ID" align="center" min-width="100px">
+          <template slot-scope="scope"> {{ scope.row.unionid }} </template>
+        </el-table-column> -->
+        <el-table-column label="手机号" align="center">
+          <template slot-scope="scope"> {{ scope.row.mobile }} </template>
+        </el-table-column>
+        <el-table-column
+          label="TA的团队"
+          align="center"
+          style="color: #409eff"
+          class="outTeam"
+          v-if="isOuter"
+        >
+          <template slot-scope="scope">
+            <span
+              @click="toDealerTeam(scope.row)"
+              style="color: #409eff; cursor: pointer"
+              >{{ scope.row.statistics.teamAmount }}</span
+            >
+          </template>
+        </el-table-column>
+        <el-table-column fixed="right" label="操作" width="250" align="center">
+          <template slot-scope="scope">
+            <!-- <el-button
+              type="text"
+              size="mini"
+              @click="infoEdit(scope.row, scope.$index)"
+              >修改信息</el-button
+            > -->
+            <el-button
+              size="mini"
+              type="text"
+              @click="dealerPay(scope.row, scope.$index)"
+              >课程名额修改</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="proness">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          @current-change="curPageChange()"
+          :current-page.sync="page.cur"
+          :page-size="page.size"
+          :total="page.total"
+          :hide-on-single-page="false"
+        >
+        </el-pagination>
+      </div>
+    </el-container>
+    <el-dialog
+      title="用户信息修改"
+      :visible.sync="eldiForm"
+      width="40%"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      center
+      @close="cancleDi"
+    >
+      <el-form
+        :model="dealerForm"
+        ref="form"
+        label-width="100px"
+        :inline="false"
+        size="normal"
+      >
+        <el-form-item label="用户名">
+          <el-input v-model="dealerForm.name"></el-input>
+        </el-form-item>
+        <el-form-item label="绑定微信ID">
+          <el-input v-model="dealerForm.unionid"></el-input>
+        </el-form-item>
+        <el-form-item label="手机号">
+          <el-input v-model="dealerForm.mobile"></el-input>
+        </el-form-item>
+      </el-form>
+      <span slot="footer">
+        <el-button @click="cancleDi">取消</el-button>
+        <el-button type="primary" @click="confirmSave">保存</el-button>
+      </span>
+    </el-dialog>
+    <el-dialog
+      :visible.sync="qrVisible"
+      width="400px"
+      title="经销商邀请二维码"
+      center
+      @close="cancleQr"
+    >
+      <div id="root" style="display: flex;justify-content: center;" ref="qrCodeUrl"></div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import QRCode from "qrcodejs2";
+import { getDealerList } from "../api";
+export default {
+  name: "dealerManage",
+  components: {},
+  props: [],
+  data() {
+    return {
+      loading: true,
+      qrVisible: false,
+      qrcode: null,
+      qrcodeStatus: false,
+      eldiForm: false,
+      dealerForm: {
+        id: 0,
+        name: "",
+        unionid: "",
+        mobile: "",
+      },
+      curTeamTel: "",
+      isOuter: false,
+      page: {
+        total: 0,
+        size: 10,
+        cur: 1,
+      },
+      teamValue: "",
+      dealerInfo: [],
+    };
+  },
+  created() {
+    this.init();
+  },
+  methods: {
+    qropen() {
+      this.qrVisible = true;
+      this.$nextTick(() => {
+        this.creatQrCode();
+      });
+    },
+    cancleQr() {},
+    creatQrCode() {
+      if (!this.qrcodeStatus) {
+        console.log(`${process.env.BASE_API}/m/#/courseLogin?pid=0`)
+        this.qrcode = new QRCode(this.$refs.qrCodeUrl, {
+          text: `${process.env.BASE_API}/m/#/courseLogin?pid=0`, // 需要转换为二维码的内容
+          width: 300,
+          height: 300,
+          colorDark: "#000000",
+          colorLight: "#ffffff",
+          correctLevel: QRCode.CorrectLevel.H,
+        });
+        this.qrcodeStatus = true;
+      }
+    },
+    //获取经销商列表
+    getDealerMap(type=1) {
+      let data = {
+        page: this.page.cur,
+        pageSize: this.page.size,
+        marketable: type,
+      };
+      if (this.$route.params.id) {
+        data.pid = this.$route.params.id;
+      }
+      if (this.teamValue) {
+        data.keyword = this.teamValue;
+      }
+      getDealerList(data).then((res) => {
+        this.loading = false;
+        this.dealerInfo = res.list;
+        this.page.cur = res.current;
+        this.page.total = res.total;
+      });
+    },
+    // 修改经销商信息
+    confirmSave() {
+      this.$confirm("确定要修改经销商信息吗?", "提示", {
+        confirmButtonText: "确认",
+        cancelButtonText: "取消",
+        type: "info",
+      })
+        .then((action) => {
+          this.$message({
+            message: "交易成功!",
+            type: "success",
+            showClose: true,
+            duration: 1500,
+          });
+          this.cancleDi();
+        })
+        .catch(() => {
+          this.cancleDi();
+        });
+    },
+    // 取消修改并重置表单
+    cancleDi() {
+      let form = {
+        id: 0,
+        name: "",
+        unionid: "",
+        mobile: "",
+      };
+      this.dealerForm = form;
+      this.eldiForm = false;
+    },
+    // 初始化
+    init() {
+      if (
+        this.$route.path.includes("/course/dealerTeam") &&
+        this.$route.params.id
+      ) {
+        this.isOuter = false;
+        this.curTeamTel = `${this.$route.query.name}的团队`;
+        this.getDealerMap(1, this.$route.params.id);
+      } else {
+        this.isOuter = true;
+        this.getDealerMap(1);
+      }
+    },
+    // 跳转到我的团队
+    toDealerTeam(row) {
+      if (row.statistics.teamAmount != 0) {
+        this.$router.push({
+          path: `/course/dealerTeam/${row.id}?name=${row.name}`,
+        });
+      } else {
+        this.$message({
+          message: "您还没有团队",
+          type: "warning",
+          showClose: true,
+          duration: 3000,
+        });
+      }
+    },
+    // 搜索
+    teamSearch() {
+      this.loading = true;
+      this.page.cur = 1;
+      this.getDealerMap();
+    },
+    // 切换当前页
+    curPageChange() {
+      this.loading = true;
+      this.getDealerMap();
+    },
+    // 打开弹窗修改个人信息
+    infoEdit(row) {
+      this.dealerForm = JSON.parse(JSON.stringify(row));
+      this.eldiForm = true;
+    },
+    // 跳转查看交易详情
+    dealerPay(row) {
+      this.$router.push(`/course/dealerEdit/${row.id}?name=${row.name}`);
+    },
+  },
+  computed: {},
+};
+</script>
+<style scoped lang="scss">
+.page {
+  padding: 15px;
+  background-color: #fff;
+  border-radius: 5px;
+  .search {
+    margin-left: 15px;
+  }
+  .course_data {
+    margin-top: 25px;
+    display: block;
+    .proness {
+      margin-top: 20px;
+      display: flex;
+      justify-content: center;
+    }
+  }
+}
+</style>

+ 101 - 0
src/course/dealerManage/record.vue

@@ -0,0 +1,101 @@
+<template>
+    <div class="page">
+      <el-page-header @back="$router.go(-1)" content='课程交易明细' style="margin-bottom: 20px;"></el-page-header>
+      <h3>{{ curTeamTel }}</h3>
+      <el-container class="course_data">
+        <el-table :data="courseRecord" border stripe highlight-current-row v-loading="loading">
+          <el-table-column label="课程名额变动明细" align="center">
+            <template slot-scope="scope"> {{ scope.row.amount }} </template>
+          </el-table-column>
+          <el-table-column label="备注" align="center">
+            <template slot-scope="scope"> {{ scope.row.content }} </template>
+          </el-table-column>
+          <el-table-column label="记录时间" align="center">
+            <template slot-scope="scope"> {{ scope.row.createTime }} </template>
+          </el-table-column>
+        </el-table>
+        <div class="proness">
+          <el-pagination
+            background
+            layout="prev, pager, next"
+            @current-change="curPageChange()"
+            :current-page.sync="page.cur"
+            :page-size="page.size"
+            :total="page.total"
+            :hide-on-single-page="false"
+          >
+          </el-pagination>
+        </div>
+      </el-container>
+    </div>
+  </template>
+  
+  <script>
+  import {getCourseTransationList} from '../api'
+  export default {
+    name: "dealerRecord",
+    components: {},
+    props: [],
+    data() {
+      return {
+        loading:true,
+        userId: this.$route.params.userId,
+        courseId: this.$route.params.courseId,
+        curTeamTel: "交易明细",
+        page: {
+          total: 0,
+          size: 10,
+          cur: 1,
+        },
+        courseRecord: [],
+      };
+    },
+    created() {
+      this.init();
+    },
+    methods: {
+      // 初始化
+      init() {
+          this.curTeamTel = `${this.$route.query.name}的交易明细`;
+          this.getList()
+      },
+      getList(){
+        let data = {
+          page:this.page.cur,
+          pageSize:this.page.size
+        }
+        getCourseTransationList(this.userId,this.courseId,data).then(res=>{
+          this.loading = false
+          this.courseRecord = res.list;
+          this.page.cur = res.current;
+          this.page.total = res.total;
+        })
+      },
+      // 切换当前页
+      curPageChange() {
+        this.loading = true
+        this.getList()
+      },
+    },
+  };
+  </script>
+  <style scoped lang="scss">
+  .page {
+    padding: 15px;
+    background-color: #fff;
+    border-radius: 5px;
+    .search {
+      margin-left: 15px;
+    }
+    .course_data {
+      margin-top: 25px;
+      display: block;
+      .proness {
+        margin-top: 20px;
+        display: flex;
+        justify-content: center;
+      }
+    }
+  }
+  </style>
+  

+ 77 - 0
src/course/home.vue

@@ -0,0 +1,77 @@
+<template>
+  <div>
+    <div>
+      <div class="flex-box">
+        <div class="flex-1">
+          <div
+            style="background-color: #fff; padding: 20px; margin-bottom: 10px"
+            class="br-5"
+          >
+            <div class="flex-box-ce">
+              <div style="margin-right: 10px">
+                <userImage
+                  :id="course_account_info.id"
+                  :img_url="course_account_info.img_url"
+                  :user_name="course_account_info.name"
+                  width="50px"
+                  height="50px"
+                ></userImage>
+              </div>
+              <div class="flex-1">
+                <div
+                  class="flex-box-ce"
+                  style="
+                    margin-bottom: 6px;
+                    font-size: 14px;
+                    color: #666;
+                    font-weight: 700;
+                  "
+                >
+                  <div
+                    style="
+                      font-size: 16px;
+                      font-weight: 700;
+                      padding-right: 15px;
+                    "
+                    class="black"
+                  >
+                    {{ course_account_info.name }}
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="other" style="background-color: #5FA4E8;overflow: hidden;border-radius: 5px;">
+        <img
+          src="static/images/login2.png"
+          style="margin:  150px auto; display: block;"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters, mapState } from "vuex";
+export default {
+  name: "",
+  components: {},
+  props: [],
+  data() {
+    return {};
+  },
+  created() {},
+  mounted() {},
+  methods: {},
+  computed: {
+    ...mapGetters(["course_account_info"]),
+  },
+};
+</script>
+<style scoped lang="scss">
+.page {
+  background-color: #fff;
+}
+</style>

+ 557 - 0
src/course/index.vue

@@ -0,0 +1,557 @@
+<template>
+  <div class="box-all" v-loading="loading">
+    <el-header>
+      <div
+        class="flex-box"
+        style="height: 60px; box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08)"
+      >
+        <div @click="homeUrl" class="logo-box flex-box flex-center-center">
+          <img
+            v-if="course_account_info.logo_url"
+            :src="course_account_info.logo_url"
+            class="logo"
+          />
+          <img v-else src="static/images/logo3.png" class="logo" />
+        </div>
+        <div
+          class="flex-1 flex-box-ce"
+          style="padding: 0 20px"
+          v-if="courseName"
+        >
+          <div class="left-menu">
+            <p>{{ courseName }}</p>
+          </div>
+          <div class="flex-1" style="text-align: center;font-size: 20px;color: #000;font-weight: 600;">功道云课程营销系统</div>
+          <div class="right-menu">
+            <!-- 退出账号 -->
+            <el-dropdown @command="logOut">
+              <span class="el-dropdown-link" style="cursor: pointer">
+                <userImage
+                  class="user_img"
+                  width="40px"
+                  height="40px"
+                  fontSize="14"
+                  :user_name="course_account_info.name"
+                  :img_url="course_account_info.img_url"
+                ></userImage>
+              </span>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item
+                  v-for="(group, index) in userConcent"
+                  :key="index"
+                  :command="group"
+                >
+                  <span v-if="group.id == 2" class="red"
+                    ><i class="el-icon-warning" style="margin-right: 10px"></i
+                    >{{ group.name }}</span
+                  >
+                </el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+          </div>
+        </div>
+      </div>
+    </el-header>
+    <el-container class="main">
+      <div class="main-left">
+        <div class="flex-box-v flex-center-center">
+          <template v-for="(item, index) in menuArr">
+            <div
+              class="flex-box-v menu-item"
+              v-if="item.show"
+              :class="{
+                'menu-active': menuIndex == item.index,
+                [item.class]: item.class,
+              }"
+              @click="openUrl(item)"
+            >
+              <svg-icon :icon-class="item.icon" class="svgIcon"></svg-icon>
+              <span style="margin-top: 5px">{{ item.name }}</span>
+            </div>
+          </template>
+        </div>
+      </div>
+      <el-main class="main-content">
+        <keep-alive v-if="isRouterAlive">
+          <router-view v-if="$route.meta.keepAlive" />
+        </keep-alive>
+        <router-view v-if="!$route.meta.keepAlive"></router-view>
+      </el-main>
+    </el-container>
+  </div>
+</template>
+
+<script>
+import { mapGetters, mapState } from "vuex";
+export default {
+  name: "courseIndex",
+  provide() {
+    //父组件中通过provide来提供变量,在子组件中通过inject来注入变量。
+    return {
+      reload: this.reload,
+    };
+  },
+  data() {
+    return {
+      courseName:'首页',
+      loading: false,
+      isLog: false,
+      menuIndex: 2,
+      isRouterAlive: true,
+      menuArr: [
+        // {
+        //   icon: "#icon-shouye",
+        //   index: 1,
+        //   name: "课程首页",
+        //   path: "/course",
+        //   show: true,
+        // },
+        {
+          icon: "#icon-kecheng",
+          index: 2,
+          name: "课程管理",
+          path: "/course/courseManage",
+          show: true,
+        },
+        {
+          icon: "#icon-xiaoshoujingxiaoshang",
+          index: 3,
+          name: "经销商管理",
+          path: "/course/dealerManage",
+          show: true,
+        },
+        {
+          icon: "#icon-tongji1",
+          index: 4,
+          name: "统计",
+          path: "/course/statistics",
+          show: true,
+        },
+        {
+          icon: "#icon-shezhi-xianxing",
+          index: 5,
+          name: "设置",
+          path: "/course/adminSetting",
+          show: true,
+        },
+      ],
+      userConcent: [{ id: 2, name: "退出账号" }],
+    };
+  },
+  watch: {
+    //监视路由变化,有变化就缓存导航状态
+    $route(to, from) {
+      var str = to.path;
+      this.menuArr.some((item, index) => {
+        if (item.path == str) {
+          this.menuIndex = item.index;
+          this.$setCache("course_path", item.index);
+          this.setTit()
+          return true;
+        }
+      });
+    },
+  },
+  created() {
+    this.judegLogin();
+    //如果当前页不是首页,则从缓存中取出导航栏状态,没有则为首页1
+    if (this.$route.path != "/course") {
+      this.menuIndex =
+        this.$getCache("course_path") != 1 ? this.$getCache("course_path") : 1;
+        this.setTit()
+    }
+  },
+  methods: {
+    setTit(){
+      this.courseName = this.$getCache("course_path")==1?'首页':this.$getCache("course_path")==2?'课程管理':this.$getCache("course_path")==3?'经销商管理':this.$getCache("course_path")==4?'统计':this.$getCache("course_path")==5?'设置':'管理员'
+    },
+    judegLogin() {
+      if (!this.$getCourseId()) {
+        if (!localStorage.getItem("Course-Id")) {
+          this.$message({
+            message: "未登录",
+            type: "warning",
+            showClose: true,
+            duration: 3000,
+          });
+          this.$router.push("/courseLogin");
+        }
+      }
+    },
+    //全局刷新不闪烁
+    reload() {
+      this.isRouterAlive = false;
+      this.$nextTick(function () {
+        this.isRouterAlive = true;
+      });
+    },
+    //退出账号
+    logOut() {
+      this.$store.dispatch("CourseLogOut");
+    },
+    //回到首页
+    homeUrl() {
+      this.$router.push({ path: "/course" });
+      this.$setCache("course_path", 2);
+    },
+    //跳转相应子页面并缓存当前状态
+    openUrl(item) {
+      if (this.menuIndex == item.index || this.isLog) {
+        return false;
+      }
+      this.isLog = true;
+      if (item) {
+        this.menuIndex = item.index;
+        this.$setCache("course_path", item.index);
+        this.$router.push({ path: item.path });
+      } else {
+        this.$setCache("course_path", 1);
+        this.$router.push({ path: "/course" });
+      }
+      setTimeout(() => {
+        this.isLog = false;
+      }, 200);
+    },
+  },
+  computed: {
+    ...mapGetters(["course_account_info"]),
+  },
+};
+</script>
+<style scoped="scoped" lang="scss">
+.el-header-p {
+  font-size: 18px;
+  font-weight: 600;
+  line-height: 60px;
+  color: #000;
+}
+.icon-item {
+  margin-right: 30px;
+  cursor: pointer;
+}
+.icon-item:hover {
+  color: #409eff;
+}
+.count_max {
+  border: 1px solid #005bea;
+  border-radius: 5px;
+  padding: 4px 10px;
+  color: #005bea;
+  cursor: pointer;
+}
+
+.menu-item {
+  width: 90px;
+  color: #ccc;
+  text-align: center;
+  padding: 10px 0;
+  cursor: pointer;
+  position: relative;
+  border-left: 3px solid #191a23;
+  transition: border-color 0.3s, background-color 0.3s, color 0.3s;
+}
+.svgIcon {
+  font-size: 16px;
+  margin: 0 auto;
+}
+.menu-item:hover {
+  background-color: #393b4b;
+}
+.menu-active {
+  background-color: #393b4b;
+  border-left: 5px solid #005bea;
+  color: #fff;
+}
+.announDetails {
+  ::v-deep img {
+    width: 100%;
+  }
+}
+.updateNotice ::v-deep .el-dialog {
+  border-radius: 10px;
+  .el-dialog__header {
+    padding: 13px 20px;
+    text-align: center;
+    background-color: #3193fc;
+    border-radius: 8px 8px 0 0;
+    .el-dialog__title {
+      font-size: 16px;
+      color: #fff;
+    }
+    .el-icon-close {
+      color: #fff;
+    }
+  }
+  .el-dialog__body {
+    padding: 20px 20px 30px 20px;
+  }
+  .el-dialog__footer {
+    .dialog-footer {
+      .is-round {
+        padding: 10px 19px;
+        border-radius: 15px;
+      }
+    }
+  }
+}
+.navigation {
+  position: fixed;
+  right: 20px;
+  bottom: 100px;
+  z-index: 999;
+}
+.navigationBox {
+  background-color: #409eff;
+  color: #fff;
+  font-size: 12px;
+  margin-top: 20px;
+  text-align: center;
+}
+.navigationItem {
+  padding: 6px;
+  cursor: pointer;
+}
+.navigationItem:hover {
+  background-color: #005bea;
+}
+.money {
+  line-height: 32px;
+  text-align: center;
+  height: 32px;
+  color: #ff9600;
+  width: 88px;
+  background: #ffffff;
+  border: 1px solid #ff9600;
+  opacity: 1;
+  border-radius: 3px;
+  cursor: pointer;
+  margin-left: 20px;
+}
+.money2 {
+  line-height: 32px;
+  text-align: center;
+  height: 32px;
+  color: #409eff;
+  width: 120px;
+  background: #ffffff;
+  border: 1px solid #409eff;
+  opacity: 1;
+  border-radius: 3px;
+  cursor: pointer;
+  margin: 0 20px;
+  padding-left: 10px;
+}
+.innerVisible p {
+  text-align: center;
+}
+.megData div:nth-child(1) {
+  background-image: linear-gradient(to bottom, #5e6e9b 0%, #232d48 100%);
+  text-align: center;
+  color: #e1bf66;
+  border-top-left-radius: 25px;
+  border-bottom-left-radius: 25px;
+  line-height: 35px;
+  height: 35px;
+  padding: 0 10px;
+}
+.megData div:nth-child(2) {
+  background-image: linear-gradient(to bottom, #ffeab2 0%, #e1bf66 100%);
+  text-align: center;
+  color: #232d48;
+  border-top-right-radius: 25px;
+  border-bottom-right-radius: 25px;
+  line-height: 35px;
+  height: 35px;
+  padding: 0 10px;
+}
+.jx {
+  width: 140px;
+  color: #fff;
+  border-radius: 3px;
+  text-align: left;
+  box-shadow: 1px 1px 0px 0px #ccc;
+  height: 45px;
+  font-size: 16px;
+  padding-left: 36px;
+  line-height: 45px;
+  cursor: pointer;
+  font-weight: 600;
+  // border: 1px solid #409EFF;
+  border-radius: 5px;
+  background-image: linear-gradient(117deg, #00c6fb 0%, #005bea 100%);
+  margin: 0 auto;
+  margin-bottom: 10px;
+}
+.PCtutorials {
+  height: 38px;
+  width: 38px;
+  display: inline-block;
+  border-radius: 50%;
+  text-align: center;
+  font-size: 18px;
+  line-height: 38px;
+  -webkit-transition: all 0.3s;
+  -moz-transition: all 0.3s;
+  -ms-transition: all 0.3s;
+  -o-transition: all 0.3s;
+  transition: all 0.3s;
+  background-color: #409eff;
+  color: #fff;
+}
+.PCtutorials:hover {
+  box-shadow: 0 0 3px #ccc;
+}
+
+.routerActive {
+  background-color: #199afb !important;
+}
+
+.active {
+  color: #409eff;
+  background-color: rgba(38, 162, 255, 0.1);
+}
+.left-menu {
+  text-align: center;
+  p {
+    font-size: 18px;
+    color: #000;
+    line-height: 60px;
+    font-weight: 600;
+  }
+}
+.right-menu {
+  float: right;
+  height: 100%;
+  display: flex;
+  align-items: center;
+
+  &:focus {
+    outline: none;
+  }
+
+  .right-menu-item {
+    display: inline-block;
+    margin: 0 8px;
+  }
+
+  .screenfull {
+    height: 20px;
+  }
+
+  .international {
+    vertical-align: top;
+  }
+
+  .theme-switch {
+    vertical-align: 15px;
+  }
+
+  .avatar-container {
+    height: 60px;
+    margin-right: 30px;
+
+    .avatar-wrapper {
+      cursor: pointer;
+      margin-top: 5px;
+      position: relative;
+
+      .user-avatar {
+        width: 40px;
+        height: 40px;
+        border-radius: 10px;
+      }
+
+      .el-icon-caret-bottom {
+        position: absolute;
+        right: -20px;
+        top: 25px;
+        font-size: 12px;
+      }
+    }
+  }
+}
+
+.el-menu-vertical-demo:not(.el-menu--collapse) {
+  width: 180px;
+}
+.el-header {
+  background-color: #fff;
+  padding: 0 !important;
+  border-bottom: 1px solid #f1f1f1;
+  min-width: 1100px;
+}
+.el-menu {
+  overflow: hidden;
+  border: none;
+}
+.con_nav_left {
+  background: #fff;
+  overflow-y: scroll;
+}
+.box-all {
+  height: 100%;
+  overflow: hidden;
+}
+.el-main {
+  background-color: #f0f4fa;
+  height: calc(100vh - 60px);
+  overflow-y: scroll;
+  padding: 10px;
+  min-width: 1100px;
+}
+// .el-main::-webkit-scrollbar {
+//   width: 8px;
+//   background-color: #fff;
+// }
+// .el-main::-webkit-scrollbar-thumb {
+//   background-color: #;
+// }
+.logo-box {
+  cursor: pointer;
+  width: 90px;
+  border-bottom: 1px solid #101117;
+  background: #191a23;
+}
+.logo-box .logo {
+  width: 30px;
+  height: 30px;
+  margin-right: 5px;
+  border-radius: 6px;
+}
+.logo-box div {
+  font-size: 16px;
+  font-weight: 600;
+}
+.wn {
+  height: 26px;
+  width: 26px;
+  margin-right: 12px;
+  cursor: pointer;
+}
+.hea-right {
+  padding: 0 20px;
+}
+.upgrade {
+  margin-left: 10px;
+  margin-right: 10px;
+}
+/deep/ .el-menu-item {
+  padding-right: 10px !important;
+}
+/deep/ .el-menu-item.is-active {
+  color: #409eff;
+  background-color: #ecf5ff;
+}
+/deep/ .el-submenu .el-menu-item {
+  min-width: 180px;
+  box-sizing: border-box;
+}
+.main-left {
+  background: #191a23;
+  -webkit-box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
+  box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
+  .flex-center-center {
+    // margin-top: 60px;
+  }
+}
+</style>

+ 303 - 0
src/course/setting/home.vue

@@ -0,0 +1,303 @@
+<template>
+  <div class="page">
+    <el-header height="">
+      <el-button type="primary" size="default" @click="setManage" plain
+        >设置管理员</el-button
+      >
+    </el-header>
+    <el-container class="course_data">
+      <el-table
+        :data="manageList"
+        border
+        stripe
+        highlight-current-row
+        v-loading="loading"
+      >
+        <el-table-column prop="accountName" label="用户名" align="center">
+        </el-table-column>
+        <el-table-column label="手机号" align="center">
+          <template slot-scope="scope">
+            {{ scope.row.accountMobile }}
+          </template>
+        </el-table-column>
+        <el-table-column fixed="right" label="操作" width="250" align="center">
+          <template slot-scope="scope">
+            <el-button type="text" v-if="showDel(scope.row)" @click="courseDel(scope.row, scope.$index)"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="proness">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          @current-change="curPageChange()"
+          :current-page.sync="page.cur"
+          :page-size="page.size"
+          :total="page.total"
+          :hide-on-single-page="true"
+        >
+        </el-pagination>
+      </div>
+    </el-container>
+    <el-dialog
+      title="设置管理员"
+      :visible.sync="showSetting"
+      :close-on-press-escape="false"
+      width="32%"
+      @close="cancle()"
+    >
+      <el-input
+        v-model="searchTel"
+        placeholder="输入手机号精确查找"
+        size="normal"
+        clearable
+        @keyup.enter.native="userSearch"
+      >
+        <el-button
+          slot="append"
+          icon="el-icon-search"
+          @click="userSearch"
+        ></el-button>
+      </el-input>
+      <el-container direction="vertical">
+        <div class="flex-box">
+          <div
+            class="userLi"
+            v-for="(item, index) in userList"
+            :key="index"
+            :class="{ active: item.active }"
+            @click="selectMange(item, index)"
+          >
+            <userImage
+              width="40px"
+              height="40px"
+              fontSize="14"
+              :user_name="item.accountName"
+              :img_url="item.img_url"
+            ></userImage>
+            <span>{{ item.accountName }}</span>
+          </div>
+        </div>
+      </el-container>
+
+      <span slot="footer">
+        <el-button @click="cancle()">取消</el-button>
+        <el-button type="primary" @click="manageSetting()">保存</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { Loading } from "element-ui";
+import { getAdminList, deleteAdmin, addAdmin, getAssignAccount } from "../api";
+import { validateTel } from "@/utils/validate";
+export default {
+  name: "",
+  components: {},
+  props: [],
+  data() {
+    return {
+      loading: true,
+      showSetting: false,
+      searchTel: "",
+      page: {
+        total: 1000,
+        size: 10,
+        cur: 1,
+      },
+      manageList: [],
+      userList: [],
+    };
+  },
+  created() {
+    this.getList();
+  },
+  computed:{
+    showDel(row){
+      return (row)=>{
+        return !(localStorage.getItem('Course-Id') == row.auId)
+      }
+    }
+  },
+  methods: {
+    // 删除管理员
+    deleteAdmin(id) {
+      deleteAdmin(id).then((res) => {
+        this.$message({
+          message: "删除管理员成功",
+          type: "success",
+          showClose: true,
+          duration: 3000,
+        });
+        this.page.cur = 1;
+        this.page.total = 0;
+        this.loading = true;
+        this.getList();
+      });
+    },
+    // 添加管理员
+    addAdmin(id) {
+      addAdmin(id).then((res) => {
+        this.$message({
+          message: "添加管理员成功",
+          type: "success",
+          showClose: true,
+          duration: 3000,
+        });
+        this.searchTel = "";
+        this.page.cur = 1;
+        this.page.total = 0;
+        this.loading = true;
+        this.getList();
+        this.cancle();
+      });
+    },
+    //获取管理员列表
+    getList() {
+      let data = {
+        page: this.page.cur,
+        pageSize: this.page.size,
+      };
+      getAdminList(data).then((res) => {
+        this.loading = false;
+        this.manageList = res.list;
+        this.page.cur = res.current;
+        this.page.total = res.total;
+      });
+    },
+    // 初始化表单并关闭弹窗
+    cancle() {
+      this.userList = [];
+      this.showSetting = false;
+    },
+    // 选择用户为管理员备选
+    selectMange(item, index) {
+      this.userList[index].active = !this.userList[index].active;
+    },
+    // 用户手机号搜索
+    userSearch() {
+      let rule = new RegExp(/^(?:(?:\+|00)86)?1[3-9]\d{9}$/)
+      if (rule.test(this.searchTel)) {
+        let data = {
+          mobile: this.searchTel,
+        };
+        getAssignAccount(data).then((res) => {
+          res.active = false;
+          this.userList =[res];
+        });
+      } else {
+        this.$message({
+          message: "请输入正确的手机号格式",
+          type: "warning",
+          showClose: true,
+          duration: 1500,
+        });
+      }
+    },
+    // 查询已选择管理员人数
+    sureActiveUser() {
+      let leng = 0;
+      this.userList.forEach((item) => {
+        item.active ? leng++ : "";
+      });
+      return leng;
+    },
+    pageReset() {
+      this.page.cur = 1;
+      this.page.total = 0;
+    },
+    //表单提交为管理员
+    manageSetting() {
+      if (this.sureActiveUser() == 1) {
+        this.$confirm("确定要将此用户设置为管理员吗?", "提示", {
+          confirmButtonText: "确认",
+          cancelButtonText: "取消",
+          type: "info",
+        })
+          .then(() => {
+            let activeItem;
+            this.userList.forEach((item, index) => {
+              if (item.active) {
+                activeItem = item;
+              }
+            });
+            this.addAdmin(activeItem.accountId);
+          })
+          .catch((err) => {
+            console.log(err);
+          });
+      } else {
+        this.$message({
+          message: "请搜索并选择用户作为管理员",
+          type: "info",
+          showClose: true,
+          duration: 2000,
+        });
+      }
+    },
+    //打开设置管理员弹窗
+    setManage() {
+      this.showSetting = true;
+    },
+    // 切换当前页
+    curPageChange() {
+      this.getList();
+    },
+    // 删除管理员
+    courseDel(row) {
+      this.$confirm("确定要删除当前用户吗?", "提示", {
+        confirmButtonText: "确认",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          this.deleteAdmin(row.auId);
+        })
+        .catch(() => {});
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.page {
+  padding: 15px;
+  background-color: #fff;
+  border-radius: 5px;
+  .course_data {
+    margin-top: 25px;
+    display: block;
+    .proness {
+      margin-top: 20px;
+      display: flex;
+      justify-content: center;
+    }
+  }
+  .flex-box {
+    margin-top: 5px;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    .userLi {
+      padding: 5px 0;
+      cursor: pointer;
+      width: 70px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      word-break: break-all;
+      text-align: center;
+      margin: 10px 5px;
+      border-radius: 5px;
+      box-sizing: border-box;
+      &.active {
+        border: 1px solid #409eff;
+        span {
+          color: #409eff;
+        }
+      }
+    }
+  }
+}
+</style>

+ 406 - 0
src/course/statistics/home.vue

@@ -0,0 +1,406 @@
+<template>
+  <div class="page">
+    <el-container direction="vertical">
+      <el-tabs v-model="activeIndex" @tab-click="handleClick">
+        <el-tab-pane label="经销商订购情况" name="1"> </el-tab-pane>
+        <el-tab-pane label="课程订购情况" name="2"></el-tab-pane>
+      </el-tabs>
+        <div class="flex-box" style="margin-bottom: 10px;">
+          <el-date-picker
+            v-model="searchTime"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+          >
+          </el-date-picker>
+          <div class="search" v-if="activeIndex == '1'">
+            <el-input
+              placeholder="搜索经销商"
+              v-model.trim="searchDealer"
+              @input="dealerSearch"
+            >
+              <i slot="prefix" class="el-input__icon el-icon-search"></i>
+            </el-input>
+          </div>
+          <!-- @keyup.enter.native="courseSearch" -->
+          <div class="search" v-else>
+            <el-input
+              placeholder="搜索课程"
+              v-model.trim="searchText"
+              @input="courseSearch"
+            >
+              <i slot="prefix" class="el-input__icon el-icon-search"></i>
+            </el-input>
+          </div>
+          <el-select
+            v-model="sortValue"
+            placeholder="排序"
+            @change="recordList.sort(sortBy('amount', sortValue))"
+          >
+            <el-option
+              v-for="item in sortOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+        </div>
+      <el-container direction="vertical">
+        <el-table :data="recordList" border stripe v-loading="loading">
+          <el-table-column
+            label="经销商"
+            align="center"
+            v-if="activeIndex == '1'"
+          >
+            <template slot-scope="scope">{{ scope.row.userName }}</template>
+          </el-table-column>
+          <el-table-column
+            label="手机号"
+            align="center"
+            v-if="activeIndex == '1'"
+          >
+            <template slot-scope="scope">{{
+              scope.row.mobile == "" ? "无" : scope.row.mobile
+            }}</template>
+          </el-table-column>
+          <el-table-column
+            prop="subjectName"
+            label="课程标题"
+            align="center"
+            v-if="activeIndex == '2'"
+          ></el-table-column>
+          <el-table-column label="时间区间" align="center">
+            <template slot-scope="scope">{{
+              scope.row.timeScope == "" ? "全部" : scope.row.timeScope
+            }}</template>
+          </el-table-column>
+          <el-table-column
+            prop="amount"
+            label="经销商订购量(套)"
+            align="center"
+          ></el-table-column>
+          <el-table-column label="操作" align="center">
+            <template slot-scope="scope">
+              <el-button type="text" size="default" @click="toDetail(scope.row)"
+                >查看明细</el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-container>
+      <!-- <div class="proness">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          @current-change="curPageChange(1)"
+          :current-page.sync="page.cur"
+          :page-size="page.size"
+          :total="page.total"
+          :hide-on-single-page="true"
+        >
+        </el-pagination>
+      </div> -->
+    </el-container>
+    <el-dialog
+      :title="recordTit"
+      :visible.sync="showDetail"
+      width="80%"
+      center
+      @close="cancle()"
+    >
+      <el-table :data="recordDetails" border stripe v-loading="rLoading">
+        <el-table-column
+          :label="fromPerson"
+          align="center"
+        >
+          <template slot-scope="scope">{{ scope.row.fromUserName }}</template>
+        </el-table-column>
+        <el-table-column
+          label="发起人手机号"
+          align="center"
+        >
+          <template slot-scope="scope">{{ scope.row.fromUserMobile===0?'平台增加':scope.row.fromUserMobile }}</template>
+        </el-table-column>
+        <el-table-column
+          :label="toPerson"
+          align="center"
+        >
+          <template slot-scope="scope">{{ scope.row.toUserName}}</template>
+        </el-table-column>
+        <el-table-column
+          label="接收人手机号"
+          align="center"
+        >
+          <template slot-scope="scope">{{ scope.row.toUserMobile===0?'平台扣除':scope.row.toUserMobile}}</template>
+        </el-table-column>
+        <el-table-column
+          prop="subjectName"
+          label="课程名称"
+          align="center"
+          v-if="activeIndex == '1'"
+        ></el-table-column>
+        <el-table-column label="名额变动数量" align="center">
+          <template slot-scope="scope">{{ scope.row.amount }}</template>
+        </el-table-column>
+        <el-table-column
+          prop="content"
+          label="备注"
+          align="center"
+        ></el-table-column>
+        <el-table-column
+          prop="createTime"
+          label="创建时间"
+          align="center"
+        ></el-table-column>
+      </el-table>
+      <div class="proness">
+        <el-pagination
+          background
+          layout="prev, pager, next"
+          @current-change="curPageChange(2)"
+          :current-page.sync="page1.cur"
+          :page-size="page1.size"
+          :total="page1.total"
+          :hide-on-single-page="true"
+        >
+        </el-pagination>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  getDealerOrCourseRecode,
+  getDealerOrderList,
+  getCourseOrderList,
+} from "../api";
+export default {
+  name: "statistics",
+  components: {},
+  props: [],
+  data() {
+    return {
+      toPerson:'接收人姓名\n(名额交易接收人)',
+      fromPerson:'发起人姓名\n(名额交易发起人)',
+      loading:true,
+      rLoading:true,
+      page: {
+        total: 0,
+        size: 10,
+        cur: 1,
+      },
+      page1: {
+        total: 0,
+        size: 10,
+        cur: 1,
+      },
+      showDetail: false,
+      recordTit:"记录明细",
+      searchTime: null,
+      searchText: "",
+      searchDealer: "",
+      activeIndex: "1",
+      sortValue: 0,
+      sortOptions: [
+        {
+          label: "由多到少",
+          value: 0,
+        },
+        {
+          label: "由少到多",
+          value: 1,
+        },
+      ],
+      recordList: [],
+      recordDetails: [],
+      subjectId:0,
+      userId:0,
+    };
+  },
+  watch: {
+    searchTime() {
+      if (this.activeIndex == "1") {
+        this.getList();
+      } else {
+        this.getCourseList();
+      }
+    },
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    sortBy(attr, type) {
+      let rev = type ? 1 : -1;
+      if (rev == undefined) {
+        rev = 1;
+      } else {
+        rev ? 1 : -1;
+      }
+      return function (a, b) {
+        a = a[attr];
+        b = b[attr];
+        if (a < b) {
+          return rev * -1;
+        }
+        if (a > b) {
+          return rev * 1;
+        }
+        return 0;
+      };
+    },
+    //获取经销商统计列表
+    getList() {
+      let data = {
+        page: this.page.cur,
+        size: this.page.size,
+      };
+      if (this.searchTime && this.searchTime.length > 0) {
+        data.startDate = this.searchTime[0];
+        data.endDate = this.searchTime[1];
+      }
+      if (this.searchDealer) {
+        data.keyword = this.searchDealer;
+      }
+      getDealerOrderList(data).then((res) => {
+        this.loading = false
+        this.page.cur = res.current;
+        this.page.total = res.total;
+        res.list.sort(this.sortBy('amount', this.sortValue))
+        this.recordList = res.list;
+      });
+    },
+    //获取课程统计列表
+    getCourseList() {
+      let data = {
+        page: this.page.cur,
+        size: this.page.size,
+      };
+      if (this.searchTime && this.searchTime.length > 0) {
+        data.startDate = this.searchTime[0];
+        data.endDate = this.searchTime[1];
+      }
+      if (this.searchText) {
+        data.keyword = this.searchText;
+      }
+      getCourseOrderList(data).then((res) => {
+        this.loading = false
+        this.page.cur = res.current;
+        this.page.total = res.total;
+        res.list.sort(this.sortBy('amount', this.sortValue))
+        this.recordList = res.list;
+      });
+    },
+    //获取指定经销商/课程的订购明细
+    getAssignDrtailList() {
+      let data = {
+        page: this.page1.cur,
+        pageSize: this.page1.size,
+      };
+      if (this.userId) {
+        data.userId = this.userId;
+      } else if(this.subjectId) {
+        data.subjectId = this.subjectId;
+      }
+      if (this.searchTime && this.searchTime.length > 0) {
+        data.startDate = this.searchTime[0];
+        data.endDate = this.searchTime[1];
+      }
+      getDealerOrCourseRecode(data).then((res) => {
+        this.rLoading = false
+        this.recordDetails = res.list;
+          this.page1.cur = res.current;
+          this.page1.total = res.total;
+      });
+    },
+    // 切换当前页
+    curPageChange(type) {
+      if (type == 1&&this.activeIndex == '1') {
+        this.loading = true
+        this.getList();
+      } else if (type == 1&&this.activeIndex != '1'){
+        this.loading = true
+        this.getCourseList(1,this.userId);
+      }else if(type == 2){
+        this.rLoading = true
+        this.getAssignDrtailList()
+      }
+    },
+    // 初始化明细表单并关闭弹窗
+    cancle() {
+      this.recordDetails=[]
+      this.page1.cur = 1;
+      this.page1.total = 0;
+      this.subjectId = 0;
+      this.userId = 0;
+      this.showDetail = false;
+    },
+    // 查看明细
+    toDetail(row) {
+      if (row.userId && !row.subjectId) {
+        this.rLoading = true
+        this.userId = row.userId;
+        this.recordTit = `${row.userName}的记录明细`
+        this.getAssignDrtailList(1);
+      } else if (!row.userId && row.subjectId) {
+        this.recordTit = `${row.subjectName}的记录明细`
+        this.rLoading = true
+        this.subjectId = row.subjectId;
+        this.getAssignDrtailList(2);
+      }
+      this.showDetail = true;
+    },
+    // 课程搜索
+    courseSearch() {
+      this.loading = true
+      this.getCourseList();
+    },
+    // 经销商名称搜索
+    dealerSearch() {
+      this.loading = true
+      this.getList();
+    },
+    // 导航标签切换
+    handleClick() {
+      this.sortValue= 0;
+      this.searchTime = null;
+      this.searchText = "";
+      this.searchDealer = "";
+      this.recordList = [];
+      if (this.activeIndex == "1") {
+        this.loading = true
+        this.getList();
+      } else {
+        this.loading = true
+        this.getCourseList();
+      }
+    },
+  },
+};
+</script>
+<style scoped lang="scss">
+.page {
+  padding: 15px;
+  background-color: #fff;
+  border-radius: 5px;
+  .search {
+    margin: 0 20px;
+  }
+  .proness {
+    display: flex;
+    justify-content: center;
+    margin-top: 20px;
+  }
+}
+/deep/ .el-tabs__item.is-active,
+.el-tabs__item:hover {
+  font-weight: 600 !important;
+}
+/deep/ .el-table .cell{
+  white-space: pre-line;
+}
+</style>

+ 262 - 0
src/course/user/login.vue

@@ -0,0 +1,262 @@
+<template>
+  <div class="login-container">
+    <div class="flex-box">
+      <div
+        class="login-left flex-1"
+        style="background-image: url(static/images/login-left.png)"
+      >
+        <div class="left-content">
+          <div class="logo" style="text-align: center; margin-bottom: 2%">
+            <img src="static/images/logo.png" />
+          </div>
+          <el-carousel indicator-position="outside" :interval="5000">
+            <el-carousel-item
+              style="text-align: center; font-size: 26px; color: #fff"
+            >
+              <div style="margin-bottom: 2.2%; letter-spacing: 3px">
+                管理执行难,就用功道云
+                <br />
+                功到自然成
+              </div>
+              <div
+                class="flex-box-v flex-center-center"
+                style="width: 76%; margin: 0 auto"
+              >
+                <img src="static/images/login1.png" style="width: 100%" />
+              </div>
+            </el-carousel-item>
+            <el-carousel-item
+              style="text-align: center; font-size: 26px; color: #fff"
+            >
+              <div style="margin-bottom: 6.5%; letter-spacing: 3px">
+                积分赋能
+                <br />
+                成就员工价值
+              </div>
+              <div
+                class="flex-box-v flex-center-center"
+                style="width: 76%; margin: 0 auto"
+              >
+                <img src="static/images/login2.png" style="width: 100%" />
+              </div>
+            </el-carousel-item>
+          </el-carousel>
+          <div
+            style="
+              text-align: center;
+              color: #fff;
+              margin-top: 3%;
+              letter-spacing: 2px;
+            "
+          >
+            <div style="font-size: 18px">100000+用户都选择功道云</div>
+            <img
+              src="static/images/loginBot.png"
+              style="width: 80%; margin: 2% 0"
+            />
+            <div style="font-size: 14px">
+              如需帮助,请拨打咨询热线:400-6877-880
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="login-right flex-2" style="position: relative">
+        <div class="login_input">
+          <div class="third-login-box">
+            <!-- <p class="third-account" @click="getToken">平台ID登录</p>
+            <el-input
+              v-model="testId"
+              placeholder="请输入平台ID,回车登录"
+              size="normal"
+              style="width: 250px; margin: 0 0 20px"
+              clearable
+              @keyup.enter.native="getToken(testId)"
+            ></el-input> -->
+            <p class="third-account">微信扫码登录</p>
+            <div class="account-login">
+              <a
+                data-href="/thirdlogin/wechat.do?appId=1006"
+                class="wechat-login"
+                @click="openWx"
+                style="background-image: url(static/images/wechat1.png)"
+              ></a>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <el-dialog
+      title="微信登录"
+      :visible.sync="isShowWxLogin"
+      append-to-body
+      width="500px"
+    >
+      <div>
+        <iframe :src="wxUrl" width="100%" height="400" frameborder="0"></iframe>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { setCourseToken, setCourseId, _debounce } from "@/utils/auth";
+import { getUserToken, getAdminTokenId } from "../api";
+export default {
+  data() {
+    return {
+      testId: "11770",
+      isShowWxLogin: false,
+      // wxUrl:process.env.BASE_API+'/wechat/auth/web?ct=1',
+      wxUrl: "https://oa.g107.com/wechat/auth/web?ct=1",
+    };
+  },
+  methods: {
+    init() {
+      this.clearData(); //进入登录界面,清除本地缓存,主要是避免用户意外清除cookies后造成本地缓存依然存在,重新登陆后显示上次的缓存,或特殊情况本地缓存未清空又登录别的账号。
+      document.title = "功道云-课程营销用户登录";
+    },
+    //临时指定id获取用户token(11770)
+    getToken(id) {
+      getUserToken(id)
+        .then((token) => {
+          this.getAccountIdToken(token);
+        })
+        .catch((err) => {
+          console.log(err);
+        });
+    },
+    //根据用户token获取用户adminUserId和auToken
+    getAccountIdToken(token) {
+      getAdminTokenId(token)
+        .then((res) => {
+          localStorage.setItem("Course-Token", res.auToken);
+          localStorage.setItem("Course-Id", res.adminUserId);
+          localStorage.setItem("course_path", 2);
+          this.$message({
+            message: "登录成功!",
+            type: "success",
+            showClose: true,
+            duration: 2000,
+          });
+          this.$router.push("/course");
+        })
+        .catch((err) => {
+          console.log(err);
+        });
+    },
+    // 微信扫码
+    openWx() {
+      this.isShowWxLogin = true;
+    },
+    // 清缓存
+    clearData() {
+      // localStorage.clear();
+      // sessionStorage.clear();
+    },
+  },
+  created() {
+    this.init();
+  },
+};
+</script>
+
+<style rel="stylesheet/css" type="text/css" scoped>
+.third-login-box {
+  position: absolute;
+  top: 400px;
+  left: 0;
+  right: 0;
+}
+.third-account {
+  text-align: center;
+  margin-bottom: 15px;
+  color: #999999;
+}
+.account-login {
+  text-align: center;
+}
+.wechat-login {
+  width: 100px;
+  height: 100px;
+  background-color: #dddddd;
+  background-repeat: no-repeat;
+  background-position: center;
+  border-radius: 50%;
+  cursor: pointer;
+}
+.wechat-login:hover {
+  background-color: #67c23a;
+}
+.account-login a {
+  display: inline-block;
+}
+.login-left {
+  min-width: 500px;
+  min-height: 700px;
+  height: 100vh;
+  /* background: url('/static/images/login-left.png') no-repeat; */
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+  position: relative;
+  filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/static/images/login-left.png', sizingMethod='scale');
+  -ms-behavior: url("/static/images/login-left.png");
+  behavior: url("/static/images/login-left.png");
+}
+.login_input {
+  position: relative;
+  text-align: center;
+  width: 508px;
+  height: 376px;
+  background: #fff;
+  /* overflow: hidden; */
+  top: 0;
+  margin: 0 auto 0 auto;
+}
+.login-container {
+  height: 100%;
+}
+
+@media screen and (min-width: 1601px) {
+  .left-content {
+    height: 800px;
+    position: relative;
+    top: 50%;
+    margin-top: -400px;
+  }
+  /deep/ .el-carousel__container {
+    position: relative;
+    height: 460px;
+  }
+}
+/* 设置了浏览器宽度不小于1201px时 abc 显示1200px宽度*/
+@media screen and (max-width: 1600px) {
+  .left-content {
+    height: 680px;
+    position: relative;
+    top: 50%;
+    margin-top: -340px;
+  }
+  /deep/ .el-carousel__container {
+    position: relative;
+    height: 330px;
+  }
+}
+/deep/ .el-carousel__indicators--outside {
+  text-align: center;
+  position: static;
+  -webkit-transform: none;
+  transform: none;
+  /* margin-top: 20px; */
+}
+/deep/ .el-carousel__button {
+  height: 8px;
+  width: 8px;
+  border-radius: 100%;
+  background-color: #fff;
+}
+/deep/ .is-active .el-carousel__button {
+  width: 30px;
+  border-radius: 5px;
+  background-color: #fff;
+}
+</style>

+ 5 - 0
src/course/utils/index.js

@@ -0,0 +1,5 @@
+export function filterWhite(list,path){
+    return list.some((item)=>{
+        return item.includes(path)
+    })
+}

文件差異過大導致無法顯示
+ 0 - 0
src/icons/iconfont.js


+ 5 - 1
src/main.js

@@ -7,7 +7,7 @@ import moment from 'moment' // 时间库
 import App from './App'
 import router from './router'
 import store from './store'
-import {getDept,openUrl, getToken, getTyps, getTypsName, supremeAuthority, getUserData, getEmployeeMap,getEmployeeMapAll,getEmployeeMapItem,getIsIdentity,getCache,setCache,removeCache,returnDeptName,getIsAdministrator} from '@/utils/auth'
+import {getDept,openUrl, getToken, getCourseId,getTyps,getLocal, getTypsName, supremeAuthority, getUserData, getEmployeeMap,getEmployeeMapAll,getEmployeeMapItem,getIsIdentity,getCache,setCache,removeCache,returnDeptName,getIsAdministrator} from '@/utils/auth'
 import './performanceSet' // 绩效系统相关配置
 import {onFilePreView } from '@/okr/utils/auth';
 // import { VueOkrTree } from "vue-okr-tree";
@@ -22,6 +22,7 @@ import * as filters from '@/utils/filters'
 import axiosKq from '@/utils/axiosKq'
 import axiosUser from '@/utils/axiosUser'
 import axios from '@/utils/axios'
+import axiosKc from '@/utils/axiosKc'
 import * as socketApi from './api/websocket'
 import * as socketApiTow from './api/websocketTow'
 import ECharts from 'echarts';
@@ -43,8 +44,10 @@ Vue.prototype.$echarts = ECharts
 Vue.prototype.$axios = axios
 Vue.prototype.$axiosUser = axiosUser
 Vue.prototype.$axiosKq = axiosKq
+Vue.prototype.$axiosKc = axiosKc
 Vue.prototype.$moment = moment
 Vue.prototype.$getToken = getToken
+Vue.prototype.$getCourseId = getCourseId
 Vue.prototype.$serveAd = process.env.SERVE_AD
 Vue.prototype.$serverdomain= process.env.BASE_API
 Vue.prototype.$getIsIdentity = getIsIdentity //在积分系统里 判断是否具备某项权限
@@ -57,6 +60,7 @@ Vue.prototype.$getEmployeeMap = getEmployeeMap  //人员列表
 Vue.prototype.$getEmployeeMapAll = getEmployeeMapAll  //人员列表(包含已删除的)
 Vue.prototype.$getEmployeeMapItem = getEmployeeMapItem  //查询人员信息(包含已删除的)
 Vue.prototype.$getCache = getCache
+Vue.prototype.$getLocal = getLocal
 Vue.prototype.$setCache = setCache
 Vue.prototype.$removeCache = removeCache
 Vue.prototype.$socketApi = socketApi   //长连接

+ 8 - 4
src/okr/components/project/Milestone.vue

@@ -213,7 +213,7 @@
             </Tooltip>
           </div>
           <span>权重</span>
-          <el-input@input="item.weight = item.weight.replace(/[^\d]/g, '');" class="input" style="width: 80px;" size="small" v-model="item.weight" clearable/>
+          <el-input @input="item.weight = item.weight.replace(/[^\d]/g, '');" class="input" style="width: 80px;" size="small" v-model="item.weight" clearable/>
           <span>%</span>
         </div>
         <div class="flex-box-ce flex-box-end" style="margin-top: 20px;">
@@ -675,14 +675,18 @@
       },
       returnStatus(item){
         //statistics.plan_primary_delay		主任务中逾期的任务
-        let isGq=this.$moment().format('YYYY-MM-DD')>item.end_date;//是否过期
+        let isGq= new Date().getTime() > new Date(item.end_date).getTime();//是否过期
+        let plansStatusArr = []
+        item.plans.forEach(item2=>{
+          plansStatusArr.push(taskStatus(item2.composite_state))
+        })
         let status='#409EFF';
         if(isGq){
-          if(item.statistics.plan_primary_delay>0){
+          if(plansStatusArr.some(e=>e.value == 3)){
             status='#f56c6c';
           }
         }else{
-          if(item.statistics.plan_primary_delay>0){
+          if(plansStatusArr.some(e=>e.value == 3)){
             status='#FF9600';
           }
         }

+ 26 - 8
src/okr/components/project/ProjectTj.vue

@@ -1,13 +1,20 @@
 <template>
   <div class="br-5 scroll-bar" style="height: calc(100vh - 258px);overflow-y: scroll;">
-    <div style="overflow-x: auto;" class="scroll-bar">
-      <div class="flex-box-ce header">
-          <div class="tab-item clamp" :class="{'active':0==milestone_id}" @click="milestone_id=0">项目总览</div>
-          <div class="tab-item clamp" :class="{'active':item.id==milestone_id}" v-for="(item, index) in milestoneList" :key="index" @click="milestone_id=item.id">
-             <Tooltip :preHtml="item.name">
-             <span>{{item.name}}</span>
-             </Tooltip>
-          </div>
+    <div class="circular_header">
+      <div style="overflow-x: auto;flex: 1;" class="scroll-bar">
+        <div class="flex-box-ce header">
+            <div class="tab-item clamp" :class="{'active':0==milestone_id}" @click="milestone_id=0">项目总览</div>
+            <div class="tab-item clamp" :class="{'active':item.id==milestone_id}" v-for="(item, index) in milestoneList" :key="index" @click="milestone_id=item.id">
+              <Tooltip :preHtml="item.name">
+              <span>{{item.name}}</span>
+              </Tooltip>
+            </div>
+        </div>
+      </div>
+      <div class=" circular_headerL" >
+        <Tooltip preHtml="本页面统计项目内的所有任务数(含子任务)">
+          <span><i class="el-icon-question" style="font-size: 16px;position: relative;top: 1px;"></i>统计说明</span>
+          </Tooltip>
       </div>
     </div>
     <div class="flex-box-ce" style="margin-bottom: 10px;" v-loading="loading">
@@ -377,6 +384,17 @@ export default {
 .select ::v-deep .el-input__inner {
   border-radius: 25px;
 }
+.circular_header{
+  display: flex;
+  justify-content: space-between;
+  // align-items: center;
+  &L{
+    width: 85px;
+    line-height: 33px;
+    display: flex;
+    flex-direction: row-reverse;
+  }
+}
 .circular_item {
   background-color: #F7F8FA;
   padding: 20px;

+ 1 - 1
src/okr/components/public/TaskItem.vue

@@ -268,7 +268,7 @@ export default {
               item.day=this.$moment(item.end_date).diff(this.$moment().format('YYYY-MM-DD'), 'day');
               item.isShow=false;
             })
-            console.log("渲染了",list,this.isParent,this.isShowChild)
+            // console.log("渲染了",list,this.isParent,this.isShowChild)
             this.parentList=list;
 
           }

+ 4 - 3
src/okr/views/project/myProject.vue

@@ -80,9 +80,10 @@
                           <span>{{$moment(item.end_date).format('MM/DD')}}截止</span>
                         </template>
                         <template v-else>
-                          <span v-if="item.day>0" class="green">剩余{{item.day}}天</span>
-                          <span v-if="item.day==0" class="green">剩余1天</span>
-                          <span v-if="item.day<0" class="red">逾期{{Math.abs(item.day)}}天</span>
+                          <span v-if="item.day>0&&item.composite_state != 4" class="green">剩余{{item.day}}天</span>
+                          <span v-if="item.day==0&&item.composite_state != 4" class="green">剩余1天</span>
+                          <span v-if="item.day<0&&item.composite_state != 4" class="red">逾期{{Math.abs(item.day)}}天</span>
+                          <span v-if="item.composite_state == 4">{{$moment(item.end_date).format('YY/MM/DD')}}截止</span>
                         </template>
                         <Progress :inputStyle="{ height: '14px', width: '140px', lineHeight: '14px' }" :status="item.composite_state==3? 3:1" :value="Number(item.process)" style="margin-left: 10px;"></Progress>
                       </div>

+ 16 - 5
src/okr/views/project/projectDetail.vue

@@ -193,20 +193,25 @@
       keyword: {
         deep: true,
         handler: _debounce(function(val) {
+          this.$store.commit('setProjectDetailTaskPage',1)
           this.getPastTask();
         })
       },
       'taskForm.composite_states'(){
-          this.getPastTask();
+        this.$store.commit('setProjectDetailTaskPage',1)
+        this.getPastTask();
       },
       'taskForm.owner_ids'(){
-          this.getPastTask();
+        this.$store.commit('setProjectDetailTaskPage',1)
+        this.getPastTask();
       },
       'taskForm.sort'(){
-          this.getPastTask();
+        this.$store.commit('setProjectDetailTaskPage',1)
+        this.getPastTask();
       },
       tabsIndex(val,lat){
         if(val==1){
+          this.$store.commit('setProjectDetailTaskPage',1)
           this.getPastTask();
         }
         if(lat==7){
@@ -216,6 +221,7 @@
     },
     created() {
         if(this.$route.query.id){
+          this.$store.commit('setProjectDetailTaskPage',1)
           this.projectId=Number(this.$route.query.id);
           this.getProjectDateil();
           this.$nextTick(()=>{
@@ -285,7 +291,10 @@
         this.tabsIndex = item.code;
       },
       getPastTask(is){
-        is? '':this.page=1;
+        // is? '':this.page=1;
+        if(!is){
+          this.page = (this.$store.state.okrStore.projectDetailTaskPage!=0)?this.$store.state.okrStore.projectDetailTaskPage:1
+        }
         this.taskShow=false;
         let data={
           project_id:this.projectId,
@@ -293,7 +302,8 @@
           start_day:'2022-01-01',
           end_day:this.$moment().format('YYYY-MM-DD'),
           employee_id:this.userInfo.id,
-          page:is? this.page:1,
+          // page:is? this.page:1,
+          page:this.page,
           page_size:this.page_size,
           keyword:this.keyword,
         }
@@ -331,6 +341,7 @@
       // 页面跳转
       handleCurrentChange(val) {
         this.page = val;
+        this.$store.commit('setProjectDetailTaskPage',val)
         this.getPastTask(true);
       },
     }

+ 28 - 6
src/performance/views/assessManagement/staffAssDet.vue

@@ -603,7 +603,6 @@ export default {
       isAdjustment:false,
       isDetails:true,//是否显示考核详情页面
       resultData:{},
-
       gradeList: [],
       dropdownMenu: [{ key: 'a', name: '重置流程',isShow:true }, { key: 'b', name: '调整目标',isShow:true }],
       lingScore_infos: [],
@@ -1390,6 +1389,18 @@ export default {
         }
       });
     },
+    deepCopyAndMakeReactive(original, vm) {  
+      if (Array.isArray(original)) {  
+        return original.map(item => this.deepCopyAndMakeReactive(item, vm));  
+      } else if (typeof original === 'object' && original !== null) {  
+        const copy = {};  
+        Object.keys(original).forEach(key => {  
+          this.$set(copy, key, this.deepCopyAndMakeReactive(original[key], vm));  
+        });  
+        return copy;  
+      }  
+      return original;  
+    },
     // 绩效考核详情
     employeeDet(is,func=function(){}) {
       let params = {};
@@ -1687,9 +1698,19 @@ export default {
                }
             });
             points.sort(this.rule("id"))//跟距ID排序
-
-            this.lingScore_infos = points; //表格   评分、说明    头部
-
+            console.log(points)
+            this.lingScore_infos = points;
+            this.isShowOneselfScore = !this.isShowOneselfScore
+            setTimeout(()=>{
+              this.isShowOneselfScore = !this.isShowOneselfScore
+            })
+            // this.lingScore_infos = this.deepCopyAndMakeReactive(points,this)
+            // console.log(this.lingScore_infos)
+            // this.lingScore_infos = []
+            // points.map((item,index) => {
+            //   this.lingScore_infos.push(item)
+            // })
+            // this.$set(this.lingScore_infos,points.map(item => ({ ...item })))
 
             let toScore = {
               theDimension: '总分',
@@ -1725,7 +1746,7 @@ export default {
                 dimeTab[0].zfLeg = dimeTab.length;
               }
             }
-            this.dimension = dimeTab; //表格数据
+            this.dimension = dimeTab.map(item => ({ ...item })); //表格数据
             //记录
             let record = res.data.data.record;
             record.forEach(item => {
@@ -2105,7 +2126,8 @@ export default {
       });
       dimenList.push(totalScore);
       this.$nextTick(()=>{
-         this.dimension = dimenList;
+        //  this.dimension = dimenList;
+         this.dimension = dimenList.map(item => ({ ...item }));
       })
     },
     gradeTurn() {

+ 30 - 14
src/permission.js

@@ -2,16 +2,20 @@ import router from './router'
 import store from './store'
 import Vue from 'vue'
 import NProgress from 'nprogress'
+import { Message } from 'element-ui'
 import 'nprogress/nprogress.css'
-import {getToken,getCache} from '@/utils/auth'
+import { getToken, getCache, getCourseToken } from '@/utils/auth'
 
 NProgress.configure({
   showSpinner: false
 })
-
+function filterWhite(path) {
+  return (path.includes('/course/dealerTeam/') || path.includes('/course/courseEdit/') || path.includes('/course/dealerEdit/') || path.includes('/course/courseRecord/'))
+}
 // 免登名单
-const whiteList = ['/login','/loginbytoken','/reg','/forgetPwd','/resetPwd','/android','/bindingPhone','/demo','/swiperShow', '/weixin','/screen','/screenSan','/tySelect']
-
+const whiteList1 = ['/login', '/loginbytoken', '/reg', '/forgetPwd', '/resetPwd', '/android', '/bindingPhone', '/demo', '/swiperShow', '/weixin', '/screen', '/screenSan', '/tySelect']
+const whiteList2 = ['/course', '/course/statistics','/freeCourseEdit', '/courseLogin', '/course/adminSetting', '/course/courseManage','/course/courseCreate', '/course/dealerManage']
+const whiteList = whiteList1.concat(whiteList2)
 router.beforeEach((to, from, next) => {
   if (Vue.$axiosUserRequestList.length > 0) { // 强行中断时才向下执行
     Vue.$axiosUserRequestList.forEach(item => {
@@ -19,25 +23,37 @@ router.beforeEach((to, from, next) => {
     })
   }
   NProgress.start()
-  if (getToken()) {
-    store.dispatch('get_point_types').then((res) => {})
-    store.dispatch('get_site_info').then((res) => {})
-    store.dispatch('get_account_info').then((res) => {})
-    store.dispatch('get_employee_map').then((res) => {}) // 取得员工列表的地图
-    store.dispatch('get_employee_map_all').then((res) => {}) // 取得员工列表的地图
-    store.dispatch('get_dept_tree').then((res) => {}) // 获取部门树型结构列表
+  if (getToken() && (whiteList2.indexOf(to.path) == -1 || !filterWhite(to.path))) {
+    store.dispatch('get_point_types').then((res) => { })
+    store.dispatch('get_site_info').then((res) => { })
+    store.dispatch('get_account_info').then((res) => { })
+    store.dispatch('get_employee_map').then((res) => { }) // 取得员工列表的地图
+    store.dispatch('get_employee_map_all').then((res) => { }) // 取得员工列表的地图
+    store.dispatch('get_dept_tree').then((res) => { }) // 获取部门树型结构列表
     if (to.path === '/login') {
-      next({path: '/'})
+      next({ path: '/' })
       NProgress.done()
     } else {
       if (!store.getters.user_info.id) { // 判断当前用户是否已拉取完user_info信息
-        store.dispatch('getUserInfo').then(res =>{next()})
+        store.dispatch('getUserInfo').then(res => { next() })
       } else {
         next()
       }
     }
+  } else if (whiteList2.indexOf(to.path) !== -1 || filterWhite(to.path)) {
+    if (localStorage.getItem('Course-Token')||localStorage.getItem('Course-Id')|| to.path == '/courseLogin') {
+      next()
+    } else {
+      Message({
+        message: '未登录!',
+        type:'warning',
+        duration: 2000
+      })
+      console.log(13)
+      next('/courseLogin')
+    }
   } else {
-    if (whiteList.indexOf(to.path) !== -1 || window.location.href.indexOf('loginbytoken/') !== -1) { // 在免登录白名单,直接进入
+    if (whiteList1.indexOf(to.path) !== -1 || window.location.href.indexOf('loginbytoken/') !== -1) { // 在免登录白名单,直接进入
       next()
     } else {
       next('/login') // 否则全部重定向到登录页

+ 9 - 9
src/point/views/attendance/attendance_classnew.vue

@@ -170,8 +170,8 @@
           break_time: ['12:00', '13:00'],
           is_break_time: false,
           is_card: false,
-          allowed_late_time: 30,
-          serious_late_time: 30,
+          // allowed_late_time: 30,
+          // serious_late_time: 30,
           time_list: [{
             id: 0,
             checkin_time: '8:00',
@@ -179,7 +179,7 @@
             end_time: '18:00',
             dinner_time: '18:30'
           }, ],
-          absenteeism_late_time: 30,
+          // absenteeism_late_time: 30,
         },
         multipleSelection: [],
         RuleDetailDialogVisible: false,
@@ -428,9 +428,9 @@
           break_time: ['12:00', '13:00'],
           is_break_time: false,
           is_card: false,
-          allowed_late_time: 3,
-          serious_late_time: 20,
-          absenteeism_late_time: 30,
+          // allowed_late_time: 3,
+          // serious_late_time: 20,
+          // absenteeism_late_time: 30,
           time_list: [{
             id: 0,
             checkin_time: '8:00',
@@ -467,9 +467,9 @@
                 self.formdata.id = res.data.data.id
                 self.formdata.is_break_time = res.data.data.is_break_time == 1
                 self.formdata.is_card = res.data.data.is_card == 1
-                self.formdata.allowed_late_time = res.data.data.allowed_late_time
-                self.formdata.serious_late_time = res.data.data.serious_late_time
-                self.formdata.absenteeism_late_time = res.data.data.absenteeism_late_time
+                // self.formdata.allowed_late_time = res.data.data.allowed_late_time
+                // self.formdata.serious_late_time = res.data.data.serious_late_time
+                // self.formdata.absenteeism_late_time = res.data.data.absenteeism_late_time
 
                 self.RuleDetailDialogVisible = true
               } else {

+ 1 - 0
src/point/views/pointHome.vue

@@ -20,6 +20,7 @@
             </el-carousel-item>
           </el-carousel>
       </div>
+      
       <el-row  style="width: 100%;">
         <el-col :span="18">
           <div class="flex-box-ce br-5" style="background-color: #fff;padding:20px;">

+ 4 - 3
src/point/views/setting/set_role.vue

@@ -21,8 +21,9 @@
             <div class="role_list">
               <div v-loading="table_loading">
                 <el-row style="margin:20px auto 10px;">
-                  <el-col :span="18">
+                  <el-col :span="18" style="display: flex;align-items: center;">
                     <span class="roleNameClass" >{{item_info.name}}</span>
+                    <span class="blue cursor" style="margin-left: 5px;" v-if="item_info.code == 'dept_manager'" @click="isShowImg=true"><i class='el-icon-question'></i>如何添加部门管理员</span>
                   </el-col>
                   <el-col :span="6" style="text-align: right;">
                     <el-button type="text" style=" padding: 0; line-height: initial;" v-show="item_info.code !== 'creator'" @click="dataAccessPopup">数据查看权限></el-button>
@@ -46,7 +47,7 @@
                         <el-button type="primary" @click="add_employee_show = true">添加</el-button>
                         <div style="display: inline-block;" class="orange">有管理范围人员才能进行积分管理和奖扣,别忘了设置哦!</div>
                       </template>
-                      <el-button type="primary" v-if="item_info.code == 'dept_manager'" @click="isShowImg=true">添加管理员</el-button>
+                      <!-- <el-button type="primary" v-if="item_info.code == 'dept_manager'" @click="isShowImg=true">添加管理员</el-button> -->
                       <el-button type="primary" plain v-if="item_info.code == 'dept_manager'" @click="syncScope"><i class="el-icon-refresh"></i>同步管理范围</el-button>
                       <el-button type="success" plain v-if="item_info.code == 'dept_manager'" @click="isShowMessage=true"><i class="el-icon-refresh"></i>同步全部人员及管理范围</el-button>
                       <div class="gap-right-8 fr" style="display:inline-block;" v-if="item_info.code == 'dept_manager'">
@@ -655,7 +656,7 @@
         </el-form-item>
       </el-form>
     </el-dialog>
-    <el-dialog title="添加管理员" :visible.sync="isShowImg">
+    <el-dialog title="添加部门管理员" :visible.sync="isShowImg">
       <div>
          <img src="static/images/tjbmgly.png" style="width: 100%;"/>
       </div>

+ 1 - 0
src/point/views/statistics/dept_rank.vue

@@ -706,6 +706,7 @@ export default {
       return data;
     },
     getEmployeeList() {
+      console.log(123)
       this.$axiosUser('get', '/api/pro/employee/index', { dept_id: this.formData.dept_id }, 'v2').then(res => {
           this.employee_map = res.data.data.list;
       })

+ 113 - 0
src/router/course.js

@@ -0,0 +1,113 @@
+// 在线课程相关
+const routes = [
+    {
+        path: '/',
+        name: 'courseHome',
+        // component: () => import('@/course/home'),
+        label: '课程营销首页',
+        redirect:"/course/courseManage",
+        meta: {
+            keepAlive: true
+        },
+    },
+    {
+        path: 'freeCourseEdit',
+        name: 'freeCourseEdit',
+        component: () => import('@/course/courseManage/freeEdit'),
+        label: '编辑免费课程',
+        meta: {
+            keepAlive: false
+        },
+    },
+    {
+        path: 'courseManage',
+        name: 'courseManage',
+        component: () => import('@/course/courseManage/home'),
+        label: '课程管理',
+        meta: {
+            keepAlive: false
+        },
+    },
+    {
+        path: 'courseEdit/:id',
+        name: 'courseEdit',
+        component: () => import('@/course/courseManage/create'),
+        label: '编辑课程',
+        meta: {
+            keepAlive:false
+        },
+    },
+    {
+        path: 'courseCreate',
+        name: 'courseCreate',
+        component: () => import('@/course/courseManage/create'),
+        label: '创建课程',
+        meta: {
+            keepAlive:false
+        },
+    },
+    {
+        path: 'dealerManage',
+        name: 'dealerManage',
+        component: () => import('@/course/dealerManage/home'),
+        label: '经销商管理',
+        meta: {
+            keepAlive:false
+        },
+    },
+    {
+        path: 'dealerTeam/:id',
+        name: 'dealerTeam',
+        component: () => import('@/course/dealerManage/home'),
+        label: '经销商团队',
+        meta: {
+            keepAlive:true
+        },
+    },
+    {
+        path: 'dealerEdit/:id',
+        name: 'dealerEdit',
+        component: () => import('@/course/dealerManage/edit'),
+        label: '经销商编辑',
+        meta: {
+            keepAlive:false
+        },
+    },
+    {
+        path: 'dealerCreate',
+        name: 'dealerCreate',
+        component: () => import('@/course/dealerManage/edit'),
+        label: '经销商创建',
+        meta: {
+            keepAlive:false
+        },
+    },
+    {
+        path: 'courseRecord/:userId/:courseId',
+        name: 'courseRecord',
+        component: () => import('@/course/dealerManage/record'),
+        label: '课程交易明细',
+        meta: {
+            keepAlive:false
+        },
+    },
+    {
+        path: 'statistics',
+        name: 'courseManage',
+        component: () => import('@/course/statistics/home'),
+        label: '统计',
+        meta: {
+            keepAlive:false
+        },
+    },
+    {
+        path: 'adminSetting',
+        name: 'adminSetting',
+        component: () => import('@/course/setting/home'),
+        label: '管理员设置',
+        meta: {
+            keepAlive:false
+        },
+    }
+]
+export default routes

+ 25 - 4
src/router/index.js

@@ -4,6 +4,7 @@ import VueRouter from 'vue-router'
 import performanceRouter from '@/router/performanceRouter'
 import okrRouter from '@/router/okrRouter'
 import examineRouter from '@/router/examineRouter'
+import courseRouter from '@/router/course'
 /* 角色*/
 /*
 创始人 creator
@@ -186,7 +187,7 @@ const constantRouterMap = [
             }
           },
           {
-           	path: '/allTask',
+            path: '/allTask',
             name: '全部任务',
             component: () => import( /* webpackChunkName: "allTask" */ '@/point/views/workbench/task/allTask'),
             meta: {
@@ -416,7 +417,26 @@ const constantRouterMap = [
       },
     ]
   },
-
+  {
+    path: '/course',
+    component: () => import('@/course/index'),
+    children: []
+  },
+  {
+    path: '/courseLogin',
+    name: 'courseLogin',
+    component: () => import('@/course/user/login'),
+    label: '课程营销登录',
+    meta: {},
+    beforeEnter: (to, from, next) => {
+      //  判断是否需要鉴定一下权限
+      if (localStorage.getItem('Course-Token')&&localStorage.getItem('Course-Id')) {
+        next('/course')
+      } else {
+        next()
+      }
+    }
+  },
   {
     path: '/login',
     name: 'login',
@@ -434,7 +454,7 @@ const constantRouterMap = [
   },
   {
     path: '/weixin',
-    name: 'weixin',    component: () => import('@/views/weixin'),
+    name: 'weixin', component: () => import('@/views/weixin'),
   },
   {
     path: '/reg',
@@ -487,7 +507,8 @@ const constantRouterMap = [
     redirect: '/login'
   },
 ]
-constantRouterMap[0].children.push(...performanceRouter,...okrRouter,...examineRouter);
+constantRouterMap[0].children.push(...performanceRouter, ...okrRouter, ...examineRouter);
+constantRouterMap[1].children.push(...courseRouter);
 export default new VueRouter({
   // mode: 'history',
   routes: constantRouterMap,

+ 5 - 0
src/store/getters.js

@@ -10,5 +10,10 @@ const getters = {
   site_info: state => state.user.site_info,
   account_info: state => state.user.account_info,
   sumTotal: state => state.okrStore.sumTotal,
+  
+  courseToken:state =>state.course.course_token,
+  course_user_info:state=>state.course.course_user_info,
+  course_site_info: state => state.course.course_site_info,
+  course_account_info: state => state.course.course_account_info,
 }
 export default getters

+ 3 - 1
src/store/index.js

@@ -2,13 +2,15 @@ import Vue from 'vue'
 import Vuex from 'vuex'
 import user from './modules/user'
 import okrStore from './modules/okrStore'
+import course from './modules/course'
 import getters from './getters'
 Vue.use(Vuex)
 
 const store = new Vuex.Store({
   modules: {
     user,
-    okrStore
+    okrStore,
+    course
   },
   getters
 })

+ 56 - 0
src/store/modules/course.js

@@ -0,0 +1,56 @@
+import {
+    getUserInfo,
+} from '@/api/course'
+import { removeAllToken, getCache, setCache } from '@/utils/auth'
+import { Message } from 'element-ui'
+import router from '../../router'
+const courseStore = {
+    state: {
+        course_account_info: {
+            "id": 2722,
+            "name": "首页",
+            "img_url": ""
+        },//个人账号信息
+    },
+
+    mutations: {
+        SET_COURSEACCOUNTINFO: (state, data) => {
+            state.course_account_info = data
+        }
+    },
+
+    actions: {
+        // 获取当前管理员信息
+        getCourseUserInfo({ commit }) {
+            return new Promise((resolve, reject) => {
+                getUserInfo().then(response => {
+                    let data = response.data.data.user
+                    commit('SET_COURSEACCOUNTINFO', data)
+                    setCache('course_account', data)
+                    resolve(data)
+                }).catch(error => {
+                    reject(error)
+                })
+            })
+        },
+        // 退出登录
+        CourseLogOut({ commit, state }) {
+            // localStorage.clear()
+            // sessionStorage.clear()
+            localStorage.removeItem("Course-Token")
+            localStorage.removeItem("Course-Id")
+            router.push('/courseLogin')
+            localStorage.setItem('course_path', 2)
+            Message({
+                message: '退出登录',
+                duration: 2000
+            })
+            // Cookies.remove('Course-Token')
+            // Cookies.remove("Course-Id")
+            // removeAllToken()
+            // location.reload() // 重新刷新页面会清空VUEX数据,所以不用清空VUEX
+        },
+    }
+}
+
+export default courseStore

+ 5 - 1
src/store/modules/okrStore.js

@@ -1,13 +1,17 @@
 import axiosUser from '@/utils/axiosUser'
 const okrStore = {
   state: {
-    sumTotal:0
+    sumTotal:0,
+    projectDetailTaskPage:0,
   },
 
   mutations: {
     sumTotal: (state, sumTotal) => {
       state.sumTotal = sumTotal
     },
+    setProjectDetailTaskPage: (state, projectDetailTaskPage) => {
+      state.projectDetailTaskPage = projectDetailTaskPage
+    },
   },
 
   actions: {

+ 2 - 1
src/store/modules/user.js

@@ -8,7 +8,7 @@ import {
   get_dept_tree,
   get_account_info
 } from '@/api/login'
-import {removeAllToken,getCache,setCache} from '@/utils/auth'
+import {removeAllToken,getCache,setCache,resetStorage} from '@/utils/auth'
 import moment from 'moment'
  function  returnArr(list,arr){
       list.forEach(item=>{
@@ -255,6 +255,7 @@ const user = {
       const newNav = getCache('newNav')
       const initImg = getCache('initImg')
       const noticeId = getCache('noticeId')
+      // resetStorage();
       localStorage.clear()
       sessionStorage.clear()
       removeAllToken()

+ 122 - 80
src/utils/auth.js

@@ -5,81 +5,100 @@ import {
 } from 'jsencrypt'
 const publicKey = hexToDec();
 const TokenKey = 'Admin-Token'
+const CourseTokenKey = 'Course-Token'
+const CourseId = 'Course-Id'
 const USER = 'user'
 const PASW = 'pasw'
 
 // 提示跳转
 export function openUrl(num) {
-  let url='http://www.baidu.com';
-  if(num==1){
-    url='https://www.yuque.com/docs/share/4551830c-25c8-44ae-8130-368c88bac624?# 《A分、B分常见问题》'
-  }else if(num==2){
-    url='https://www.yuque.com/docs/share/2300b9bb-84ab-48ae-afd9-a19da38147ba?# 《如何设置自动积分?》'
-  }else if(num==3){
-    url='https://www.yuque.com/docs/share/4cb21924-c9ee-4a4d-91f4-58db8be9547b?# 《基础分、工龄分是什么?》'
-  }else if(num==4){
-    url='https://www.yuque.com/docs/share/971c4cd7-5498-4fd6-a97c-ef08d62079c1?# 《系统配置》'
-  }else if(num==5){
-    url='https://www.yuque.com/docs/share/4551830c-25c8-44ae-8130-368c88bac624?# 《A分、B分常见问题》'
-  }else if(num==6){
-    url='https://www.yuque.com/docs/share/8cae70cf-3961-4e91-848d-d903f0323004?# 《如何邀请员工注册并加入企业?》'
-  }else if(num==7){
-    url='https://www.yuque.com/docs/share/8f7a1871-a886-48f7-9745-fd2ad13cbbcc?# 《角色权限操作说明(视频)》'
-  }else if(num==8){
-    url='https://www.yuque.com/docs/share/bd17afd5-8381-467d-ab65-a10661c73388?# 《积分权限是什么?有什么用?》'
-  }else if(num==9){
-    url='https://www.yuque.com/docs/share/2ef16237-4bc3-4ab8-8195-bc506098c0d5?# 《什么是每月奖扣目标,有什么用?》'
-  }else if(num==10){
-    url='https://www.yuque.com/docs/share/e8c6c82d-0f9f-4663-ada5-95dbd46ab1db?# 《审批流程说明》'
-  }else if(num==11){
-    url='https://www.yuque.com/docs/share/155191a9-fab6-447f-a7da-099506b322e6?# 《第一步:班次管理》'
-  }else if(num==12){
-    url='https://www.yuque.com/docs/share/6e16186a-21a1-4f26-bd76-0967cfbcff85?# 《第二步:创建加班规则》'
-  }else if(num==13){
-    url='https://www.yuque.com/docs/share/86a48ef0-5b91-416b-8bb4-b51248bab89b?# 《第三步:创建考勤组》'
-  }else if(num==14){
-    url='https://www.yuque.com/docs/share/6c233543-b04e-442b-8629-622b41465c56?# 《第四步:创建假期类型》'
-  }else if(num==15){
-    url='https://www.yuque.com/docs/share/44aa8b5b-ef80-420b-8fd2-6902a08179ae?# 《自定义B分的使用场景有哪些?》'
-  }else if(num==16){
-    url='https://www.yuque.com/docs/share/a3c8a68c-6706-4dbf-9cad-8886a8c904ff?# 《积分规则常见问题》'
-  }else if(num==17){
-    url='https://www.yuque.com/docs/share/4551830c-25c8-44ae-8130-368c88bac624?# 《A分、B分常见问题》'
-  }else if(num==18){
-    url='https://www.yuque.com/docs/share/2ef16237-4bc3-4ab8-8195-bc506098c0d5?# 《什么是每月奖扣目标,如何使用?》'
-  }else if(num==19){
-    url='https://www.yuque.com/docs/share/97a89371-71c4-42c0-b01e-4c51b746ffe0?# 《什么是重复任务》'
+  let url = 'http://www.baidu.com';
+  if (num == 1) {
+    url = 'https://www.yuque.com/docs/share/4551830c-25c8-44ae-8130-368c88bac624?# 《A分、B分常见问题》'
+  } else if (num == 2) {
+    url = 'https://www.yuque.com/docs/share/2300b9bb-84ab-48ae-afd9-a19da38147ba?# 《如何设置自动积分?》'
+  } else if (num == 3) {
+    url = 'https://www.yuque.com/docs/share/4cb21924-c9ee-4a4d-91f4-58db8be9547b?# 《基础分、工龄分是什么?》'
+  } else if (num == 4) {
+    url = 'https://www.yuque.com/docs/share/971c4cd7-5498-4fd6-a97c-ef08d62079c1?# 《系统配置》'
+  } else if (num == 5) {
+    url = 'https://www.yuque.com/docs/share/4551830c-25c8-44ae-8130-368c88bac624?# 《A分、B分常见问题》'
+  } else if (num == 6) {
+    url = 'https://www.yuque.com/docs/share/8cae70cf-3961-4e91-848d-d903f0323004?# 《如何邀请员工注册并加入企业?》'
+  } else if (num == 7) {
+    url = 'https://www.yuque.com/docs/share/8f7a1871-a886-48f7-9745-fd2ad13cbbcc?# 《角色权限操作说明(视频)》'
+  } else if (num == 8) {
+    url = 'https://www.yuque.com/docs/share/bd17afd5-8381-467d-ab65-a10661c73388?# 《积分权限是什么?有什么用?》'
+  } else if (num == 9) {
+    url = 'https://www.yuque.com/docs/share/2ef16237-4bc3-4ab8-8195-bc506098c0d5?# 《什么是每月奖扣目标,有什么用?》'
+  } else if (num == 10) {
+    url = 'https://www.yuque.com/docs/share/e8c6c82d-0f9f-4663-ada5-95dbd46ab1db?# 《审批流程说明》'
+  } else if (num == 11) {
+    url = 'https://www.yuque.com/docs/share/155191a9-fab6-447f-a7da-099506b322e6?# 《第一步:班次管理》'
+  } else if (num == 12) {
+    url = 'https://www.yuque.com/docs/share/6e16186a-21a1-4f26-bd76-0967cfbcff85?# 《第二步:创建加班规则》'
+  } else if (num == 13) {
+    url = 'https://www.yuque.com/docs/share/86a48ef0-5b91-416b-8bb4-b51248bab89b?# 《第三步:创建考勤组》'
+  } else if (num == 14) {
+    url = 'https://www.yuque.com/docs/share/6c233543-b04e-442b-8629-622b41465c56?# 《第四步:创建假期类型》'
+  } else if (num == 15) {
+    url = 'https://www.yuque.com/docs/share/44aa8b5b-ef80-420b-8fd2-6902a08179ae?# 《自定义B分的使用场景有哪些?》'
+  } else if (num == 16) {
+    url = 'https://www.yuque.com/docs/share/a3c8a68c-6706-4dbf-9cad-8886a8c904ff?# 《积分规则常见问题》'
+  } else if (num == 17) {
+    url = 'https://www.yuque.com/docs/share/4551830c-25c8-44ae-8130-368c88bac624?# 《A分、B分常见问题》'
+  } else if (num == 18) {
+    url = 'https://www.yuque.com/docs/share/2ef16237-4bc3-4ab8-8195-bc506098c0d5?# 《什么是每月奖扣目标,如何使用?》'
+  } else if (num == 19) {
+    url = 'https://www.yuque.com/docs/share/97a89371-71c4-42c0-b01e-4c51b746ffe0?# 《什么是重复任务》'
   }
 
-  window.open(url,'_blank');
+  window.open(url, '_blank');
 }
 
 // 获取唯一标识(uid)
 export function generateUUID() {
-	var d = new Date().getTime();
-	var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
-		var r = (d + Math.random() * 16) % 16 | 0;
-		d = Math.floor(d / 16);
-		return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
-	});
-	return uuid;
+  var d = new Date().getTime();
+  var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+    var r = (d + Math.random() * 16) % 16 | 0;
+    d = Math.floor(d / 16);
+    return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
+  });
+  return uuid;
 };
 
-  //将部门链接在一起
-export function returnDeptName(arr){
-    let data=arr.map(item=>{
-        let str='';
-        item.dept_list.forEach((e,index)=>{
-            if(item.dept_list.length-index>1){
-               str+=e.dept_name+','
-            }else{
-               str+=e.dept_name
-            }
-        })
-        item.deptName=str
-        return item
-      })
-    return data
+// 清楚本地缓存
+export function resetStorage(){
+  localStorage.removeItem('userInfo')
+  localStorage.removeItem('accountToken')
+  localStorage.removeItem('SET_POINT_TYPES')
+  localStorage.removeItem('SET_EMPLOYEE_MAP_ALL')
+  localStorage.removeItem('site_info')
+  localStorage.removeItem('dept_tree')
+  localStorage.removeItem('account_info')
+  localStorage.removeItem('SET_EMPLOYEE_MAP')
+  localStorage.removeItem('dept_tree_pin')
+  localStorage.removeItem('login_code')
+  localStorage.removeItem('loglevel:webpack-dev-server')
+  sessionStorage.clear()
+  removeAllToken()
+}
+
+//将部门链接在一起
+export function returnDeptName(arr) {
+  let data = arr.map(item => {
+    let str = '';
+    item.dept_list.forEach((e, index) => {
+      if (item.dept_list.length - index > 1) {
+        str += e.dept_name + ','
+      } else {
+        str += e.dept_name
+      }
+    })
+    item.deptName = str
+    return item
+  })
+  return data
 }
 function hexToDec() {
   let str =
@@ -112,13 +131,16 @@ export function returnJSEncrypt(data, is = true) {
 export function getCache(key) {
   return JSON.parse(localStorage.getItem(key))
 }
+export function getLocal(key) {
+  return localStorage.getItem(key)
+}
 // 设置缓存
 export function setCache(key, data) {
   localStorage.setItem(key, JSON.stringify(data))
 }
 // 清除缓存
 export function removeCache(key) {
-  if (typeof(key) === 'string') {
+  if (typeof (key) === 'string') {
     localStorage.removeItem(key)
   } else {
     if (key.length > 0) {
@@ -132,7 +154,7 @@ export function removeCache(key) {
 export function getDept(id) {
   if (id) {
     let map = getCache('dept_tree_pin')[id];
-    return map||{}
+    return map || {}
   } else {
     return getCache('dept_tree_pin')
   }
@@ -154,13 +176,13 @@ export function getEmployeeMap(status) {
 export function getEmployeeMapAll() {
   return JSON.parse(localStorage.getItem('SET_EMPLOYEE_MAP_ALL'))
 }
-export function getEmployeeMapItem(id){
-   let map=JSON.parse(localStorage.getItem('SET_EMPLOYEE_MAP_ALL'))
-   if(map[id]){
-      return map[id]
-   }else{
-      return {}
-   }
+export function getEmployeeMapItem(id) {
+  let map = JSON.parse(localStorage.getItem('SET_EMPLOYEE_MAP_ALL'))
+  if (map[id]) {
+    return map[id]
+  } else {
+    return {}
+  }
 }
 
 // 获取积分类型
@@ -168,12 +190,12 @@ export function getTyps(id) {
   if (id) {
     var arr = getCache('SET_POINT_TYPES')
     var item = arr.filter(element => {
-      return typeof(id) === 'string' ? element.code == id : element.id == id
+      return typeof (id) === 'string' ? element.code == id : element.id == id
     })
     return item[0]
   } else {
     var arr = getCache('SET_POINT_TYPES')
-    return arr.filter(function(item) {
+    return arr.filter(function (item) {
       return item.code != 'JX';
     });
   }
@@ -187,14 +209,19 @@ export function getUserData() {
   return store.getters.user_info || getCache('userInfo')
 }
 
+// 获取当前课程用户详情
+export function getCourseUserData() {
+  return store.getters.course_user_info || getCache('courseUserData')
+}
+
 //是否平台管理或者平台创始人
 export function getIsAdministrator() {
   var userInfo = getUserData();
-  return userInfo.is_site_owner||userInfo.is_site_manager
+  return userInfo.is_site_owner || userInfo.is_site_manager
 }
 
-function returnRole(str){
-  return supremeAuthority()==str
+function returnRole(str) {
+  return supremeAuthority() == str
 }
 
 //判断是否具有权限
@@ -209,10 +236,10 @@ export function getIsIdentity(key) {
   return is
 }
 // 返回高权限  str最高权限是否匹配  id指定人员最高权限
-export function supremeAuthority(str,id) {
-  if(str){
+export function supremeAuthority(str, id) {
+  if (str) {
     return returnRole(str)
-  }else if (id) {
+  } else if (id) {
     const roleList = getEmployeeMapItem(id).employee_detail.role_list
     const roleAll = ['creator', 'admin', 'point_manager', 'dept_manager', 'employee']
     const userRole = roleList.map(e => e.name)
@@ -242,7 +269,7 @@ export function supremeAuthority(str,id) {
 // _debounce(this.XXX(),1000)
 export function _debounce(fn, delay = 500) {
   let timer = null
-  return function() {
+  return function () {
     const arg = arguments
     clearTimeout(timer)
     timer = setTimeout(() => {
@@ -257,6 +284,19 @@ export function setToken(token) {
 export function getToken() {
   return Cookies.get(TokenKey)
 }
+export function setCourseToken(token) {
+  return Cookies.set(CourseTokenKey, token)
+}
+export function getCourseToken() {
+  return Cookies.get(CourseTokenKey)
+}
+export function setCourseId(id) {
+  return Cookies.set(CourseId, id)
+}
+export function getCourseId() {
+  return localStorage.getItem('Course-Id')
+  // return Cookies.get(CourseId)
+}
 export function getUser() {
   return Cookies.get(USER)
 }
@@ -278,5 +318,7 @@ export function removeAllToken() {
   Cookies.remove('user')
   Cookies.remove('pasw')
   Cookies.remove(TokenKey)
+  Cookies.remove(CourseTokenKey)
+  Cookies.remove(CourseId)
   return true
 }

+ 187 - 0
src/utils/axiosKc.js

@@ -0,0 +1,187 @@
+import axios from 'axios'
+import {
+  Message,
+  MessageBox
+} from 'element-ui'
+import store from '@/store'
+import Router from '@/router'
+import {  getCourseId } from '@/utils/auth'
+import {
+  getLocal,
+  removeAllToken
+} from '@/utils/auth'
+import qs from 'qs'
+import Vue from 'vue'
+const service = axios.create({
+  // baseURL: process.env.BASE_API,
+  baseURL:'https://oa.g107.com',
+  // baseURL:'https://3g954g5149.picp.vip',
+  // baseURL:'http://192.168.0.66:8081',
+  
+  timeout: 20000,
+  headers: {
+    'Content-Type': 'application/x-www-form-urlencoded',
+    "Cache-Control": 'no-cache',
+  },
+  // transformRequest: [function(data) {
+  //   return qs.stringify(data)
+  // }]
+})
+
+service.interceptors.request.use(
+  config => {
+    return config
+  },
+  error => {
+    Promise.reject(error)
+  }
+)
+
+// 50008:非法的token; 50012:其他客户端登录了;  401:Token 过期了; 2000 考勤系统的token过期
+var bool = true // 五秒执行一次变量
+service.interceptors.response.use(
+  response => {
+    const res = response.data
+    if (res.code === 401) {
+      MessageBox.confirm('你已被登出,请重新登录', '确定登出', {
+        confirmButtonText: '重新登录',
+        showClose: false,
+        closeOnClickModal: false,
+        closeOnPressEscape: false,
+        showCancelButton: false,
+        type: 'warning'
+      }).then(() => {
+        store.dispatch('LogOut')
+      }).catch(() => {
+        store.dispatch('LogOut')
+      })
+      return Promise.reject(response)
+    } else if (res.code === 0) {
+      if (res.msg == '') {
+        return
+      }
+      Message({
+        message: res.message
+      })
+      return Promise.reject(response)
+    } else if (res.code === 999) {
+      Message({
+        message: res.message
+      })
+      return Promise.reject(response)
+    } else if (res.code === 2) {
+      Message({
+        message: res.message
+      })
+      return Promise.reject(response)
+    } else if (res.code === 0) {
+      Message({
+        message: res.message
+      })
+      return Promise.reject(response)
+    } else if (res.code === 3) {
+      Message({
+        message: res.message
+      })
+      return Promise.reject(response)
+    } else {
+      return response
+    }
+  },
+  error => {
+    if (error.message == 'interrupt') { // 是强制中断请求就拦截报错
+      return Promise.reject(error)
+    }
+    // 五秒内只执行一次
+    if (bool) {
+      Message({
+        message: error.message == 'timeout of 20000ms exceeded' ? '请求服务器超时,请稍后重试' : '请求网络错误,请稍后重试',
+        duration: 1 * 2000,
+        type: 'error'
+      })
+      bool = false
+      setTimeout(() => {
+        bool = true
+      }, 10000)
+    } else {
+      console.log('不执行')
+    }
+     return Promise.reject(error)
+  }
+)
+// 接口再次封装
+var CancelToken = axios.CancelToken // 中断请求
+Vue.$axiosUserRequestList = []
+export default (type, url, data, versions, Content_Type, transform,isToken) => {
+  if(!getCourseId()){
+    console.log('同浏览器下公道云8.0PC退出登录导致课程营销系统报错:系统异常')
+    // return false
+  }
+  var Accept, Token, ContentType, transformRequest = ''
+  switch (versions) {
+    case '':
+      Accept = 'application/json, text/plain, */*'
+      break
+    case undefined:
+      Accept = 'application/json, text/plain, */*'
+      break
+    case 'v2':
+      Accept = 'application/vnd.test.v2+json'
+      break
+    case 'v3':
+      Accept = 'application/vnd.test.v3+json'
+      break
+    case 'v4':
+      Accept = 'application/vnd.test.v4+json'
+      break
+  }
+  if (Content_Type == '' || Content_Type == undefined) {
+    // ContentType = 'application/x-www-form-urlencoded'
+    ContentType = 'application/json'
+  } else {
+    ContentType = Content_Type
+  }
+  if (transform) {
+    transformRequest = transform
+  }
+  if (getLocal('Course-Token')) {
+    Token = getLocal('Course-Token');
+  }
+  if(isToken){
+    Token=isToken
+  }
+  return new Promise((resolve, reject) => { // 封装ajax
+    var aa = {
+      method: type,
+      url: url,
+      headers: {
+        'Accept': Accept,
+        'Content-Type': ContentType,
+        'A-TOKEN':Token
+      },
+      cancelToken: new CancelToken(c => { // 强行中断请求要用到的
+        Vue.$axiosUserRequestList.push(c)
+      })
+    }
+    var json = (type == 'get') ? Object.assign(aa, {
+      params: data
+    }) : Object.assign(aa, {
+      data: data
+    })
+    // var json = (type == 'get') ? Object.assign(aa, {
+    //   params: data
+    // }, transformRequest) : Object.assign(aa, {
+    //   data: data
+    // }, transformRequest)
+    var ajax = service(json).then(res => {
+      resolve(res)
+    }).catch(error => { // 中断请求和请求出错的处理
+      if (error.message == 'interrupt') {
+        return
+      } else {
+        reject(error)
+      }
+    })
+    return ajax
+  })
+}

+ 19 - 2
src/views/login.vue

@@ -65,7 +65,7 @@
               <div class="login_reg">
                 <el-button type="text" @click="$router.push({ path: '/reg' })" style="float:right">
                   <span style="color:#909399">还没账号?</span>
-                  <span style="color: #006EFF;">免费注册体验</span>
+                  <span style="color: #006EFF;">注册账号</span>
                 </el-button>
               </div>
             </div>
@@ -106,7 +106,7 @@
 <script>
 import pastDue from '@/components/pastDue.vue';
 import QRCode from 'qrcodejs2';
-import { setToken, getUser, getPasw, setUser, setPasw } from '@/utils/auth';
+import { setToken, getUser, getPasw, setUser, setPasw ,removeAllToken} from '@/utils/auth';
 import { constants } from 'fs';
 import { timestamps } from '@/utils/index';
 import { validateTel } from '@/utils/validate';
@@ -312,6 +312,7 @@ export default {
       const newNav = this.$getCache('newNav');
       const initImg = this.$getCache('initImg');
       const noticeId = this.$getCache('noticeId');
+      // this.resetStorage()
       localStorage.clear();
       sessionStorage.clear();
       if (newNav) {
@@ -323,6 +324,22 @@ export default {
       if (noticeId) {
         this.$setCache('noticeId', noticeId);
       }
+    },
+    // 清楚本地缓存
+    resetStorage(){
+      localStorage.removeItem('userInfo')
+      localStorage.removeItem('accountToken')
+      localStorage.removeItem('SET_POINT_TYPES')
+      localStorage.removeItem('SET_EMPLOYEE_MAP_ALL')
+      localStorage.removeItem('site_info')
+      localStorage.removeItem('dept_tree')
+      localStorage.removeItem('account_info')
+      localStorage.removeItem('SET_EMPLOYEE_MAP')
+      localStorage.removeItem('dept_tree_pin')
+      localStorage.removeItem('login_code')
+      localStorage.removeItem('loglevel:webpack-dev-server')
+      sessionStorage.clear()
+      removeAllToken()
     }
   },
   watch: {

+ 24 - 3
src/views/weixin.vue

@@ -87,6 +87,8 @@
 import { setToken,returnJSEncrypt } from '@/utils/auth';
 import pastDue from '@/components/pastDue.vue';
 import axios from 'axios';
+import {getAdminTokenId} from '@/course/api'
+import { setCourseToken, setCourseId, _debounce } from "@/utils/auth";
 import qs from 'qs';
 import { validateTel,validatePassword } from '@/utils/validate';
 export default {
@@ -116,10 +118,12 @@ export default {
       account_id: '',
       dialogVisible: false,
       account_site: [],
+      course_account_site:[],
       isShowSelect: false,
       exist:false,
       setp:1,
       wo_token:'',
+      course_wo_token:''
     };
   },
   watch: {
@@ -228,11 +232,26 @@ export default {
           this.loading = false
         }
     },
-
+    courseWxLogin(token){
+      getAdminTokenId(token).then(res=>{
+        setCourseToken(res.auToken);
+        setCourseId(res.adminUserId);
+        localStorage.setItem("Course-Token", res.auToken);
+        localStorage.setItem("Course-Id", res.adminUserId);
+        localStorage.setItem("course_path", 2);
+        this.$message({
+          message: "登录成功!",
+          type: "success",
+          showClose: true,
+          duration: 2000,
+        });
+        this.$router.push("/course");
+      })
+    },
     wxLogin() {
       axios({
         method: 'get',
-        url: process.env.BASE_API + '/api/pro/wo/oui',
+        url: 'https://oa.g107.com/api/pro/wo/oui',
         headers: {
           'Content-Type': 'application/x-www-form-urlencoded',
           pl: 'b',
@@ -278,8 +297,10 @@ export default {
     },
   },
   created() {
-    if (this.$route.query.secret) {
+    if (this.$route.query.secret&&this.$route.query.ct != 1) {
       this.wxLogin();
+    }else{
+      this.courseWxLogin(this.$route.query.secret);
     }
   }
 };

二進制
static/images/tjbmgly.png


二進制
static/images/wechat1.png


部分文件因文件數量過多而無法顯示