zhouwx
2024-07-04 00c6c38846f94687cfc4ce6d3c0506f8349a26e5
提交
已修改11个文件
已添加15个文件
2952 ■■■■■ 文件已修改
package.json 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/hash.js 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/spark-md5.min.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/onlineEducation/chapters.js 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/onlineEducation/courseManage.js 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/onlineEducation/courseResource.js 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/onlineEducation/student.js 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/onlineEducation/upload.js 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Navbar.vue 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/menu.js 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/components/upload.vue 530 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/courseManage/components/courseManageDialog.vue 320 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/courseManage/courseChapters/components/chapterDialog.vue 249 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/courseManage/courseChapters/components/chooseResource.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/courseManage/courseChapters/index.vue 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/courseManage/courseResource/componets/resourceDialog.vue 345 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/courseManage/courseResource/index.vue 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/courseManage/index.vue 265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/people/components/stuDialog.vue 311 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/people/index.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/systemManage/banner/components/bannerDialog.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/systemManage/courseClassification/components/courseClassDialog.vue 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/systemManage/courseClassification/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/onlineEducation/systemManage/user/components/userDialog.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -31,9 +31,12 @@
    "js-cookie": "3.0.1",
    "jsencrypt": "3.3.1",
    "nprogress": "0.2.0",
    "p-limit": "^5.0.0",
    "pinia": "2.0.22",
    "quill": "^2.0.0-dev.3",
    "spark-md5": "^3.0.2",
    "tinymce": "^5.10.2",
    "video.js": "^8.12.0",
    "vue": "3.2.45",
    "vue-baidu-map-3x": "^1.0.35",
    "vue-cropper": "1.0.3",
public/hash.js
对比新文件
@@ -0,0 +1,31 @@
self.importScripts("/spark-md5.min.js"); // 导入脚本
// 生成文件 hash
self.onmessage = e => {
  const { fileChunkList } = e.data;
  const spark = new self.SparkMD5.ArrayBuffer();
  let percentage = 0;
  let count = 0;
  const loadNext = index => {
    const reader = new FileReader();
    reader.readAsArrayBuffer(fileChunkList[index].file);
    reader.onload = e => {
      count++;
      spark.append(e.target.result);
      if (count === fileChunkList.length) {
        self.postMessage({
          percentage: 100,
          hash: spark.end()
        });
        self.close();
      } else {
        percentage += 100 / fileChunkList.length;
        self.postMessage({
          percentage
        });
        loadNext(count);
      }
    };
  };
  loadNext(0);
};
public/spark-md5.min.js
对比新文件
@@ -0,0 +1 @@
(function(factory){if(typeof exports==="object"){module.exports=factory()}else if(typeof define==="function"&&define.amd){define(factory)}else{var glob;try{glob=window}catch(e){glob=self}glob.SparkMD5=factory()}})(function(undefined){"use strict";var add32=function(a,b){return a+b&4294967295},hex_chr=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function cmn(q,a,b,x,s,t){a=add32(add32(a,q),add32(x,t));return add32(a<<s|a>>>32-s,b)}function md5cycle(x,k){var a=x[0],b=x[1],c=x[2],d=x[3];a+=(b&c|~b&d)+k[0]-680876936|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[1]-389564586|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[2]+606105819|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[3]-1044525330|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[4]-176418897|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[5]+1200080426|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[6]-1473231341|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[7]-45705983|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[8]+1770035416|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[9]-1958414417|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[10]-42063|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[11]-1990404162|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[12]+1804603682|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[13]-40341101|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[14]-1502002290|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[15]+1236535329|0;b=(b<<22|b>>>10)+c|0;a+=(b&d|c&~d)+k[1]-165796510|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[6]-1069501632|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[11]+643717713|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[0]-373897302|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[5]-701558691|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[10]+38016083|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[15]-660478335|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[4]-405537848|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[9]+568446438|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[14]-1019803690|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[3]-187363961|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[8]+1163531501|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[13]-1444681467|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[2]-51403784|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[7]+1735328473|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[12]-1926607734|0;b=(b<<20|b>>>12)+c|0;a+=(b^c^d)+k[5]-378558|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[8]-2022574463|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[11]+1839030562|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[14]-35309556|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[1]-1530992060|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[4]+1272893353|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[7]-155497632|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[10]-1094730640|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[13]+681279174|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[0]-358537222|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[3]-722521979|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[6]+76029189|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[9]-640364487|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[12]-421815835|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[15]+530742520|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[2]-995338651|0;b=(b<<23|b>>>9)+c|0;a+=(c^(b|~d))+k[0]-198630844|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[7]+1126891415|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[14]-1416354905|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[5]-57434055|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[12]+1700485571|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[3]-1894986606|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[10]-1051523|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[1]-2054922799|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[8]+1873313359|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[15]-30611744|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[6]-1560198380|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[13]+1309151649|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[4]-145523070|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[11]-1120210379|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[2]+718787259|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[9]-343485551|0;b=(b<<21|b>>>11)+c|0;x[0]=a+x[0]|0;x[1]=b+x[1]|0;x[2]=c+x[2]|0;x[3]=d+x[3]|0}function md5blk(s){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=s.charCodeAt(i)+(s.charCodeAt(i+1)<<8)+(s.charCodeAt(i+2)<<16)+(s.charCodeAt(i+3)<<24)}return md5blks}function md5blk_array(a){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=a[i]+(a[i+1]<<8)+(a[i+2]<<16)+(a[i+3]<<24)}return md5blks}function md51(s){var n=s.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk(s.substring(i-64,i)))}s=s.substring(i-64);length=s.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i<length;i+=1){tail[i>>2]|=s.charCodeAt(i)<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function md51_array(a){var n=a.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk_array(a.subarray(i-64,i)))}a=i-64<n?a.subarray(i-64):new Uint8Array(0);length=a.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i<length;i+=1){tail[i>>2]|=a[i]<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function rhex(n){var s="",j;for(j=0;j<4;j+=1){s+=hex_chr[n>>j*8+4&15]+hex_chr[n>>j*8&15]}return s}function hex(x){var i;for(i=0;i<x.length;i+=1){x[i]=rhex(x[i])}return x.join("")}if(hex(md51("hello"))!=="5d41402abc4b2a76b9719d911017c592"){add32=function(x,y){var lsw=(x&65535)+(y&65535),msw=(x>>16)+(y>>16)+(lsw>>16);return msw<<16|lsw&65535}}if(typeof ArrayBuffer!=="undefined"&&!ArrayBuffer.prototype.slice){(function(){function clamp(val,length){val=val|0||0;if(val<0){return Math.max(val+length,0)}return Math.min(val,length)}ArrayBuffer.prototype.slice=function(from,to){var length=this.byteLength,begin=clamp(from,length),end=length,num,target,targetArray,sourceArray;if(to!==undefined){end=clamp(to,length)}if(begin>end){return new ArrayBuffer(0)}num=end-begin;target=new ArrayBuffer(num);targetArray=new Uint8Array(target);sourceArray=new Uint8Array(this,begin,num);targetArray.set(sourceArray);return target}})()}function toUtf8(str){if(/[\u0080-\uFFFF]/.test(str)){str=unescape(encodeURIComponent(str))}return str}function utf8Str2ArrayBuffer(str,returnUInt8Array){var length=str.length,buff=new ArrayBuffer(length),arr=new Uint8Array(buff),i;for(i=0;i<length;i+=1){arr[i]=str.charCodeAt(i)}return returnUInt8Array?arr:buff}function arrayBuffer2Utf8Str(buff){return String.fromCharCode.apply(null,new Uint8Array(buff))}function concatenateArrayBuffers(first,second,returnUInt8Array){var result=new Uint8Array(first.byteLength+second.byteLength);result.set(new Uint8Array(first));result.set(new Uint8Array(second),first.byteLength);return returnUInt8Array?result:result.buffer}function hexToBinaryString(hex){var bytes=[],length=hex.length,x;for(x=0;x<length-1;x+=2){bytes.push(parseInt(hex.substr(x,2),16))}return String.fromCharCode.apply(String,bytes)}function SparkMD5(){this.reset()}SparkMD5.prototype.append=function(str){this.appendBinary(toUtf8(str));return this};SparkMD5.prototype.appendBinary=function(contents){this._buff+=contents;this._length+=contents.length;var length=this._buff.length,i;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk(this._buff.substring(i-64,i)))}this._buff=this._buff.substring(i-64);return this};SparkMD5.prototype.end=function(raw){var buff=this._buff,length=buff.length,i,tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],ret;for(i=0;i<length;i+=1){tail[i>>2]|=buff.charCodeAt(i)<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.prototype.reset=function(){this._buff="";this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash}};SparkMD5.prototype.setState=function(state){this._buff=state.buff;this._length=state.length;this._hash=state.hash;return this};SparkMD5.prototype.destroy=function(){delete this._hash;delete this._buff;delete this._length};SparkMD5.prototype._finish=function(tail,length){var i=length,tmp,lo,hi;tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(this._hash,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=this._length*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(this._hash,tail)};SparkMD5.hash=function(str,raw){return SparkMD5.hashBinary(toUtf8(str),raw)};SparkMD5.hashBinary=function(content,raw){var hash=md51(content),ret=hex(hash);return raw?hexToBinaryString(ret):ret};SparkMD5.ArrayBuffer=function(){this.reset()};SparkMD5.ArrayBuffer.prototype.append=function(arr){var buff=concatenateArrayBuffers(this._buff.buffer,arr,true),length=buff.length,i;this._length+=arr.byteLength;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk_array(buff.subarray(i-64,i)))}this._buff=i-64<length?new Uint8Array(buff.buffer.slice(i-64)):new Uint8Array(0);return this};SparkMD5.ArrayBuffer.prototype.end=function(raw){var buff=this._buff,length=buff.length,tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],i,ret;for(i=0;i<length;i+=1){tail[i>>2]|=buff[i]<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.ArrayBuffer.prototype.reset=function(){this._buff=new Uint8Array(0);this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.ArrayBuffer.prototype.getState=function(){var state=SparkMD5.prototype.getState.call(this);state.buff=arrayBuffer2Utf8Str(state.buff);return state};SparkMD5.ArrayBuffer.prototype.setState=function(state){state.buff=utf8Str2ArrayBuffer(state.buff,true);return SparkMD5.prototype.setState.call(this,state)};SparkMD5.ArrayBuffer.prototype.destroy=SparkMD5.prototype.destroy;SparkMD5.ArrayBuffer.prototype._finish=SparkMD5.prototype._finish;SparkMD5.ArrayBuffer.hash=function(arr,raw){var hash=md51_array(new Uint8Array(arr)),ret=hex(hash);return raw?hexToBinaryString(ret):ret};return SparkMD5});
src/api/onlineEducation/chapters.js
对比新文件
@@ -0,0 +1,70 @@
import request from "@/utils/request";
export function checkChapterName(data) {
    return request({
        url: '/course-chapter/checkNameUnique',
        method: 'post',
        data: data
    })
}
export function getChapters(params) {
    return request({
        url: '/course-chapter/getCourseChapter',
        method: 'get',
        params: params
    })
}
export function addChapter(data) {
    return request({
        url: '/course-chapter',
        method: 'post',
        data: data
    })
}
export function addChapterPeriod(data) {
    return request({
        url: '/course-chapter-period',
        method: 'post',
        data: data
    })
}
export function editChapter(params) {
    return request({
        url: `/course-chapter`,
        method: 'put',
        data: params
    })
}
export function editChapterPeriod(params) {
    return request({
        url: `/course-chapter-period`,
        method: 'put',
        data: params
    })
}
export function getChapterById(params) {
    return request({
        url: '/course-chapter/' +params ,
        method: 'get',
        params: params
    })
}
export function delChapter(data) {
    return request({
        url: `/course-chapter/` + data,
        method: 'delete'
    })
}
export function delPeriod(data) {
    return request({
        url: `/course-chapter-period/` + data,
        method: 'delete'
    })
}
src/api/onlineEducation/courseManage.js
对比新文件
@@ -0,0 +1,65 @@
import request from "@/utils/request";
export function checkCourseName(data) {
    return request({
        url: '/course/checkNameUnique',
        method: 'post',
        data: data
    })
}
export function getCourse(params) {
    return request({
        url: '/course/list',
        method: 'get',
        params: params
    })
}
export function addCourse(data) {
    return request({
        url: '/course',
        method: 'post',
        data: data
    })
}
export function editCourse(params) {
    return request({
        url: `/course`,
        method: 'put',
        data: params
    })
}
export function getCourseById(params) {
    return request({
        url: '/course/' +params ,
        method: 'get',
        params: params
    })
}
export function delCourse(data) {
    return request({
        url: `/course/` + data,
        method: 'delete'
    })
}
export function doCourse(data) {
    return request({
        url: '/course/doApprove',
        method: 'post',
        data: data
    })
}
export function changeCourseStatus(params) {
    return request({
        url: '/course/changeStatus',
        method: 'put',
        data: params
    })
}
src/api/onlineEducation/courseResource.js
对比新文件
@@ -0,0 +1,49 @@
import request from "@/utils/request";
export function checkResourceName(data) {
    return request({
        url: '/resource/checkNameUnique',
        method: 'post',
        data: data
    })
}
export function getResource(params) {
    return request({
        url: '/resource/list',
        method: 'get',
        params: params
    })
}
export function addResource(data) {
    return request({
        url: '/resource',
        method: 'post',
        data: data
    })
}
export function editResource(params) {
    return request({
        url: `/resource`,
        method: 'put',
        data: params
    })
}
export function getResourceById(params) {
    return request({
        url: '/resource/' +params ,
        method: 'get',
        params: params
    })
}
export function delResource(data) {
    return request({
        url: `/resource/` + data,
        method: 'delete'
    })
}
src/api/onlineEducation/student.js
对比新文件
@@ -0,0 +1,67 @@
import request from '@/utils/request'
export function getStudent(param) {
    return request({
        url: '/student/list',
        method: 'get',
        params: param
    })
}
export function getStudentById(params) {
    return request({
        url: '/system/user/' +params ,
        method: 'get',
        params: params
    })
}
export function addStudent(data) {
    return request({
        url: '/student',
        method: 'post',
        data: data
    })
}
export function checkStuIdNo(data) {
    return request({
        url: '/student/checkIdNoUnique',
        method: 'post',
        data: data
    })
}
export function checkStuPhone(data) {
    return request({
        url: '/student/checkPhoneUnique',
        method: 'post',
        data: data
    })
}
export function editStudent(params) {
    return request({
        url: `/student`,
        method: 'put',
        data: params
    })
}
export function resetPwd(params) {
    return request({
        url: `/student/resetPwd`,
        method: 'put',
        data: params
    })
}
export function delStudent(userId) {
    return request({
        url: '/student/' + userId,
        method: 'delete'
    })
}
src/api/onlineEducation/upload.js
对比新文件
@@ -0,0 +1,21 @@
import request from '@/utils/request'
export function uploadFileRequest(data,uploadProgressHandle) {
    return request({
        url: '/system/common/uploadSlice',
        method: 'post',
        headers:{'Content-Type':'multipart/form-data'},
        data: data,
        onUploadProgress: uploadProgressHandle
    })
}
export function mergeFileRequest(data) {
    return request({
        url: '/system/common/uploadMerge',
        headers:{'Content-Type':'multipart/form-data'},
        method: 'post',
        data: data
    })
}
src/layout/components/Navbar.vue
@@ -48,7 +48,8 @@
        </el-dropdown>
      </div>
    </div>
