diff --git a/src/main/java/io/v/nutz/mobile/trainEducation/MTrainEducationController.java b/src/main/java/io/v/nutz/mobile/trainEducation/MTrainEducationController.java new file mode 100644 index 0000000..0f87bac --- /dev/null +++ b/src/main/java/io/v/nutz/mobile/trainEducation/MTrainEducationController.java @@ -0,0 +1,234 @@ +package io.v.nutz.mobile.trainEducation; + +import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.service.BaseService; +import io.v.nutz.trainEducation.models.TrainEduVideo; +import io.v.nutz.trainEducation.models.TrainEduVideoWatchRecord; +import io.v.nutz.web.commons.utils.ShiroUtil; +import org.apache.shiro.authz.annotation.RequiresAuthentication; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.Static; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +@IocBean +@At("/mobile/trainEducation") +@Ok("json:full") +public class MTrainEducationController { + + @Inject + private Dao dao; + + @Inject + private BaseService baseService; + + @At + @RequiresAuthentication + @Ok("beetl:/mobile/trainEducation/index.html") + public void index() { + } + + @At + @RequiresAuthentication + @Ok("beetl:/mobile/trainEducation/AlbumList.html") + public void AlbumList() { + } + + @At + @RequiresAuthentication + @Ok("beetl:/mobile/trainEducation/videoPage.html") + public void videoPage() { + } + + /** + * 获取最新的视频 + * + * @return + */ + @At + @ViReturn + @RequiresAuthentication + public Object getNewestVideo() { + Sql sql = Sqls.create(""" + SELECT + tea.*, + count( tev.id ) AS videoCount, + tet.typeName + FROM + train_edu_album tea + LEFT JOIN train_edu_video tev ON tev.albumId = tea.id + LEFT JOIN train_edu_type tet ON tet.id = tea.typeId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and(new Static("tea.id = (select albumId from train_edu_video order by createdAt desc LIMIT 0,1)")); + sql.setCondition(cnd); + sql.setCallback(Sqls.callback.map()); + dao.execute(sql); + return sql.getResult(); + } + + /** + * 获取某个类型下的专辑 + * + * @param typeId + * @param pageNumber + * @param pageSize + * @return + */ + @At + @ViReturn + @RequiresAuthentication + public Object getAlbumList(@Param(value = "typeId", required = false) String typeId, + @Param("pageNumber") Integer pageNumber, + @Param("pageSize") Integer pageSize) { + Sql sql = Sqls.create(""" + SELECT + tea.*, + count( tev.id ) AS videoCount, + tet.typeName + FROM + train_edu_album tea + LEFT JOIN train_edu_video tev ON tev.albumId = tea.id + LEFT JOIN train_edu_type tet ON tet.id = tea.typeId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("tea.typeId", "=", typeId); + cnd.groupBy("tea.id"); + sql.setCondition(cnd); + return baseService.listPageMap(pageNumber, pageSize, sql); + } + + /** + * 获取某个专辑的详细信息 + * + * @param id + * @return + */ + @At + @ViReturn + @RequiresAuthentication + public Object getAlbumInfo(@Param(value = "id", required = false) String id) { + Sql sql = Sqls.create(""" + SELECT + tea.*, + count( tev.id ) AS videoCount, + tet.typeName + FROM + train_edu_album tea + LEFT JOIN train_edu_video tev ON tev.albumId = tea.id + LEFT JOIN train_edu_type tet ON tet.id = tea.typeId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("tea.id", "=", id); + cnd.groupBy("tea.id"); + sql.setCondition(cnd); + sql.setCallback(Sqls.callback.map()); + dao.execute(sql); + return (NutMap) sql.getResult(); + } + + /** + * 根据专辑获取视频 + * + * @param albumId + * @return + */ + @At + @ViReturn + @RequiresAuthentication + public Object getVideoList(@Param(value = "albumId", required = false) String albumId) { + Sql sql = Sqls.create(""" + SELECT + tev.*, + tea.title AS albumTitle, + tet.typeName, + tea.cover + FROM + train_edu_video tev + LEFT JOIN train_edu_album tea ON tea.id = tev.albumId + LEFT JOIN train_edu_type tet ON tet.id = tea.typeId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("tev.albumId", "=", albumId); + cnd.and("tev.disabled", "=", 0); + sql.setCondition(cnd); + return baseService.listMap(sql); + } + + /** + * 储存观看记录 + * + * @param videoId 视频ID + * @param currentTime 观看时长(秒) + * @return + */ + @At + @ViReturn + @RequiresAuthentication + public Object addWatchRecord(@Param(value = "videoId", required = false) String videoId, + @Param(value = "albumId", required = false) String albumId, + @Param(value = "currentTime", required = false) long currentTime) { + String userId = (String) ShiroUtil.getPrincipalProperty("id"); + TrainEduVideo video = dao.fetch(TrainEduVideo.class, Cnd.where("id", "=", videoId)); + TrainEduVideoWatchRecord thisVideoRecord = dao.fetch(TrainEduVideoWatchRecord.class, Cnd.where("userId", "=", userId).and("videoId", "=", videoId)); + + if(Lang.isNotEmpty(thisVideoRecord) && thisVideoRecord.getFinish()){ + //已看完的就不要更改了 + return null; + } + + if (Lang.isEmpty(thisVideoRecord)) { + TrainEduVideoWatchRecord videoWatchRecord = new TrainEduVideoWatchRecord(); + videoWatchRecord.setVideoId(videoId); + videoWatchRecord.setWatchDuration(currentTime); + videoWatchRecord.setAlbumId(albumId); + videoWatchRecord.setUserId((String) ShiroUtil.getPrincipalProperty("id")); + videoWatchRecord.setFinish(video.getFileDuration() == currentTime); + dao.insert(videoWatchRecord); + } else { + Chain updateChain = Chain.make("watchDuration", currentTime); + updateChain.add("finish", video.getFileDuration() == currentTime ? 1 : 0); + Cnd cnd = Cnd.where("userId", "=", userId).and("videoId", "=", videoId); + dao.update(TrainEduVideoWatchRecord.class, updateChain, cnd); + } + return null; + } + + /** + * 获取我的观看记录 + * + * @param albumId + * @return + */ + @At + @ViReturn + @RequiresAuthentication + public Object getMyWatchRecord(@Param(value = "albumId", required = false) String albumId) { + Sql sql = Sqls.create(""" + SELECT + tevwr.* + FROM + `train_edu_video_watch_record` tevwr + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("tevwr.albumId", "=", albumId); + cnd.andEX("tevwr.userId", "=", ShiroUtil.getPrincipalProperty("id")); + sql.setCondition(cnd); + return baseService.listMap(sql); + } + +} diff --git a/src/main/java/io/v/nutz/trainEducation/controller/TrainEduAlbumController.java b/src/main/java/io/v/nutz/trainEducation/controller/TrainEduAlbumController.java new file mode 100644 index 0000000..489fac6 --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/controller/TrainEduAlbumController.java @@ -0,0 +1,134 @@ +package io.v.nutz.trainEducation.controller; + +import cn.hutool.core.util.StrUtil; +import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.service.SimpleService; +import io.v.nutz.base.utils.Vi; +import io.v.nutz.modules.models.PageForm; +import io.v.nutz.trainEducation.models.TrainEduAlbum; +import io.v.nutz.web.commons.utils.ShiroUtil; +import org.apache.shiro.authz.annotation.RequiresAuthentication; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +import java.util.List; + +@IocBean +@At("/platform/trainEdu/album") +@Ok("json:full") +public class TrainEduAlbumController { + + @Inject + private Dao dao; + + @Inject + private SimpleService simpleService; + + @At("") + @Ok("beetl:/platform/trainEdu/album.html") + @RequiresPermissions("trainEdu.album") + public void index() { + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.album") + public Object doAdd(TrainEduAlbum trainEduAlbum) { + trainEduAlbum.setUnionId(Vi.getUnionId()); + trainEduAlbum.setUnitId(Vi.getUnit().getId()); + dao.insert(trainEduAlbum); + return null; + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.album") + public Object doEdit(TrainEduAlbum trainEduAlbum) { + dao.update(trainEduAlbum); + return null; + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.album") + public Object doDelete(String id) { + dao.clear(TrainEduAlbum.class, Cnd.where("id", "=", id)); + return null; + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.album") + public Object pageData(PageForm page, + @Param(value = "typeId",required = false) String typeId) { + Sql sql = Sqls.create(""" + SELECT + tea.*, + count( tev.id ) AS videoCount, + tet.typeName + FROM + train_edu_album tea + LEFT JOIN train_edu_video tev ON tev.albumId = tea.id + LEFT JOIN train_edu_type tet ON tet.id = tea.typeId + $condition + """); + Cnd cnd = Cnd.NEW(); + if(!ShiroUtil.hasAnyRoles("sysadmin, A06")) { + cnd.and("tea.createType", "=", 1).and("tea.unionId", "=", Vi.getUnionId()); + } + if (StrUtil.isNotBlank(page.getSearchName()) && StrUtil.isNotBlank(page.getSearchKeyword())) { + cnd.and(Cnd.likeEX(page.getSearchName(), page.getSearchKeyword())); + } + cnd.andEX("tea.typeId", "=", typeId); + cnd.groupBy("tea.id"); + sql.setCondition(cnd); + return simpleService.listPageMap(page.getPageNumber(), page.getPageSize(), sql); + } + + @At + @ViReturn + @RequiresAuthentication + public Object getAllAlbum() { + Cnd cnd = Cnd.NEW(); + if(!ShiroUtil.hasAnyRoles("sysadmin, A06")) { + cnd.and(Cnd.exps("createType", "=", 2).or(Cnd.exps("createType", "=", 1).and("unionId", "=", ShiroUtil.getPlatformUid()))); + } + List list = dao.query(TrainEduAlbum.class, cnd); + for (TrainEduAlbum trainEduAlbum : list) { + dao.fetchLinks(list, "eduType"); + } + return list; + } + + /** + * 获取专辑根据类型id + * + * @param typeId id类型 + * @param pageForm 分页参数 + * @return {@link Object} + */ + @At + @ViReturn + @RequiresAuthentication + public Object getAlbumByTypeId(PageForm pageForm, + @Param(value = "typeId", required = false) String typeId) { + Sql sql = Sqls.create("select * from train_edu_album $condition"); + Cnd cnd = Cnd.NEW(); + if(!ShiroUtil.hasAnyRoles("sysadmin, A06")) { + cnd.and(Cnd.exps("createType", "=", 2).or(Cnd.exps("createType", "=", 1).and("unionId", "=", ShiroUtil.getPlatformUid()))); + } + cnd.andEX("typeId", "=", typeId); + cnd.and(Cnd.likeEX("title", pageForm.getSearchKeyword())); + sql.setCondition(cnd); + return simpleService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + +} diff --git a/src/main/java/io/v/nutz/trainEducation/controller/TrainEduTypeController.java b/src/main/java/io/v/nutz/trainEducation/controller/TrainEduTypeController.java new file mode 100644 index 0000000..9b9ea07 --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/controller/TrainEduTypeController.java @@ -0,0 +1,79 @@ +package io.v.nutz.trainEducation.controller; + +import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.service.SimpleService; +import io.v.nutz.modules.models.PageForm; +import io.v.nutz.trainEducation.models.TrainEduType; +import org.apache.shiro.authz.annotation.RequiresAuthentication; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +@IocBean +@At("/platform/trainEdu/type") +@Ok("json:full") +public class TrainEduTypeController { + + @Inject + private Dao dao; + + @Inject + private SimpleService simpleService; + + @At("") + @Ok("beetl:/platform/trainEdu/type.html") + @RequiresPermissions("trainEdu.type") + public void index() { + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.type") + public Object doAdd(@Param("trainEduType") TrainEduType trainEduType) { + dao.insert(trainEduType); + return null; + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.type") + public Object doEdit(@Param("trainEduType") TrainEduType trainEduType) { + dao.update(trainEduType); + return null; + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.type") + public Object doDelete(String id) { + dao.clear(TrainEduType.class, Cnd.where("id", "=", id)); + return null; + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @return {@link Object} + */ + @At + @ViReturn + @RequiresAuthentication + public Object pageData(PageForm pageForm) { + Sql sql = Sqls.create(""" + select + id, + typeName, + files + from train_edu_type + """); + return simpleService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } +} diff --git a/src/main/java/io/v/nutz/trainEducation/controller/TrainEduVideoController.java b/src/main/java/io/v/nutz/trainEducation/controller/TrainEduVideoController.java new file mode 100644 index 0000000..16789f1 --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/controller/TrainEduVideoController.java @@ -0,0 +1,187 @@ +package io.v.nutz.trainEducation.controller; + +import cn.hutool.core.util.StrUtil; +import cn.wizzer.framework.base.Result; +import com.qcloud.vod.model.VodUploadResponse; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.vod.v20180717.models.DeleteMediaResponse; +import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.service.BaseService; +import io.v.nutz.base.utils.PageUtil; +import io.v.nutz.base.utils.Vi; +import io.v.nutz.modules.models.PageForm; +import io.v.nutz.trainEducation.models.TrainEduVideo; +import io.v.nutz.trainEducation.util.TencentVideoService; +import io.v.nutz.web.commons.utils.ShiroUtil; +import org.apache.shiro.authz.annotation.RequiresAuthentication; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.json.Json; +import org.nutz.mvc.annotation.*; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; + +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@IocBean +@At("/platform/trainEdu/video") +@Ok("json:full") +public class TrainEduVideoController { + + @Inject + private Dao dao; + + @Inject + private BaseService baseService; + + @At("") + @Ok("beetl:/platform/trainEdu/video.html") + @RequiresPermissions("trainEdu.video") + public void index() { + } + + @At + @ViReturn + @RequiresAuthentication + @RequiresPermissions("trainEdu.video") + public Object pageData(PageForm page, @Param(value = "albumId", required = false) String albumId) { + Sql sql = Sqls.create(""" + SELECT + tev.*, + tea.title AS albumTitle, + u.username AS createUserName, + FROM_UNIXTIME(tev.createdAt/1000,'%Y-%m-%d %H:%i:%s') AS createTime + FROM + train_edu_video tev + LEFT JOIN train_edu_album tea ON tea.id = tev.albumId + LEFT JOIN sys_user u on u.id = tev.createdBy + $condition + """); + Cnd cnd = Cnd.NEW(); + if(!ShiroUtil.hasAnyRoles("sysadmin, A06")) { + cnd.and("tea.createType", "=", 1).and("tea.unionId", "=", Vi.getUnionId()); + } + cnd.andEX("tev.albumId", "=", albumId); + if (StrUtil.isNotBlank(page.getSearchName()) && StrUtil.isNotBlank(page.getSearchKeyword())) { + cnd.and(Cnd.likeEX(page.getSearchName(), page.getSearchKeyword())); + } + if (StrUtil.isAllNotBlank(page.getPageOrderName(), page.getPageOrderBy())) { + cnd.orderBy(page.getPageOrderName(), PageUtil.getOrder(page.getPageOrderBy())); + } + sql.setCondition(cnd); + return baseService.listPageMap(page.getPageNumber(), page.getPageSize(), sql); + } + + @At + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @POST + @ViReturn + @RequiresPermissions("trainEdu.video") + public Object doAdd(@Param("file") TempFile file, @Param("data") String data) { + TrainEduVideo trainEduVideo = Json.fromJson(TrainEduVideo.class, data); + try { + VodUploadResponse response = TencentVideoService.uploadFile(file.getFile(), TencentVideoService.trainEducationClassId); + String fileId = response.getFileId(); + String mediaUrl = response.getMediaUrl(); + + trainEduVideo.setFileSize(TencentVideoService.getFileLength(file.getFile())); + trainEduVideo.setFileDuration(TencentVideoService.getFileDuration(file.getFile())); + + trainEduVideo.setMediaUrl(mediaUrl); + trainEduVideo.setFileId(fileId); + dao.insert(trainEduVideo); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 编辑文件信息 + * + * @param file + * @param data + * @return + */ + @At + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @POST + @ViReturn + @RequiresPermissions("trainEdu.video") + public Object doEdit(@Param("file") TempFile file, @Param("data") String data) { + TrainEduVideo trainEduVideo = Json.fromJson(TrainEduVideo.class, data); + + //有新上传的文件采取删除旧文件 + if (file != null) { + try { + DeleteMediaResponse response = TencentVideoService.deleteFile(trainEduVideo.getFileId(), TencentVideoService.subAppId); + VodUploadResponse uploadResponse = TencentVideoService.uploadFile(file.getFile(), TencentVideoService.trainEducationClassId); + String fileId = uploadResponse.getFileId(); + String mediaUrl = uploadResponse.getMediaUrl(); + + trainEduVideo.setFileSize(TencentVideoService.getFileLength(file.getFile())); + trainEduVideo.setFileDuration(TencentVideoService.getFileDuration(file.getFile())); + + trainEduVideo.setMediaUrl(mediaUrl); + trainEduVideo.setFileId(fileId); + dao.updateIgnoreNull(trainEduVideo); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + dao.updateIgnoreNull(trainEduVideo); + } + + return null; + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.video") + public Object doDelete(String id) { + TrainEduVideo eduVideo = dao.fetch(TrainEduVideo.class, Cnd.where("id", "=", id)); + String fileId = eduVideo.getFileId(); + try { + DeleteMediaResponse response = TencentVideoService.deleteFile(fileId, TencentVideoService.subAppId); + System.out.println(response); + dao.delete(eduVideo); + return Result.success(); + } catch (TencentCloudSDKException e) { + e.printStackTrace(); + return Result.error(); + } + } + + @At + @ViReturn + @RequiresAuthentication + public Object getVideoList(@Param("albumId") String albumId) { + List list = dao.query(TrainEduVideo.class, Cnd.where("albumId", "=", albumId)); + + List fileIdsList = list.stream().map(TrainEduVideo::getFileId).collect(Collectors.toList()); + String[] fileIdArray = fileIdsList.toArray(new String[fileIdsList.size()]); + + List> mediaCoverInfos = TencentVideoService.getMediaCoverInfo(fileIdArray); + + for (TrainEduVideo trainEduVideo : list) { + Optional> optionalHashMap = mediaCoverInfos.stream().filter(v -> v.get("fileId").equals(trainEduVideo.getFileId())).findFirst(); + optionalHashMap.ifPresent(stringStringHashMap -> trainEduVideo.setCoverUrl(stringStringHashMap.get("coverUrl"))); + } + return list; + } + + @At + @ViReturn + @RequiresAuthentication + public Object getDescribeMediaInfos(@Param("fileId") String fileId) { + return TencentVideoService.getMediaCoverInfo(new String[]{fileId}); + } +} diff --git a/src/main/java/io/v/nutz/trainEducation/controller/TrainStudyController.java b/src/main/java/io/v/nutz/trainEducation/controller/TrainStudyController.java new file mode 100644 index 0000000..7c704bd --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/controller/TrainStudyController.java @@ -0,0 +1,32 @@ +package io.v.nutz.trainEducation.controller; + +import io.v.nutz.base.service.BaseService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +/** + * @Author JyuHsin + * @Date 2022/8/11 + * @Description 视频学习 + */ +@IocBean +@At("/platform/trainEdu/study") +@Ok("json:full") +public class TrainStudyController { + + @Inject + private Dao dao; + + @Inject + private BaseService baseService; + + @At("") + @Ok("beetl:/platform/trainEdu/study.html") + @RequiresPermissions("trainEdu.study") + public void index() { + } +} diff --git a/src/main/java/io/v/nutz/trainEducation/controller/statistics/TrainEduStatisticsUnionController.java b/src/main/java/io/v/nutz/trainEducation/controller/statistics/TrainEduStatisticsUnionController.java new file mode 100644 index 0000000..d047f9b --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/controller/statistics/TrainEduStatisticsUnionController.java @@ -0,0 +1,103 @@ +package io.v.nutz.trainEducation.controller.statistics; + +import cn.wizzer.framework.page.Pagination; +import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.service.BaseService; +import io.v.nutz.base.utils.Vi; +import io.v.nutz.web.commons.utils.ShiroUtil; +import org.apache.shiro.authz.annotation.RequiresAuthentication; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.Static; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +/** + * 按工会来分析学习参与度 + */ +@IocBean +@At("/platform/trainEdu/statistics/union") +@Ok("json:full") +public class TrainEduStatisticsUnionController { + + @Inject + private Dao dao; + + @Inject + private BaseService baseService; + + @At("") + @Ok("beetl:/platform/trainEdu/statistics/union.html") + @RequiresPermissions("trainEdu.statistics.union") + public void index() { + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.statistics.union") + public Object pageData(@Param(value = "searchType", required = false) String searchType) { + Sql sql = null; + if (searchType.equals("") || searchType.equals("按分工会分析")) { + Cnd cnd = Cnd.NEW(); + sql = Sqls.create(""" + SELECT + gh.id, + gh.unionname AS unionName, + gh.unioncode AS unionCode, + COUNT(u.id) AS unionSum, + COUNT(DISTINCT ( tevwr.userId )) AS studyNum + FROM + sys_union gh + LEFT JOIN `user` u ON u.unionid = gh.id + LEFT JOIN train_edu_video_watch_record tevwr ON tevwr.userId = u.id + LEFT JOIN train_edu_album tea ON tea.id = tevwr.albumId + $condition + GROUP BY + gh.id + ORDER BY + gh.unioncode ASC + """); + if(!ShiroUtil.hasAnyRoles("sysadmin, A06")) { + cnd.and("gh.id", "=", Vi.getUnionId()); + cnd.and(new Static("IF(tea.createType = 1, u.unionId = tea.unionId , 1=1)")); + } + sql.setCondition(cnd); + } else { + Cnd cnd = Cnd.NEW(); + sql = Sqls.create(""" + SELECT + dw.id, + dw.`name` AS unitName, + dw.unitcode AS unitCode, + COUNT( u.id ) AS unionSum, + COUNT(DISTINCT ( tevwr.userId )) AS studyNum + FROM + sys_unit dw + LEFT JOIN `user` u ON u.unitid = dw.id + LEFT JOIN train_edu_video_watch_record tevwr ON tevwr.userId = u.id + LEFT JOIN train_edu_album tea ON tea.id = tevwr.albumId + $condition + GROUP BY + dw.id + ORDER BY + dw.unitcode ASC + """); + if(!ShiroUtil.hasAnyRoles("sysadmin, A06")) { + cnd.and("dw.id", "=", Vi.getUnit().getId()); + cnd.and(new Static("IF(tea.createType = 1, u.unitId = tea.unitId , 1=1)")); + } + sql.setCondition(cnd); + } + + Pagination pagination = new Pagination(); + pagination.setList(baseService.listMap(sql)); + return pagination; + } + +} diff --git a/src/main/java/io/v/nutz/trainEducation/controller/statistics/TrainEduStatisticsVideoController.java b/src/main/java/io/v/nutz/trainEducation/controller/statistics/TrainEduStatisticsVideoController.java new file mode 100644 index 0000000..4a321ee --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/controller/statistics/TrainEduStatisticsVideoController.java @@ -0,0 +1,103 @@ +package io.v.nutz.trainEducation.controller.statistics; + +import cn.wizzer.framework.page.Pagination; +import io.v.nutz.annontation.ViReturn; +import io.v.nutz.base.service.BaseService; +import io.v.nutz.base.utils.Vi; +import io.v.nutz.modules.models.PageForm; +import io.v.nutz.web.commons.utils.ShiroUtil; +import org.apache.shiro.authz.annotation.RequiresAuthentication; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +import java.util.List; + + +/** + * 统计各视频学习人数 + */ +@IocBean +@At("/platform/trainEdu/statistics/video") +@Ok("json:full") +public class TrainEduStatisticsVideoController { + + @Inject + private Dao dao; + + @Inject + private BaseService baseService; + + @At("") + @Ok("beetl:/platform/trainEdu/statistics/video.html") + @RequiresPermissions("trainEdu.statistics.video") + public void index() { + } + + @At + @ViReturn + @RequiresPermissions("trainEdu.statistics.video") + public Object pageData() { + Sql sql = Sqls.create(""" + SELECT + tea.*, + tet.typeName, + ( SELECT sum( fileDuration ) FROM train_edu_video WHERE albumId = tea.id ) AS sumDuration, + ( SELECT count( DISTINCT ( userid )) FROM train_edu_video_watch_record WHERE albumId = tea.id ) AS studyNum + FROM + train_edu_album tea + LEFT JOIN train_edu_type tet ON tet.id = tea.typeId\s + $condition + """); + Cnd cnd = Cnd.NEW(); + if(!ShiroUtil.hasAnyRoles("sysadmin, A06")) { + cnd.and("tea.createType", "=", 1).and("tea.unionId", "=", Vi.getUnionId()); + } + sql.setCondition(cnd); + List list = baseService.listMap(sql); + Pagination pagination = new Pagination(); + pagination.setList(list); + return pagination; + } + + + /** + * 统计每个课程每个人的学习时常 + * + * @param pageForm + * @param albumId + * @return + */ + @At + @ViReturn + @RequiresPermissions("trainEdu.statistics.video") + public Object getWatchDuration(PageForm pageForm, + @Param(value = "albumId", required = false) String albumId) { + Sql sql = Sqls.create(""" + SELECT + u.username, + u.loginname, + u.unitname, + u.unionname, + sum( tevwr.watchDuration ) AS studyDuration + FROM + `train_edu_video_watch_record` tevwr + LEFT JOIN train_edu_album tea on tea.id = tevwr.albumId + LEFT JOIN `user` u ON u.id = tevwr.userId + WHERE + tevwr.albumId = @albumId + AND IF(tea.createType = 1, u.unionId = tea.unionId , 1=1) + GROUP BY + tevwr.userId + """); + sql.setParam("albumId", albumId); + return baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } +} diff --git a/src/main/java/io/v/nutz/trainEducation/models/TrainEduAlbum.java b/src/main/java/io/v/nutz/trainEducation/models/TrainEduAlbum.java new file mode 100644 index 0000000..6082670 --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/models/TrainEduAlbum.java @@ -0,0 +1,60 @@ +package io.v.nutz.trainEducation.models; + +import lombok.Data; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.List; + +@Table +@Data +public class TrainEduAlbum { + + @Name + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("视频总标题") + private String title; + + @Column + @ColDefine(type = ColType.TEXT) + @Comment("视频简介") + private String description; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 200) + @Comment("视频封面") + private String cover; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("视频类型") + private String typeId; + + @Column + @ColDefine(type = ColType.MYSQL_JSON) + @Comment("视频标签") + private List tags; + + @One(field = "typeId") + private TrainEduType eduType; + + @Column + @ColDefine(type = ColType.INT) + @Comment("创建类型,1.分工会, 2.校工会") + private Integer createType; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("工会id") + private String unionId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("单位id") + private String unitId; + +} diff --git a/src/main/java/io/v/nutz/trainEducation/models/TrainEduType.java b/src/main/java/io/v/nutz/trainEducation/models/TrainEduType.java new file mode 100644 index 0000000..21706b9 --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/models/TrainEduType.java @@ -0,0 +1,31 @@ +package io.v.nutz.trainEducation.models; + +import io.v.nutz.sys.models.Sys_file; +import lombok.Data; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.List; + +@Table +@Data +public class TrainEduType { + + @Name + @PrevInsert(uu32 = true) + @ColDefine(type = ColType.VARCHAR, width = 32) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + private String typeName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 500) + private String icon; + + @Column + @ColDefine(type = ColType.MYSQL_JSON) + private List files; + +} diff --git a/src/main/java/io/v/nutz/trainEducation/models/TrainEduVideo.java b/src/main/java/io/v/nutz/trainEducation/models/TrainEduVideo.java new file mode 100644 index 0000000..c3c8a94 --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/models/TrainEduVideo.java @@ -0,0 +1,62 @@ +package io.v.nutz.trainEducation.models; + +import io.v.nutz.base.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +@EqualsAndHashCode(callSuper = true) +@Table +@Data +public class TrainEduVideo extends BaseModel { + + @Name + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 15) + @Comment("小标题") + private String title; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("albumId") + private String albumId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 500) + @Comment("视频地址") + private String mediaUrl; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 500) + @Comment("封面地址") + private String coverUrl; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 500) + @Comment("视频Id") + private String fileId; + + @Column + @ColDefine(type = ColType.INT) + @Comment("排序编号") + private int sortNo; + + @Column + @Comment("是否禁用") + @ColDefine(type = ColType.BOOLEAN) + private boolean disabled; + + @Column + @Comment("视频大小") + @ColDefine(type = ColType.VARCHAR) + private String fileSize; + + @Column + @Comment("视频时常") + private Long fileDuration; + +} diff --git a/src/main/java/io/v/nutz/trainEducation/models/TrainEduVideoWatchRecord.java b/src/main/java/io/v/nutz/trainEducation/models/TrainEduVideoWatchRecord.java new file mode 100644 index 0000000..93edb39 --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/models/TrainEduVideoWatchRecord.java @@ -0,0 +1,37 @@ +package io.v.nutz.trainEducation.models; + +import lombok.Data; +import org.nutz.dao.entity.annotation.*; + +/** + * 视频播放记录 + */ +@Table +@Data +public class TrainEduVideoWatchRecord { + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("观看用户") + private String userId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("观看视频Id") + private String videoId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("观看视频Id") + private String albumId; + + @Column + @Comment("观看时长(秒)") + private Long watchDuration; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否看完") + private Boolean finish; + +} diff --git a/src/main/java/io/v/nutz/trainEducation/util/TencentVideoService.java b/src/main/java/io/v/nutz/trainEducation/util/TencentVideoService.java new file mode 100644 index 0000000..62d8c3d --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/util/TencentVideoService.java @@ -0,0 +1,153 @@ +package io.v.nutz.trainEducation.util; + + +import com.qcloud.vod.VodUploadClient; +import com.qcloud.vod.model.VodUploadRequest; +import com.qcloud.vod.model.VodUploadResponse; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.vod.v20180717.VodClient; +import com.tencentcloudapi.vod.v20180717.models.DeleteMediaRequest; +import com.tencentcloudapi.vod.v20180717.models.DeleteMediaResponse; +import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest; +import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse; +import org.nutz.lang.Lang; +import ws.schild.jave.EncoderException; +import ws.schild.jave.MultimediaInfo; +import ws.schild.jave.MultimediaObject; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +public class TencentVideoService { + + /** + * 应用id + */ + public static final Long subAppId = 1500014618L; + + + /** + * 培训教育类别id + */ + public static final Long trainEducationClassId = 906527L; + + private static final String SECRETID = "AKIDsdHpFTTFwdP5czBAB4pdSJEyhVHaIvNc"; + private static final String SECRETKEY = "8ELFE5JSRCwKZr5cEuXOUTKlSCwlhgeO"; + + /** + * 上传文件 + * + * @param file + * @param classId + * @return + * @throws Exception + */ + public static VodUploadResponse uploadFile(File file, long classId) throws Exception { + VodUploadClient client = new VodUploadClient(SECRETID, SECRETKEY); + VodUploadRequest request = new VodUploadRequest(); + request.setMediaFilePath(file.getPath()); + request.setProcedure("captureCover"); + request.setSubAppId(TencentVideoService.subAppId); + request.setClassId(classId); + VodUploadResponse response = client.upload("ap-guangzhou", request); + return response; + } + + /** + * 删除文件 + * + * @param fileId + * @param classId + * @return + * @throws TencentCloudSDKException + */ + public static DeleteMediaResponse deleteFile(String fileId, long classId) throws TencentCloudSDKException { + Credential cred = new Credential(SECRETID, SECRETKEY); + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("vod.tencentcloudapi.com"); + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + VodClient client = new VodClient(cred, "", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + DeleteMediaRequest req = new DeleteMediaRequest(); + req.setFileId(fileId); + req.setSubAppId(classId); + DeleteMediaResponse resp = client.DeleteMedia(req); + return resp; + } + + /** + * 获取文件大小 MB + * + * @param file + * @return + */ + public static String getFileLength(File file) { + long fileLength = file.length(); + return Math.round((double) fileLength / 1024 / 1024) + "MB"; + } + + /** + * 获取视频文件时常 + * + * @param file + * @return + */ + public static long getFileDuration(File file) throws EncoderException { + MultimediaObject multimediaObject = new MultimediaObject(file); + MultimediaInfo multimediaInfo = multimediaObject.getInfo(); + return multimediaInfo.getDuration()/1000; + } + + /** + * 得到描述媒体信息 + * + * @param fileIds 文件id + * @return {@link Object} + */ + public static List> getMediaCoverInfo(String[] fileIds) { + try { + // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密 + // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取 + Credential cred = new Credential(SECRETID, SECRETKEY); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("vod.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + VodClient client = new VodClient(cred, "", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + DescribeMediaInfosRequest req = new DescribeMediaInfosRequest(); + req.setSubAppId(TencentVideoService.subAppId); + req.setFileIds(fileIds); + req.setFilters(new String[]{"basicInfo"}); + + // 返回的resp是一个DescribeMediaInfosResponse的实例,与请求对象对应 + DescribeMediaInfosResponse resp = client.DescribeMediaInfos(req); + // 输出json格式的字符串回包 + System.out.println(DescribeMediaInfosResponse.toJsonString(resp)); + + if (Lang.isNotEmpty(resp.getMediaInfoSet())) { + return Arrays.stream(resp.getMediaInfoSet()).map(v -> new HashMap(2) {{ + put("coverUrl", v.getBasicInfo().getCoverUrl()); + put("fileId", v.getFileId()); + }}).collect(Collectors.toList()); + } + return null; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + + +} diff --git a/src/main/java/io/v/nutz/trainEducation/util/TencentVideoSignature.java b/src/main/java/io/v/nutz/trainEducation/util/TencentVideoSignature.java new file mode 100644 index 0000000..0bcdc0d --- /dev/null +++ b/src/main/java/io/v/nutz/trainEducation/util/TencentVideoSignature.java @@ -0,0 +1,59 @@ +package io.v.nutz.trainEducation.util; + + +import lombok.Setter; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; + +@Setter +public class TencentVideoSignature { + + + private String secretId = "1400611918"; + private String secretKey = "3563986157db18e7dda93ab7a9b64817a15f9983499558efd592458e39297bbf"; + private long currentTime; + private int random; + private int signValidDuration; + private static final String HMAC_ALGORITHM = "HmacSHA1"; //签名算法 + private static final String CONTENT_CHARSET = "UTF-8"; + + private static byte[] byteMerger(byte[] byte1, byte[] byte2) { + byte[] byte3 = new byte[byte1.length + byte2.length]; + System.arraycopy(byte1, 0, byte3, 0, byte1.length); + System.arraycopy(byte2, 0, byte3, byte1.length, byte2.length); + return byte3; + } + + // 获取签名 + public String getUploadSignature() throws Exception { + String strSign = ""; + String contextStr = ""; + // 生成原始参数字符串 + long endTime = (currentTime + signValidDuration); + contextStr += "secretId=" + java.net.URLEncoder.encode(secretId, "utf8"); + contextStr += "¤tTimeStamp=" + currentTime; + contextStr += "&expireTime=" + endTime; + contextStr += "&random=" + random; + try { + Mac mac = Mac.getInstance(HMAC_ALGORITHM); + SecretKeySpec secretKey = new SecretKeySpec(this.secretKey.getBytes(CONTENT_CHARSET), mac.getAlgorithm()); + mac.init(secretKey); + byte[] hash = mac.doFinal(contextStr.getBytes(CONTENT_CHARSET)); + byte[] sigBuf = byteMerger(hash, contextStr.getBytes("utf8")); + strSign = base64Encode(sigBuf); + strSign = strSign.replace(" ", "").replace("\n", "").replace("\r", ""); + } catch (Exception e) { + throw e; + } + return strSign; + } + + private String base64Encode(byte[] buffer) { + Base64.Encoder encoder = Base64.getEncoder(); + return encoder.encodeToString(buffer); + } + +} + diff --git a/src/main/resources/views/mobile/home.html b/src/main/resources/views/mobile/home.html index 8c61533..222bd69 100644 --- a/src/main/resources/views/mobile/home.html +++ b/src/main/resources/views/mobile/home.html @@ -315,6 +315,7 @@ layout("/mobile/platform.html"){
+
疗休养 @@ -331,6 +332,24 @@ layout("/mobile/platform.html"){
+ +
+
+ 培训教育 +
+ + + + 疗休养 + + + + + 我的疗休养 + + +
+
diff --git a/src/main/resources/views/mobile/newHome.html b/src/main/resources/views/mobile/newHome.html index dc70d12..f7a0bc1 100644 --- a/src/main/resources/views/mobile/newHome.html +++ b/src/main/resources/views/mobile/newHome.html @@ -55,11 +55,21 @@ layout("/mobile/platform.html"){
- +
解除绑定
+ + +
+
+ +
+ 培训教育 +
+
\ No newline at end of file +#--> diff --git a/src/main/resources/views/mobile/trainEducation/index.html b/src/main/resources/views/mobile/trainEducation/index.html index 733f4c3..50a7d83 100644 --- a/src/main/resources/views/mobile/trainEducation/index.html +++ b/src/main/resources/views/mobile/trainEducation/index.html @@ -32,6 +32,7 @@ layout("/mobile/platform.html"){ left-arrow placeholder fixed + @click-left="history.back()" > @@ -47,7 +48,7 @@ layout("/mobile/platform.html"){ @@ -63,7 +64,7 @@ layout("/mobile/platform.html"){ style="margin-right: 10px" width="90" height="90" - :src="'${AppFileDomain!}'+o.cover" + :src="FILE_DOMAIN+'/fileStreamPreview?id='+o.cover" >
{{o.title}}
@@ -101,11 +102,18 @@ layout("/mobile/platform.html"){ this.tableData = [] const {data} = await $.get('/mobile/trainEducation/getNewestVideo') this.tableData.push(data) - console.log(data) } }, async created() { - this.videoTypeList = await getVideoType() + const videoTypeList = await getVideoType() + if (videoTypeList.length > 0) { + videoTypeList.map(v => { + if (v.files) { + v.icon = JSON.parse(v.files)[0].id + } + }) + } + this.videoTypeList = videoTypeList await this.getNewVideo() } }) diff --git a/src/main/resources/views/mobile/trainEducation/videoPage.html b/src/main/resources/views/mobile/trainEducation/videoPage.html index a684ddd..9679a97 100644 --- a/src/main/resources/views/mobile/trainEducation/videoPage.html +++ b/src/main/resources/views/mobile/trainEducation/videoPage.html @@ -2,6 +2,23 @@ layout("/mobile/platform.html"){ #--> + + @@ -78,7 +95,7 @@ layout("/mobile/platform.html"){
@@ -107,7 +124,7 @@ layout("/mobile/platform.html"){
- + - - - - - - - - +
+ 结束本次学习 +
+ diff --git a/src/main/resources/views/platform/trainEdu/album.html b/src/main/resources/views/platform/trainEdu/album.html new file mode 100644 index 0000000..ef54013 --- /dev/null +++ b/src/main/resources/views/platform/trainEdu/album.html @@ -0,0 +1,331 @@ + + + + +
+ + +
+ + + + + +
+ +
+ + + +
+ +
+ 搜索 +
+ +
+ + + 新增专辑 + +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + + + diff --git a/src/main/resources/views/platform/trainEdu/include/include.js b/src/main/resources/views/platform/trainEdu/include/include.js new file mode 100644 index 0000000..7877934 --- /dev/null +++ b/src/main/resources/views/platform/trainEdu/include/include.js @@ -0,0 +1,9 @@ +const getAllAlbum = async () => { + const {data} = await $.get('/platform/trainEdu/album/getAllAlbum') + return data +} + +const getVideoType = async () => { + const resp = await $.get('/platform/trainEdu/type/pageData', {pageForm: 1, pageSize: 10000}) + return resp.data.list +} diff --git a/src/main/resources/views/platform/trainEdu/statistics/union.html b/src/main/resources/views/platform/trainEdu/statistics/union.html new file mode 100644 index 0000000..05bd79c --- /dev/null +++ b/src/main/resources/views/platform/trainEdu/statistics/union.html @@ -0,0 +1,144 @@ + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/views/platform/trainEdu/statistics/video.html b/src/main/resources/views/platform/trainEdu/statistics/video.html new file mode 100644 index 0000000..2495131 --- /dev/null +++ b/src/main/resources/views/platform/trainEdu/statistics/video.html @@ -0,0 +1,122 @@ + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/src/main/resources/views/platform/trainEdu/study.html b/src/main/resources/views/platform/trainEdu/study.html new file mode 100644 index 0000000..136c5fc --- /dev/null +++ b/src/main/resources/views/platform/trainEdu/study.html @@ -0,0 +1,442 @@ + + + + + + + + + + + +
+ + + + +
+ +
+ +
+ 搜索 +
+
+ + +
+ {{item.typeName}} + +
+
+
+ + +
+

+ {{item.title}} +

+

+

+
+
+
+
+ + + +
+ +
+ + + + + \ No newline at end of file diff --git a/src/main/resources/views/platform/trainEdu/type.html b/src/main/resources/views/platform/trainEdu/type.html new file mode 100644 index 0000000..7622930 --- /dev/null +++ b/src/main/resources/views/platform/trainEdu/type.html @@ -0,0 +1,188 @@ + + + + +
+ + +
+ + + 新增类型 + +
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + \ No newline at end of file diff --git a/src/main/resources/views/platform/trainEdu/video.html b/src/main/resources/views/platform/trainEdu/video.html new file mode 100644 index 0000000..4e64d10 --- /dev/null +++ b/src/main/resources/views/platform/trainEdu/video.html @@ -0,0 +1,360 @@ + + + + + + + + + + + + +
+ + +
+ + + + +
+ +
+ + + + + +
+ +
+ 搜索 +
+ +
+ + + 上传视频 + +
+
+ + + + + + + + + + + + + + + + + + + + +
+ + +

+ {{viewData.albumTitle + '-' + viewData.title}} +

+ +
+ +
+ + + + +