userCourseCatalogDetails.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. <template>
  2. <div class="app-container">
  3. <div style="padding-bottom: 20px">
  4. <span v-if="courseName!=null">{{ courseName }}</span>
  5. </div>
  6. <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  7. <el-form-item label="小节名称" prop="title">
  8. <el-input
  9. v-model="queryParams.title"
  10. placeholder="请输入小节名称"
  11. clearable
  12. size="small"
  13. @keyup.enter.native="handleQuery"
  14. />
  15. </el-form-item>
  16. <el-form-item>
  17. <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  18. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  19. </el-form-item>
  20. </el-form>
  21. <el-table border v-loading="loading" :data="userCourseVideoList" @selection-change="handleSelectionChange">
  22. <el-table-column type="selection" width="55" align="center" />
  23. <el-table-column label="视频ID" align="center" prop="videoId" />
  24. <el-table-column label="小节名称" align="center" show-overflow-tooltip prop="title" />
  25. <el-table-column label="视频文件名称" align="center" show-overflow-tooltip prop="fileName" >
  26. </el-table-column>
  27. <el-table-column label="视频时长" align="center" prop="duration">
  28. <template slot-scope="{ row }">
  29. {{ formatDuration(row.duration) }}
  30. </template>
  31. </el-table-column>
  32. <el-table-column label="排序" align="center" prop="courseSort" />
  33. <el-table-column label="上传时间" align="center" prop="createTime" />
  34. <el-table-column label="默认红包" align="center" prop="redPacketMoney" />
  35. <el-table-column label="公司红包" align="center" prop="companyRedPacketMoney" />
  36. <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  37. <template slot-scope="scope">
  38. <el-button
  39. size="mini"
  40. type="text"
  41. @click="handleDetails(scope.row)"
  42. >查看</el-button>
  43. <el-button
  44. size="mini"
  45. type="text"
  46. v-hasPermi="['course:userCourseVideo:edit']"
  47. @click="updateMoney(scope.row)"
  48. >设置红包金额</el-button>
  49. <!-- <el-button-->
  50. <!-- size="mini"-->
  51. <!-- type="text"-->
  52. <!-- @click="openDialog(scope.row)"-->
  53. <!-- v-hasPermi="['course:courseLink:create']"-->
  54. <!-- >生成应急短链</el-button>-->
  55. </template>
  56. </el-table-column>
  57. </el-table>
  58. <pagination
  59. v-show="total>0"
  60. :total="total"
  61. :page.sync="queryParams.pageNum"
  62. :limit.sync="queryParams.pageSize"
  63. @pagination="getList"
  64. />
  65. <el-drawer
  66. :with-header="false"
  67. size="75%"
  68. :visible.sync="open" append-to-body>
  69. <userCourseVideoDetails ref="userCourseVideoDetails" />
  70. </el-drawer>
  71. <el-dialog title="设置红包金额" :visible.sync="moneyOpen" width="600px" append-to-body>
  72. <el-form ref="form" label-width="100px">
  73. <el-form-item label="红包金额" prop="corpId">
  74. <el-input-number v-model="redPacketMoneyForm.redPacketMoney" :min="0.1" :max="200" :step="0.1" ></el-input-number>
  75. </el-form-item>
  76. </el-form>
  77. <div slot="footer" class="dialog-footer">
  78. <el-button type="primary" @click="submitForm">确 定</el-button>
  79. <el-button @click="cancel">取 消</el-button>
  80. </div>
  81. </el-dialog>
  82. <el-dialog
  83. title="生成链接"
  84. :visible.sync="dialogVisible"
  85. width="400px"
  86. @close="resetForm"
  87. append-to-body
  88. >
  89. <div>
  90. <p style="color: gray;">不传默认以系统参数为准</p>
  91. <el-form :model="linkForm" label-width="120px">
  92. <el-form-item label="链接有效时长(天)">
  93. <el-input
  94. v-model="linkForm.days"
  95. placeholder="请输入有效时长"
  96. type="number"
  97. ></el-input>
  98. </el-form-item>
  99. </el-form>
  100. </div>
  101. <div slot="footer" class="dialog-footer">
  102. <el-button @click="dialogVisible = false">取消</el-button>
  103. <el-button type="primary" @click="confirm">确认</el-button>
  104. </div>
  105. </el-dialog>
  106. <!-- <el-dialog title="设置红包金额" :visible.sync="moneyOpen" width="600px" append-to-body>-->
  107. <!-- <el-form ref="form" label-width="100px">-->
  108. <!-- <el-form-item label="红包金额" prop="corpId">-->
  109. <!-- <el-input-number v-model="redPacketMoneyForm.redPacketMoney" :min="0.1" :max="200" :step="0.1" ></el-input-number>-->
  110. <!-- </el-form-item>-->
  111. <!-- </el-form>-->
  112. <!-- <div slot="footer" class="dialog-footer">-->
  113. <!-- <el-button @click="cancel">取 消</el-button>-->
  114. <!-- </div>-->
  115. <!-- </el-dialog>-->
  116. </div>
  117. </template>
  118. <script>
  119. import { updatePacketMoney,getSort,getVideoListByCourseId,delUserCourseVideo,getUserCourseVideo,addUserCourseVideo,updateUserCourseVideo } from "@/api/course/userCourseVideo";
  120. import userCourseVideoDetails from '../../components/course/userCourseVideoDetails.vue';
  121. import { createLinkUrl } from "@/api/course/sopCourseLink";
  122. import { userList } from "@/api/qw/user";
  123. import request from '@/utils/request'
  124. export default {
  125. name: "userCourseCatalog",
  126. components: {
  127. userCourseVideoDetails
  128. },
  129. data() {
  130. return {
  131. linkForm:{
  132. days:null,
  133. courseId:null,
  134. videoId:null
  135. },
  136. dialogVisible: false, // 控制弹框显示
  137. //短链
  138. sortLink:'',
  139. //课题
  140. questionBank:{
  141. title:'',
  142. open:false,
  143. },
  144. moneyOpen:false,
  145. videoUrl: "",
  146. uploadTypeOptions: [
  147. { dictLabel: "线路一", dictValue: 2 },
  148. { dictLabel: "线路二", dictValue: 1 },
  149. { dictLabel: "线路三", dictValue: 3 },
  150. ],
  151. uploadLoading:false,
  152. courseId:null,
  153. videoName:'',
  154. title: "",
  155. redPacketMoneyForm:{
  156. redPacketMoney:null,
  157. voidId:null
  158. },
  159. // 是否显示弹出层
  160. open: false,
  161. uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadHuaWeiObs",
  162. baseUrl: process.env.VUE_APP_BASE_API,
  163. typeOptions:[],
  164. files:[],
  165. fileList: [],
  166. // 上传成功后的地址
  167. videoURL: '',
  168. // 进度条百分比
  169. progress: 0,
  170. // 上传视频获取成功后拿到的fileID【备用】
  171. fileId: '',
  172. courseName:null,
  173. userCourseVideoList:[],
  174. total: 0,
  175. queryParams: {
  176. pageNum: 1,
  177. pageSize: 10,
  178. courseId:null,
  179. title:null
  180. },
  181. // 显示搜索条件
  182. showSearch: true,
  183. // 遮罩层
  184. loading: true,
  185. // 导出遮罩层
  186. exportLoading: false,
  187. // 选中数组
  188. ids: [],
  189. // 非单个禁用
  190. single: true,
  191. // 非多个禁用
  192. multiple: true,
  193. // 表单参数
  194. form: {},
  195. // 表单校验
  196. rules: {
  197. title: [
  198. { required: true, message: "小节名称不能为空", trigger: "change" }
  199. ],
  200. courseSort: [
  201. { required: true, message: "排序不能为空", trigger: "change" }
  202. ],
  203. }
  204. }
  205. },
  206. created() {
  207. this.getDicts("sys_course_temp_type").then(response => {
  208. this.typeOptions = response.data;
  209. });
  210. },
  211. methods: {
  212. // 打开弹框
  213. openDialog(row) {
  214. this.linkForm.courseId = row.courseId;
  215. this.linkForm.videoId = row.videoId;
  216. this.dialogVisible = true;
  217. },
  218. // 确认按钮操作
  219. confirm() {
  220. if (!this.linkForm.days) {
  221. this.$message.error("请输入有效时长!");
  222. return;
  223. }
  224. this.handleCreateLink();
  225. // 关闭弹框
  226. this.dialogVisible = false;
  227. },
  228. // 重置表单
  229. resetForm() {
  230. this.linkForm={
  231. days:null,
  232. courseId:null,
  233. videoId:null
  234. }
  235. },
  236. handleCreateLink(){
  237. createLinkUrl(this.linkForm).then(response => {
  238. if (response.code === 200){
  239. this.copyLink(response.url);
  240. }
  241. });
  242. },
  243. copyLink(url) {
  244. const link = url;
  245. // navigator clipboard 需要https等安全上下文
  246. if (navigator.clipboard && window.isSecureContext) {
  247. // navigator clipboard 向剪贴板写文本
  248. navigator.clipboard.writeText(link).then(() => {
  249. this.$message.success('链接已复制到剪贴板');
  250. });
  251. } else {
  252. // document.execCommand('copy') 向剪贴板写文本
  253. let input = document.createElement('input')
  254. input.style.position = 'fixed'
  255. input.style.top = '-10000px'
  256. input.style.zIndex = '-999'
  257. document.body.appendChild(input)
  258. input.value = link
  259. input.focus()
  260. input.select()
  261. try {
  262. let result = document.execCommand('copy')
  263. document.body.removeChild(input)
  264. if (!result || result === 'unsuccessful') {
  265. this.$message.error('复制失败');
  266. console.log('复制失败')
  267. } else {
  268. this.$message.success('链接已复制到剪贴板');
  269. console.log('复制成功')
  270. }
  271. } catch (e) {
  272. document.body.removeChild(input)
  273. alert('当前浏览器不支持复制功能,请检查更新或更换其他浏览器操作')
  274. }
  275. }
  276. },
  277. formatDuration(seconds) {
  278. if (seconds === null || seconds === undefined) {
  279. return '未上传视频'; // 或者您可以根据具体需求返回其他默认值
  280. }
  281. const hours = Math.floor(seconds / 3600);
  282. const minutes = Math.floor((seconds % 3600) / 60);
  283. const remainingSeconds = seconds % 60;
  284. const formattedHours = hours > 0 ? hours.toString() + ':' : '';
  285. const formattedMinutes = minutes.toString().padStart(2, '0');
  286. const formattedSeconds = remainingSeconds.toString().padStart(2, '0');
  287. return `${formattedHours}${formattedMinutes}:${formattedSeconds}`;
  288. },
  289. getDetails(courseId,courseName) {
  290. this.courseName = courseName
  291. this.courseId = courseId;
  292. this.queryParams.courseId = courseId;
  293. this.getList();
  294. },
  295. getList() {
  296. this.loading = true;
  297. getVideoListByCourseId(this.queryParams).then(response => {
  298. this.userCourseVideoList = response.rows;
  299. this.total = response.total;
  300. this.loading = false;
  301. });
  302. },
  303. // 取消按钮
  304. cancel() {
  305. this.open = false;
  306. this.reset();
  307. },
  308. updateMoney(row){
  309. this.redPacketMoneyForm.redPacketMoney=row.companyRedPacketMoney;
  310. this.redPacketMoneyForm.videoId=row.videoId;
  311. this.moneyOpen=true;
  312. },
  313. submitForm(){
  314. updatePacketMoney(this.redPacketMoneyForm).then(response => {
  315. this.msgSuccess("修改成功");
  316. this.moneyOpen=false;
  317. this.getList()
  318. });
  319. },
  320. updateMoneycancel(){
  321. this.moneyOpen=false;
  322. },
  323. // 表单重置
  324. reset() {
  325. this.form = {
  326. videoId: null,
  327. title: null,
  328. description: null,
  329. url: null,
  330. thumbnail: null,
  331. duration: null,
  332. createTime: null,
  333. uploadType:null,
  334. lineOne:null,
  335. lineTwo:null,
  336. lineThree:null,
  337. fileName:null,
  338. userId: null,
  339. cateId: null,
  340. courseId: null,
  341. likes: null,
  342. views: null,
  343. comments: null,
  344. status: 0,
  345. courseSort: 1,
  346. isHot: null,
  347. isShow: null,
  348. isAudit: null,
  349. auditBy: null,
  350. auditTime: null,
  351. updateTime: null,
  352. source: null,
  353. isDel: null,
  354. shares: null,
  355. tags: null,
  356. productId: null,
  357. productJson: null,
  358. questionBankId:null,
  359. questionBankList:[],
  360. };
  361. this.videoURL = '';
  362. this.progress=0;
  363. this.resetForm("form");
  364. },
  365. /** 搜索按钮操作 */
  366. handleQuery() {
  367. this.queryParams.pageNum = 1;
  368. this.getList();
  369. },
  370. /** 重置按钮操作 */
  371. resetQuery() {
  372. this.resetForm("queryForm");
  373. this.queryParams.title = null;
  374. this.handleQuery();
  375. },
  376. // 多选框选中数据
  377. handleSelectionChange(selection) {
  378. this.ids = selection.map(item => item.courseId)
  379. this.single = selection.length!==1
  380. this.multiple = !selection.length
  381. },
  382. /** 修改按钮操作 */
  383. handleDetails(row) {
  384. this.open=true;
  385. setTimeout(() => {
  386. this.$refs.userCourseVideoDetails.getDetails(row.videoId);
  387. }, 500);
  388. }
  389. }
  390. }
  391. </script>
  392. <style>
  393. .avatar-uploader .el-upload {
  394. border: 1px dashed #d9d9d9;
  395. border-radius: 6px;
  396. cursor: pointer;
  397. position: relative;
  398. overflow: hidden;
  399. }
  400. .avatar-uploader .el-upload:hover {
  401. border-color: #409EFF;
  402. }
  403. .avatar-uploader-icon {
  404. font-size: 28px;
  405. color: #8c939d;
  406. width: 150px;
  407. height: 150px;
  408. line-height: 150px;
  409. text-align: center;
  410. }
  411. </style>