|
@@ -0,0 +1,1524 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="app-container">
|
|
|
|
|
+ <div style="padding-bottom: 20px">
|
|
|
|
|
+ <span v-if="courseName != null">{{ courseName }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
|
|
|
|
+ <el-form-item label="小节名称" prop="title">
|
|
|
|
|
+ <el-input v-model="queryParams.title" placeholder="请输入小节名称" clearable size="small"
|
|
|
|
|
+ @keyup.enter.native="handleQuery"/>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="小节id" prop="videoId">
|
|
|
|
|
+ <el-input v-model="queryParams.videoId" placeholder="请输入小节id" clearable size="small"
|
|
|
|
|
+ @keyup.enter.native="handleQuery"/>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
|
|
|
|
+ <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <el-row :gutter="10" class="mb8">
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:add']">新增目录
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="primary" plain :disabled="!ids || ids.length <= 0" size="mini" @click="openUpdates"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:updateTime']">修改时间
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="primary" plain size="mini" @click="openAdds"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:batchAdd']">批量添加
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="primary" plain size="mini" @click="updateRedPageckeOpen"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:updateRed']">修改红包
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:remove']">删除
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="warning" plain icon="el-icon-edit" size="mini" @click="handleCourseSort"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:sort']">修改课节排序
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="primary" plain icon="el-icon-delete" size="mini" @click="handleSync"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:sync']">同步模板数据
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="primary" plain icon="el-icon-edit" size="mini" :disabled="multiple" @click="handleDown"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:batchDown']">批量下架
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="primary" plain icon="el-icon-edit" size="mini" :disabled="multiple" @click="handleUp"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:batchUp']">批量上架</el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="1.5">
|
|
|
|
|
+ <el-button type="primary" plain icon="el-icon-edit" size="mini" :disabled="multiple" @click="handleEditCover"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:batchEditCover']">批量修改封面图
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ <el-table border v-loading="loading" :data="userCourseVideoList" @selection-change="handleSelectionChange">
|
|
|
|
|
+ <el-table-column type="selection" width="55" align="center"/>
|
|
|
|
|
+ <el-table-column label="视频ID" align="center" prop="videoId"/>
|
|
|
|
|
+ <el-table-column label="小节名称" align="center" show-overflow-tooltip prop="title"/>
|
|
|
|
|
+ <el-table-column label="视频文件名称" align="center" show-overflow-tooltip prop="fileName">
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="视频时长" align="center" prop="duration">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ {{ formatDuration(row.duration) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="看课开始时间" align="center" prop="duration">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ <el-tag v-if="row.viewStartTime">{{ row.viewStartTime }}</el-tag>
|
|
|
|
|
+ <el-tag type="danger" v-if="!row.viewStartTime">无</el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="看课结束时间" align="center" prop="duration">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ <el-tag v-if="row.viewEndTime">{{ row.viewEndTime }}</el-tag>
|
|
|
|
|
+ <el-tag type="danger" v-if="!row.viewEndTime">无</el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="领取红包时间" align="center" prop="duration">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ <el-tag v-if="row.lastJoinTime">{{ row.lastJoinTime }}</el-tag>
|
|
|
|
|
+ <el-tag type="danger" v-if="!row.lastJoinTime">无</el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="红包金额" align="center" prop="redPacketMoney"/>
|
|
|
|
|
+ <el-table-column label="排序" align="center" prop="courseSort"/>
|
|
|
|
|
+ <el-table-column label="上传时间" align="center" prop="createTime"/>
|
|
|
|
|
+ <el-table-column label="是否上架" align="center" prop="isOnPut">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ <el-tag v-if="row.isOnPut == 0">是</el-tag>
|
|
|
|
|
+ <el-tag type="danger" v-if="row.isOnPut == 1">否</el-tag>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:edit']">修改
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button size="mini" type="text" icon="el-icon-edit" @click="handleComment(scope.row)"
|
|
|
|
|
+ v-hasPermi="['course:courseWatchComment:list']">查看评论
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
|
|
|
|
+ v-hasPermi="['course:userCourseVideo:remove']">删除
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
|
|
|
|
|
+ @pagination="getList"/>
|
|
|
|
|
+ <el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
|
|
|
|
|
+ <el-form ref="form" :model="form" :rules="rules" label-width="110px" v-loading="uploadLoading">
|
|
|
|
|
+ <el-form-item label="视频标题" prop="title">
|
|
|
|
|
+ <el-input v-model="form.title" placeholder="请输入内容"/>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="视频描述" prop="description">
|
|
|
|
|
+ <el-input v-model="form.description" type="textarea" :rows="2" placeholder="请输入内容"/>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="课程排序" prop="courseSort">
|
|
|
|
|
+ <el-input-number v-model="form.courseSort" :min="1"></el-input-number>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="视频缩略图" prop="thumbnail">
|
|
|
|
|
+ <el-upload v-model="form.thumbnail" class="avatar-uploader" :action="uploadUrl" :show-file-list="false"
|
|
|
|
|
+ :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload">
|
|
|
|
|
+ <img v-if="form.thumbnail" :src="form.thumbnail" class="avatar" width="300px">
|
|
|
|
|
+ <i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
|
|
+ </el-upload>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <video-upload :type="1" :isPrivate="isPrivate" :fileKey.sync="form.fileKey" :fileSize.sync="form.fileSize"
|
|
|
|
|
+ :videoUrl.sync="videoUrl" :fileName.sync="form.fileName" :line_1.sync="form.lineOne"
|
|
|
|
|
+ :line_2.sync="form.lineTwo" :line_3.sync="form.lineThree" :thumbnail.sync="form.thumbnail"
|
|
|
|
|
+ :uploadType.sync="form.uploadType" :isTranscode.sync="form.isTranscode"
|
|
|
|
|
+ :transcodeFileKey.sync="form.transcodeFileKey" @video-duration="handleVideoDuration"
|
|
|
|
|
+ @change="handleVideoChange" @selectProjects="handleSelectProjects" ref="videoUpload"
|
|
|
|
|
+ append-to-body/>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="关联疗法" >
|
|
|
|
|
+ <el-button size="small" type="primary" @click="choosePackage">选取疗法</el-button>
|
|
|
|
|
+ <el-table border width="100%" style="margin-top:5px;" :data="packageList">
|
|
|
|
|
+ <el-table-column label="疗法名称" align="center" prop="packageName"/>
|
|
|
|
|
+ <el-table-column label="疗法图片" align="center" prop="imgUrl">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <img :src="scope.row.imgUrl" style="height: 80px;">
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="疗法别名" align="center" prop="secondName"/>
|
|
|
|
|
+ <el-table-column label="总金额" align="center" prop="totalPrice"/>
|
|
|
|
|
+ <!-- 根据课程类型控制是否显示弹出时间列:0是公域(显示),1是私域(不显示) -->
|
|
|
|
|
+ <el-table-column label="弹出时间" align="center" width="250px" v-if="isPrivate == 0">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <el-time-select
|
|
|
|
|
+ v-model="scope.row.duration"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ placeholder="选择时间"
|
|
|
|
|
+ :picker-options="getPickerOptions()"
|
|
|
|
|
+ @change="handleTimeChange(scope.$index, scope.row)"
|
|
|
|
|
+ ></el-time-select>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="操作" align="center" width="100px" fixed="right">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ icon="el-icon-delete"
|
|
|
|
|
+ @click="handlePackageDelete(scope.row)"
|
|
|
|
|
+ >删除</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </el-form-item >
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="课题选择" prop="questionBankId">
|
|
|
|
|
+ <el-button size="small" type="primary" @click="chooseQuestionBank">选取课题</el-button>
|
|
|
|
|
+ <el-table border width="100%" style="margin-top:5px;" :data="form.questionBankList">
|
|
|
|
|
+ <el-table-column label="问题" align="center" prop="title">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-tooltip class="item" effect="dark" :content="scope.row.title" placement="top">
|
|
|
|
|
+ <div
|
|
|
|
|
+ style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; text-overflow: ellipsis;">
|
|
|
|
|
+ <span>{{ scope.row.title }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-tooltip>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="类别" align="center" prop="type">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <dict-tag :options="typeOptions" :value="scope.row.type"/>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="答案" align="center" prop="answer"/>
|
|
|
|
|
+ <el-table-column label="操作" align="center" width="100px" fixed="right">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-button size="mini" type="text" icon="el-icon-delete"
|
|
|
|
|
+ @click="handleQuestionBankDelete(scope.row)">删除
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="红包金额" prop="redPacketMoney">
|
|
|
|
|
+ <el-input-number v-model="form.redPacketMoney" :min="0.1" :max="200" :step="0.1"></el-input-number>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <!-- v-if="!!form.randomRedPacketRulesArr" -->
|
|
|
|
|
+ <el-form-item v-if="!!enableRandomRedPacket" label="随机红包金额" >
|
|
|
|
|
+ <template >
|
|
|
|
|
+ <div v-for="(rule, index) in form.randomRedPacketRulesArr" :key="index" class="form-row">
|
|
|
|
|
+ <el-form-item
|
|
|
|
|
+ label="随机红包金额区间"
|
|
|
|
|
+ :prop="`randomRedPacketRulesArr.${index}.minAmount`"
|
|
|
|
|
+ :rules="[
|
|
|
|
|
+ { required: true, message: '请输入最小金额', trigger: 'blur' },
|
|
|
|
|
+ { validator: validateMinAmount, trigger: 'blur', index: index }
|
|
|
|
|
+ ]"
|
|
|
|
|
+ class="form-item-amount"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model.number="rule.minAmount"
|
|
|
|
|
+ type="number"
|
|
|
|
|
+ :min="0.01"
|
|
|
|
|
+ :precision="2"
|
|
|
|
|
+ :step="0.01"
|
|
|
|
|
+ placeholder="最小金额"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ class="amount-input"
|
|
|
|
|
+ @input="handleAmountInput(rule, 'minAmount')"
|
|
|
|
|
+ ></el-input>
|
|
|
|
|
+ <span class="separator">-</span>
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model.number="rule.maxAmount"
|
|
|
|
|
+ type="number"
|
|
|
|
|
+ :min="rule.minAmount || 0.01"
|
|
|
|
|
+ :precision="2"
|
|
|
|
|
+ :step="0.01"
|
|
|
|
|
+ placeholder="最大金额"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ class="amount-input"
|
|
|
|
|
+ @input="handleAmountInput(rule, 'maxAmount')"
|
|
|
|
|
+ ></el-input>
|
|
|
|
|
+ <span class="suffix">元</span>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item
|
|
|
|
|
+ label="随机权重"
|
|
|
|
|
+ :prop="`randomRedPacketRulesArr.${index}.weight`"
|
|
|
|
|
+ :rules="[
|
|
|
|
|
+ { required: true, message: '请输入权重', trigger: 'blur' },
|
|
|
|
|
+ { type: 'integer', message: '权重必须为整数', trigger: 'blur' },
|
|
|
|
|
+ ]"
|
|
|
|
|
+ class="form-item-weight"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model.number="rule.weight"
|
|
|
|
|
+ type="number"
|
|
|
|
|
+ :min="1"
|
|
|
|
|
+ placeholder="权重"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ ></el-input>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-tooltip class="item" effect="dark" content="权重越高,被随机到的概率越大" placement="top">
|
|
|
|
|
+ <i class="el-icon-question"></i>
|
|
|
|
|
+ </el-tooltip>
|
|
|
|
|
+ <div class="action-buttons">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ icon="el-icon-plus"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ @click="addRule(index)"
|
|
|
|
|
+ class="add-btn"
|
|
|
|
|
+ >
|
|
|
|
|
+ 新增
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ icon="el-icon-delete"
|
|
|
|
|
+ size="mini"
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ @click="deleteRule(index)"
|
|
|
|
|
+ :disabled="form.randomRedPacketRulesArr.length <= 1"
|
|
|
|
|
+ class="delete-btn"
|
|
|
|
|
+ >
|
|
|
|
|
+ 删除
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="是否关联商品">
|
|
|
|
|
+ <el-radio v-model="form.isProduct" :label=0>否</el-radio>
|
|
|
|
|
+ <el-radio v-model="form.isProduct" :label=1>是</el-radio>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="是否先导课" prop="isFirst">
|
|
|
|
|
+ <el-radio-group v-model="form.isFirst">
|
|
|
|
|
+ <el-radio :label="1">是</el-radio>
|
|
|
|
|
+ <el-radio :label="0">否</el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="是否启用倍速" prop="isSpeed">
|
|
|
|
|
+ <el-radio-group v-model="form.isSpeed">
|
|
|
|
|
+ <el-radio :label="1">是</el-radio>
|
|
|
|
|
+ <el-radio :label="0">否</el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="是否上架" prop="isOnPut">
|
|
|
|
|
+ <el-radio-group v-model="form.isOnPut">
|
|
|
|
|
+ <el-radio :label="0">上架</el-radio>
|
|
|
|
|
+ <el-radio :label="1">下架</el-radio>
|
|
|
|
|
+ </el-radio-group>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="商品选择" v-if="form.isProduct === 1">
|
|
|
|
|
+ <el-button size="small" type="primary" @click="chooseCourseProduct">选取商品</el-button>
|
|
|
|
|
+ <el-table border width="100%" style="margin-top:5px;" :data="form.courseProducts">
|
|
|
|
|
+ <el-table-column label="商品名称" align="center" prop="productName"/>
|
|
|
|
|
+ <el-table-column label="产品条码" align="center" prop="barCode"/>
|
|
|
|
|
+ <el-table-column label="商品价格" align="center" prop="price"/>
|
|
|
|
|
+ <el-table-column label="库存" align="center" prop="stock"/>
|
|
|
|
|
+ <el-table-column label="操作" align="center" width="100px" fixed="right">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-button size="mini" type="text" icon="el-icon-delete"
|
|
|
|
|
+ @click="handleCourseProductDelete(scope.row)">删除
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-row>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item v-if="form.isProduct === 1" label="商品售卖时间" prop="listingStartTime">
|
|
|
|
|
+ <el-input-number v-model="form.listingStartTime" :min="0" label="商品售卖时间"></el-input-number>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item v-if="form.isProduct === 1" label="结束售卖时间" prop="listingStartTime">
|
|
|
|
|
+ <el-input-number v-model="form.listingEndTime" :min="0" label="结束售卖时间"></el-input-number>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
|
|
+ <el-button type="primary" @click="submitForm">确 定</el-button>
|
|
|
|
|
+ <el-button @click="cancel">取 消</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+ <el-dialog :title="title" :visible.sync="updateBatchData.open" width="1000px" append-to-body>
|
|
|
|
|
+ <el-form ref="form" :model="updateBatchData.form" label-width="110px">
|
|
|
|
|
+ <el-form-item label="看课时间" prop="timeRange">
|
|
|
|
|
+ <el-time-picker is-range v-model="updateBatchData.form.timeRange" range-separator="至"
|
|
|
|
|
+ start-placeholder="开始时间"
|
|
|
|
|
+ value-format="HH:mm:ss" end-placeholder="结束时间" placeholder="选择时间范围">
|
|
|
|
|
+ </el-time-picker>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="领取红包时间" prop="lastJoinTime">
|
|
|
|
|
+ <el-time-picker v-model="updateBatchData.form.lastJoinTime" :selectableRange="updateBatchData.form.timeRange"
|
|
|
|
|
+ value-format="HH:mm:ss" placeholder="选择时间范围">
|
|
|
|
|
+ </el-time-picker>
|
|
|
|
|
+ <p style="color: red;margin: 0;font-size: 12px">超过领取红包时间,只允许看课,不允许领取红包</p>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
|
|
+ <el-button type="primary" @click="updateBatch">确 定</el-button>
|
|
|
|
|
+ <el-button @click="updateBatchData.open = false">取 消</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+ <el-dialog :title="questionBank.title" :visible.sync="questionBank.open" width="1000px" append-to-body>
|
|
|
|
|
+ <question-bank ref="questionBank" @questionBankResult="questionBankResult"></question-bank>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+ <el-dialog :title="courseProduct.title" :visible.sync="courseProduct.open" width="1000px" append-to-body>
|
|
|
|
|
+ <course-product ref="courseProduct" @courseProductResult="courseProductResult"></course-product>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+ <el-dialog title="视频库选择" :visible.sync="addBatchData.open" width="900px" append-to-body>
|
|
|
|
|
+ <!-- 搜索条件 -->
|
|
|
|
|
+ <el-form :inline="true" :model="addBatchData.queryParams" class="library-search">
|
|
|
|
|
+ <el-form-item label="素材名称">
|
|
|
|
|
+ <el-input v-model="addBatchData.queryParams.resourceName" placeholder="请输入素材名称" clearable size="small"
|
|
|
|
|
+ @keyup.enter.native="resourceList"/>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="类型">
|
|
|
|
|
+ <el-select v-model="addBatchData.queryParams.typeId" @change="changeCateType" placeholder="请选择素材类型"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ size="small">
|
|
|
|
|
+ <el-option v-for="item in addBatchData.typeOptions" :key="item.dictValue" :label="item.dictLabel"
|
|
|
|
|
+ :value="item.dictValue"/>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="子类型">
|
|
|
|
|
+ <el-select v-model="addBatchData.queryParams.typeSubId" placeholder="请选择素材子类型" clearable size="small">
|
|
|
|
|
+ <el-option v-for="item in addBatchData.typeSubOptions" :key="item.dictValue" :label="item.dictLabel"
|
|
|
|
|
+ :value="item.dictValue"/>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button type="primary" icon="el-icon-search" size="mini" @click="resourceList">搜索</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 视频列表 -->
|
|
|
|
|
+ <el-table v-loading="addBatchData.loading" :data="addBatchData.list"
|
|
|
|
|
+ @selection-change="handVideoleSelectionChange" height="400px">
|
|
|
|
|
+ <el-table-column type="selection" width="55" align="center"/>
|
|
|
|
|
+ <el-table-column label="素材名称" align="center" prop="resourceName"/>
|
|
|
|
|
+ <el-table-column label="文件名称" align="center" prop="fileName"/>
|
|
|
|
|
+ <el-table-column label="排序" align="center" prop="sort"/>
|
|
|
|
|
+ <el-table-column label="缩略图" align="center">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-popover placement="right" title="" trigger="hover">
|
|
|
|
|
+ <img alt="" slot="reference" :src="scope.row.thumbnail" style="width: 80px; height: 50px"/>
|
|
|
|
|
+ <img alt="" :src="scope.row.thumbnail" style="max-width: 150px;"/>
|
|
|
|
|
+ </el-popover>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="视频时长" align="center">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <span>{{ formatDuration(scope.row.duration) }}</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 分页 -->
|
|
|
|
|
+ <pagination v-show="addBatchData.total > 0" :total="addBatchData.total"
|
|
|
|
|
+ :page.sync="addBatchData.queryParams.pageNum" :limit.sync="addBatchData.queryParams.pageSize"
|
|
|
|
|
+ @pagination="resourceList"/>
|
|
|
|
|
+
|
|
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
|
|
+ <el-button type="primary" @click="batchVideoSave">确 定</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+ <el-dialog title="章节红包" :visible.sync="redData.open" width="900px" append-to-body>
|
|
|
|
|
+ <el-table border v-loading="redData.loading" :data="redData.list" height="600px">
|
|
|
|
|
+ <el-table-column label="小节名称" align="center" show-overflow-tooltip prop="title"/>
|
|
|
|
|
+ <el-table-column label="视频文件名称" align="center" show-overflow-tooltip prop="fileName">
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="视频时长" align="center" prop="duration">
|
|
|
|
|
+ <template slot-scope="{ row }">
|
|
|
|
|
+ {{ formatDuration(row.duration) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="红包金额" align="center" prop="redPacketMoney">
|
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
|
+ <el-input class="el-input" v-model="scope.row.redPacketMoney"/>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="排序" align="center" prop="courseSort"/>
|
|
|
|
|
+ <el-table-column label="上传时间" align="center" prop="createTime"/>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
|
|
+ <el-button type="primary" @click="batchRedSave">确 定</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+ <el-dialog :title="commentDialog.title" :visible.sync="commentDialog.open" width="1000px" append-to-body
|
|
|
|
|
+ :close-on-click-modal="false">
|
|
|
|
|
+ <course-watch-comment ref="courseWatchComment" :courseId="commentDialog.courseId" :videoId="commentDialog.videoId"
|
|
|
|
|
+ v-if="commentDialog.open">
|
|
|
|
|
+ </course-watch-comment>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ <el-dialog title="修改课节排序" :visible.sync="openVideoSort" style="width: 1600px;" append-to-body>
|
|
|
|
|
+ <draggable v-model="userCourseVideoSortList" @end="onDragEndDay" style="padding: 10px">
|
|
|
|
|
+ <el-button style="margin: 8px 4px;" v-for="(item, index) in userCourseVideoSortList"
|
|
|
|
|
+ :class="item.newCourseSort != item.courseSort ? 'red':''">第{{
|
|
|
|
|
+ item.newCourseSort
|
|
|
|
|
+ }}序(原排序第{{ item.courseSort }})
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </draggable>
|
|
|
|
|
+ <div style="float: right;margin-top: -20px">
|
|
|
|
|
+ <el-button type="primary" @click="saveSorts">保存</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 批量修改封面 -->
|
|
|
|
|
+ <el-dialog :title="batchEditCoverDialog.title" :visible.sync="batchEditCoverDialog.visible" width="500px" append-to-body>
|
|
|
|
|
+ <el-form ref="batchEditCoverDialogForm"
|
|
|
|
|
+ :model="batchEditCoverDialog.form"
|
|
|
|
|
+ :rules="batchEditCoverDialog.rules"
|
|
|
|
|
+ v-loading="batchEditCoverDialog.uploadLoading">
|
|
|
|
|
+ <el-form-item label="视频封面" prop="thumbnail">
|
|
|
|
|
+ <el-upload v-model="batchEditCoverDialog.form.thumbnail"
|
|
|
|
|
+ class="avatar-uploader"
|
|
|
|
|
+ :action="uploadUrl"
|
|
|
|
|
+ :show-file-list="false"
|
|
|
|
|
+ :on-success="handleCoverSuccess"
|
|
|
|
|
+ :before-upload="beforeAvatarUpload">
|
|
|
|
|
+ <img v-if="batchEditCoverDialog.form.thumbnail" :src="batchEditCoverDialog.form.thumbnail" class="avatar" width="300px">
|
|
|
|
|
+ <i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
|
|
+ </el-upload>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
|
|
+ <el-button type="primary" @click="submitEditCoverForm">确 定</el-button>
|
|
|
|
|
+ <el-button @click="cancelEditCoverForm">取 消</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script>
|
|
|
|
|
+import {
|
|
|
|
|
+ addUserCourseVideo,
|
|
|
|
|
+ batchSaveVideo,
|
|
|
|
|
+ batchUpdateRed,
|
|
|
|
|
+ delUserCourseVideo,
|
|
|
|
|
+ getSort,
|
|
|
|
|
+ getUserCourseVideo,
|
|
|
|
|
+ getVideoListByCourseId,
|
|
|
|
|
+ getVideoListByCourseIdAll,
|
|
|
|
|
+ sortCourseVideo,
|
|
|
|
|
+ updates,
|
|
|
|
|
+ updateUserCourseVideo,
|
|
|
|
|
+ syncTemplate, batchDownUserCourseVideo, batchEditCover, batchUpUserCourseVideo
|
|
|
|
|
+} from '@/api/course/userCourseVideo'
|
|
|
|
|
+// import {syncTemplate} from '@/api/course/userCourse'
|
|
|
|
|
+import QuestionBank from "@/views/course/courseQuestionBank/QuestionBank.vue";
|
|
|
|
|
+import CourseProduct from "@/views/course/fsCourseProduct/CourseProductZM.vue";
|
|
|
|
|
+import VideoUpload from "@/components/VideoUpload/index.vue";
|
|
|
|
|
+import {listVideoResource} from '@/api/course/videoResource';
|
|
|
|
|
+import {getByIds} from '@/api/course/courseQuestionBank'
|
|
|
|
|
+import CourseWatchComment from "./courseWatchComment.vue";
|
|
|
|
|
+import {getCateListByPid, getCatePidList} from '@/api/course/userCourseCategory'
|
|
|
|
|
+import draggable from 'vuedraggable'
|
|
|
|
|
+import { getConfigByKey } from '@/api/system/config'
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ name: "userCourseCatalog",
|
|
|
|
|
+ components: {VideoUpload, QuestionBank, CourseWatchComment, CourseProduct, draggable},
|
|
|
|
|
+ watch:{
|
|
|
|
|
+ // 深度监听 rules 数组的变化,以更新总权重
|
|
|
|
|
+ "form.randomRedPacketRulesArr": {
|
|
|
|
|
+ handler(val) {
|
|
|
|
|
+ // this.calculateTotalWeight();
|
|
|
|
|
+ this.validateRules();
|
|
|
|
|
+ },
|
|
|
|
|
+ deep: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ data() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ duration: null,
|
|
|
|
|
+ packageList: [],
|
|
|
|
|
+ //课题
|
|
|
|
|
+ package: {
|
|
|
|
|
+ title: '',
|
|
|
|
|
+ open: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ //课题
|
|
|
|
|
+ questionBank: {
|
|
|
|
|
+ title: '',
|
|
|
|
|
+ open: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ //拍商品
|
|
|
|
|
+ courseProduct: {
|
|
|
|
|
+ title: '',
|
|
|
|
|
+ open: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ isPrivate: null,
|
|
|
|
|
+ videoUrl: "",
|
|
|
|
|
+ uploadTypeOptions: [
|
|
|
|
|
+ {dictLabel: "线路一", dictValue: 2},
|
|
|
|
|
+ {dictLabel: "线路二", dictValue: 3},
|
|
|
|
|
+ ],
|
|
|
|
|
+ uploadLoading: false,
|
|
|
|
|
+ courseId: null,
|
|
|
|
|
+ videoName: '',
|
|
|
|
|
+ title: "",
|
|
|
|
|
+ // 是否显示弹出层
|
|
|
|
|
+ open: false,
|
|
|
|
|
+ uploadUrl: process.env.VUE_APP_BASE_API + "/common/uploadOSS",
|
|
|
|
|
+ baseUrl: process.env.VUE_APP_BASE_API,
|
|
|
|
|
+ typeOptions: [],
|
|
|
|
|
+ files: [],
|
|
|
|
|
+ fileList: [],
|
|
|
|
|
+ // 上传成功后的地址
|
|
|
|
|
+ videoURL: '',
|
|
|
|
|
+ // 进度条百分比
|
|
|
|
|
+ progress: 0,
|
|
|
|
|
+ // 上传视频获取成功后拿到的fileID【备用】
|
|
|
|
|
+ fileId: '',
|
|
|
|
|
+ courseName: null,
|
|
|
|
|
+ userCourseVideoList: [],
|
|
|
|
|
+ userCourseVideoSortList: [],
|
|
|
|
|
+ total: 0,
|
|
|
|
|
+ redData: {
|
|
|
|
|
+ queryParams: {
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 99999,
|
|
|
|
|
+ courseId: null,
|
|
|
|
|
+ },
|
|
|
|
|
+ list: [],
|
|
|
|
|
+ open: false,
|
|
|
|
|
+ loading: true,
|
|
|
|
|
+ form: {}
|
|
|
|
|
+ },
|
|
|
|
|
+ queryParams: {
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ courseId: null,
|
|
|
|
|
+ videoId: null,
|
|
|
|
|
+ title: null
|
|
|
|
|
+ },
|
|
|
|
|
+ addBatchData: {
|
|
|
|
|
+ open: false,
|
|
|
|
|
+ loading: true,
|
|
|
|
|
+ form: {},
|
|
|
|
|
+ select: [], // 按用户选择顺序存储视频ID
|
|
|
|
|
+ total: 0,
|
|
|
|
|
+ queryParams: {
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ resourceName: null,
|
|
|
|
|
+ typeId: null,
|
|
|
|
|
+ typeSubId: null
|
|
|
|
|
+ },
|
|
|
|
|
+ typeOptions: [],
|
|
|
|
|
+ typeSubOptions: []
|
|
|
|
|
+ },
|
|
|
|
|
+ // 显示搜索条件
|
|
|
|
|
+ showSearch: true,
|
|
|
|
|
+ // 遮罩层
|
|
|
|
|
+ loading: true,
|
|
|
|
|
+ // 导出遮罩层
|
|
|
|
|
+ exportLoading: false,
|
|
|
|
|
+ // 选中数组
|
|
|
|
|
+ ids: [],
|
|
|
|
|
+ // 非单个禁用
|
|
|
|
|
+ single: true,
|
|
|
|
|
+ // 非多个禁用
|
|
|
|
|
+ multiple: true,
|
|
|
|
|
+ loading3: false,
|
|
|
|
|
+ openVideoSort: false,
|
|
|
|
|
+ // 表单参数
|
|
|
|
|
+ form: {
|
|
|
|
|
+ isOnPut: 0,
|
|
|
|
|
+ courseProducts: [],
|
|
|
|
|
+ randomRedPacketRules:null,
|
|
|
|
|
+ randomRedPacketRulesArr:[
|
|
|
|
|
+ {
|
|
|
|
|
+ minAmount: 0.01,
|
|
|
|
|
+ maxAmount: 0.01,
|
|
|
|
|
+ weight: 100,
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ updateBatchData: {
|
|
|
|
|
+ open: false,
|
|
|
|
|
+ form: {}
|
|
|
|
|
+ },
|
|
|
|
|
+ // 表单校验
|
|
|
|
|
+ rules: {
|
|
|
|
|
+ title: [
|
|
|
|
|
+ {required: true, message: "小节名称不能为空", trigger: "change"}
|
|
|
|
|
+ ],
|
|
|
|
|
+ courseSort: [
|
|
|
|
|
+ {required: true, message: "排序不能为空", trigger: "change"}
|
|
|
|
|
+ ],
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ // 评论弹窗数据
|
|
|
|
|
+ commentDialog: {
|
|
|
|
|
+ open: false,
|
|
|
|
|
+ courseId: null,
|
|
|
|
|
+ videoId: null,
|
|
|
|
|
+ title: ""
|
|
|
|
|
+ },
|
|
|
|
|
+ enableRandomRedPacket:false,
|
|
|
|
|
+ // 批量修改封面
|
|
|
|
|
+ batchEditCoverDialog: {
|
|
|
|
|
+ title: '修改视频封面',
|
|
|
|
|
+ visible: false,
|
|
|
|
|
+ uploadLoading: false,
|
|
|
|
|
+ form: {
|
|
|
|
|
+ thumbnail: null,
|
|
|
|
|
+ },
|
|
|
|
|
+ rules: {
|
|
|
|
|
+ thumbnail: [
|
|
|
|
|
+ {required: true, message: "视频封面不能为空", trigger: "change"}
|
|
|
|
|
+ ],
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ created() {
|
|
|
|
|
+ this.getDicts("sys_course_temp_type").then(response => {
|
|
|
|
|
+ this.typeOptions = response.data;
|
|
|
|
|
+ });
|
|
|
|
|
+ getConfigByKey('randomRedpacket:config').then(res=>{
|
|
|
|
|
+ let configData = res.data;
|
|
|
|
|
+ if(!!configData && !!configData.configValue){
|
|
|
|
|
+ let configValue = JSON.parse(configData.configValue);
|
|
|
|
|
+ if(!!configValue.enableRandomRedpacket){
|
|
|
|
|
+ this.enableRandomRedPacket = configValue.enableRandomRedpacket;
|
|
|
|
|
+ console.log("this.enableRandomRedPacket ::" + this.enableRandomRedPacket)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(res=>{
|
|
|
|
|
+
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ methods: {
|
|
|
|
|
+ getPickerOptions() {
|
|
|
|
|
+ const durationInMinutes = Math.floor(this.form.duration / 60); // 将秒转换为分钟
|
|
|
|
|
+ const endHour = Math.floor(durationInMinutes / 60); // 起始小时
|
|
|
|
|
+ const endMinute = durationInMinutes % 60; // 起始分钟
|
|
|
|
|
+ return {
|
|
|
|
|
+ start: "00:00", // 固定开始时间
|
|
|
|
|
+ step: "00:01", // 时间间隔
|
|
|
|
|
+ end: `${endHour.toString().padStart(2, "0")}:${endMinute
|
|
|
|
|
+ .toString()
|
|
|
|
|
+ .padStart(2, "0")}`, // 动态结束时间
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 处理时间选择框值变化
|
|
|
|
|
+ handleTimeChange(index, row) {
|
|
|
|
|
+ // 确保 packageList 中的数据被正确更新
|
|
|
|
|
+ this.$set(this.packageList, index, row);
|
|
|
|
|
+ // 同步更新 form.packageJson 字段
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ // 确保每个疗法包都有 duration 字段
|
|
|
|
|
+ this.packageList.forEach(item => {
|
|
|
|
|
+ if (item.duration === undefined || item.duration === null) {
|
|
|
|
|
+ item.duration = ''; // 空值应初始化为空字符串而不是null,避免显示"null"
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ this.form.packageJson = JSON.stringify(this.packageList);
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ handlePackageDelete(row) {
|
|
|
|
|
+ this.packageList.splice(this.packageList.findIndex(item => item.packageId === row.packageId), 1)
|
|
|
|
|
+ },
|
|
|
|
|
+ choosePackage() {
|
|
|
|
|
+ this.package.open = true;
|
|
|
|
|
+ this.package.title = '疗法选择';
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 选择课题
|
|
|
|
|
+ */
|
|
|
|
|
+ chooseQuestionBank() {
|
|
|
|
|
+ this.questionBank.open = true;
|
|
|
|
|
+ this.questionBank.title = '课题选择';
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 选择拍商品
|
|
|
|
|
+ */
|
|
|
|
|
+ chooseCourseProduct() {
|
|
|
|
|
+ this.courseProduct.open = true;
|
|
|
|
|
+ this.courseProduct.title = '拍商品选择';
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //选择疗法
|
|
|
|
|
+ selectPackage(row) {
|
|
|
|
|
+ const drug = {};
|
|
|
|
|
+ for (var i = 0; i < this.packageList.length; i++) {
|
|
|
|
|
+ if (this.packageList[i].packageId == row.packageId) {
|
|
|
|
|
+ this.$message.warning("疗法已存在!")
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ drug.packageId = row.packageId;
|
|
|
|
|
+ drug.packageName = row.packageName;
|
|
|
|
|
+ drug.secondName = row.secondName;
|
|
|
|
|
+ drug.totalPrice = row.totalPrice;
|
|
|
|
|
+ drug.imgUrl = row.imgUrl;
|
|
|
|
|
+ this.packageList.push(drug);
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '添加成功',
|
|
|
|
|
+ type: 'success'
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ courseProductResult(val) {
|
|
|
|
|
+ this.form.courseProducts = this.form.courseProducts || [];
|
|
|
|
|
+
|
|
|
|
|
+ // 检查商品是否已存在
|
|
|
|
|
+ const exists = this.form.courseProducts.some(item => item.productId === val.productId);
|
|
|
|
|
+ if (exists) {
|
|
|
|
|
+ this.$message.error("当前商品已选择");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 添加商品到列表
|
|
|
|
|
+ this.form.courseProducts.push(val);
|
|
|
|
|
+ this.$message.success("添加成功");
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ //选择结果
|
|
|
|
|
+ questionBankResult(val) {
|
|
|
|
|
+
|
|
|
|
|
+ // 确保 questionBankList 是数组
|
|
|
|
|
+ this.form.questionBankList = this.form.questionBankList || [];
|
|
|
|
|
+
|
|
|
|
|
+ for (var i = 0; i < this.form.questionBankList.length; i++) {
|
|
|
|
|
+ if (this.form.questionBankList[i].id == val.id) {
|
|
|
|
|
+ return this.$message.error("当前课题已选择")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.form.questionBankList.push(val);
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '添加成功',
|
|
|
|
|
+ type: 'success'
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ //删除课题
|
|
|
|
|
+ handleQuestionBankDelete(row) {
|
|
|
|
|
+ this.form.questionBankList.splice(this.form.questionBankList.findIndex(item => item.id === row.id), 1)
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ //删除商品
|
|
|
|
|
+ handleCourseProductDelete(row) {
|
|
|
|
|
+ const index = this.form.courseProducts.findIndex(item => item.id === row.id);
|
|
|
|
|
+ if (index > -1) {
|
|
|
|
|
+ this.form.courseProducts.splice(index, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ handleVideoChange() {
|
|
|
|
|
+ if (this.form.uploadType == 1) {
|
|
|
|
|
+ this.videoUrl = this.form.lineOne;
|
|
|
|
|
+ } else if (this.form.uploadType == 2) {
|
|
|
|
|
+ this.videoUrl = this.form.lineTwo;
|
|
|
|
|
+ } else if (this.form.uploadType == 3) {
|
|
|
|
|
+ this.videoUrl = this.form.lineThree;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ // 视频库课题
|
|
|
|
|
+ handleSelectProjects(projectIds) {
|
|
|
|
|
+ this.form.questionBankList = []
|
|
|
|
|
+ if (!projectIds || projectIds.length === 0 || this.isPrivate === 0) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const params = {ids: projectIds}
|
|
|
|
|
+ getByIds(params).then(response => {
|
|
|
|
|
+ if (response.code === 200) {
|
|
|
|
|
+ response.data.forEach(item => {
|
|
|
|
|
+ let isExist = this.form.questionBankList.some(q => q.id === item.id)
|
|
|
|
|
+ if (!isExist) {
|
|
|
|
|
+ this.form.questionBankList.push(item)
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ handleVideoDuration(duration) {
|
|
|
|
|
+ this.form.duration = duration;
|
|
|
|
|
+ },
|
|
|
|
|
+ formatDuration(seconds) {
|
|
|
|
|
+ if (seconds === null || seconds === undefined) {
|
|
|
|
|
+ return '未上传视频';
|
|
|
|
|
+ }
|
|
|
|
|
+ const hours = Math.floor(seconds / 3600);
|
|
|
|
|
+ const minutes = Math.floor((seconds % 3600) / 60);
|
|
|
|
|
+ const remainingSeconds = seconds % 60;
|
|
|
|
|
+
|
|
|
|
|
+ const formattedHours = hours > 0 ? hours.toString() + ':' : '';
|
|
|
|
|
+ const formattedMinutes = minutes.toString().padStart(2, '0');
|
|
|
|
|
+ const formattedSeconds = remainingSeconds.toString().padStart(2, '0');
|
|
|
|
|
+
|
|
|
|
|
+ return `${formattedHours}${formattedMinutes}:${formattedSeconds}`;
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ handleAvatarSuccess(res, file) {
|
|
|
|
|
+ if (res.code == 200) {
|
|
|
|
|
+ this.form.thumbnail = res.url;
|
|
|
|
|
+ this.$forceUpdate()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.msgError(res.msg);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ beforeAvatarUpload(file) {
|
|
|
|
|
+ const isLt1M = file.size / 1024 / 1024 < 5;
|
|
|
|
|
+ if (!isLt1M) {
|
|
|
|
|
+ this.$message.error('上传图片大小不能超过 5MB!');
|
|
|
|
|
+ }
|
|
|
|
|
+ return isLt1M;
|
|
|
|
|
+ },
|
|
|
|
|
+ getDetails(courseId, courseName, isPrivate) {
|
|
|
|
|
+ this.isPrivate = isPrivate
|
|
|
|
|
+ this.courseName = courseName
|
|
|
|
|
+ this.courseId = courseId;
|
|
|
|
|
+ this.queryParams.courseId = courseId;
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ },
|
|
|
|
|
+ getList() {
|
|
|
|
|
+ this.loading = true;
|
|
|
|
|
+ getVideoListByCourseId(this.queryParams).then(response => {
|
|
|
|
|
+ this.userCourseVideoList = response.rows;
|
|
|
|
|
+ this.total = response.total;
|
|
|
|
|
+ this.loading = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ // 取消按钮
|
|
|
|
|
+ cancel() {
|
|
|
|
|
+ this.open = false;
|
|
|
|
|
+ this.reset();
|
|
|
|
|
+ },
|
|
|
|
|
+ // 表单重置
|
|
|
|
|
+ reset() {
|
|
|
|
|
+ this.form = {
|
|
|
|
|
+ videoId: null,
|
|
|
|
|
+ title: null,
|
|
|
|
|
+ description: null,
|
|
|
|
|
+ url: null,
|
|
|
|
|
+ thumbnail: null,
|
|
|
|
|
+ duration: null,
|
|
|
|
|
+ createTime: null,
|
|
|
|
|
+ uploadType: null,
|
|
|
|
|
+ lineOne: null,
|
|
|
|
|
+ lineTwo: null,
|
|
|
|
|
+ lineThree: null,
|
|
|
|
|
+ fileName: null,
|
|
|
|
|
+ userId: null,
|
|
|
|
|
+ cateId: null,
|
|
|
|
|
+ courseId: null,
|
|
|
|
|
+ likes: null,
|
|
|
|
|
+ views: null,
|
|
|
|
|
+ comments: null,
|
|
|
|
|
+ status: 0,
|
|
|
|
|
+ courseSort: 1,
|
|
|
|
|
+ isHot: null,
|
|
|
|
|
+ isShow: null,
|
|
|
|
|
+ isAudit: null,
|
|
|
|
|
+ auditBy: null,
|
|
|
|
|
+ auditTime: null,
|
|
|
|
|
+ updateTime: null,
|
|
|
|
|
+ source: null,
|
|
|
|
|
+ isDel: null,
|
|
|
|
|
+ shares: null,
|
|
|
|
|
+ tags: null,
|
|
|
|
|
+ productId: null,
|
|
|
|
|
+ id: null,
|
|
|
|
|
+ packageJson: null,
|
|
|
|
|
+ questionBankId: null,
|
|
|
|
|
+ questionBankList: [],
|
|
|
|
|
+ redPacketMoney: 0,
|
|
|
|
|
+ isTranscode: 0,
|
|
|
|
|
+ transcodeFileKey: null,
|
|
|
|
|
+ isProduct: 0,
|
|
|
|
|
+ isFirst: 0,
|
|
|
|
|
+ isSpeed: 0,
|
|
|
|
|
+ isOnPut: 0,
|
|
|
|
|
+ listingStartTime: null,
|
|
|
|
|
+ listingEndTime: null,
|
|
|
|
|
+ showProduct: 1, // 默认无商品
|
|
|
|
|
+ randomRedPacketRules:null,
|
|
|
|
|
+ randomRedPacketRulesArr:[
|
|
|
|
|
+ {
|
|
|
|
|
+ minAmount: 0.01,
|
|
|
|
|
+ maxAmount: 0.01,
|
|
|
|
|
+ weight: 100,
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ };
|
|
|
|
|
+ this.videoURL = '';
|
|
|
|
|
+ this.progress = 0;
|
|
|
|
|
+ this.resetForm("form");
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 搜索按钮操作 */
|
|
|
|
|
+ handleQuery() {
|
|
|
|
|
+ this.queryParams.pageNum = 1;
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 重置按钮操作 */
|
|
|
|
|
+ resetQuery() {
|
|
|
|
|
+ this.resetForm("queryForm");
|
|
|
|
|
+ this.handleQuery();
|
|
|
|
|
+ },
|
|
|
|
|
+ // 多选框选中数据
|
|
|
|
|
+ handleSelectionChange(selection) {
|
|
|
|
|
+ this.ids = selection.map(item => item.videoId)
|
|
|
|
|
+ this.single = selection.length !== 1
|
|
|
|
|
+ this.multiple = !selection.length
|
|
|
|
|
+ },
|
|
|
|
|
+ // 视频库多选框选中数据(按用户点击顺序记录)
|
|
|
|
|
+ handVideoleSelectionChange(selection) {
|
|
|
|
|
+ // 提取当前选中的所有ID
|
|
|
|
|
+ const selectedIds = selection.map(item => item.id);
|
|
|
|
|
+ // 处理新增选中项:保留用户点击顺序
|
|
|
|
|
+ selectedIds.forEach(id => {
|
|
|
|
|
+ if (!this.addBatchData.select.includes(id)) {
|
|
|
|
|
+ this.addBatchData.select.push(id);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ // 处理取消选中项:移除已取消的ID
|
|
|
|
|
+ this.addBatchData.select = this.addBatchData.select.filter(id => selectedIds.includes(id));
|
|
|
|
|
+ },
|
|
|
|
|
+ handleAdd() {
|
|
|
|
|
+ this.reset();
|
|
|
|
|
+ this.form.courseId = this.courseId;
|
|
|
|
|
+ this.open = true;
|
|
|
|
|
+ this.title = "添加课堂视频";
|
|
|
|
|
+ this.videoUrl = '';
|
|
|
|
|
+ this.packageList = [];
|
|
|
|
|
+ getSort(this.courseId).then(response => {
|
|
|
|
|
+ this.form.courseSort = Number(response.data);
|
|
|
|
|
+ })
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.$refs.videoUpload.resetUpload();
|
|
|
|
|
+ }, 500);
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 修改按钮操作 */
|
|
|
|
|
+ handleUpdate(row) {
|
|
|
|
|
+ this.reset();
|
|
|
|
|
+ this.form.isOnPut = row.isOnPut;
|
|
|
|
|
+ this.packageList = [];
|
|
|
|
|
+ const videoId = row.videoId || this.ids;
|
|
|
|
|
+ getUserCourseVideo(videoId).then(response => {
|
|
|
|
|
+ console.log(response);
|
|
|
|
|
+ this.form = response.data;
|
|
|
|
|
+ this.$set(this.form, 'isOnPut', response.data.isOnPut !== undefined ? response.data.isOnPut : 0);
|
|
|
|
|
+
|
|
|
|
|
+ if (this.form.randomRedPacketRules) {
|
|
|
|
|
+ this.$set(this.form, 'randomRedPacketRulesArr', JSON.parse(this.form.randomRedPacketRules));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 处理初始值
|
|
|
|
|
+ this.form.randomRedPacketRulesArr = [{
|
|
|
|
|
+ minAmount: 0.01,
|
|
|
|
|
+ maxAmount: 0.01,
|
|
|
|
|
+ weight: 100,
|
|
|
|
|
+ }];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (response.data.videoUrl != null && response.data.videoUrl !== '') {
|
|
|
|
|
+ this.videoUrl = response.data.videoUrl;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.form.packageJson != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 检查 packageJson 是否包含商品数据,如果是则解析为 courseProducts
|
|
|
|
|
+ const parsedData = JSON.parse(this.form.packageJson);
|
|
|
|
|
+ if (Array.isArray(parsedData) && parsedData.length > 0 && parsedData[0].hasOwnProperty('productName')) {
|
|
|
|
|
+ // 如果是商品数据格式,则设置到 courseProducts
|
|
|
|
|
+ this.form.courseProducts = parsedData;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 否则按照原有逻辑设置到 packageList
|
|
|
|
|
+ this.packageList = parsedData;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // 如果解析失败,按原来的处理方式
|
|
|
|
|
+ this.packageList = JSON.parse(this.form.packageJson);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (response.data.viewStartTime != null && response.data.viewEndTime != null) {
|
|
|
|
|
+ this.form.timeRange = [response.data.viewStartTime, response.data.viewEndTime];
|
|
|
|
|
+ }
|
|
|
|
|
+ // 根据商品数量设置是否关联商品状态
|
|
|
|
|
+ if (this.form.courseProducts && this.form.courseProducts.length > 0) {
|
|
|
|
|
+ this.form.isProduct = 1; // 有关联商品时设为1(是)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.form.isProduct = 0; // 无关联商品时设为0(否)
|
|
|
|
|
+ }
|
|
|
|
|
+ // 设置商品选择状态
|
|
|
|
|
+ if (this.form.id) {
|
|
|
|
|
+ this.form.showProduct = 0; // 有商品时设为0
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.form.showProduct = 1; // 无商品时设为1
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.$refs.videoUpload.resetUpload();
|
|
|
|
|
+ }, 500);
|
|
|
|
|
+ this.open = true;
|
|
|
|
|
+ this.title = "修改课堂视频";
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 提交按钮 */
|
|
|
|
|
+ submitForm() {
|
|
|
|
|
+ this.$refs["form"].validate(valid => {
|
|
|
|
|
+ if (valid) {
|
|
|
|
|
+ this.form.videoUrl = this.videoUrl;
|
|
|
|
|
+ if (this.form.videoUrl == null || this.form.videoUrl === '') {
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '请上传视频!',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ });
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.form.timeRange && this.form.timeRange.length === 2) {
|
|
|
|
|
+ this.form.viewStartTime = this.form.timeRange[0];
|
|
|
|
|
+ this.form.viewEndTime = this.form.timeRange[1];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.form.duration == null) {
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '未识别到视频时长请稍等。。。',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ });
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.form.isProduct != null && this.form.isProduct == 1 && (this.form.courseProducts == null || this.form.courseProducts.length < 1)) {
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '请选择关联商品',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ });
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.form.questionBankList !== null) {
|
|
|
|
|
+ this.form.questionBankId = this.form.questionBankList.map(item => item.id).join(',');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理商品选择逻辑
|
|
|
|
|
+ if (this.form.courseProducts && this.form.courseProducts.length > 0) {
|
|
|
|
|
+ this.form.id = this.form.courseProducts.map(item => item.id).join(',');
|
|
|
|
|
+ this.form.showProduct = 0; // 有商品选择时设为0
|
|
|
|
|
+
|
|
|
|
|
+ // 将商品数据序列化为JSON字符串传递给packageJson
|
|
|
|
|
+ this.form.packageJson = JSON.stringify(this.form.courseProducts);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.form.id = null;
|
|
|
|
|
+ this.form.showProduct = 1; // 无商品选择时设为1
|
|
|
|
|
+ this.form.packageJson = "[]"; // 无商品时传递空数组
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.form.randomRedPacketRulesArr) {
|
|
|
|
|
+ let rulesJson = JSON.stringify(this.form.randomRedPacketRulesArr);
|
|
|
|
|
+ this.form.randomRedPacketRules = rulesJson;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (this.form.videoId != null) {
|
|
|
|
|
+ updateUserCourseVideo(this.form).then(response => {
|
|
|
|
|
+ this.msgSuccess("修改成功");
|
|
|
|
|
+ this.open = false;
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ addUserCourseVideo(this.form).then(response => {
|
|
|
|
|
+ this.msgSuccess("新增成功");
|
|
|
|
|
+ this.open = false;
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ openUpdates() {
|
|
|
|
|
+ this.updateBatchData.form = {};
|
|
|
|
|
+ this.updateBatchData.open = true;
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 提交按钮 */
|
|
|
|
|
+ updateBatch() {
|
|
|
|
|
+ this.updateBatchData.form.ids = this.ids;
|
|
|
|
|
+ if (this.updateBatchData.form.timeRange != null && this.updateBatchData.form.timeRange.length === 2) {
|
|
|
|
|
+ this.updateBatchData.form.viewStartTime = this.updateBatchData.form.timeRange[0];
|
|
|
|
|
+ this.updateBatchData.form.viewEndTime = this.updateBatchData.form.timeRange[1];
|
|
|
|
|
+ }
|
|
|
|
|
+ updates(this.updateBatchData.form).then(response => {
|
|
|
|
|
+ this.msgSuccess("修改成功");
|
|
|
|
|
+ this.updateBatchData.open = false;
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 删除按钮操作 */
|
|
|
|
|
+ handleDelete(row) {
|
|
|
|
|
+ const videoIds = row.videoId || this.ids;
|
|
|
|
|
+ this.$confirm('是否确认删除视频编号为"' + videoIds + '"的数据项?', "警告", {
|
|
|
|
|
+ confirmButtonText: "确定",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ type: "warning"
|
|
|
|
|
+ }).then(function () {
|
|
|
|
|
+ return delUserCourseVideo(videoIds);
|
|
|
|
|
+ }).then(() => {
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ this.msgSuccess("删除成功");
|
|
|
|
|
+ }).catch(() => {
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 同步模板数据*/
|
|
|
|
|
+ handleSync() {
|
|
|
|
|
+ const courseId = this.courseId;
|
|
|
|
|
+ this.$confirm('是否同步课程数据至模板', "确认", {
|
|
|
|
|
+ confirmButtonText: "确定",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ type: "warning"
|
|
|
|
|
+ }).then(function () {
|
|
|
|
|
+ return syncTemplate(courseId);
|
|
|
|
|
+ }).then(() => {
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ this.msgSuccess("正在同步模板中!!请稍后!");
|
|
|
|
|
+ }).catch(() => {
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ handleCourseSort() {
|
|
|
|
|
+
|
|
|
|
|
+ getVideoListByCourseIdAll(this.queryParams.courseId).then(response => {
|
|
|
|
|
+
|
|
|
|
|
+ response.rows.forEach((item) => item.newCourseSort = item.courseSort);
|
|
|
|
|
+ this.userCourseVideoSortList = response.rows.sort((a, b) => a.courseSort - b.courseSort);
|
|
|
|
|
+ if (this.userCourseVideoSortList == null || this.userCourseVideoSortList.length == 0) {
|
|
|
|
|
+ this.$message.error("暂无课节天数")
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.openVideoSort = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ onDragEndDay() {
|
|
|
|
|
+ this.userCourseVideoSortList.forEach((item, index) => {
|
|
|
|
|
+ item.newCourseSort = index + 1;
|
|
|
|
|
+ })
|
|
|
|
|
+ this.$forceUpdate()
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ saveSorts() {
|
|
|
|
|
+ let list = this.userCourseVideoSortList.filter(e => e.courseSort != e.newCourseSort).map(e => {
|
|
|
|
|
+ return {courseSort: e.newCourseSort, videoId: e.videoId}
|
|
|
|
|
+ })
|
|
|
|
|
+ this.loading3 = true;
|
|
|
|
|
+ sortCourseVideo(list).then(e => {
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ }).finally(() => {
|
|
|
|
|
+ this.userCourseVideoSortList = [];
|
|
|
|
|
+ this.openVideoSort = false;
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ openAdds() {
|
|
|
|
|
+ this.addBatchData.open = true;
|
|
|
|
|
+ this.getRootTypeList();
|
|
|
|
|
+ this.addBatchData.form = {
|
|
|
|
|
+ courseId: this.courseId,
|
|
|
|
|
+ };
|
|
|
|
|
+ // 重置选择顺序数组
|
|
|
|
|
+ this.addBatchData.select = [];
|
|
|
|
|
+ this.resourceList();
|
|
|
|
|
+ },
|
|
|
|
|
+ getRootTypeList() {
|
|
|
|
|
+ getCatePidList().then(response => {
|
|
|
|
|
+ this.addBatchData.typeOptions = response.data
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ async changeCateType(val) {
|
|
|
|
|
+ this.addBatchData.queryParams.typeSubId = null
|
|
|
|
|
+ this.addBatchData.typeSubOptions = []
|
|
|
|
|
+ if (!val) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ await getCateListByPid(val).then(response => {
|
|
|
|
|
+ this.addBatchData.typeSubOptions = response.data
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ resourceList() {
|
|
|
|
|
+ this.addBatchData.loading = true;
|
|
|
|
|
+ listVideoResource(this.addBatchData.queryParams).then(response => {
|
|
|
|
|
+ this.addBatchData.loading = false;
|
|
|
|
|
+ this.addBatchData.list = response.rows;
|
|
|
|
|
+ this.addBatchData.total = response.total;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ batchVideoSave() {
|
|
|
|
|
+ if (this.addBatchData.select.length === 0) {
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '请选择视频!!',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ });
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ this.addBatchData.form.ids = this.addBatchData.select; // 按用户选择顺序提交
|
|
|
|
|
+ batchSaveVideo(this.addBatchData.form).then(response => {
|
|
|
|
|
+ this.addBatchData.open = false;
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ updateRedPageckeOpen() {
|
|
|
|
|
+ this.redData.open = true;
|
|
|
|
|
+ this.redData.loading = true;
|
|
|
|
|
+ this.redData.queryParams.courseId = this.courseId;
|
|
|
|
|
+ getVideoListByCourseId(this.redData.queryParams).then(response => {
|
|
|
|
|
+ if(!!response.rows && response.rows.length >0){
|
|
|
|
|
+ for(let i = 0; i < response.rows.length; i++){
|
|
|
|
|
+ if(!!response.rows[i].randomRedPacketRules){
|
|
|
|
|
+ this.$set(response.rows[i], 'randomRedPacketRulesArr', JSON.parse(response.rows[i].randomRedPacketRules)) ;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ this.redData.list = response.rows;
|
|
|
|
|
+ console.log(this.redData.list);
|
|
|
|
|
+ this.redData.loading = false;
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ batchRedSave() {
|
|
|
|
|
+ batchUpdateRed(this.redData.list).then(response => {
|
|
|
|
|
+ this.redData.open = false;
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 查看评论按钮操作 */
|
|
|
|
|
+ handleComment(row) {
|
|
|
|
|
+ this.commentDialog.courseId = row.courseId || this.courseId;
|
|
|
|
|
+ this.commentDialog.videoId = row.videoId;
|
|
|
|
|
+ this.commentDialog.title = `查看评论 - ${row.title}`;
|
|
|
|
|
+ this.commentDialog.open = true;
|
|
|
|
|
+ },
|
|
|
|
|
+ // 实时过滤金额输入,只允许两位小数
|
|
|
|
|
+ handleAmountInput(rule, field) {
|
|
|
|
|
+ let value = rule[field];
|
|
|
|
|
+ if (value === null || value === undefined) return;
|
|
|
|
|
+
|
|
|
|
|
+ // 转换为字符串处理
|
|
|
|
|
+ let str = value.toString();
|
|
|
|
|
+
|
|
|
|
|
+ // 移除除数字和小数点外的所有字符
|
|
|
|
|
+ str = str.replace(/[^0-9.]/g, '');
|
|
|
|
|
+
|
|
|
|
|
+ // 只保留一个小数点
|
|
|
|
|
+ const dotIndex = str.indexOf('.');
|
|
|
|
|
+ if (dotIndex !== -1) {
|
|
|
|
|
+ str = str.substring(0, dotIndex + 1) + str.substring(dotIndex + 1).replace(/\./g, '');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 限制小数点后最多两位
|
|
|
|
|
+ if (dotIndex !== -1 && str.length > dotIndex + 3) {
|
|
|
|
|
+ str = str.substring(0, dotIndex + 3);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 转换回数字并更新
|
|
|
|
|
+ rule[field] = parseFloat(str) || 0;
|
|
|
|
|
+ },
|
|
|
|
|
+ deleteRule(index) {
|
|
|
|
|
+ this.$confirm("确定要删除这个区间吗?", "提示", {
|
|
|
|
|
+ confirmButtonText: "确定",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ type: "warning",
|
|
|
|
|
+ }).then(() => {
|
|
|
|
|
+ this.form.randomRedPacketRulesArr.splice(index, 1);
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ type: "success",
|
|
|
|
|
+ message: "删除成功!",
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ addRule(index) {
|
|
|
|
|
+ // 在当前行的后面插入一个新行
|
|
|
|
|
+ this.form.randomRedPacketRulesArr.splice(index + 1, 0, {
|
|
|
|
|
+ minAmount: 0.01,
|
|
|
|
|
+ maxAmount: 0.01,
|
|
|
|
|
+ weight: 100,
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ // 自定义校验规则:确保最大金额大于最小金额
|
|
|
|
|
+ validateMinAmount(rule, value, callback) {
|
|
|
|
|
+ // debugger;
|
|
|
|
|
+ // const maxAmount = this.form29.rules[].maxAmount
|
|
|
|
|
+
|
|
|
|
|
+ const index = rule.index;
|
|
|
|
|
+ const maxAmount = this.form.randomRedPacketRulesArr[index].maxAmount;
|
|
|
|
|
+
|
|
|
|
|
+ if (value > maxAmount) {
|
|
|
|
|
+ callback(new Error("最小金额不能大于最大金额"));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ callback();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ validateRules() {
|
|
|
|
|
+ this.form.randomRedPacketRulesArr.forEach((rule) => {
|
|
|
|
|
+ if (rule.minAmount === undefined || rule.minAmount < 0.01) {
|
|
|
|
|
+ rule.minAmount = 0.01;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (rule.maxAmount === undefined || rule.maxAmount < rule.minAmount) {
|
|
|
|
|
+ rule.maxAmount = rule.minAmount;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (rule.weight === undefined || rule.weight < 1) {
|
|
|
|
|
+ rule.weight = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 下架 **/
|
|
|
|
|
+ handleDown() {
|
|
|
|
|
+ const videoIds = this.ids;
|
|
|
|
|
+ this.$confirm('是否确认下架视频编号为"' + videoIds + '"的数据项?', "警告", {
|
|
|
|
|
+ confirmButtonText: "确定",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ type: "warning"
|
|
|
|
|
+ }).then(function () {
|
|
|
|
|
+ return batchDownUserCourseVideo(videoIds);
|
|
|
|
|
+ }).then(() => {
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ this.msgSuccess("下架成功");
|
|
|
|
|
+ }).catch(() => {
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 上架按钮操作 */
|
|
|
|
|
+ handleUp() {
|
|
|
|
|
+ const videoIds = this.ids;
|
|
|
|
|
+ this.$confirm('是否确认上架视频编号为"' + videoIds + '"的数据项?', "警告", {
|
|
|
|
|
+ confirmButtonText: "确定",
|
|
|
|
|
+ cancelButtonText: "取消",
|
|
|
|
|
+ type: "warning"
|
|
|
|
|
+ }).then(function () {
|
|
|
|
|
+ return batchUpUserCourseVideo(videoIds);
|
|
|
|
|
+ }).then(() => {
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ this.msgSuccess("上架成功");
|
|
|
|
|
+ }).catch(function () {
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 修改封面 **/
|
|
|
|
|
+ handleEditCover() {
|
|
|
|
|
+ this.batchEditCoverDialog.form = {
|
|
|
|
|
+ thumbnail: null
|
|
|
|
|
+ }
|
|
|
|
|
+ this.batchEditCoverDialog.visible = true
|
|
|
|
|
+ },
|
|
|
|
|
+ handleCoverSuccess(res, file) {
|
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
|
+ this.batchEditCoverDialog.form.thumbnail = res.url;
|
|
|
|
|
+ this.$forceUpdate()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.msgError(res.msg);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ submitEditCoverForm() {
|
|
|
|
|
+ this.$refs["batchEditCoverDialogForm"].validate(valid => {
|
|
|
|
|
+ if (!valid) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const thumbnail = this.batchEditCoverDialog.form.thumbnail
|
|
|
|
|
+ const videoIds = this.ids
|
|
|
|
|
+
|
|
|
|
|
+ if (!thumbnail || thumbnail === '') {
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '请上传封面!',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ });
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!videoIds || videoIds.length === 0) {
|
|
|
|
|
+ this.$message({
|
|
|
|
|
+ message: '请选择小节!',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ });
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ thumbnail: thumbnail,
|
|
|
|
|
+ videoIds: videoIds
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ batchEditCover(params).then(response => {
|
|
|
|
|
+ this.msgSuccess("修改成功")
|
|
|
|
|
+ this.batchEditCoverDialog.visible = false
|
|
|
|
|
+ this.getList();
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ cancelEditCoverForm() {
|
|
|
|
|
+ this.batchEditCoverDialog.visible = false
|
|
|
|
|
+ this.batchEditCoverDialog.form = {
|
|
|
|
|
+ thumbnail: null,
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</script>
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+.avatar-uploader-icon {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|
|
|
|
|
+<style>
|
|
|
|
|
+.avatar-uploader .el-upload {
|
|
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.avatar-uploader .el-upload:hover {
|
|
|
|
|
+ border-color: #409EFF;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.avatar-uploader-icon {
|
|
|
|
|
+ font-size: 28px;
|
|
|
|
|
+ color: #8c939d;
|
|
|
|
|
+ width: 150px;
|
|
|
|
|
+ height: 150px;
|
|
|
|
|
+ line-height: 150px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+.red:hover {
|
|
|
|
|
+ color: #dbdbdb !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.red {
|
|
|
|
|
+ background-color: #F56C6C !important;
|
|
|
|
|
+ color: #fff !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+</style>
|