Helius
2021-12-16 d22f5bdfdaa8502a5f2496248da932b3c50c1fd0
finish video add/update/list
4 files added
16 files modified
895 ■■■■■ changed files
src/main/java/cc/mrbird/febs/video/controller/AdminVideoController.java 23 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/controller/ViewController.java 7 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/entity/VideoMasterDataEntity.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/entity/VideoMasterInfoEntity.java 11 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/entity/VideoMasterItemsEntity.java 6 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/entity/VideoMasterSourceEntity.java 5 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/mapper/VideoMasterDataMapper.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/mapper/VideoMasterInfoMapper.java 1 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/mapper/VideoMasterItemsMapper.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/service/IVideoMasterInfoService.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/service/impl/VideoMasterInfoServiceImpl.java 120 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/video/VideoMasterDataMapper.xml 5 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/video/VideoMasterInfoMapper.xml 42 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/video/VideoMasterItemsMapper.xml 34 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/video/video/video-add.html 73 ●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/video/video/video-list.html 43 ●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/video/video/video-source-add.html 48 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/video/video/video-source-list-select.html 9 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/video/video/video-source-list.html 9 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/video/video/video-update.html 413 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/video/controller/AdminVideoController.java
@@ -113,14 +113,31 @@
    @RequiresPermissions("source:view")
    @ControllerEndpoint(operation = "视频列表", exceptionMessage = "获取视频列表失败")
    public FebsResponse videoList(VideoMasterInfoEntity info, QueryRequest request) {
        return new FebsResponse().success();
        return new FebsResponse().success().data(getDataTable(this.videoMasterInfoService.findInPage(info, request)));
    }
    @PostMapping("/video/add")
    @RequiresPermissions("source:add")
    @ControllerEndpoint(operation = "添加视频", exceptionMessage = "添加视频失败")
    public FebsResponse videoAdd(@RequestBody VideoMasterInfoEntity info) {
        System.out.println(info);
        return null;
        this.videoMasterInfoService.addVideo(info);
        return new FebsResponse().success();
    }
    @PostMapping("/video/update")
    @RequiresPermissions("source:update")
    @ControllerEndpoint(operation = "修改视频", exceptionMessage = "修改视频失败")
    public FebsResponse videoUpdate(@RequestBody VideoMasterInfoEntity info) {
        this.videoMasterInfoService.updateVideo(info);
        return new FebsResponse().success();
    }
    @PostMapping("/video/changeIsUp/{id}")
    @RequiresPermissions("source:update")
    @ControllerEndpoint(operation = "上下架", exceptionMessage = "上下架失败")
    public FebsResponse changeIsUp(@PathVariable("id") Long id) {
        this.videoMasterInfoService.changeIsUp(id);
        return new FebsResponse().success();
    }
}
src/main/java/cc/mrbird/febs/video/controller/ViewController.java
@@ -2,7 +2,9 @@
import cc.mrbird.febs.common.entity.FebsConstant;
import cc.mrbird.febs.common.utils.FebsUtil;
import cc.mrbird.febs.video.entity.VideoMasterInfoEntity;
import cc.mrbird.febs.video.entity.VideoMasterSourceEntity;
import cc.mrbird.febs.video.service.IVideoMasterInfoService;
import cc.mrbird.febs.video.service.IVideoMasterSourceService;
import lombok.RequiredArgsConstructor;
import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -16,6 +18,7 @@
public class ViewController {
    private final IVideoMasterSourceService videoMasterSourceService;
    private final IVideoMasterInfoService videoMasterInfoService;
    @GetMapping(FebsConstant.VIEW_PREFIX + "video/category")
    @RequiresPermissions("category:view")
@@ -64,7 +67,9 @@
    @GetMapping(FebsConstant.VIEW_PREFIX + "video/update/{id}")
    @RequiresPermissions("video:update")
    public String videoUpdate(@PathVariable("id") Long id) {
    public String videoUpdate(@PathVariable("id") Long id, Model model) {
        VideoMasterInfoEntity masterInfo = this.videoMasterInfoService.findById(id);
        model.addAttribute("video", masterInfo);
        return FebsUtil.view("video/video/video-update");
    }
}
src/main/java/cc/mrbird/febs/video/entity/VideoMasterDataEntity.java
New file
@@ -0,0 +1,22 @@
package cc.mrbird.febs.video.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
 * @author wzy
 * @date 2021-12-16
 **/
@Data
@TableName("video_master_data")
public class VideoMasterDataEntity extends BaseEntity {
    private Long masterId;
    private int starCnt;
    private int collectCnt;
    private int playCnt;
}
src/main/java/cc/mrbird/febs/video/entity/VideoMasterInfoEntity.java
@@ -13,6 +13,8 @@
    private String title;
    private String code;
    private String intro;
    private String thumb;
@@ -31,4 +33,13 @@
    @TableField(exist = false)
    private List<VideoMasterItemsEntity> items;
    @TableField(exist = false)
    private int playCnt;
    @TableField(exist = false)
    private int collectCnt;
    @TableField(exist = false)
    private int starCnt;
}
src/main/java/cc/mrbird/febs/video/entity/VideoMasterItemsEntity.java
@@ -1,6 +1,7 @@
package cc.mrbird.febs.video.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -20,7 +21,10 @@
    private String videoUrl;
    private String seq;
    private Integer seq;
    private Long sourceId;
    @TableField(exist = false)
    private String sourceName;
}
src/main/java/cc/mrbird/febs/video/entity/VideoMasterSourceEntity.java
@@ -23,6 +23,11 @@
    private Integer isDel;
    /**
     * 缩略图
     */
    private String thumb;
    /**
     * 是否同步修改
     */
    @TableField(exist = false)