<!--    <review-dialog ref="reviewRef" ></review-dialog>-->
    <user-dialog ref="reviewRef" ></user-dialog>
<!--    <register ref="regRef" @getList="getList" />-->
<!--    <supervise-dialog ref="superRef"></supervise-dialog>-->
  </div>
@@ -72,6 +73,7 @@
import Cookies from "js-cookie";
import {getUserById} from "@/api/sysUsers";
import menu from "@/layout/components/Sidebar/menu";
import userDialog from '@/views/onlineEducation/systemManage/user/components/userDialog.vue'
const appStore = useAppStore()
const userStore = useUserStore()
@@ -135,34 +137,10 @@
function getInfo() {
  console.log("getInfo",userInfo.value)
  //机构用户
  if(userInfo.value.identity === 1){
    //审核驳回(可修改)
    if(userInfo.value.state === 3){
      const obj = {
        id: userInfo.value.id,
        username: userInfo.value.username,
        agencyId: userInfo.value.agentId
      }
      regRef.value.openDialog('reject', obj);
    }else{
      //审核通过、未审核状态(不可修改)
      const obj = {
        agencyId: userInfo.value.agentId
      }
      reviewRef.value.openDialog(obj,'view')
    }
  }
  //监管用户
  else if (userInfo.value.identity === 0) {
    const obj = {
      id: userInfo.value.id
    }
    superRef.value.openDialog('view', obj);
  }
  reviewRef.value.openDialog('view',userInfo.value)
}
function editPsd() {
  superRef.value.openDialog('pwd', userInfo.value);
  reviewRef.value.openDialog('pwd',userInfo.value)
}
const sidebarRouters = ref([])
src/layout/components/Sidebar/menu.js
@@ -1,10 +1,27 @@
import Layout from '@/layout'
const menu = {
    adminMenu: [
        // {
        //     path: '/course',
        //     name: 'Course',
        //     meta: { title: '课程管理',icon: 'documentation',affix: true }
        // },
        {
            path: '/course',
            name: 'Course',
            meta: { title: '课程管理',icon: 'documentation',affix: true }
            path: '/onlineEducation',
            redirect: '/onlineEducation/courseManage',
            meta: { title: '课程管理',icon: 'form'},
            children: [
                {
                    path: 'course',
                    name: 'course',
                    meta: { title: '课程列表',icon: 'list'}
                } ,
                {
                    path: 'courseResource',
                    name: 'courseResource',
                    meta: { title: '课程资源',icon: 'education'}
                } ,
            ]
        },
        {
            path: '/question',
@@ -66,9 +83,21 @@
    ],
    companyMenu: [
        {
            path: '/course',
            name: 'Course',
            meta: { title: '课程管理',icon: 'documentation',affix: true }
            path: '/onlineEducation',
            redirect: '/onlineEducation/courseManage',
            meta: { title: '课程管理',icon: 'form'},
            children: [
                {
                    path: 'course',
                    name: 'course',
                    meta: { title: '课程列表',icon: 'list'}
                } ,
                {
                    path: 'courseResource',
                    name: 'courseResource',
                    meta: { title: '课程资源',icon: 'education'}
                } ,
            ]
        },
        {
            path: '/question',
src/main.js
@@ -51,6 +51,7 @@
import { Boot } from '@wangeditor/editor'
import attachmentModule from '@wangeditor/plugin-upload-attachment'
import loadMore from '@/utils/selectLoadMoreDirective'
import "video.js/dist/video-js.css"
Boot.registerModule(attachmentModule)
const app = createApp(App)
src/router/index.js
@@ -53,6 +53,18 @@
    hidden: true
  },
  {
    path: '/chapters',
    component: Layout,
    redirect: '/chapters',
    children: [
      {
        path: '/chapters',
        component: () => import('@/views/onlineEducation/courseManage/courseChapters/index.vue'),
        name: 'Chapters',
      }
    ]
  },
  // {
  //   path: '',
  //   component: Layout,
@@ -79,16 +91,23 @@
    ]
  },
  {
    path: '/course',
    path: '/onlineEducation',
    component: Layout,
    redirect: '/course',
    redirect: '/onlineEducation/courseManage',
    meta: { title: '课程管理'},
    children: [
      {
        path: '/course',
        path: 'course',
        component: () => import('@/views/onlineEducation/courseManage/index.vue'),
        name: 'course',
        meta: { title: '课程管理',icon: 'form',  affix: true }
      }
        meta: { title: '课程列表',icon: 'form',  affix: true }
      },
      {
        path: 'courseResource',
        component: () => import('@/views/onlineEducation/courseManage/courseResource/index.vue'),
        name: 'courseResource',
        meta: { title: '课程资源',icon: 'form',  affix: true }
      },
    ]
  },
  {
src/views/components/upload.vue
对比新文件
@@ -0,0 +1,530 @@
<template>
  <div class="greetings">
    <el-upload accept=".mp4, .mp3, .xls, .xlsx, .doc, .docx, .ppt, .pptx, .pdf"   :on-change="handleFileChange" :on-preview="view"  :auto-upload="false" ref="uploadfileComponent" :limit="1" :on-exceed="handleExceed"  v-model:file-list="fileList">
      <template #trigger>
        <el-button type="primary">选择文件</el-button>
      </template>
      <el-button :disabled="uploadDisabled" style="margin-left: 10px" type="success" @click="handlerUpload">上传</el-button>
      <el-button class="ml-3" type="success" @click="resetData" >重置</el-button>
      <template #tip>
        <br /><br />
        <span>上传进度:{{ fakeUploadPercentage }}%</span>
        <el-progress :text-inside="true" :stroke-width="26" :percentage="fakeUploadPercentage" />
        <div class="el-upload__tip text-red">限制一个文件, 新文件将会覆盖原文件</div>
      </template>
    </el-upload>
    <br>
    <div v-if="container.showVideo" style="width: 300px;height: 200px">
      <video   ref="videoPlayer" class="video-js" style="margin: auto auto"></video>
    </div>
  </div>
</template>
<script setup>
import { ElMessage } from "element-plus";
import videojs from "video.js"
import { computed, nextTick, onMounted, onUnmounted,ref,reactive,watch  } from "vue";
import SparkMD5 from "spark-md5";
import {uploadFileRequest,mergeFileRequest} from "@/api/onlineEducation/upload"
import pLimit from 'p-limit'
const videoPlayer = ref(null)
const myPlayer = ref(null)
const uploadDisabled=ref(false)
const chunkSize = ref(10 * 1024 * 1024) // 切片大小
const uploadedCount=ref(0) //已上传的分配个数
const fileChunkList=ref([])
const fileList=ref([])
const uploadfileComponent=ref(null)
const emit = defineEmits(["getFile"]);
const props = defineProps({
  responseType: {
    type: Number,
    default: 0
  }
})
const container=reactive({
  file:{
    name:'',
    percentage:0,
    status:1,
    size:0,
    url:'',
    raw:null,
    uid:0
  },
  fileMd5:'',
  worker:null,
  showVideo:false
})
// 生成文件hash的进度
const hashPercentage = ref(0)
// 显示在页面上的文件上传进度
const fakeUploadPercentage = ref(0)
const type = ref();
onMounted(() => {
  type.value = props.responseType
  // getVideo(props.responseType)
})
const resourcePath = ref();
const getVideo = (value) => {
  type.value = value;
  if(value == 1){
    // container.showVideo = true
    nextTick(() => {
      console.log("111111",videoPlayer.value)
      myPlayer.value = videojs(videoPlayer.value, {
        poster: "",//视频封面
        controls: true,//视频控件
        autoplay:true,//自动播放
        sources: [
          {
            src: resourcePath.value ? "http://192.168.2.16:9000/trainexam/" + resourcePath.value : '',
            // src:'',
            type: 'application/x-mpegURL',
          }
        ],
        controlBar: {
          remainingTimeDisplay: {
            displayNegative: false
          }
        },
        playbackRates: [0.5, 1, 1.5, 2]//设置播放速度
      }, onPlayerReady)
    });
  }
}
// watch(() => props.responseType, value => getVideo(value))
onUnmounted(() => {
  if (myPlayer.value) {
    myPlayer.value.dispose()
  }
})
const dispose = () => {
  // if (myPlayer.value) {
  //   myPlayer.value.dispose()
  //   resourcePath.value = ''
  // }
  container.showVideo = false;
  resourcePath.value = ''
  hashPercentage.value=0
  uploadPercentage.value=0
  fakeUploadPercentage.value=0
  uploadedCount.value=0
  fileChunkList.value=[]
  fileList.value=[]
}
const changeType = (val) => {
  type.value = val
  dispose()
  if(val == 1){
    container.showVideo = true
    nextTick(() => {
      getVideo(val)
    })
  }
}
const openValue = ref();
const open = (val) => {
  console.log("val",val)
  openValue.value = val
  fakeUploadPercentage.value = 100
  if(val.resourceType == 1){
    container.showVideo = true
    resourcePath.value = val.resourcePath;
    getVideo(val.resourceType)
  }else {
    container.showVideo = false
    // if (myPlayer.value) {
    //   myPlayer.value.dispose()
    // }
    fileList.value.push({
      path: val.resourcePath,
      name: val.originName
    })
  }
}
const view = (file) => {
  console.log('vlco',file)
  // console.log("点击文件=>", file);
  const url = 'http://192.168.2.16:9000/trainexam/' + file.path;
  const link = document.createElement("a");
  link.href = url;
  link.download = file.name;
  // link.target = "_blank";
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}
// video初始化完成的回调函数
const onPlayerReady = () => {
  myPlayer.value.log("play.....")
  bindVideoEvents()
}
// 绑定事件
const bindVideoEvents = () => {
  if (!myPlayer.value) return
  myPlayer.value.on('play', onPlay)
  myPlayer.value.on('pause', onPause)
  myPlayer.value.on('ended', onEnded)
  myPlayer.value.on('timeupdate', onTimeupdate)
  myPlayer.value.on('loadedmetadata', onLoadedmetadata)
  myPlayer.value.on('fullscreenchange', onFullscreenchange)
  myPlayer.value.on('error', err => {
    console.log('视频加载发生错误', err)
  })
}
const onPlay = () => {
  console.log('播放视频')
}
const onPause = () => {
  console.log('暂停播放')
}
const onEnded = () => {}
const onTimeupdate = () => {
  console.log('播放位置已更改时,播放时间更新')
}
// 全屏切换
const onFullscreenchange = () => {
  console.log('全屏状态改变')
}
// 元数据加载完成
const onLoadedmetadata = () => {
  console.log('元数据加载完成')
}
//计算文件上传的进度
const uploadPercentage= computed({
  get(){
    if(!container.file||!fileChunkList.value.length){
      return 0
    }
    const loaded=fileChunkList.value.map(item => item.size * item.percentage).reduce((acc,cur) => {
      return acc+cur
    })
    console.log('loaded',uploadedCount.value,loaded)
    return parseInt((loaded/container.file.size).toFixed(2))
  },
  set(value){
    return value
  }
})
// watch uploadPercentage,得到fakeUploadPercentage
watch(uploadPercentage, (newValue) => {
  if (newValue >= fakeUploadPercentage.value) {
    fakeUploadPercentage.value = newValue
  }
})
const resetData = () => {
  container.showVideo = false
  resourcePath.value = ''
  hashPercentage.value=0
  uploadPercentage.value=0
  fakeUploadPercentage.value=0
  uploadedCount.value=0
  fileChunkList.value=[]
  fileList.value=[]
  if(container.worker){
    container.worker.onmessage=null
  }
  // if (myPlayer.value) {
  //   myPlayer.value.dispose()
  // }
  const file = {
    resourceSize: null,
    md5: '',
    resourcePath: '',
    mediaType: '',
    docPage: 0,
    resourceLength: '',
    originName:''
  }
  emit("getFile",file)
}
//选择了文件
const handleFileChange=(uploadFile,uploadFiles) =>{
  // resetData()
  if(!uploadFile){
    return
  }
  container.file=uploadFile
  fileList.value=uploadFiles
}
const handleExceed= (files) => {
  uploadfileComponent.value.clearFiles()
  nextTick(() => {
    uploadfileComponent.value.handleStart(files[0])
  })
}
//上传
const handlerUpload= async() => {
  if(type.value == null){
    ElMessage({
      type: 'warning',
      message: '请先选择资源类型'
    });
    return false
  }
  if(!container.file.raw){
    return
  }
  if(container.file.raw.size > 1024 * 1024 * 1000){
      ElMessage({
        type: 'warning',
        message: '文件大小不能超过1G'
      });
      return false
  }
  const filetype = container.file.raw.name.split(".").pop();
  const extension = (filetype === "mp4" || filetype ==="mp3" || filetype ==="xls" || filetype === "xlsx" || filetype ==="doc" || filetype ==="docx" || filetype === "ppt" || filetype ==="pptx" || filetype ==="pdf");
  if (!extension ) {
    ElMessage({
      type: 'warning',
      message: '暂不支持该格式上传'
    });
    return false;
  }
  if((type.value == 1 && filetype != 'mp4') || (type.value == 2 && filetype != 'mp3')){
    ElMessage({
      type: 'warning',
      message: '请上传所选资源类型的文件'
    });
    return false;
  }
  if(type.value == 3){
    if( filetype == 'xls' || filetype == 'xlsx' || filetype == 'doc'|| filetype == 'docx'|| filetype == 'ppt'|| filetype == 'pptx'|| filetype == 'pdf' ){
    }else {
      ElMessage({
        type: 'warning',
        message: '请上传所选资源类型的文件'
      });
      return false;
    }
  }
  //文件分片
  const chunkList=createFileChunk(container.file.raw)
  console.log('文件分了多少片:',chunkList.length)
  //通过webworker计算出文件hash
  container.fileMd5=await calculateMd5(chunkList)
  console.log('文件hash1:',container.fileMd5)
  // container.fileMd5=await getFileMD5(container.file.raw)
  // console.log('文件hash2:',container.hash)
  fileChunkList.value=[]
  fileChunkList.value=chunkList.map(({file},index) => ({
    fileMd5:container.fileMd5,
    index,
    chunkName: `${container.fileMd5}-${index}`,
    chunk:file,
    size:file.size,
    // 如果已上传切片数组uploadedList中包含这个切片,则证明这个切片之前已经上传成功了,进度设为100。
    percentage:0
  }))
  uploadChunks(fileChunkList)
}
//文件分片
const createFileChunk = (file,size=chunkSize.value) => {
  const chunkList=[]
  let cur=0
  while(cur<file.size){
    chunkList.push({
      file:file.slice(cur,cur+size),
    })
    cur+=size
  }
  return chunkList
}
//计算文件md5 方法1
const calculateMd5 = (chunkList) => {
  return new Promise((resolve) => {
    container.worker=new Worker('/hash.js')
    container.worker.postMessage({fileChunkList:chunkList})
    container.worker.onmessage= (e) => {
      const {percentage,hash} = e.data
      hashPercentage.value=percentage.toFixed(2)
      if(hash){
        resolve(hash)
      }
    }
  })
}
//计算文件md5 方法2
const  getFileMD5 = (file) => {
  return new Promise((resolve, reject) => {
    const spark = new SparkMD5.ArrayBuffer()
    const fileReader = new FileReader()
    fileReader.onload = (e) => {
      spark.append(e.target?.result)
      resolve(spark.end())
    }
    fileReader.onerror = () => {
      reject('')
    }
    fileReader.readAsArrayBuffer(file)
  })
}
//计算上传进度
const createProgressHandler = (item) => {
  console.log('createProgresshandler -> item', item);
  return (p) => {
    if(item.percentage>=100){
      item.percentage = 100
    }else{
      item.percentage=parseInt(String((p.loaded/p.total)*100))
    }
    // 确保进度百分比不会超过100%
    if (item.percentage > 100) item.percentage = 100
  }
}
//上传切片
const uploadChunks= async(uploadedList) => {
  const limit = pLimit(10); // 控制并发数为10
  const requestList=uploadedList.value.map(({chunk,chunkName,index,fileMd5}) => {
    const formdata=new FormData()
    formdata.append('file',chunk)
    formdata.append('chunkName',chunkName)
    formdata.append('fileName',container.file.name)
    formdata.append('fileMd5',fileMd5)
    formdata.append('index',index)
    return {formdata,index}
  }).map(async ({formdata,index}) => {
    return limit(() => doUploadChunk({data:formdata,onUploadProgress:createProgressHandler(fileChunkList.value[index])}))
  })
  await Promise.all(requestList)
  console.log("数组:",fileChunkList)
  if(uploadedCount.value>=fileChunkList.value.length){
    mergeRequest()
  }
}
const doUploadChunk = ({data,onUploadProgress}) => {
  return new Promise((resolve) => {
    uploadFileRequest(data,onUploadProgress).then((result) => {
      let resData=result.data
      if(result&&result.code==200){
        uploadedCount.value=uploadedCount.value+1
        fileChunkList.value[data.get('index')].percentage=100 //手动更新进度
        console.log(uploadedCount.value,'result--------------')
      }
      resolve('done')
    })
  })
}
const mergeRequest = async() => {
  if(container.file.name.lastIndexOf(".") === -1){
    ElMessage.warning("请输入文件后缀名")
    return
  }
  let data=await mergeFileRequest({fileMd5:container.fileMd5,fileName:container.file.name})
  console.log(data,"mege------------222")
  if(data && data.code==200){
    const filetype = data.data.originName.split(".").pop();
    if(filetype == 'mp4' || filetype == 'MP4'){
      container.showVideo = true
      await nextTick(() => {
        console.log("myPlayer.value",myPlayer.value)
        myPlayer.value.src(
            {
              src:"http://192.168.2.16:9000/trainexam/"+data.data.path,
              type: 'application/x-mpegURL',
            })
        //   myPlayer.value.load()
        myPlayer.value.play().catch((error) => {
          console.error('Error playing video:', error);
        });
      })
        //  myPlayer.value.pause()
        //myPlayer.value.reset()
    }
    const file = {
      resourceSize: data.data.size,
      md5: data.data.md5,
      resourcePath: data.data.path,
      mediaType: filetype,
      docPage: data.data.docPage,
      resourceLength: data.data.resourceLength,
      originName: data.data.originName
    }
    emit("getFile",file)
    ElMessage.success("上传成功")
  }else{
    ElMessage.success("合并数据失败")
  }
}
defineExpose({
  dispose,
  changeType,
  open
});
</script>
<style scoped>
.greetings{
  :deep(.video-js) {
    width: 300px;
    height: 200px;
  }
  :deep(.el-icon--close) {
    display: none;
  }
}
h1 {
  font-weight: 500;
  font-size: 2.6rem;
  position: relative;
  top: -10px;
}
h3 {
  font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
  text-align: center;
}
@media (min-width: 1024px) {
  .greetings h1,
  .greetings h3 {
    text-align: left;
  }
}
</style>
src/views/onlineEducation/courseManage/components/courseManageDialog.vue
对比新文件
@@ -0,0 +1,320 @@
<template>
  <div class="notice">
    <el-dialog
        v-model="dialogVisible"
        :title="title"
        width="500px"
        :before-close="handleClose"
    >
      <el-form :model="state.form" size="default" ref="busRef" :rules="state.formRules" label-width="150px" >
        <el-form-item label="课程名称:" prop="name">
          <el-input v-model.trim="state.form.name" placeholder="请输入课程名称"></el-input>
        </el-form-item>
        <el-form-item label="课程分类:" prop="categoryId" >
<!--          <el-select clearable v-model="state.form.categoryId" style="width: 100%" placeholder="请选择课程分类" @change="changeType">-->
<!--            <el-option v-for="item in state.classifyList" :key="item" :label="item.name" :value="item.id" />-->
<!--          </el-select>-->
          <el-cascader
              ref="classifyRef"
              v-model="state.form.categoryId"
              :options="state.classifyList"
              :props="state.props"
              clearable
              :show-all-levels="false"
              @change="handleChange"
          />
        </el-form-item>
        <el-form-item label="要求课时:" prop="period">
          <el-input v-model="state.form.period" placeholder="请输入要求课时">
            <template #append>分钟</template>
          </el-input>
        </el-form-item>
        <el-form-item label="提交单位:" prop="companyName" >
          <el-input v-model="state.form.companyName" disabled/>
        </el-form-item>
        <el-form-item label="封面:">
          <el-upload accept="image/*" :action="state.uploadUrl" :headers="state.header" method="post" :on-success="(res, uploadFile)=>handleAvatarSuccess(res, uploadFile)" :on-exceed="showTip" :limit='state.imgLimit' v-model:file-list="state.imgList" list-type="picture-card" :before-upload="picSize" :on-remove="(file, uploadFiles)=>handleRemove(file, uploadFiles)" >
            <el-icon><Plus /></el-icon>
            <template #tip>
              <div class="el-upload__tip">上传jpg/png图片尺寸小于5M,最多可上传1张</div>
            </template>
          </el-upload>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
            <el-button @click="handleClose" size="default">取 消</el-button>
            <el-button type="primary"  @click="onSubmit" size="default" v-preReClick>确认</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {reactive, ref, toRefs} from 'vue'
import Editor from "@/components/Editor/index.vue";
import {ElMessage} from "element-plus";
import {addNotice} from "@/api/backManage/notice";
import {addDict, editDict, getDictDetail} from "@/api/backManage/evaluate";
import {addCompany, checkName, distributeCompany, editCompany} from "@/api/onlineEducation/company";
import {verifyPhone} from "@/utils/validate";
import {
  addClassification,
  checkClassName,
  editClassification,
  getClassification
} from "@/api/onlineEducation/courseClass";
import {addCourse, checkCourseName, editCourse, getCourseById} from "@/api/onlineEducation/courseManage";
import {getToken} from "@/utils/auth";
import {delPic, getBannerById} from "@/api/onlineEducation/banner";
import Cookies from "js-cookie";
const dialogVisible = ref(false);
const title = ref("");
const busRef = ref();
const length = ref()
const emit = defineEmits(["getList"]);
const startUsername = ref('');
const classifyRef = ref(null)
const validateName = (rule, value, callback)=>{
  if(value === ''){
    callback(new Error('请输入课程名称'))
  }else if(title.value === '编辑' && value === startUsername.value){
    callback()
  }else{
    let param = {}
    if(title.value === '新增') {
      param = {
        name:value
      }
    }else if(title.value === '编辑'){
      param = {
        name:value,
        id: state.form.id
      }
    }
    checkCourseName(param).then((res)=>{
      if(res.data == false){
        callback(new Error('课程名称已被占用,请更换其他名称'))
      }else{
        callback()
      }
    })
  }
}
const state = reactive({
  form: {
    id: '',
    name: '',
    categoryId: null,
    period: null,
    logo: '',
    companyId: null
  },
  formRules: {
    name: [{required: true, trigger: "blur", validator: validateName}],
    categoryId: [{required: true, message: '请选择课程分类', trigger: 'blur'}],
    period: [{required: true, message: '请输入要求课时', trigger: 'blur'}],
  },
  classifyList: [],
  uploadUrl: import.meta.env.VITE_APP_BASE_API + '/system/common/uploadFile',
  header: {
    Authorization: getToken()
  },
  imgLimit: 1,
  imgList: [],
  isAdmin: false,
  props: {
    checkStrictly: true,
  }
})
const openDialog = async (type, value) => {
  await getClassifyList();
  const userInfo = JSON.parse(Cookies.get('userInfo'))
  console.log("userInfo",userInfo)
  if(userInfo.userType === 0){
    state.isAdmin = true;
    state.form.companyName = '公开课'
    state.form.companyId = null
  }else {
    state.isAdmin = false;
    state.form.companyName = userInfo.companyName
    state.form.companyId = userInfo.companyId
  }
  title.value = type === 'addFirst' || type === 'add' ? '新增' : type ==='edit' ? '编辑' : '' ;
  if(type === 'edit') {
    const res = await getCourseById(value.id);
    if(res.code === 200){
      state.form = res.data
      console.log("11",res.data)
      if(res.data.logo) {
        const obj = {
          url: import.meta.env.VITE_APP_BASE_API + "/" +  res.data.logo,
          name: ''
        }
        state.imgList = [obj]
      }
    }else{
      ElMessage.warning(res.message)
    }
    startUsername.value = value.username;
  }else if(type === 'add' && value ){
    state.form.parentId = value.id
  }
  dialogVisible.value = true;
}
const  getClassifyList = async () => {
  const res = await getClassification();
  if(res.code === 200){
    state.classifyList = recursion(res.data)
  }else{
    ElMessage.warning(res.message)
  }
}
const recursion = (data) => {
  let tmp = []
  for (let i = 0; i < data.length; i++) {
    let item = data[i]
    // children为空
    if (item.children&& item.children.length==0) {
      tmp.push({
        value: item.id,
        label: item.name
      })
      // 有children
    } else {
      tmp.push({
        value: item.id,
        label: item.name,
        children:recursion(item.children)
      })
    }
  }
  return tmp;
}
const handleAvatarSuccess = (res, uploadFile) => {
  if(res.code == 200){
    state.form.logo = res.data.path
  }else{
    state.imgList = []
    ElMessage({
      type: 'warning',
      message: '文件上传失败'
    })
  }
}
const handleChange = ()=> {
  console.log("label====",classifyRef.value.getCheckedNodes()[0].value)
  state.form.categoryId = classifyRef.value.getCheckedNodes()[0].value
  // 我这里只是打印了一下label的值哦,需要赋值的话自己去赋值哦
}
const showTip =()=>{
  ElMessage({
    type: 'warning',
    message: '超出文件上传数量'
  });
}
const picSize = async (rawFile) => {
  if(rawFile.size / 1024 / 1024 > 5){
    ElMessage({
      type: 'warning',
      message: '文件大小不能超过5M'
    });
    return false
  }
};
const handleRemove = async (file, uploadFiles) => {
  let path = state.form.logo;
  await delPic({path: path}).then(res => {
    if(res.code == 200){
      // ElMessage({
      //   type: 'success',
      //   message: '文件已删除'
      // })
      state.form.logo = ''
    }else{
      ElMessage({
        type: 'warning',
        message: res.message
      })
    }
  }).catch(() => {
    state.form.imgUrl = ''
  });
}
const onSubmit = async () => {
  const valid = await busRef.value.validate();
  if(valid){
    if(title.value === '新增'){
      const {id, ...data} = JSON.parse(JSON.stringify(state.form))
      const res = await addCourse(data)
      if(res.code === 200){
        ElMessage({
          type: 'success',
          message: '新增成功'
        });
      }else{
        ElMessage.warning(res.message)
      }
      emit("getList")
      busRef.value.clearValidate();
      reset();
      dialogVisible.value = false;
    }else if(title.value === '编辑'){
      const {...data} = JSON.parse(JSON.stringify(state.form))
      const res = await editCourse(data)
      if(res.code === 200){
        ElMessage({
          type: 'success',
          message: '编辑成功'
        });
      }else{
        ElMessage.warning(res.message)
      }
      emit("getList")
      busRef.value.clearValidate();
      reset();
      dialogVisible.value = false;
    }
  }
}
const handleClose = () => {
  busRef.value.clearValidate();
  reset();
  dialogVisible.value = false;
  emit("getList")
}
const reset = () => {
  state.form = {
    id: '',
    name: '',
    categoryId: null,
    period: null,
    logo: '',
    companyId: null
  }
}
defineExpose({
  openDialog
});
</script>
<style scoped lang="scss">
.notice{
  :deep(.el-form .el-form-item__label) {
    font-size: 15px;
  }
  .file {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
}
</style>
src/views/onlineEducation/courseManage/courseChapters/components/chapterDialog.vue
对比新文件
@@ -0,0 +1,249 @@
<template>
  <div class="notice">
    <el-dialog
        v-model="dialogVisible"
        :title="title"
        width="550px"
        :before-close="handleClose"
    >
      <el-form :model="state.form" size="default" ref="busRef" :rules="state.formRules" label-width="100px" >
        <el-form-item label="章名称:" prop="name">
          <el-input v-model.trim="state.form.name" maxlength="100" show-word-limit :disabled="!state.isFirst"></el-input>
        </el-form-item>
        <el-form-item label="节名称:" prop="chapter.name" v-if="!state.isFirst">
          <el-input v-model.trim="state.chapter.name"></el-input>
        </el-form-item>
        <el-form-item label="资源:" v-if="!state.isFirst">
          <div style="display: flex;align-items: center; width: 100%;justify-content: space-between;">
            <el-input v-model.trim="state.chapter.resourceName" disabled style="width: 80%"></el-input>
            <el-button type="primary" style="margin-left: 20px" plain size="default" @click="openResource">选择资源</el-button>
          </div>
        </el-form-item>
        <el-form-item label="排序:" prop="sort" >
          <el-input-number v-model="state.form.sort" />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
            <el-button @click="handleClose" size="default">取 消</el-button>
            <el-button type="primary"  @click="onSubmit" size="default" v-preReClick>确认</el-button>
        </span>
      </template>
    </el-dialog>
    <courseDialog ref="courseRef" @choose-res="choosedResource" ></courseDialog>
  </div>
</template>
<script setup>
import {reactive, ref, toRefs} from 'vue'
import Editor from "@/components/Editor/index.vue";
import {ElMessage} from "element-plus";
import {addNotice} from "@/api/backManage/notice";
import {addDict, editDict, getDictDetail} from "@/api/backManage/evaluate";
import {addCompany, checkName, distributeCompany, editCompany} from "@/api/onlineEducation/company";
import {verifyPhone} from "@/utils/validate";
import {addClassification, checkClassName, editClassification} from "@/api/onlineEducation/courseClass";
import courseDialog from './chooseResource.vue'
import {
  addChapter,
  addChapterPeriod,
  checkChapterName,
  editChapter,
  editChapterPeriod
} from "@/api/onlineEducation/chapters";
const dialogVisible = ref(false);
const title = ref("");
const busRef = ref();
const courseRef = ref()
const length = ref()
const emit = defineEmits(["getList"]);
const startUsername = ref('');
const startUsernamePeriod = ref('');
const validateName = (rule, value, callback)=>{
  if(value === ''){
    callback(new Error('请输入章名称'))
  }else if(title.value === '编辑' && value === startUsername.value || title.value === '新增' && value === startUsername.value){
    callback()
  }else{
    let param = {}
    if(title.value === '新增') {
      param = {
        name:value,
        courseId: state.form.courseId
      }
    }else if(title.value === '编辑'){
      param = {
        name:value,
        id: state.form.id,
        courseId: state.form.courseId
      }
    }
    checkChapterName(param).then((res)=>{
      if(res.data == false){
        callback(new Error('名称已被占用,请更换其他名称'))
      }else{
        callback()
      }
    })
  }
}
const state = reactive({
  form: {
    id: '',
    name: '',
    sort: 0,
    courseId: null,
    chapterPeriods: []
  },
  formRules:{
    name: [{ required: true, trigger: "blur", validator: validateName }],
  },
  isFirst: true,
  chapter: {}
})
const openDialog = async (type, value) => {
  length.value = value.listLength
  state.form.courseId = value.courseId
  title.value = type === 'addFirst' || type === 'add' ? '新增' : type ==='edit' ? '编辑' : '' ;
  if(type === 'edit') {
    if(!value.chapterId){
      state.isFirst = true;
      startUsername.value = value.name;
      state.form = value;
      state.form.sort = value.sort;
    }else {
      state.isFirst = false;
      startUsernamePeriod.value = value.name;
      state.chapter = value;
      state.form.name = value.capterName;
      startUsername.value = value.capterName;
      state.chapter.resourceName = value.resource.name
    }
  }else if(type === 'add' && value ){
    startUsername.value = value.name;
    state.chapter.chapterId = value.id;
    state.chapter.courseId = value.courseId;
    state.form.name = value.name
    state.isFirst = false;
  }else {
    state.isFirst = true;
  }
  dialogVisible.value = true;
}
const choosedResource = (val) => {
  state.chapter.resourceName = val.name
  state.chapter.resourceId = val.id
}
const onSubmit = async () => {
  const valid = await busRef.value.validate();
  if(valid){
    if(title.value === '新增'){
      if(state.chapter.chapterId){
        const {id, ...data} = JSON.parse(JSON.stringify(state.chapter))
        const res = await addChapterPeriod(data)
        if(res.code === 200){
          ElMessage({
            type: 'success',
            message: '新增成功'
          });
        }else{
          ElMessage.warning(res.message)
        }
      }else{
        const {id, ...data} = JSON.parse(JSON.stringify(state.form))
        const res = await addChapter(data)
        if(res.code === 200){
          ElMessage({
            type: 'success',
            message: '新增成功'
          });
        }else{
          ElMessage.warning(res.message)
        }
      }
      emit("getList")
      busRef.value.clearValidate();
      reset();
      dialogVisible.value = false;
    }else if(title.value === '编辑'){
      if(state.chapter.chapterId){
        const {...data} = JSON.parse(JSON.stringify(state.chapter))
        const res = await editChapterPeriod(data)
        if(res.code === 200){
          ElMessage({
            type: 'success',
            message: '编辑成功'
          });
        }else{
          ElMessage.warning(res.message)
        }
        emit("getList")
        busRef.value.clearValidate();
        reset();
        dialogVisible.value = false;
      }else {
        const {...data} = JSON.parse(JSON.stringify(state.form))
        const res = await editChapter(data)
        if(res.code === 200){
          ElMessage({
            type: 'success',
            message: '编辑成功'
          });
        }else{
          ElMessage.warning(res.message)
        }
        emit("getList")
        busRef.value.clearValidate();
        reset();
        dialogVisible.value = false;
      }
    }
  }
}
const handleClose = () => {
  busRef.value.clearValidate();
  reset();
  dialogVisible.value = false;
  emit("getList")
}
const openResource = () => {
  courseRef.value.openDialog()
}
const reset = () => {
  state.form = {
    id: '',
    name: '',
    sort: 0,
    courseId: null,
    chapterPeriods: []
  }
  state.chapter={}
}
defineExpose({
  openDialog
});
</script>
<style scoped lang="scss">
.notice{
  :deep(.el-form .el-form-item__label) {
    font-size: 15px;
  }
  .file {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
}
</style>
src/views/onlineEducation/courseManage/courseChapters/components/chooseResource.vue
对比新文件
@@ -0,0 +1,123 @@
<template>
  <div class="app-container">
    <el-dialog
        v-model="dialogVisible"
        title="选择资源"
        width="600px"
        :before-close="handleClose"
    >
    <div style="margin-bottom: 10px">
      <el-form>
        <el-form-item label="资源名称">
          <el-input style="width: 20%" v-model="data.queryParams.name "></el-input>
          <el-button type="primary" style="margin-left: 30px" @click="getList">查询</el-button>
          <el-button plain @click="reset">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
    <!-- 表格数据 -->
    <el-table v-loading="loading" :data="dataList" :border="true">
      <el-table-column label="序号" type="index" align="center" width="80" />
      <el-table-column label="资源名称" prop="name" align="center"  />
      <el-table-column label="资源类型" prop="resourceType" align="center"  >
        <template #default="scope">
          <span>{{scope.row.resourceType == 1 ? '视频':scope.row.resourceType == 2 ? '音频':'文档'}}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" >
        <template #default="scope">
          <el-button link type="primary" @click="choose(scope.row)">选择</el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination
        v-show="total > 0"
        :total="total"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        @pagination="getList"
    />
    </el-dialog>
  </div>
</template>
<script setup>
import {getCurrentInstance, onMounted, onUnmounted, reactive, ref, toRefs} from "vue";
import {ElMessage, ElMessageBox} from "element-plus";
import {checkResourceName, delResource, getResource} from "@/api/onlineEducation/courseResource";
import {checkName} from "@/api/onlineEducation/company";
const { proxy } = getCurrentInstance();
const loading = ref(false);
const emit = defineEmits(["chooseRes"]);
const dialogRef = ref();
const data = reactive({
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    name: ''
  },
  total: 0,
  dataList: []
});
const dialogVisible = ref(false);
const { queryParams, total, dataList } = toRefs(data);
onMounted(()=>{
})
onUnmounted(()=>{
})
const openDialog = async () => {
  await getList()
  dialogVisible.value = true;
}
const handleClose = () => {
  dialogVisible.value = false;
}
const getList = async () => {
  loading.value = true
  const res = await getResource(data.queryParams)
  if(res.code == 200){
    data.dataList = res.data.list.map(item => {
      return{
        ...item,
        sizeMB: Number((item.resourceSize /1024 /1024).toFixed(2))+'MB'
      }
    })
    console.log("ddd",data.dataList)
    data.total = res.data.total
  }else{
    ElMessage.warning(res.message)
  }
  loading.value = false
}
const choose = (value) => {
  console.log("co",value)
  emit('chooseRes',value)
  dialogVisible.value = false
  // dialogRef.value.openDialog(type, value);
}
defineExpose({
  openDialog
});
/** 重置新增的表单以及其他数据  */
function reset() {
  data.queryParams = {
    pageNum: 1,
        pageSize: 10,
        name: ''
  }
  getList()
}
</script>
src/views/onlineEducation/courseManage/courseChapters/index.vue
对比新文件
@@ -0,0 +1,124 @@
<template>
  <div class="app-container">
    <div style="margin-bottom: 10px">
      <el-button type="success" plain @click="openDialog('addFirst',{courseId: data.courseId})">章添加</el-button>
    </div>
    <!-- 表格数据 -->
    <el-table v-loading="loading" :data="dataList" :border="true" row-key="id" :tree-props="{ children: 'chapterPeriods' }">
      <el-table-column label="序号" type="index" align="center" width="80" />
      <el-table-column label="章节名称" >
        <template #default="scope">
          <span>{{scope.row.name}}</span>
        </template>
      </el-table-column>
      <el-table-column label="排序" prop="sort" align="center" width="80" />
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="250" >
        <template #default="scope">
          <el-button type="success" plain @click="openDialog('add',scope.row)" v-if="!scope.row.chapterId">节添加</el-button>
          <el-button type="primary" plain @click="openDialog('edit',scope.row)">编辑</el-button>
          <el-button type="danger" plain @click="handleDelete(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <chapters-dialog ref="areaRef" @getList="getList"></chapters-dialog>
  </div>
</template>
<script setup>
import {getCurrentInstance, onMounted, reactive, ref, toRefs} from "vue";
import {ElMessage, ElMessageBox} from "element-plus";
import chaptersDialog from "./components/chapterDialog.vue"
import {delArea, getArea} from "@/api/backManage/area";
import {getDictList} from "@/api/backManage/evaluate";
import {delMonitor} from "@/api/sysUsers";
import {useRoute} from 'vue-router'
import {delClassification, getClassification} from "@/api/onlineEducation/courseClass";
import {delChapter, delPeriod, getChapters} from "@/api/onlineEducation/chapters";
const { proxy } = getCurrentInstance();
const route = useRoute()
const loading = ref(false);
const areaRef = ref();
const cityList = ref([])
const data = reactive({
  queryParams: {
    name: '',
  },
  total: 0,
  dataList: [
  ],
  courseId: ''
});
const { queryParams, total, dataList } = toRefs(data);
//页面加载
onMounted(() => {
  data.courseId = route.query.courseId
  console.log("rou",data.courseId)
  getList();
});
const getList = async () => {
  loading.value = true;
  const param = {
    courseId: data.courseId
  }
  const res = await getChapters(param);
  if(res.code === 200){
    dataList.value = res.data
  }else{
    ElMessage.warning(res.message)
  }
  loading.value = false;
  console.log('dataList.value',dataList.value)
}
const openDialog = (type, value) => {
  dataList.value.forEach(item => {
    if(item.id == value.chapterId){
      value.capterName = item.name
    }
  })
  areaRef.value.openDialog(type, value);
}
/** 重置新增的表单以及其他数据  */
function reset() {
  data.queryParams.name = '';
  data.queryParams.pageNum = 1;
  getList();
}
const handleDelete = (val) => {
  ElMessageBox.confirm(
      '确定删除此条数据?',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
      .then( async() => {
        if(!val.chapterId){
          const res = await delChapter(val.id)
          if(res.code == 200){
            ElMessage.success('数据删除成功')
            await getList()
          }else{
            ElMessage.warning(res.message)
          }
        }else {
          const res = await delPeriod(val.id)
          if(res.code == 200){
            ElMessage.success('数据删除成功')
            await getList()
          }else{
            ElMessage.warning(res.message)
          }
        }
      })
}
</script>
src/views/onlineEducation/courseManage/courseResource/componets/resourceDialog.vue
对比新文件
@@ -0,0 +1,345 @@
<template>
  <div class="notice">
    <el-dialog
        v-model="dialogVisible"
        :title="title"
        width="550px"
        :before-close="handleClose"
    >
      <el-form :model="state.form" size="default" ref="busRef" :rules="state.formRules" label-width="130px" >
        <el-form-item label="资源名称:" prop="name" >
          <el-input v-model.trim="state.form.name" placeholder="请输入资源名称"></el-input>
        </el-form-item>
        <el-form-item label="资源类型:" prop="resourceType" >
          <el-select
              @change="changeType"
              v-model="state.form.resourceType"
              placeholder="请选择资源类型"
              size="default"
              style="width: 100%"
          >
            <el-option
                v-for="item in state.typeList"
                :key="item.id"
                :label="item.name"
                :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item  label="资源时长(秒):" prop="resourceLength"  v-if="(state.form.resourceType == 1 || state.form.resourceType == 2)&& state.form.resourceLength">
          <el-input
              :disabled="state.form.resourceLength!=0"
              v-model="state.form.resourceLength"
              style="width: 100%"
              placeholder="请输入资源时长(秒)"
          >
            <template #append>秒</template>
          </el-input>
        </el-form-item>
        <el-form-item  label="文档页数:" prop="docPage"  v-if="state.form.resourceType == 3 && state.form.docPage ">
          <el-input
              :disabled="state.form.docPage!=0"
              v-model="state.form.docPage"
              style="width: 100%"
              placeholder="请输入文档页数:"
          >
            <template #append>页</template>
          </el-input>
        </el-form-item>
        <el-form-item  label="资源上传:">
          <file-upload ref="fileRef" :responseType="state.form.resourceType" @getFile="getFile"></file-upload>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
            <el-button @click="handleClose" size="default">取 消</el-button>
            <el-button type="primary"  @click="onSubmit" size="default" v-preReClick>确认</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {nextTick, reactive, ref, toRefs} from 'vue'
import Editor from "@/components/Editor/index.vue";
import {ElMessage} from "element-plus";
import {addNotice} from "@/api/backManage/notice";
import {addDict, editDict, getDictDetail} from "@/api/backManage/evaluate";
import {addCompany, checkName, distributeCompany, editCompany} from "@/api/onlineEducation/company";
import {verifyPhone} from "@/utils/validate";
import {addBanner, delPic, editBanner, getBannerById} from "@/api/onlineEducation/banner";
import {getToken} from "@/utils/auth";
import {getUserById} from "@/api/onlineEducation/user";
import {addResource, checkResourceName, editResource, getResourceById} from "@/api/onlineEducation/courseResource";
import fileUpload from '@/views/components/upload.vue'
import Cookies from "js-cookie";
const dialogVisible = ref(false);
const title = ref("");
const fileRef = ref();
const busRef = ref();
const length = ref()
const emit = defineEmits(["getList"]);
const startUsername = ref('');
const startPhone = ref('');
const validateName = (rule, value, callback)=>{
  if(value === ''){
    callback(new Error('请输入资源名称'))
  }else if(title.value === '编辑' && value === startUsername.value){
    callback()
  }else{
    let param = {}
    if(title.value === '新增') {
      param = {
        name:value,
      }
    }else if(title.value === '编辑'){
      param = {
        name:value,
        id: state.form.id
      }
    }
    checkResourceName(param).then((res)=>{
      if(res.data == false){
        callback(new Error('资源名称已被占用,请更换其他名称'))
      }else{
        callback()
      }
    })
  }
}
const state = reactive({
  form: {
    id: '',
    name: '',
    mediaType: '',
    resourceType: null,
    companyId: null,
    resourcePath:'',
    md5: '',
    resourceSize: null,
    resourceLength: '',
    docPage: null,
    originName: ''
  },
  formRules:{
    name: [{ required: true, trigger: "blur", validator: validateName }],
    resourceType:[{ required: true, message: '请选择资源类型', trigger: 'blur' }],
    resourceLength: [{ required: true, trigger: "blur", message: '请输入资源时长(秒)' }],
  },
  uploadUrl: import.meta.env.VITE_APP_BASE_API + '/system/common/uploadFile',
  header: {
    Authorization:getToken()
  },
  imgLimit: 1,
  imgList: [],
  typeList: [
    {
      id: 1,
      name: '视频'
    },
    {
      id: 2,
      name: '音频'
    },
    {
      id: 3,
      name: '文档'
    },
  ]
})
const  handleChange = (file, fileLists) => {
  state.form.file = file.raw;
  console.log(file);
  // 这里把数组置空是为了每次只能上传一个文件,以防报错
  state.imgList = [];
  state.form.mediaType = file.raw.type
}
const handleAvatarSuccess = (response, file, fileList) => {
  if(response.code == 200){
    if(file && file.raw){
      state.form.mediaType = file.raw.type
    }
    state.form.file = file
  }else{
    state.imgList = []
    ElMessage({
      type: 'warning',
      message: '文件上传失败'
    })
  }
}
const showTip =()=>{
  ElMessage({
    type: 'warning',
    message: '超出文件上传数量'
  });
}
const picSize = async (rawFile) => {
  if(rawFile.size / 1024 / 1024 > 5){
    ElMessage({
      type: 'warning',
      message: '文件大小不能超过5M'
    });
    return false
  }
};
const handleRemove = async (file, uploadFiles) => {
  let path = state.form.imgUrl;
  await delPic({path: path}).then(res => {
    if(res.code == 200){
      // ElMessage({
      //   type: 'success',
      //   message: '文件已删除'
      // })
      state.form.imgUrl = ''
    }else{
      ElMessage({
        type: 'warning',
        message: res.message
      })
    }
  }).catch(() => {
    state.form.imgUrl = ''
  });
}
const openDialog = async (type, value) => {
  length.value = value.listLength
  title.value = type === 'add' ? '新增' : type ==='edit' ? '编辑' : '' ;
  if(type === 'edit') {
    const res = await getResourceById(value.id);
    if(res.code === 200){
      state.form = res.data
    }else{
      ElMessage.warning(res.message)
    }
  }
  dialogVisible.value = true;
  if(type === 'edit') {
    await nextTick(() => {
      fileRef.value.open(state.form);
    })
  }
}
const getFile = (val) => {
  if(val.md5 != ''){
    state.form.md5 = val.md5
    state.form.resourcePath = val.resourcePath
    state.form.mediaType = val.mediaType
    state.form.resourceSize = val.resourceSize
    state.form.docPage = val.docPage
    state.form.resourceLength = val.resourceLength
    state.form.originName = val.originName
  } else if( val.md5 == ''){
    state.form.resourceType = ''
  } else {
      ElMessage({
        type: 'warning',
        message: '请上传题库资源'
      });
  }
}
const changeType = (val) => {
  state.form.md5 = ''
  state.form.resourcePath = ''
  state.form.mediaType =''
  state.form.resourceSize = null
  state.form.docPage = null
  state.form.resourceLength = null
  state.form.originName = ''
  fileRef.value.changeType(val);
}
const onSubmit = async () => {
  const valid = await busRef.value.validate();
  if(valid){
    if(title.value === '新增'){
      const {id,...data} = JSON.parse(JSON.stringify(state.form))
      const res = await addResource(data)
      if(res.code === 200){
        ElMessage({
          type: 'success',
          message: '新增成功'
        });
      }else{
        ElMessage.warning(res.message)
      }
      dialogVisible.value = false;
      emit("getList")
      busRef.value.clearValidate();
      fileRef.value.dispose();
      reset();
    }else if(title.value === '编辑'){
      const {...data} = JSON.parse(JSON.stringify(state.form))
      const res = await editResource(data)
      if(res.code === 200){
        ElMessage({
          type: 'success',
          message: '编辑成功'
        });
      }else{
        ElMessage.warning(res.message)
      }
      dialogVisible.value = false;
      emit("getList")
      busRef.value.clearValidate();
      fileRef.value.dispose();
      reset();
    }
  }
}
const handleClose = () => {
  dialogVisible.value = false;
  fileRef.value.dispose();
  busRef.value.clearValidate();
  reset();
  emit("getList")
}
const reset = () => {
  state.form = {
    id: '',
    name: '',
    mediaType: '',
    resourceType: null,
    companyId: null,
    resourcePath:'',
    md5: '',
    resourceSize: null,
    resourceLength: '',
    docPage: null,
    originName: ''
  }
}
defineExpose({
  openDialog
});
</script>
<style scoped lang="scss">
.notice{
  :deep(.el-form .el-form-item__label) {
    font-size: 15px;
  }
  .file {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
}
</style>
src/views/onlineEducation/courseManage/courseResource/index.vue
对比新文件
@@ -0,0 +1,115 @@
<template>
  <div class="app-container">
    <div style="margin-bottom: 10px">
      <el-button
          type="primary"
          plain
          icon="Plus"
          @click="openDialog('add',{})"
      >新增</el-button>
    </div>
    <!-- 表格数据 -->
    <el-table v-loading="loading" :data="dataList" :border="true">
      <el-table-column label="序号" type="index" align="center" width="80" />
      <el-table-column label="资源名称" prop="name" align="center"  />
      <el-table-column label="资源大小" prop="sizeMB" align="center"  >
      </el-table-column>
      <el-table-column label="资源类型" prop="resourceType" align="center"  >
        <template #default="scope">
          <span>{{scope.row.resourceType == 1 ? '视频':scope.row.resourceType == 2 ? '音频':'文档'}}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" >
        <template #default="scope">
          <el-button link type="primary" @click="openDialog('edit',scope.row)">编辑</el-button>
          <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination
        v-show="total > 0"
        :total="total"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        @pagination="getList"
    />
<resource-dialog ref="dialogRef" @getList="getList"></resource-dialog>
  </div>
</template>
<script setup>
import {getCurrentInstance, onMounted, onUnmounted, reactive, ref, toRefs} from "vue";
import {ElMessage, ElMessageBox} from "element-plus";
import resourceDialog from './componets/resourceDialog.vue'
import {checkResourceName, delResource, getResource} from "@/api/onlineEducation/courseResource";
import {checkName} from "@/api/onlineEducation/company";
const { proxy } = getCurrentInstance();
const loading = ref(false);
const dialogRef = ref();
const data = reactive({
  queryParams: {
    pageNum: 1,
    pageSize: 10,
  },
  total: 0,
  dataList: []
});
const { queryParams, total, dataList } = toRefs(data);
onMounted(()=>{
  getList()
})
onUnmounted(()=>{
})
const getList = async () => {
  loading.value = true
  const res = await getResource(data.queryParams)
  if(res.code == 200){
    data.dataList = res.data.list.map(item => {
      return{
        ...item,
        sizeMB: Number((item.resourceSize /1024 /1024).toFixed(2))+'MB'
      }
    })
    console.log("ddd",data.dataList)
    data.total = res.data.total
  }else{
    ElMessage.warning(res.message)
  }
  loading.value = false
}
const openDialog = (type, value) => {
  dialogRef.value.openDialog(type, value);
}
/** 重置新增的表单以及其他数据  */
function reset() {
  proxy.resetForm("roleRef");
}
const handleDelete = (val) => {
  ElMessageBox.confirm(
      '确定删除此条数据?',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
      .then( async() => {
        const res = await delResource(val.id)
        if(res.code == 200){
          ElMessage.success('数据删除成功')
          await getList()
        }else{
          ElMessage.warning(res.message)
        }
      })
}
</script>
src/views/onlineEducation/courseManage/index.vue
@@ -1,12 +1,263 @@
<template>
<div>课程管理</div>
  <div class="app-container">
    <div style="margin-bottom: 10px">
      <el-button
          type="primary"
          plain
          icon="Plus"
          @click="openDialog('add',{})"
      >新增</el-button>
    </div>
    <!-- 表格数据 -->
    <el-table v-loading="loading" :data="dataList" :border="true">
      <el-table-column label="序号" type="index" align="center" width="80" />
      <el-table-column label="封面" prop="logo" align="center"  >
        <template #default="scope">
          <div class="demo-image__preview" v-if="scope.row.logo && scope.row.logo.length>0">
            <el-image
                style="width: 100px; height: 100px"
                :src= "scope.row.logo[0]"
                :zoom-rate="1.2"
                :max-scale="7"
                :min-scale="0.2"
                :preview-src-list="scope.row.logo"
                :initial-index="0"
                fit="cover"
                :preview-teleported=true
            />
          </div>
</template>
      </el-table-column>
      <el-table-column label="课程名称" prop="name" align="center"  />
      <el-table-column label="课程分类" prop="categoryName" align="center" />
      <el-table-column label="要求课时" prop="period" align="center" />
      <el-table-column label="提交单位" prop="companyName" align="center" />
      <el-table-column label="审核状态" prop="state" align="center" >
        <template #default="scope">
          <span>{{scope.row.state == 1?'待审核':scope.row.state == 2?'审批通过':'审批不通过'}}</span>
        </template>
      </el-table-column>
      <el-table-column label="创建时间" prop="createTime" align="center" width="180" />
      <el-table-column label="状态" prop="status" align="center" >
        <template #default="scope" v-if="data.isAdmin">
          <el-switch
              v-if="scope.row.state == 2"
              v-model="scope.row.status"
              :active-value="0"
              :inactive-value="1"
              inline-prompt
              active-text="正常"
              inactive-text="停用"
              @change="switchStatus($event,scope.row)"
          />
          <span v-else>--</span>
        </template>
        <template #default="scope" v-else>
          <span v-if="scope.row.state == 2">{{scope.row.status == 1? '停用' : '正常'}}</span>
          <span v-else>--</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
        <template #default="scope">
          <div v-if="scope.row.state == 2">
            <div v-if="data.isAdmin">
              <el-button link type="primary" @click="openDialog('edit',scope.row)">编辑</el-button>
              <el-button link type="primary" @click="toChapters(scope.row)">章节</el-button>
              <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
            </div>
            <div v-else>--</div>
          </div>
          <div v-else-if="scope.row.state == 1" >
              <el-button link type="primary" @click="openDialog('edit',scope.row)">编辑</el-button>
              <el-button link type="primary" v-if="data.isAdmin" @click="openApprove(scope.row)">审核</el-button>
            <el-button link type="primary" @click="toChapters(scope.row)">章节</el-button>
              <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
          </div>
          <div v-else-if="scope.row.state == 3" >
            <div v-if="data.isAdmin">--</div>
            <div v-else>
              <el-button link type="primary" @click="openDialog('edit',scope.row)">编辑</el-button>
              <el-button link type="primary" @click="submitApprove(scope.row)">提交审核</el-button>
              <el-button link type="primary" @click="toChapters(scope.row)">章节</el-button>
              <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
            </div>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <pagination
        v-show="total > 0"
        :total="total"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        @pagination="getList"
    />
    <course-manage-dialog ref="dialogRef" @getList=getList></course-manage-dialog>
    <el-dialog v-model="data.appDialog" title="审批课程" width="30%" center align-center>
      <el-radio-group v-model="data.appoveForm.state" style="width: 100%">
        <el-radio :label="2" size="large" border>通过</el-radio>
        <el-radio :label="3" size="large" border>驳回</el-radio>
      </el-radio-group>
      <template #footer>
            <span class="dialog-footer">
              <el-button @click="data.appDialog = false">取消</el-button>
              <el-button type="primary" @click="confirmApproval">确认</el-button>
            </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {getCurrentInstance, onMounted, onUnmounted, reactive, ref, toRefs} from "vue";
import {ElMessage, ElMessageBox} from "element-plus";
import {delCompany, getCompany} from "@/api/onlineEducation/company";
import courseManageDialog from  './components/courseManageDialog.vue'
import {delBanner, getBanner} from "@/api/onlineEducation/banner";
import {useRouter} from 'vue-router'
import Cookies from "js-cookie";
import {changeCourseStatus, delCourse, doCourse, getCourse} from "@/api/onlineEducation/courseManage";
const { proxy } = getCurrentInstance();
const router = useRouter()
const loading = ref(false);
const dialogRef = ref();
const data = reactive({
  queryParams: {
    pageNum: 1,
    pageSize: 10,
  },
  total: 0,
  dataList: [],
  isAdmin: false,
  appDialog: false,
  appoveForm: {
    id: null,
    state: null
  },
});
const { queryParams, total, dataList } = toRefs(data);
onMounted(async ()=>{
  const userInfo = JSON.parse(Cookies.get('userInfo'))
  console.log("userInfo",userInfo)
  if(userInfo.userType === 0){
    data.isAdmin = true;
  }else {
    data.isAdmin = false;
  }
  await getList()
})
onUnmounted(()=>{
})
const getList = async () => {
  loading.value = true
  const res = await getCourse(data.queryParams)
  if(res.code == 200){
    data.dataList = res.data.list.map(item => {
      return {
        ...item,
        logo: item.logo ?[import.meta.env.VITE_APP_BASE_API + "/" +  item.logo] : [],
      }
    })
    console.log("ddd",data.dataList)
    data.total = res.data.total
  }else{
    ElMessage.warning(res.message)
  }
  loading.value = false
}
const openDialog = (type, value) => {
  dialogRef.value.openDialog(type, value);
}
/** 重置新增的表单以及其他数据  */
function reset() {
  proxy.resetForm("roleRef");
}
const handleDelete = (val) => {
  ElMessageBox.confirm(
      '确定删除此条数据?',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
      .then( async() => {
        const res = await delCourse(val.id)
        if(res.code == 200){
          ElMessage.success('数据删除成功')
          await getList()
        }else{
          ElMessage.warning(res.message)
        }
      })
}
const switchStatus = (e,val) => {
  ElMessageBox.confirm(
      '确定修改该课程当前状态?',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
      .then( async() => {
        const res = await changeCourseStatus({id: val.id,status: e})
        if(res.code == 200){
          ElMessage.success('状态修改成功')
          await getList()
        }else{
          ElMessage.warning(res.message)
        }
      })
      .catch(() => {
        getList()
      })
}
const openApprove  = (val) => {
  data.appoveForm = {
    id: null,
    state: null
  }
  data.appoveForm.id = val.id
  data.appDialog = true
}
const confirmApproval = async () =>{
  if(data.appoveForm.state !== null){
    const res = await doCourse(data.appoveForm)
    if(res.code == 200){
      ElMessage.success('审批成功')
      await getList()
      data.appDialog = false
    }else{
      ElMessage.warning(res.message)
    }
  }
}
const submitApprove = async (val) => {
  const param = {
    id: val.id,
    state: 1
  }
  const res = await doCourse(param)
  if(res.code == 200){
    ElMessage.success('提交成功')
    await getList()
  }else{
    ElMessage.warning(res.message)
  }
}
const toChapters = (val) => {
  router.push({ path: "/chapters", query: { courseId: val.id } });
}
</script>
<style scoped lang="scss">
</style>
src/views/onlineEducation/people/components/stuDialog.vue
对比新文件
@@ -0,0 +1,311 @@
<template>
  <div class="notice">
    <el-dialog
        v-model="dialogVisible"
        :title="state.title"
        width="550px"
        :before-close="handleClose"
    >
      <el-form :model="state.form" size="default" ref="superRef" :rules="state.formRules" label-width="180px" >
        <el-form-item label="企业:"  prop="companyName" v-if="state.title !== '修改密码'">
          <el-input v-model.trim="state.form.companyName" disabled></el-input>
        </el-form-item>
        <el-form-item label="姓名:"  prop="name" v-if="state.title !== '修改密码'">
          <el-input v-model.trim="state.form.name" :disabled="disabled" placeholder="请输入姓名" ></el-input>
        </el-form-item>
        <el-form-item label="性别:"  prop="sex" v-if="state.title !== '修改密码'">
          <el-radio-group v-model="state.form.sex"  :disabled="disabled">
            <el-radio :label="0">男</el-radio>
            <el-radio :label="1">女</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="身份证号:"  prop="idNo" v-if="state.title !== '修改密码'">
          <el-input v-model.trim="state.form.idNo" :disabled="disabled" placeholder="请输入身份证号" ></el-input>
        </el-form-item>
        <el-form-item label="手机号(登录用户名):" prop="phone" v-if="state.title !== '修改密码'" >
          <el-input v-model.trim="state.form.phone" :maxlength="11" :disabled="disabled" placeholder="请输入手机号"></el-input>
        </el-form-item>
        <el-form-item label="密码:" prop="password" v-if="state.title == '新增' || state.title == '修改密码'">
          <el-input v-model.trim="state.form.password" type="password" show-password placeholder="请输入密码"></el-input>
        </el-form-item>
        <el-form-item label="重复密码:" prop="confirmPassword" v-if="state.title == '新增' || state.title == '修改密码'">
          <el-input v-model.trim="state.form.confirmPassword" type="password" show-password placeholder="请输入确认密码"></el-input>
        </el-form-item>
        <el-form-item label="工号:"  prop="empno" v-if="state.title !== '修改密码'">
          <el-input v-model.trim="state.form.empno" :disabled="disabled" placeholder="请输入工号" ></el-input>
        </el-form-item>
        <el-form-item label="岗位:"  prop="post" v-if="state.title !== '修改密码'">
          <el-input v-model.trim="state.form.post" :disabled="disabled" placeholder="请输入岗位" ></el-input>
        </el-form-item>
        <el-form-item label="职务:"  prop="duty" v-if="state.title !== '修改密码'">
          <el-input v-model.trim="state.form.duty" :disabled="disabled" placeholder="请输入职务" ></el-input>
        </el-form-item>
      </el-form>
      <template #footer v-if="state.title !='查看'">
        <span class="dialog-footer">
            <el-button @click="handleClose" size="default">取 消</el-button>
            <el-button type="primary"  @click="onSubmit" size="default" v-preReClick>确认</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import {reactive, ref, toRefs, defineEmits, nextTick, onMounted} from 'vue'
import { View } from "@element-plus/icons-vue";
import scorllSelect from '@/components/scrollSelect/index.vue'
import {ElMessage, ElMessageBox} from "element-plus";
import {verifyPhone, verifyPwd, verifyUsername} from "@/utils/validate";
import { checkUserName, checkPhone } from "@/api/login"
import {resetPwd} from "@/api/onlineEducation/student"
import {Base64} from "js-base64"
import Cookies from "js-cookie";
import {addStudent, checkStuIdNo, checkStuPhone, editStudent} from "@/api/onlineEducation/student";
const emit = defineEmits(["getList"]);
const dialogVisible = ref(false)
const superRef = ref(null)
const scrollRef = ref(null)
const equalToPassword = (rule, value, callback) => {
  if (state.form.password !== value) {
    callback(new Error("两次输入的密码不一致"));
  } else {
    callback();
  }
};
const validateUserPhone = (rule, value, callback)=>{
  if(value === ''){
    callback(new Error('请输入手机号'))
  }else if(state.title === '编辑' && value === startPhone.value){
    callback()
  } else if(!verifyPhone(value)){
    callback(new Error('手机号格式有误'))
  }else{
    let param = {}
    if(state.title === '新增') {
      param = {
        phone:value
      }
    }else if(state.title === '编辑'){
      param = {
        phone:value,
        id: state.form.id
      }
    }
    checkStuPhone(param).then((res)=>{
      if(res.data == false){
        callback(new Error('手机号已被占用,请更换其他手机号'))
      }else{
        callback()
      }
    })
  }
}
let validatePwd = (rule, value, callback)=>{
  if(value === ''){
    callback(new Error('请输入密码'))
  }else{
    if(!verifyPwd(value)){
      callback(new Error('密码须包含字母、数字、特殊字符,长度在6-16之间'))
    }else{
      callback()
    }
  }
}
let validateIdNo = (rule, value, callback)=>{
  if(value === ''){
    callback(new Error('请输入身份证号'))
  }else if(state.title === '编辑' && value === startIdNo.value){
    callback()
  }else{
    let param = {}
    if(state.title === '新增') {
      param = {
        idNo:value
      }
    }else if(state.title === '编辑'){
      param = {
        idNo:value,
        id: state.form.id
      }
    }
    checkStuIdNo(param).then((res)=>{
      if(res.data == false){
        callback(new Error('身份证号已被占用,请更换其他身份证号'))
        // ElMessageBox.confirm(
        //     `该人员${state.form.name}(身份证号:${state.form.idNo})与${state.form.idNo}已经绑定,确定将该人员的责任归属变更到贵公企业?`,
        //     '提示',
        //     {
        //       confirmButtonText: '确认',
        //       cancelButtonText: '取消',
        //       type: 'warning',
        //       icon: ''
        //     }
        // )
        //     .then(() => {
        //       ElMessage({
        //         type: 'success',
        //         message: 'Delete completed',
        //       })
        //     })
        //     .catch(() => {
        //       callback(new Error('身份证号已被占用,请更换其他身份证号'))
        //     })
      }else{
        callback()
      }
    })
  }
}
const state = reactive({
  title: '',
  form: {
    id: null,
    name: '',
    phone: '',
    password: '',
    confirmPassword: '',
    sex: 0,
    companyId: null,
    empno: '',
    post: '',
    duty: '',
    idNo: ''
  },
  formRules:{
    name: [{ required: true, message: '请输入公司、部门或者车间岗位名称', trigger: 'blur' }],
    password: [{ required: true, validator: validatePwd, trigger: 'blur' }],
    confirmPassword: [{ required: true, validator: equalToPassword, trigger: 'blur' }],
    phone: [{ required: true, validator: validateUserPhone, trigger: 'blur' }],
    idNo: [{ required: true, validator: validateIdNo, trigger: 'blur' }],
  },
  isAdmin: false
})
const startPhone = ref('');
const startIdNo = ref('');
const UisMounted = ref(false);
onMounted(() => {
  UisMounted.value = true;
});
const disabled = ref(false);
const openDialog = async (type, value) => {
  const userInfo = JSON.parse(Cookies.get('userInfo'))
  console.log("userInfo",userInfo)
  if(userInfo.userType === 0){
    state.isAdmin = true;
    state.form.userType = 0;
  }else {
    state.isAdmin = false;
    state.form.companyId = userInfo.companyId;
    state.form.companyName = userInfo.companyName;
    state.form.userType = 1;
  }
  state.title = type === 'add' ? '新增' : type ==='edit' ? '编辑' : type ==='pwd' ? '修改密码' : '查看' ;
  if(type === 'edit' || type === 'view') {
    if( type === 'view'){
      disabled.value = true;
    }
    startPhone.value = value.phone
    startIdNo.value = value.idNo
    state.form = value
    state.form.companyName = value.company.name;
    console.log("ba",state.form)
  }
  if(type == 'pwd'){
    state.form.id = value.id
  }
  dialogVisible.value = true
}
const onSubmit = async () => {
  const valid = await superRef.value.validate();
  if(valid){
    if(state.title == '新增'){
      const {confirmPassword,id,...data} = state.form
      data.password = Base64.encode(data.password)
      const res = await addStudent(data)
      if(res.code == 200){
        ElMessage.success(res.message)
        emit('getList')
        handleClose()
        dialogVisible.value = false;
      }else{
        ElMessage.warning(res.message)
      }
    }else if(state.title == '编辑'){
      const {id, name, phone, sex, companyId, empno, post, duty, idNo} = state.form
      const data = {id, name, phone, sex, companyId, empno, post, duty, idNo}
      const res = await editStudent(data)
      if(res.code == 200){
        ElMessage.success(res.message)
        emit('getList')
        handleClose()
      }else{
        ElMessage.warning(res.message)
      }
    }else{
      const {id,password} = state.form
      const data = {id,password}
      data.password = Base64.encode(data.password)
      const res = await resetPwd(data)
      if(res.code == 200){
        ElMessage.success(res.message)
        emit('getList')
        handleClose()
      }else{
        ElMessage.warning(res.message)
      }
    }
  }
}
const handleClose = () => {
  state.form = {
    id: null,
    name: '',
    phone: '',
    password: '',
    confirmPassword: '',
    sex: 0,
    companyId: null,
    empno: '',
    post: '',
    duty: '',
    idNo: ''
  }
  superRef.value.clearValidate();
  superRef.value.resetFields()
  dialogVisible.value = false;
}
defineExpose({
  openDialog
});
</script>
<style scoped lang="scss">
.notice{
  :deep(.el-form .el-form-item__label) {
    font-size: 15px;
  }
  .file {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
}
</style>
src/views/onlineEducation/people/index.vue
@@ -1,12 +1,138 @@
<template>
<div>人员管理</div>
  <div class="app-container">
    <div style="margin-bottom: 10px">
      <el-button
          type="primary"
          plain
          icon="Plus"
          @click="openDialog('add',{})"
      >新增</el-button>
    </div>
    <!-- 表格数据 -->
    <el-table v-loading="loading" :data="dataList" :border="true">
      <el-table-column label="序号" type="index" align="center" width="80" />
      <el-table-column label="工号" prop="empno" align="center"  />
      <el-table-column label="姓名" prop="name" align="center"  />
      <el-table-column label="性别" prop="sex" align="center" >
        <template #default="scope">
          <span>{{scope.row.sex == 0 ? '男':'女'}}</span>
</template>
      </el-table-column>
      <el-table-column label="手机号" prop="phone" align="center" width="130"/>
      <el-table-column label="身份证" prop="idNo" align="center" width="200" :show-overflow-tooltip="true"/>
      <el-table-column label="创建人" prop="createBy" align="center"/>
      <el-table-column label="工作岗位" prop="post" align="center"/>
      <el-table-column label="职务" prop="duty" align="center"/>
      <el-table-column label="一人一档" prop="duty" align="center" width="120">
        <template #default="scope">
          <el-button link type="primary">培训考试记录</el-button>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width"  width="180">
        <template #default="scope">
          <el-button link type="primary" @click="openDialog('edit',scope.row)">编辑</el-button>
          <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
          <el-button link type="primary" @click="openDialog('pwd',scope.row)">修改密码</el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination
        v-show="total > 0"
        :total="total"
        v-model:page="queryParams.pageNum"
        v-model:limit="queryParams.pageSize"
        @pagination="getList"
    />
    <stu-dialog ref="dialogRef" @getList=getList></stu-dialog>
  </div>
</template>
<script setup>
import {getCurrentInstance, onMounted, onUnmounted, reactive, ref, toRefs} from "vue";
import {ElMessage, ElMessageBox} from "element-plus";
import {delCompany, getCompany} from "@/api/onlineEducation/company";
import stuDialog from "./components/stuDialog.vue"
import {delUser, getUser} from "@/api/onlineEducation/user";
import Cookies from "js-cookie";
import {delStudent, getStudent} from "@/api/onlineEducation/student";
const { proxy } = getCurrentInstance();
const loading = ref(false);
const dialogRef = ref();
const data = reactive({
  queryParams: {
    pageNum: 1,
    pageSize: 10,
  },
  total: 0,
  dataList: [],
  isAdmin: false
});
const { queryParams, total, dataList } = toRefs(data);
onMounted(async ()=>{
  const userInfo = JSON.parse(Cookies.get('userInfo'))
  console.log("userInfo",userInfo)
  if(userInfo.userType === 0){
    data.isAdmin = true;
  }else {
    data.isAdmin = false;
  }
  await getList()
})
onUnmounted(()=>{
})
const getList = async () => {
  loading.value = true
  const res = await getStudent(data.queryParams)
  if(res.code == 200){
    data.dataList = res.data.list
    data.total = res.data.total
  }else{
    ElMessage.warning(res.message)
  }
  loading.value = false
}
const openDialog = (type, value) => {
  if(type == 'add' && data.isAdmin){
    ElMessage.warning('监管部门请联系企业创建企业学员')
  }else{
    dialogRef.value.openDialog(type, value);
  }
}
/** 重置新增的表单以及其他数据  */
function reset() {
  proxy.resetForm("roleRef");
}
const handleDelete = (val) => {
  ElMessageBox.confirm(
      '确定删除此条数据?',
      '提示',
      {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
      .then( async() => {
        const res = await delStudent(val.id)
        if(res.code == 200){
          ElMessage.success('数据删除成功')
          await getList()
        }else{
          ElMessage.warning(res.message)
        }
      })
}
</script>
<style scoped lang="scss">
</style>
src/views/onlineEducation/systemManage/banner/components/bannerDialog.vue
@@ -11,7 +11,7 @@
          <el-input v-model.trim="state.form.title"></el-input>
        </el-form-item>
        <el-form-item prop="imgUrl" label="图片:">
          <el-upload accept="image/*" :action="state.uploadUrl" :headers="state.header" method="post" :on-success="(res, uploadFile)=>handleAvatarSuccess(res, uploadFile)" :on-exceed="showTip" :limit='state.imgLimit' v-model:file-list="state.imgList" list-type="picture-card" :before-upload="picSize" :on-remove="(file, uploadFiles)=>handleRemove(file, uploadFiles,'证书')" >
          <el-upload accept="image/*" :action="state.uploadUrl" :headers="state.header" method="post" :on-success="(res, uploadFile)=>handleAvatarSuccess(res, uploadFile)" :on-exceed="showTip" :limit='state.imgLimit' v-model:file-list="state.imgList" list-type="picture-card" :before-upload="picSize" :on-remove="(file, uploadFiles)=>handleRemove(file, uploadFiles)" >
            <el-icon><Plus /></el-icon>
            <template #tip>
              <div class="el-upload__tip">上传jpg/png图片尺寸小于5M,最多可上传1张</div>
src/views/onlineEducation/systemManage/courseClassification/components/courseClassDialog.vue
@@ -7,6 +7,9 @@
        :before-close="handleClose"
    >
      <el-form :model="state.form" size="default" ref="busRef" :rules="state.formRules" label-width="150px" >
        <el-form-item label="上级分类:" prop="name" v-if="!state.isFirst">
          <el-input v-model.trim="state.form.parentName" disabled></el-input>
        </el-form-item>
        <el-form-item label="名称:" prop="name">
          <el-input v-model.trim="state.form.name"></el-input>
        </el-form-item>
@@ -76,6 +79,7 @@
  form: {
    id: '',
    name: '',
    parentName: '',
    sort: 0,
    parentId: null,
    status: true
@@ -83,8 +87,8 @@
  formRules:{
    name: [{ required: true, trigger: "blur", validator: validateName }],
  },
  isFirst: true
})
const openDialog = async (type, value) => {
  length.value = value.listLength
@@ -95,7 +99,11 @@
    state.form.sort = value.sort;
    startUsername.value = value.username;
  }else if(type === 'add' && value ){
    state.form.parentId = value.id
    state.isFirst = false;
    state.form.parentId = value.id;
    state.form.parentName = value.name;
  }else {
    state.isFirst = true;
  }
  dialogVisible.value = true;
}
@@ -150,6 +158,7 @@
  state.form = {
    id: '',
    name: '',
    parentName: '',
    sort: 0,
    parentId: null,
    status: true
src/views/onlineEducation/systemManage/courseClassification/index.vue
@@ -52,8 +52,6 @@
const data = reactive({
  queryParams: {
    name: '',
    pageNum: 1,
    pageSize: 10,
  },
  total: 0,
  dataList: [
src/views/onlineEducation/systemManage/user/components/userDialog.vue
@@ -57,6 +57,7 @@
            </el-select>
          <el-input v-else disabled style="width: 45%" v-model="state.form.companyName"></el-input>
            <scorllSelect
                :disabled="disabled"
                ref="scrollRef"
                v-if="UisMounted && (state.form.userType === 2 || state.form.userType === 3)"
                v-model="state.form.parentName"
@@ -190,7 +191,9 @@
    state.form.userType = 1;
  }
  if(type !== 'view' && type !== 'pwd'){
  await getCompanyList('open')
  }
  state.title = type === 'add' ? '新增' : type ==='edit' ? '编辑' : type ==='pwd' ? '修改密码' : '查看' ;
  if(type === 'edit' || type === 'view') {
    if( type === 'view'){