src/main/java/cc/mrbird/febs/video/mapper/VideoMasterDataMapper.java
New file
@@ -0,0 +1,7 @@
package cc.mrbird.febs.video.mapper;
import cc.mrbird.febs.video.entity.VideoMasterDataEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface VideoMasterDataMapper extends BaseMapper<VideoMasterDataEntity> {
}
src/main/java/cc/mrbird/febs/video/mapper/VideoMasterInfoMapper.java
@@ -10,4 +10,5 @@
    IPage<VideoMasterInfoEntity> selectInPage(@Param("record") VideoMasterInfoEntity record, Page<VideoMasterInfoEntity> page);
    VideoMasterInfoEntity selectEntityById(@Param("id") Long id);
}
src/main/java/cc/mrbird/febs/video/mapper/VideoMasterItemsMapper.java
@@ -4,7 +4,15 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface VideoMasterItemsMapper extends BaseMapper<VideoMasterItemsEntity> {
    int updateVideoUrlBySourceId(@Param("url") String url, @Param("sourceId") Long sourceId);
    List<VideoMasterItemsEntity> selectItemsByMasterId(@Param("masterId") Long masterId);
    int deleteNotInIds(@Param("list") List<Long> list, @Param("masterId") Long masterId);
//    int batchInsert(@Param("list") List<VideoMasterItemsEntity> list);
}
src/main/java/cc/mrbird/febs/video/service/IVideoMasterInfoService.java
@@ -8,4 +8,13 @@
public interface IVideoMasterInfoService extends IService<VideoMasterInfoEntity> {
    IPage<VideoMasterInfoEntity> findInPage(VideoMasterInfoEntity info, QueryRequest request);
    void addVideo(VideoMasterInfoEntity info);
    void updateVideo(VideoMasterInfoEntity info);
    VideoMasterInfoEntity findById(Long id);
    void changeIsUp(Long id);
}
src/main/java/cc/mrbird/febs/video/service/impl/VideoMasterInfoServiceImpl.java
@@ -1,14 +1,29 @@
package cc.mrbird.febs.video.service.impl;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.utils.AppContants;
import cc.mrbird.febs.video.entity.VideoMasterDataEntity;
import cc.mrbird.febs.video.entity.VideoMasterInfoEntity;
import cc.mrbird.febs.video.entity.VideoMasterItemsEntity;
import cc.mrbird.febs.video.entity.VideoMasterSourceEntity;
import cc.mrbird.febs.video.mapper.VideoMasterDataMapper;
import cc.mrbird.febs.video.mapper.VideoMasterInfoMapper;
import cc.mrbird.febs.video.mapper.VideoMasterItemsMapper;
import cc.mrbird.febs.video.mapper.VideoMasterSourceMapper;
import cc.mrbird.febs.video.service.IVideoMasterInfoService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
/**
 * @author wzy
@@ -19,8 +34,111 @@
@RequiredArgsConstructor
public class VideoMasterInfoServiceImpl extends ServiceImpl<VideoMasterInfoMapper, VideoMasterInfoEntity> implements IVideoMasterInfoService {
    private final VideoMasterItemsMapper videoMasterItemsMapper;
    private final VideoMasterSourceMapper videoMasterSourceMapper;
    private final VideoMasterDataMapper videoMasterDataMapper;
    @Override
    public IPage<VideoMasterInfoEntity> findInPage(VideoMasterInfoEntity info, QueryRequest request) {
        return null;
        Page<VideoMasterInfoEntity> page = new Page<>(request.getPageNum(), request.getPageSize());
        return this.baseMapper.selectInPage(info, page);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addVideo(VideoMasterInfoEntity info) {
        this.baseMapper.insert(info);
        List<VideoMasterItemsEntity> items = info.getItems();
        if (CollUtil.isEmpty(items)) {
            throw new FebsException("章节异常");
        }
        int i = 1;
        for (VideoMasterItemsEntity item : items) {
            if (StrUtil.isBlank(item.getName())){
                throw new FebsException("章节标题未填写");
            }
            VideoMasterSourceEntity source = this.videoMasterSourceMapper.selectById(item.getSourceId());
            item.setMasterId(info.getId());
            item.setSeq(i);
            item.setVideoUrl(source.getUrl());
            this.videoMasterItemsMapper.insert(item);
            i++;
        }
        VideoMasterDataEntity data = new VideoMasterDataEntity();
        data.setMasterId(info.getId());
        data.setCollectCnt(0);
        data.setPlayCnt(0);
        data.setStarCnt(0);
        this.videoMasterDataMapper.insert(data);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateVideo(VideoMasterInfoEntity info) {
        this.baseMapper.updateById(info);
//        List<VideoMasterItemsEntity> beforeItems = this.videoMasterItemsMapper.selectItemsByMasterId(info.getId());
        List<VideoMasterItemsEntity> newItems = info.getItems();
        if (CollUtil.isEmpty(newItems)) {
            throw new FebsException("章节异常");
        }
        List<Long> existID = new ArrayList<>();
        List<VideoMasterItemsEntity> newInsert = new ArrayList<>();
        int i = 1;
        for (VideoMasterItemsEntity newItem : newItems) {
            if (StrUtil.isBlank(newItem.getName())) {
                throw new FebsException("章节标题未填写");
            }
            if (newItem.getId() != null) {
                newItem.setSeq(i);
                this.videoMasterItemsMapper.updateById(newItem);
                existID.add(newItem.getId());
                i++;
            } else {
                newInsert.add(newItem);
            }
        }
        if (CollUtil.isNotEmpty(existID)) {
            this.videoMasterItemsMapper.deleteNotInIds(existID, info.getId());
        }
        if (CollUtil.isNotEmpty(newInsert)) {
            for (VideoMasterItemsEntity item : newInsert) {
                VideoMasterSourceEntity source = this.videoMasterSourceMapper.selectById(item.getSourceId());
                item.setMasterId(info.getId());
                item.setVideoUrl(source.getUrl());
                item.setSeq(i);
                this.videoMasterItemsMapper.insert(item);
                i++;
            }
        }
    }
    @Override
    public VideoMasterInfoEntity findById(Long id) {
        return this.baseMapper.selectEntityById(id);
    }
    @Override
    public void changeIsUp(Long id) {
        VideoMasterInfoEntity masterInfo = this.baseMapper.selectById(id);
        if (masterInfo == null) {
            throw new FebsException("视频不存在");
        }
        if (AppContants.FLAG_INT_Y.equals(masterInfo.getIsUp())) {
            masterInfo.setIsUp(AppContants.FLAG_INT_N);
        } else {
            masterInfo.setIsUp(AppContants.FLAG_INT_Y);
        }
        this.baseMapper.updateById(masterInfo);
    }
}
src/main/resources/mapper/video/VideoMasterDataMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cc.mrbird.febs.video.mapper.VideoMasterDataMapper">
</mapper>
src/main/resources/mapper/video/VideoMasterInfoMapper.xml
@@ -3,6 +3,48 @@
<mapper namespace="cc.mrbird.febs.video.mapper.VideoMasterInfoMapper">
    <select id="selectInPage" resultType="cc.mrbird.febs.video.entity.VideoMasterInfoEntity">
        select
            a.*,
            count(b.id) itemCnt,
            c.play_cnt,
            c.collect_cnt,
            c.star_cnt
        from video_master_info a, video_master_items b, video_master_data c
        where a.id=b.master_id and a.id=c.master_id
        <if test="record.title != null and record.title != ''">
            and a.title like concat('%', #{record.title}, '%')
        </if>
        group by a.id
    </select>
    <resultMap id="videoMasterInfoMap" type="cc.mrbird.febs.video.entity.VideoMasterInfoEntity">
        <id property="id" column="id" />
        <result property="cateIds" column="cate_ids" />
        <result property="code" column="code" />
        <result property="title" column="title" />
        <result property="isFree" column="is_free" />
        <result property="isUp" column="is_up" />
        <result property="intro" column="intro" />
        <result property="thumb" column="thumb" />
        <collection property="items" ofType="cc.mrbird.febs.video.entity.VideoMasterItemsEntity" >
            <id property="id" column="item_id" />
            <result property="name" column="name" />
            <result property="thumb" column="item_thumb" />
            <result property="sourceId" column="source_id" />
            <result property="sourceName" column="sourceName" />
        </collection>
    </resultMap>
    <select id="selectEntityById" resultMap="videoMasterInfoMap">
        select
            a.*,
            b.id item_id,
            b.name,
            b.thumb item_thumb,
            b.source_id,
            c.name sourceName
        from video_master_info a, video_master_items b, video_master_source c
        where a.id=b.master_id and a.id=#{id} and b.source_id=c.id
    </select>
</mapper>
src/main/resources/mapper/video/VideoMasterItemsMapper.xml
@@ -9,4 +9,38 @@
        where source_id=#{sourceId}
    </update>
    <select id="selectItemsByMasterId" resultType="cc.mrbird.febs.video.entity.VideoMasterItemsEntity">
        select * from video_master_items
        where master_id=#{masterId}
    </select>
    <delete id="deleteNotInIds">
        delete from video_master_items
        where master_id=#{masterId} and id not in
        <foreach collection="list" item="item" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </delete>
<!--    <insert id="batchInsert">-->
<!--        insert video_master_items (-->
<!--            revision,-->
<!--            created_by,-->
<!--            created_time,-->
<!--            update_by,-->
<!--            updated_time,-->
<!--            id,-->
<!--            master_id,-->
<!--            name,-->
<!--            thumb,-->
<!--            video_url,-->
<!--            seq,-->
<!--            source_id-->
<!--        ) values-->
<!--        <foreach collection="list" item="item" separator=",">-->
<!--            (-->
<!--            )-->
<!--        </foreach>-->
<!--    </insert>-->
</mapper>
src/main/resources/templates/febs/views/video/video/video-add.html
@@ -47,6 +47,7 @@
                    <button type="button" class="layui-btn" id="thumbUpload">上传图片</button>
                    <div class="layui-upload-list">
                        <img class="layui-upload-img" id="thumb" style="width: 150px;"/>
                        <input class="layui-input febs-hide" name="thumb" autocomplete="off" />
                    </div>
                </div>
            </div>
@@ -64,52 +65,13 @@
                <table class="layui-table">
                    <thead>
                        <tr>
                            <th>排序</th>
                            <th>视频标题</th>
                            <th>视频缩略图</th>
                            <th>章节标题</th>
                            <th>缩略图</th>
                            <th>资源名称</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody id="itemList">
<!--                    <tr>-->
<!--                        <th>-->
<!--                            1-->
<!--                        </th>-->
<!--                        <th>-->
<!--                            <input type="text" class="layui-input" placeholder="" />-->
<!--                        </th>-->
<!--                        <th>-->
<!--                            <div class="upload">-->
<!--                                <img class="layui-upload-img item-img febs-hide" style="width: 150px;"/>-->
<!--                                <button class="layui-btn layui-btn-xs"  type="button">点击上传</button>-->
<!--                                <input type="text" class="febs-hide" name="itemThumb" />-->
<!--                            </div>-->
<!--                        </th>-->
<!--                        <th>123</th>-->
<!--                        <th>-->
<!--                            <button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>-->
<!--                        </th>-->
<!--                    </tr>-->
<!--                    <tr>-->
<!--                        <th>-->
<!--                            2-->
<!--                        </th>-->
<!--                        <th>-->
<!--                            <input type="text" class="layui-input" placeholder="" />-->
<!--                        </th>-->
<!--                        <th>-->
<!--                            <div class="upload">-->
<!--                                <img class="layui-upload-img item-img" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp05%2F19100120461512E-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg" style="width: 150px;"/>-->
<!--                                <button class="layui-btn layui-btn-xs febs-hide" type="button">点击上传</button>-->
<!--                                <input type="text" class="febs-hide" name="itemThumb" />-->
<!--                            </div>-->
<!--                        </th>-->
<!--                        <th>123</th>-->
<!--                        <th>-->
<!--                            <button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>-->
<!--                        </th>-->
<!--                    </tr>-->
                    </tbody>
                </table>
            </div>
@@ -140,10 +102,7 @@
    {{#  layui.each(d, function(index, item){ }}
    <tr>
        <th>
            {{item.seq}}
            <input type="text" class="febs-hide" name="sourceId" value="{{item.id}}"/>
        </th>
        <th>
            <input type="text" class="layui-input" name="name" placeholder="" value=""/>
        </th>
        <th>
@@ -151,11 +110,11 @@
                {{#  if(!item.thumb || item.thumb == ''){ }}
                <img class="layui-upload-img item-img  febs-hide" src="" style="width: 150px;"/>
                <button class="layui-btn layui-btn-xs" type="button">点击上传</button>
                <input type="text" class="febs-hide" name="itemThumb" />
                <input type="text" class="febs-hide" autocomplete="off" name="itemThumb" />
                {{# } else { }}
                <img class="layui-upload-img item-img" src="" style="width: 150px;"/>
                <img class="layui-upload-img item-img" src="{{item.thumb}}" style="width: 150px;"/>
                <button class="layui-btn layui-btn-xs febs-hide" type="button">点击上传</button>
                <input type="text" class="febs-hide" name="itemThumb" />
                <input type="text" class="febs-hide" autocomplete="off" name="itemThumb" />
                {{# } }}
            </div>
        </th>
@@ -269,6 +228,7 @@
                    return layer.msg('上传失败');
                }
                $('#thumb').next().val(res.data[0])
                layer.msg('上传成功', {icon: 1});
            }
            ,error: function(){
@@ -350,17 +310,19 @@
                itemData.push(data);
            });
            if (!data.field.thumb) {
                febs.alert.warn('未上传缩略图');
                return;
            }
            var field = {};
            field.items = itemData;
            field.title = data.field.title;
            field.cateIds = cateIds.join(",");
            field.thumb = data.field.thumb;
            field.isFree = data.field.isFree;
            field.intro = data.field.intro;
            console.log(field);
            // febs.post(ctx + 'video/video/add', data.field, function () {
            //     layer.closeAll();
            // });
            $.ajax({
                url : ctx + 'video/video/add',
@@ -370,9 +332,16 @@
                data : JSON.stringify(field),
                success : function(res) {
                    console.log(res)
                    if (res.code != 200) {
                        febs.alert.warn(res.message);
                        return;
                    }
                    febs.alert.success('新增成功');
                    $('#febs-video').find('#query').click();
                    layer.closeAll();
                },
                error : function(err) {
                    layer.msg("请求错误");
                }
            })
            return false;
src/main/resources/templates/febs/views/video/video/video-list.html
@@ -56,6 +56,14 @@
        </div>
    </div>
</div>
<style>
    .layui-table-cell {
        height: 100%;
    }
</style>
<script type="text/html" id="thumbFormat">
    <img src="{{d.thumb}}" />
</script>
<script type="text/html" id="is-up-format">
    {{#
    var status = {
@@ -78,6 +86,11 @@
    <span shiro:lacksPermission="video:view,video:update,video:delete">
        <span class="layui-badge-dot febs-bg-orange"></span> 无权限
    </span>
    {{# if(d.isUp == 1) { }}
    <button lay-event="isUp" type="button" class="layui-btn layui-btn-xs layui-btn-danger isUp">下架</button>
    {{# } else { }}
    <button lay-event="isUp" type="button" class="layui-btn layui-btn-xs layui-btn-normal isUp">上架</button>
    {{# } }}
    <a lay-event="edit" shiro:hasPermission="video:update"><i
            class="layui-icon febs-edit-area febs-blue">&#xe7a4;</i></a>
    <a lay-event="del" shiro:hasPermission="video:delete"><i class="layui-icon febs-edit-area febs-red">&#xe7f9;</i></a>
@@ -155,16 +168,29 @@
                });
            }
            if (layEvent === 'edit') {
                febs.modal.open('修改视频', 'video/update/' + data.name, {
                    area: $(window).width() <= 750 ? '90%' : '50%',
                    offset: '30px',
                febs.modal.open('修改视频', 'video/update/' + data.id, {
                    area: ['100%', '100%'],
                    btn: ['提交', '取消'],
                    yes: function (index, layero) {
                        $('#user-update').find('#submit').trigger('click');
                        $('#video-update').find('#submit').trigger('click');
                    },
                    btn2: function () {
                        layer.closeAll();
                    }
                });
            }
            if (layEvent === 'isUp') {
                var text;
                if (data.isUp == 1) {
                    text = "下架";
                } else {
                    text = "上架";
                }
                febs.modal.confirm('是否' + text + "该视频", '确定' + text + '该视频?', function () {
                    febs.post(ctx + 'video/video/changeIsUp/' + data.id, null, function () {
                        febs.alert.success(text + '视频成功');
                        $query.click();
                    });
                });
            }
        });
@@ -201,11 +227,14 @@
                cols: [[
                    {type: 'checkbox'},
                    {field: 'title', title: '视频名', minWidth: 100},
                    {field: 'thumb', title: '缩略图'},
                    {templet: '#thumbFormat', title: '缩略图'},
                    {title: '是否上架', templet: '#is-up-format'},
                    {title: '会员', templet: '#is-free-format'},
                    {field: 'createdTime', title: '创建时间', minWidth: 180, sort: true},
                    {title: '操作', toolbar: '#user-option', minWidth: 140}
                    {field: 'playCnt', title: '播放量'},
                    {field: 'collectCnt', title: '收藏量'},
                    {field: 'starCnt', title: '点赞量'},
                    {field: 'createdTime', title: '创建时间', minWidth: 180},
                    {title: '操作', toolbar: '#user-option'}
                ]]
            });
        }
src/main/resources/templates/febs/views/video/video/video-source-add.html
@@ -26,12 +26,25 @@
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">缩略图:</label>
            <div class="layui-input-block">
                <div class="layui-upload">
                    <button type="button" class="layui-btn" id="thumbUpload">上传图片</button>
                    <div class="layui-upload-list">
                        <img class="layui-upload-img" id="thumb" style="width: 150px;"/>
                        <input class="layui-input febs-hide" name="thumb" autocomplete="off" />
                    </div>
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label"></label>
            <div class="layui-input-block">
                <div class="layui-upload-drag" id="upload">
                    <div class="upload-text" id="upload-text">
                        <i class="layui-icon layui-icon-upload-drag"></i>
                        <p>点击上传,或将文件拖拽到此处</p>
                        <p>点击上传,或将视频文件拖拽到此处</p>
                    </div>
                    <div class="upload-progress" id="upload-progress" style="display: none;">
@@ -69,6 +82,15 @@
        form.render();
        form.on('submit(source-add-form-submit)', function (data) {
            if (!data.field.url) {
                febs.alert.warn('未上传视频文件');
                return;
            }
            if (!data.field.thumb) {
                febs.alert.warn('未上传视频文件');
                return;
            }
            febs.post(ctx + 'video/source/add', data.field, function () {
                layer.closeAll();
                febs.alert.success('新增成功');
@@ -112,5 +134,29 @@
                }
            }
        });
        upload.render({
            elem: '#thumbUpload'
            ,url: 'common/upload'
            ,before: function(obj){
                //预读本地文件示例,不支持ie8
                obj.preview(function(index, file, result){
                    $('#thumb').attr('src', result);
                });
                layer.msg('上传中', {icon: 16, time: 0});
            }
            ,done: function(res){
                //如果上传失败
                if(res.code != 200){
                    return layer.msg('上传失败');
                }
                $('#thumb').next().val(res.data[0])
                layer.msg('上传成功', {icon: 1});
            }
            ,error: function(){
                layer.msg('上传失败');
            }
        });
    });
</script>
src/main/resources/templates/febs/views/video/video/video-source-list-select.html
@@ -28,6 +28,14 @@
        </div>
    </div>
</div>
<style>
    .layui-table-cell {
        height: 100%;
    }
</style>
<script type="text/html" id="thumbFormat">
    <img src="{{d.thumb}}" />
</script>
<script data-th-inline="none" type="text/javascript">
    layui.use(['dropdown', 'jquery', 'laydate', 'form', 'table', 'febs', 'treeSelect'], function () {
        var $ = layui.jquery,
@@ -76,6 +84,7 @@
                cols: [[
                    {type: 'checkbox'},
                    {field: 'name', title: '视频名称', minWidth: 100},
                    {templet: '#thumbFormat', title: '缩略图', minWidth: 100},
                    {field: 'createdTime', title: '创建时间', minWidth: 180, sort: true}
                ]]
            });
src/main/resources/templates/febs/views/video/video/video-source-list.html
@@ -35,6 +35,14 @@
        </div>
    </div>
</div>
<style>
    .layui-table-cell {
        height: 100%;
    }
</style>
<script type="text/html" id="thumbFormat">
    <img src="{{d.thumb}}" />
</script>
<script type="text/html" id="source-option">
    <span shiro:lacksPermission="source:update,source:delete">
        <span class="layui-badge-dot febs-bg-orange"></span> 无权限
@@ -163,6 +171,7 @@
                cols: [[
                    {type: 'checkbox'},
                    {field: 'name', title: '视频名称', minWidth: 100},
                    {templet: '#thumbFormat', title: '缩略图', minWidth: 100},
                    {field: 'createdTime', title: '创建时间', minWidth: 180, sort: true},
                    {title: '操作', toolbar: '#source-option', minWidth: 140}
                ]]
src/main/resources/templates/febs/views/video/video/video-update.html
New file
@@ -0,0 +1,413 @@
<style>
    #video-update {
        padding: 20px 25px 25px 0;
    }
    #video-update .layui-treeSelect .ztree li a, .ztree li span {
        margin: 0 0 2px 3px !important;
    }
    #video-update #data-permission-tree-block {
        border: 1px solid #eee;
        border-radius: 2px;
        padding: 3px 0;
    }
    #video-update .layui-treeSelect .ztree li span.button.switch {
        top: 1px;
        left: 3px;
    }
    #video-update .upload {
        cursor: pointer;
    }
</style>
<div class="layui-fluid" id="video-update">
    <form class="layui-form" action="" lay-filter="video-update-form">
        <input class="layui-input febs-hide" name="id" data-th-value="${video.id}" />
        <div class="layui-form-item">
            <div class="layui-col-md6">
                <label class="layui-form-label febs-form-item-require">视频标题:</label>
                <div class="layui-input-block">
                    <input type="text" name="title" minlength="2" maxlength="10" lay-verify="range"
                           autocomplete="off" class="layui-input">
                </div>
            </div>
            <div class="layui-col-md6">
                <label class="layui-form-label febs-form-item-require">视频分类:</label>
                <div class="layui-input-block" id="video-cate">
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">简介:</label>
            <div class="layui-input-block">
                <textarea name="intro" autocomplete="off" placeholder="请输入简介" class="layui-textarea"></textarea>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">缩略图:</label>
            <div class="layui-input-block">
                <div class="layui-upload">
                    <button type="button" class="layui-btn" id="thumbUpload">上传图片</button>
                    <div class="layui-upload-list">
                        <img class="layui-upload-img" id="thumb" th:src="${video.thumb}" style="width: 150px;"/>
                        <input class="layui-input febs-hide" name="thumb" autocomplete="off" />
                    </div>
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">章节:</label>
            <div class="layui-input-block">
                <button class="layui-btn" type="button" id="addItem">新增章节</button>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label"></label>
            <div class="layui-input-block">
                <table class="layui-table">
                    <thead>
                        <tr>
                            <th>章节标题</th>
                            <th>缩略图</th>
                            <th>资源名称</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody id="itemList">
                    </tbody>
                </table>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">是否免费:</label>
            <div class="layui-input-block">
                <input type="radio" name="isFree" value="1" title="免费">
                <input type="radio" name="isFree" value="2" title="会员">
            </div>
        </div>
<!--        <div class="layui-form-item layui-form-text">-->
<!--            <label class="layui-form-label">备注:</label>-->
<!--            <div class="layui-input-block">-->
<!--                <textarea name="description" maxlength="100" class="layui-textarea"></textarea>-->
<!--            </div>-->
<!--        </div>-->
        <div class="layui-form-item febs-hide">
            <button class="layui-btn" lay-submit="" lay-filter="video-update-form-submit" id="submit"></button>
            <button type="reset" class="layui-btn" id="reset"></button>
        </div>
    </form>
</div>
<script type="text/html" id="tableRowTemplate">
    {{#  layui.each(d, function(index, item){ }}
    <tr>
        <th>
            <input type="text" class="febs-hide" name="itemId" value="{{item.id}}"/>
            <input type="text" class="febs-hide" name="sourceId" value="{{item.sourceId}}"/>
            <input type="text" class="layui-input" name="name" value="{{item.name}}"/>
        </th>
        <th>
            <div class="upload{{item.sourceId}}">
                {{#  if(!item.thumb || item.thumb == ''){ }}
                <img class="layui-upload-img item-img  febs-hide" src="" style="width: 150px;"/>
                <button class="layui-btn layui-btn-xs" type="button">点击上传</button>
                <input type="text" class="febs-hide" autocomplete="off" name="itemThumb" value="{{item.thumb}}" />
                {{# } else { }}
                <img class="layui-upload-img item-img" src="{{item.thumb}}" style="width: 150px;"/>
                <button class="layui-btn layui-btn-xs febs-hide" type="button">点击上传</button>
                <input type="text" class="febs-hide" autocomplete="off" name="itemThumb" value="{{item.thumb}}" />
                {{# } }}
            </div>
        </th>
        <th>{{item.sourceName}}</th>
        <th>
            <button class="layui-btn layui-btn-xs layui-btn-danger item-delete" type="button">删除</button>
        </th>
    </tr>
    {{#  }); }}
</script>
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree', 'upload', 'xmSelect', 'laytpl', 'table'], function () {
        var $ = layui.$,
            febs = layui.febs,
            layer = layui.layer,
            form = layui.form,
            table = layui.table,
            $view = $('#video-update'),
            upload = layui.upload,
            validate = layui.validate,
            laytpl = layui.laytpl,
            tableUpload,
            video = [[${video}]],
            templateHtml = tableRowTemplate.innerHTML,
            $itemList = $("#itemList");
        form.verify(validate);
        form.render();
        // 已添加的item数据
        var itemData = [];
        var videoCate = xmSelect.render({
            el: '#video-cate',
            language: 'zn',
            prop : {
                value : 'id'
            },
            data: []
        })
        febs.get(ctx + 'video/categoryTree', null, function(res) {
            videoCate.update({
                data : res.data,
                autoRow: true,
            });
            initValue();
        });
        function initValue() {
            form.val("video-update-form", {
                "title" : video.title,
                "intro" : video.intro,
                "isFree" : video.isFree + "",
                "thumb" : video.thumb
            })
            videoCate.setValue(video.cateIds.split(','));
            var items = video.items;
            laytpl(templateHtml).render(items, function(html) {
                $itemList.append(html);
            });
            for (var i = 0; i < items.length; i++) {
                bindUpload(items[i].sourceId);
                var item = {};
                item.id = items[i].sourceId;
                itemData.push(item);
            }
            deleteBind();
        }
        $("#addItem").on('click', function() {
            febs.modal.open('选择视频资源', 'video/source/select/list', {
                area: $(window).width() <= 750 ? '90%' : '50%',
                offset: '30px',
                btn: ['提交', '取消'],
                yes: function (index, layero) {
                    var selectData = table.checkStatus('videoSourceSelectTable').data;
                    // 去重
                    var noRepeatData = [];
                    if (itemData.length != 0) {
                        for (var i = 0; i < selectData.length; i++) {
                            var flag = true;
                            for(var j = 0; j < itemData.length; j++) {
                                if (selectData[i].id == itemData[j].id) {
                                    flag = false;
                                    break;
                                }
                            }
                            if (flag) {
                                noRepeatData.push(selectData[i]);
                            }
                        }
                    } else {
                        noRepeatData = selectData;
                    }
                    if (noRepeatData.length > 0) {
                        itemData = itemData.concat(noRepeatData);
                        // 转化字段
                        for (var i = 0; i < noRepeatData.length; i++) {
                            noRepeatData[i].sourceId = noRepeatData[i].id;
                            noRepeatData[i].sourceName = noRepeatData[i].name;
                            noRepeatData[i].name = "";
                            noRepeatData[i].id = "";
                        }
                        laytpl(templateHtml).render(noRepeatData, function(html) {
                            $itemList.append(html);
                        })
                        for (var i = 0; i < noRepeatData.length; i++) {
                            bindUpload(noRepeatData[i].sourceId);
                        }
                    }
``
                    deleteUnBind();
                    deleteBind();
                    layer.close(layer.index);
                },
                btn2: function () {
                    layer.close(layer.index);
                }
            });
        });
        upload.render({
            elem: '#thumbUpload'
            ,url: 'common/upload'
            ,before: function(obj){
                //预读本地文件示例,不支持ie8
                obj.preview(function(index, file, result){
                    $('#thumb').attr('src', result);
                });
                layer.msg('上传中', {icon: 16, time: 0});
            }
            ,done: function(res){
                //如果上传失败
                if(res.code != 200){
                    return layer.msg('上传失败');
                }
                $('#thumb').next().val(res.data[0])
                layer.msg('上传成功', {icon: 1});
            }
            ,error: function(){
                layer.msg('上传失败');
            }
        });
        // 表格中的图片上传
        function bindUpload(id) {
            upload.render({
                elem: '.upload' + id
                ,url: ctx + 'common/upload' //改成您自己的上传接口
                // ,accept: 'file'
                ,before: function(obj){
                    var item = this.item;
                    var $button = $(item).find("button");
                    var $img = $(item).find('img');
                    // 如果img标签内没有src,说明没有上传图片,故此时显示的是button,所以需要操作一遍显示隐藏
                    if (!$img.attr("src")) {
                        $button.addClass("febs-hide");
                        $img.removeClass("febs-hide");
                    }
                    obj.preview(function(index, file, result){
                        $img.attr('src', result);
                    });
                    layer.msg('上传中', {icon: 16, time: 0});
                }
                ,done: function(res){
                    var item = this.item;
                    var $itemThumb = $(item).find('input[name="itemThumb"]');
                    var $button = $(item).find("button");
                    var $img = $(item).find('img');
                    //如果上传失败
                    if(res.code !== 200){
                        layer.msg('上传失败');
                        // 上传失败则重置
                        $button.removeClass("febs-hide");
                        $img.addClass("febs-hide");
                        $img.attr('src', '');
                        return
                    }
                    $itemThumb.val(res.data[0]);
                    layer.msg('上传完毕', {icon: 1});
                }
                ,error: function(){
                    return layer.msg('上传失败');
                }
            });
        }
        form.on('submit(video-update-form-submit)', function (data) {
            var $tr = $("#itemList").find("tr");
            var itemLength = $tr.length;
            if (itemLength == 0) {
                layer.msg('请添加章节!');
                return;
            }
            var cateIds = videoCate.getValue('value');
            if (cateIds.length <= 0) {
                febs.alert.warn('至少选择一个目录');
                return false;
            }
            var itemData = [];
            $tr.each(function() {
                var data = {};
                var sourceId = $(this).find("input[name = 'sourceId']").val();
                var itemId = $(this).find("input[name = 'itemId']").val();
                var videoItemName = $(this).find("input[name = 'name']").val();
                var itemThumb = $(this).find("input[name = 'itemThumb']").val();
                data.sourceId = sourceId;
                data.id = itemId;
                data.name = videoItemName;
                data.thumb = itemThumb;
                itemData.push(data);
            });
            if (!data.field.thumb) {
                febs.alert.warn('未上传缩略图');
                return;
            }
            var field = {};
            field.items = itemData;
            field.id = data.field.id;
            field.title = data.field.title;
            field.cateIds = cateIds.join(",");
            field.thumb = data.field.thumb;
            field.isFree = data.field.isFree;
            field.intro = data.field.intro;
            $.ajax({
                url : ctx + 'video/video/update',
                type : "post",
                dataType : "json",
                contentType : "application/json",
                data : JSON.stringify(field),
                success : function(res) {
                    console.log(res)
                    if (res.code != 200) {
                        febs.alert.warn(res.message);
                        return;
                    }
                    febs.alert.success('修改成功');
                    $('#febs-video').find('#query').click();
                    layer.closeAll();
                },
                error : function(err) {
                    layer.msg("请求错误");
                }
            })
            return false;
        });
        function deleteBind() {
            $(".item-delete").each(function(index, element) {
                $(this).on("click", function() {
                    var $tr = $(this).parents("tr");
                    var id = $tr.find("input[name='sourceId']").val();
                    for (var i = 0; i < itemData.length; i++) {
                        if (itemData[i].id == id) {
                            itemData.splice(i, 1);
                            break;
                        }
                    }
                    $tr.remove();
                });
            })
        }
        function deleteUnBind() {
            $(".item-delete").each(function(index, element) {
                $(this).unbind('click');
            })
        }
    });
</script>