chapter-list.php 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602
  1. <?php
  2. use common\helpers\ComponentHelper;
  3. ComponentHelper::loadComponentView('com-dialog-select');
  4. ComponentHelper::loadComponentView('com-image');
  5. ?>
  6. <style>
  7. .table-body {
  8. padding: 5px 20px;
  9. background-color: #fff;
  10. /* flex: 1; */
  11. width: calc(100% - 320px);
  12. }
  13. .chapter-list {
  14. /* background: #FFFFFF; */
  15. border-right: 1px solid #f2f2f2;
  16. padding: 0 10px;
  17. margin: 5px 0;
  18. }
  19. .info_body {
  20. display: flex;
  21. background: #FFFFFF;
  22. border-top: 1px solid #f5f5f5;
  23. padding-top: 10px;
  24. box-sizing: border-box;
  25. }
  26. .body-top {
  27. display: flex;
  28. justify-content: space-between;
  29. align-items: center;
  30. }
  31. .input-item {
  32. display: inline-block;
  33. width: 250px;
  34. /* margin: 0 0 20px; */
  35. }
  36. .input-item .el-input__inner {
  37. border-right: 0;
  38. }
  39. .input-item .el-input__inner:hover {
  40. border: 1px solid #dcdfe6;
  41. border-right: 0;
  42. outline: 0;
  43. }
  44. .input-item .el-input__inner:focus {
  45. border: 1px solid #dcdfe6;
  46. border-right: 0;
  47. outline: 0;
  48. }
  49. .input-item .el-input-group__append {
  50. background-color: #fff;
  51. border-left: 0;
  52. width: 10%;
  53. padding: 0;
  54. }
  55. .input-item .el-input-group__append .el-button {
  56. padding: 0;
  57. }
  58. .input-item .el-input-group__append .el-button {
  59. margin: 0;
  60. }
  61. /* .table-body .el-button {
  62. padding: 0 !important;
  63. border: 0;
  64. margin: 0 5px;
  65. } */
  66. .com-btn {
  67. padding: 0 !important;
  68. border: 0;
  69. margin: 0 5px;
  70. }
  71. .form-body {
  72. background-color: #fff;
  73. margin-bottom: 20px;
  74. }
  75. .el-tabs__header {
  76. background-color: #fff;
  77. }
  78. .el-tabs__item {
  79. width: 100px;
  80. text-align: center;
  81. }
  82. .el-table th>.cell {
  83. color: #333;
  84. font-weight: bold;
  85. font-size: 14px;
  86. }
  87. .el-table__footer-wrapper,
  88. .el-table__header-wrapper {
  89. border-bottom: 1.4px solid #D6D6D6;
  90. }
  91. .info-top {
  92. display: flex;
  93. justify-content: space-between;
  94. background-color: #fff;
  95. padding: 10px 15px;
  96. width: 100%;
  97. }
  98. .info-top-lf {
  99. display: flex;
  100. }
  101. .lf-column {
  102. display: flex;
  103. flex-direction: column;
  104. justify-content: space-between;
  105. padding-left: 10px;
  106. }
  107. .column-title {
  108. font-size: 18px;
  109. font-weight: 700;
  110. padding-bottom: 5px;
  111. }
  112. .column-dec {
  113. color: #666;
  114. font-size: 14px;
  115. width: 100%;
  116. }
  117. .choose-box {
  118. padding-top: 20px;
  119. padding-bottom: 5px;
  120. }
  121. .tree_flex {
  122. display: flex;
  123. width: 100%;
  124. align-items: center;
  125. }
  126. .el-tree-node {
  127. margin-bottom: 5px;
  128. }
  129. .tree_top_text {
  130. flex: 1;
  131. }
  132. .noClick {
  133. color: #999999;
  134. }
  135. </style>
  136. <div id="app" v-cloak>
  137. <el-card shadow="never" body-style="background-color: #f3f3f3;padding: 10px 0 0;">
  138. <div slot="header">
  139. <div>
  140. <span>章节列表</span>
  141. <div style="float: right">
  142. <!-- <el-button type="primary" size="small" style="padding: 9px 15px !important;" @click="toLook(false,0)">创建章节</el-button>-->
  143. <el-button type="primary" size="small" style="padding: 9px 15px !important;" @click="editCourse(course_info.id)">编辑课程</el-button>
  144. </div>
  145. </div>
  146. </div>
  147. <div class="info-top">
  148. <div class="info-top-lf">
  149. <com-image width="160px" height="110px" mode="scaleToFill" :src="course_info.logo"></com-image>
  150. <div class="lf-column">
  151. <div>
  152. <div class="column-title">{{course_info.course_name}}</div>
  153. <div class="column-dec">{{course_info.introduce}}</div>
  154. </div>
  155. <div class="column-amount column-dec">
  156. <span style="margin-right: 20px;">¥{{course_info.price}}</span>
  157. <span>已售:{{course_info.sales}}</span>
  158. </div>
  159. </div>
  160. </div>
  161. <div class="info-top-rg" style="display: flex;position:relative;right:25px;bottom:20px;">
  162. <!-- <el-button type="text" size="mini" @click="editCourse(course_info.id)">编辑</el-button>-->
  163. <el-button type="text" size="mini" class="copy_btn" @click="copyLink(course_info.id)">复制链接</el-button>
  164. <el-button type="text" size="mini" @click="switchCourseStatus(course_info.id, course_info.status)" v-if="course_info.status==1"> 立即下架 </el-button>
  165. <el-button type="text" size="mini" @click="switchCourseStatus(course_info.id, course_info.status)" v-else> 立即上架 </el-button>
  166. </div>
  167. </div>
  168. <div class="info_body">
  169. <div class="chapter-list" :loading="lableLoading">
  170. <el-button plain style="width: calc(100% - 10px);" @click="addDirectory">添加目录</el-button>
  171. <div style="padding: 20px 0 10px" @click="onAllNode">全部目录({{chapter_all_count}})</div>
  172. <el-tree :data="directory_list" node-key="id" :expand-on-click-node="false" @node-click="selectNode">
  173. <span class="custom-tree-node tree_flex" slot-scope="{ node, data }">
  174. <span class="tree_top_text">
  175. {{node.label}}
  176. <el-tooltip v-if="data.id == 0" effect="dark" content="未选择目录的章节默认进入未分类目录" placement="top">
  177. <i class="el-icon-info"></i>
  178. </el-tooltip>
  179. ({{data.chapter_number || 0}})
  180. </span>
  181. <span v-if="data.id != 0">
  182. <el-button type="text" size="mini" @click="addChild(data,node,1)" v-if="data.children && data.id != 0">
  183. 添加子目录
  184. </el-button>
  185. <el-button type="text" size="mini" @click="moveChild(data,node,1)" :disabled="data.sort == 0">
  186. 上移
  187. </el-button>
  188. <el-button type="text" size="mini" @click="moveChild(data,node,2)" :disabled="data.end == 1">
  189. 下移
  190. </el-button>
  191. <el-button type="text" size="mini" @click="addChild(data,node,2)">
  192. 编辑
  193. </el-button>
  194. <el-button type="text" size="mini" @click="() => removeChild(data,node)">
  195. 删除
  196. </el-button>
  197. </span>
  198. </span>
  199. </el-tree>
  200. </div>
  201. <div class="table-body">
  202. <div class="body-top">
  203. <el-button type="primary" @click="toLook(false,0)">创建章节</el-button>
  204. <div class="input-item" style="margin-right: 120px;">
  205. <el-input @keyup.enter.native="search" size="small" placeholder="请输入章节名称" v-model="keyword" clearable @clear="search">
  206. <el-button slot="append" icon="el-icon-search" @click="search"></el-button>
  207. </el-input>
  208. </div>
  209. </div>
  210. <div class="choose-box">
  211. <!-- <el-checkbox v-model="checked" style="margin-right: 20px;" @change="changes">全选</el-checkbox> -->
  212. <el-button plain @click="moveToDirectory(course_info.id)">移动</el-button>
  213. <el-button plain @click="multipleChapterDelete(course_info.id)">删除</el-button>
  214. </div>
  215. <el-table v-loading="listLoading" ref="multipleTable" :data="list" stripe style="width: 100%" @selection-change="handleSelectionChange" :row-class-name="tableRowClassName" @cell-click="tabClick">
  216. <el-table-column type="selection" width="55">
  217. </el-table-column>
  218. <el-table-column label="章节名称" prop="name" min-width="180">
  219. <template slot-scope="scope">
  220. <div size="small">{{scope.row.name}}</div>
  221. </template>
  222. </el-table-column>
  223. <el-table-column label="所属目录" prop="course_name" min-width="180">
  224. <template slot-scope="scope">
  225. <div size="small">{{scope.row.directory_name}}</div>
  226. <!-- <el-tag size="small" type="info" v-if="scope.row.course_id == 0"></el-tag>
  227. <el-tag size="small" v-else>{{scope.row.course_name}}</el-tag> -->
  228. </template>
  229. </el-table-column>
  230. <el-table-column label="是否关联商品" min-width="180" align="center">
  231. <template slot-scope="scope">
  232. <div>{{scope.row.goods_list ? '是' : '否'}}</div>
  233. </template>
  234. </el-table-column>
  235. <!-- <el-table-column label="关联商品" min-width="180" align="center">
  236. <template slot-scope="scope">
  237. <div flex="box:first" v-if="scope.row.goods_info.length">
  238. <div style="padding-right: 10px;">
  239. <com-image mode="aspectFill" :src="scope.row.goods_info[0].cover_pic"></com-image>
  240. </div>
  241. <div flex="cross:top cross:top">
  242. {{scope.row.goods_info[0].name}}<br />&yen;{{scope.row.goods_info[0].price}}
  243. </div>
  244. </div>
  245. </template>
  246. </el-table-column> -->
  247. <el-table-column label="播放次数" prop="views" min-width="90" align="center">
  248. <template slot-scope="scope">
  249. <div size="small">{{scope.row.views}}</div>
  250. </template>
  251. </el-table-column>
  252. <el-table-column label="排序" prop="sort" min-width="80" align="center">
  253. <template slot-scope="scope">
  254. <!-- <div size="small">{{scope.row.sort}}</div> -->
  255. <span v-if="scope.row.index === tabClickIndex && tabClickLabel === '排序'">
  256. <el-input v-model="scope.row.sort" maxlength="300" placeholder="请输入排序" size="mini" @change="sortValueChange(scope.row)" />
  257. </span>
  258. <span v-else>{{ scope.row.sort }}</span>
  259. </template>
  260. </el-table-column>
  261. <el-table-column label="是否试看" width="120" align="center">
  262. <template slot-scope="scope">
  263. <el-tag v-if="scope.row.can_see == 0" type="danger">禁止试看</el-tag>
  264. <el-tooltip v-if="scope.row.can_see == 1" :content="scope.row.can_see_time == 0 ? '全程可试看' : '试看时长:' + scope.row.can_see_time + '秒'" placement="top" effect="light">
  265. <el-tag type="success">允许试看</el-tag>
  266. </el-tooltip>
  267. </template>
  268. </el-table-column>
  269. <!-- <el-table-column prop="thumb_url,video_url" label="视频" width="120" align="center">
  270. <template slot-scope="scope">
  271. <div flex="box:first">
  272. <div style="padding-right: 10px; ">
  273. <el-tooltip placement="top" effect="light">
  274. <div class="index-video-url" slot="content">
  275. <video :src="scope.row.video_url" controls="controls" style="width: 300px;height: 300px;">
  276. </video>
  277. </div>
  278. <com-image mode="aspectFill" :src="scope.row.thumb_url"></com-image>
  279. </el-tooltip>
  280. </div>
  281. </div>
  282. </template>
  283. </el-table-column> -->
  284. <el-table-column label="操作" min-width="200" align="center">
  285. <template slot-scope="scope">
  286. <el-button circle size="mini" type="text" @click="toLook(scope.row,scope.row.id)">
  287. 编辑
  288. </el-button>
  289. <el-button circle size="mini" type="text" @click="chapterDelete(scope.row, scope.$index)">
  290. 删除
  291. </el-button>
  292. </template>
  293. </el-table-column>
  294. </el-table>
  295. <div style="text-align: right;margin: 20px 0;">
  296. <el-pagination @current-change="pagination" background layout="prev, pager, next" :page-count="pageCount"></el-pagination>
  297. </div>
  298. </div>
  299. </div>
  300. </el-card>
  301. <!-- 移动弹框 -->
  302. <el-dialog title="选择目录" :visible.sync="shiftVisible">
  303. <div class="shift_body">
  304. <div style="margin-bottom: 5px;">请选择你想要移动到的目录</div>
  305. <div style="display: flex;line-height: 50px;background: #F2F2F2;padding: 0 20px;">
  306. <div style="flex:1;">目录名称</div>
  307. <div>章节数量</div>
  308. </div>
  309. <el-tree :data="directory_list" node-key="id" :expand-on-click-node="false" @node-click="handleNodeClick">
  310. <span class="custom-tree-node tree_flex" slot-scope="{ node, data }" style="font-size: 16px;">
  311. <div class="tree_top_text">{{node.label}}</div>
  312. <div style="margin-right: 40px;">
  313. {{data.chapter_number || 0}}
  314. </div>
  315. </span>
  316. </el-tree>
  317. <div style="text-align: end;margin-top: 10px;">
  318. <el-button type="primary" @click="subShifVisible">确定</el-button>
  319. </div>
  320. </div>
  321. </el-dialog>
  322. <!-- 这个是创建章节弹窗 -->
  323. <el-dialog :title="dialogText" :visible.sync="dialogFormVisible" center width="40%">
  324. <el-form ref="ruleForm" :model="ruleForm" label-width="100px" size="small">
  325. <el-form-item label="关联课程" prop="course_id">
  326. <div>{{course_info.course_name}}</div>
  327. <!-- <el-select class="select" size="small" v-model="ruleForm.course_id" @change="courseDirList(ruleForm.course_id)" filterable placeholder="请选择课程"> -->
  328. <!-- <el-option key="all" label="请选择课程" value=""></el-option> -->
  329. <!-- <el-option :key="item.id" :label="item.name" :value="item.id" v-for="(item, index) in courseList"></el-option> -->
  330. <!-- </el-select> -->
  331. </el-form-item>
  332. <el-form-item label="所属目录" prop="dir_id">
  333. <el-select class="select" size="small" v-model="ruleForm.dir_id" filterable placeholder="请选择目录">
  334. <el-option key="0" label="未分类" :value="0"></el-option>
  335. <el-option :key="item.id" :label="item.name" :value="item.id" v-for="(item, index) in course_dir_list"></el-option>
  336. </el-select>
  337. </el-form-item>
  338. <el-form-item label="排序" prop="sort">
  339. <el-input type="number" :min="1" v-model="ruleForm.sort" placeholder="请输入章节排序" style="width: 50%">
  340. <!-- <template slot="append">元</template> -->
  341. </el-input>
  342. </el-form-item>
  343. <el-form-item label="章节名称" prop="name">
  344. <el-input type="text" v-model="ruleForm.name" placeholder="请输入章节名称" style="width: 50%">
  345. </el-input>
  346. </el-form-item>
  347. <el-form-item label="视频类型" prop="type">
  348. <el-radio-group v-model="ruleForm.type">
  349. <el-radio :label="1">视频 </el-radio>
  350. <el-radio :label="2">音频 </el-radio>
  351. </el-radio-group>
  352. </el-form-item>
  353. <template v-if="ruleForm.type==1">
  354. <el-form-item label="视频上传方式">
  355. <el-radio-group v-model="ruleForm.select_type">
  356. <el-radio :label="1">选择文件</el-radio>
  357. <el-radio :label="2">输入链接</el-radio>
  358. </el-radio-group>
  359. </el-form-item>
  360. <!-- 直接输入链接 -->
  361. <el-form-item label="视频" prop="video_url" v-if="ruleForm.select_type==2">
  362. <label slot="label">视频
  363. <el-tooltip class="item" effect="dark" content="支持格式mp4;支持编码H.264;视频大小不能超过50 MB,文件过大建议使用外链,请点击 输入链接" placement="top">
  364. <i class="el-icon-info"></i>
  365. </el-tooltip>
  366. </label>
  367. <el-input type="text" v-model="ruleForm.video_url" placeholder="请输入完整的视频链接" style="width: 80%"></el-input>
  368. <video v-if='ruleForm.video_url' :src="ruleForm.video_url" controls="controls" width="200px">
  369. </el-form-item>
  370. <!-- 选择上传文件 -->
  371. <el-form-item label="视频" prop="video_url" v-if="ruleForm.select_type==1">
  372. <label slot="label">视频
  373. <el-tooltip class="item" effect="dark" content="支持格式mp4;支持编码H.264;视频大小不能超过50 MB,文件过大建议使用外链,请点击 输入链接" placement="top">
  374. <i class="el-icon-info"></i>
  375. </el-tooltip>
  376. </label>
  377. <com-attachment :type="'videos'" :multiple="false" :max="1" v-model="ruleForm.video_url" @selected="handleSelected">
  378. <el-button size="mini">选择文件</el-button>
  379. <span style="margin-left: 15px;">{{selectedVideo}}</span>
  380. </com-attachment>
  381. <video v-if='ruleForm.video_url' :src="ruleForm.video_url" controls="controls" width="200px">
  382. </el-form-item>
  383. </template>
  384. <template v-else>
  385. <el-form-item label="音频上传方式">
  386. <el-radio-group v-model="ruleForm.select_type">
  387. <el-radio :label="1">选择文件</el-radio>
  388. <el-radio :label="2">输入链接</el-radio>
  389. </el-radio-group>
  390. </el-form-item>
  391. <!-- 直接输入链接 -->
  392. <el-form-item label="音频" prop="video_url" v-if="ruleForm.select_type==2">
  393. <label slot="label">音频
  394. <el-tooltip class="item" effect="dark" content="支持格式mp3;音频大小不能超过50 MB,文件过大建议使用外链,请点击 输入链接" placement="top">
  395. <i class="el-icon-info"></i>
  396. </el-tooltip>
  397. </label>
  398. <el-input type="text" v-model="ruleForm.video_url" placeholder="请输入完整的音频链接" style="width: 80%"></el-input>
  399. </el-form-item>
  400. <!-- 选择上传文件 -->
  401. <el-form-item label="音频" prop="video_url" v-if="ruleForm.select_type==1">
  402. <label slot="label">音频
  403. <el-tooltip class="item" effect="dark" content="支持格式mp3;音频大小不能超过50 MB,文件过大建议使用外链,请点击 输入链接" placement="top">
  404. <i class="el-icon-info"></i>
  405. </el-tooltip>
  406. </label>
  407. <com-attachment :type="'voices'" :multiple="false" :max="1" v-model="ruleForm.video_url" @selected="handleSelected">
  408. <el-button size="mini">选择文件</el-button>
  409. <span style="margin-left: 15px;">{{selectedVideo}}</span>
  410. </com-attachment>
  411. </el-form-item>
  412. </template>
  413. <el-form-item label="关联商品" prop="goods_list">
  414. <div style="display: inline-block;">
  415. <div flex="cross:center">
  416. <div style="margin-left: 10px;">
  417. <com-dialog-select :multiple="true" @selected="goodsSelect" title="商品选择">
  418. <el-button type="text">选择商品</el-button>
  419. </com-dialog-select>
  420. </div>
  421. </div>
  422. </div>
  423. </el-form-item>
  424. <el-form-item prop="goods">
  425. <template>
  426. <div style="color: #ff4544;">最多可添加5个商品</div>
  427. <div style="max-height: 300px;overflow-y: auto">
  428. <el-table :data="ruleForm.goods" :show-header="false" border>
  429. <el-table-column label="">
  430. <template slot-scope="scope">
  431. <div flex>
  432. <div style="padding-right: 10px;flex-grow: 0">
  433. <com-image mode="aspectFill" :src="scope.row.cover_pic"></com-image>
  434. </div>
  435. <div style="flex-grow: 1;">
  436. <com-ellipsis :line="2">{{scope.row.name}}
  437. </com-ellipsis>
  438. </div>
  439. <div style="flex-grow: 0;">
  440. <el-button @click="deleteGoods(scope.$index)" type="text" circle size="mini">
  441. <el-tooltip class="item" effect="dark" content="删除" placement="top">
  442. <img src="/resources/img/common/del.png" alt="">
  443. </el-tooltip>
  444. </el-button>
  445. </div>
  446. </div>
  447. </template>
  448. </el-table-column>
  449. </el-table>
  450. </div>
  451. </template>
  452. </el-form-item>
  453. <el-form-item label="是否试看" prop="can_see">
  454. <el-switch v-model="ruleForm.can_see" :active-value="1" :inactive-value="0"></el-switch>
  455. </el-form-item>
  456. <el-form-item v-if="ruleForm.can_see == 1" label="试看时长" prop="can_see_time">
  457. <el-input placeholder="请输入试看时长" v-model="ruleForm.can_see_time" style="width: 200px;" onInput="value=toNumber(value,0)">
  458. <template slot="append">秒</template>
  459. </el-input>
  460. </el-form-item>
  461. </el-form>
  462. <div slot="footer" class="dialog-footer" style="display: flex;justify-content: center;">
  463. <el-button size="small" @click="dialogFormVisible = false">取 消</el-button>
  464. <el-button size="small" type="primary" @click="editSave('ruleForm')" :loading="editBtnLoading">确 定</el-button>
  465. </div>
  466. </el-dialog>
  467. </div>
  468. <script src="/resources/unpkg/clipboard@1.0.0/dist/clipboard.min.js"></script>
  469. <script>
  470. const app = new Vue({
  471. el: '#app',
  472. data() {
  473. return {
  474. tabClickIndex: null, // 点击的单元格
  475. tabClickLabel: '', // 当前点击的列名
  476. before_edit_sort: 0, // 点击编辑之前的排序序号
  477. before_edit_index: 0, // 点击编辑的那一行的索引
  478. chapter_all_count: 0, // 当前课程下所有章节数据量
  479. can_see: 0,
  480. list: [],
  481. multipleSelection: [], // 表格选中的数组
  482. checked: false,
  483. courseList: [],
  484. dir_list: [],
  485. keyword: '',
  486. listLoading: false,
  487. editBtnLoading: false,
  488. page: 1,
  489. pageCount: 0,
  490. dialogVisible: false, //充值弹窗
  491. lableLoading: false,
  492. dialogFormVisible: false,
  493. btnLoading: false,
  494. addStatus: 1, //默认是增加
  495. selectIndex: 0, //充值item的索引
  496. selectRow: {},
  497. dialogLoading2: false,
  498. dialogText: '',
  499. edit: {
  500. show: false,
  501. },
  502. course_info: {},
  503. ruleForm: {
  504. goods_list: [],
  505. goods: [],
  506. sort: 1,
  507. name: '',
  508. video_url: '',
  509. select_type:1,
  510. type: 1,
  511. can_see: 0,
  512. course_id: "",
  513. id: 0,
  514. thumb_url: '',
  515. can_see_time: 0,
  516. },
  517. rules: {
  518. name: [{
  519. required: true,
  520. message: '请输入章节名称',
  521. trigger: 'change'
  522. }, ],
  523. sort: [{
  524. required: true,
  525. message: '请输入章节排序',
  526. trigger: 'change'
  527. }, ],
  528. course_id: [{
  529. required: true,
  530. message: "请选择课程章节",
  531. trigger: 'change'
  532. }, ]
  533. },
  534. directory_list: [{
  535. id: 1,
  536. label: '一级 1',
  537. parent_id: 0,
  538. course_id: 1,
  539. chapter_number: 0,
  540. children: [{
  541. id: 5,
  542. label: '二级 1-1',
  543. parent_id: 1,
  544. course_id: 1,
  545. chapter_number: 0
  546. }, {
  547. id: 6,
  548. label: '二级 1-2',
  549. parent_id: 1,
  550. course_id: 1,
  551. chapter_number: 0
  552. }, {
  553. id: 7,
  554. label: '二级 1-3',
  555. parent_id: 1,
  556. course_id: 1,
  557. chapter_number: 0
  558. }]
  559. }, {
  560. id: 2,
  561. label: '一级 2',
  562. parent_id: 0,
  563. course_id: 2,
  564. chapter_number: 0,
  565. children: [{
  566. id: 21,
  567. label: '二级 2-1',
  568. parent_id: 2,
  569. course_id: 2,
  570. chapter_number: 0
  571. }, {
  572. id: 22,
  573. label: '二级 2-2',
  574. parent_id: 2,
  575. course_id: 2,
  576. chapter_number: 0
  577. }, {
  578. id: 23,
  579. label: '二级 2-3',
  580. parent_id: 2,
  581. course_id: 2,
  582. chapter_number: 0
  583. }]
  584. }, {
  585. id: 3,
  586. label: '一级 3',
  587. parent_id: 0,
  588. course_id: 3,
  589. chapter_number: 0,
  590. children: [{
  591. id: 31,
  592. label: '二级 3-1',
  593. parent_id: 3,
  594. course_id: 3,
  595. chapter_number: 0
  596. }, {
  597. id: 32,
  598. label: '二级 3-2',
  599. parent_id: 3,
  600. course_id: 3,
  601. chapter_number: 0
  602. }, {
  603. id: 33,
  604. label: '二级 3-3',
  605. parent_id: 3,
  606. course_id: 3,
  607. chapter_number: 0
  608. }]
  609. }],
  610. shiftVisible: false, //移动弹框
  611. checkDirectoryId: -1, //获取选中目录的id
  612. course_dir_list: [],
  613. selectedVideo: '', // 已选择的视频文件
  614. select_type: 1, // 是否直接输入视频链接
  615. dir_id: 0,
  616. parent_id: 0
  617. };
  618. },
  619. methods: {
  620. // 选择课程联动获取课程目录
  621. courseDirList(course_id) {
  622. var self = this;
  623. self.listLoading = true;
  624. self.course_dir_list = [];
  625. // self.ruleForm.dir_id = 0;
  626. // console.log('getDirList course_id: ', course_id);
  627. request({
  628. params: {
  629. r: 'course/directory/list',
  630. course_id: course_id,
  631. list_type: 1
  632. },
  633. method: 'get',
  634. }).then(e => {
  635. // console.log('dir list:', ...e.data.data.tree);return null;
  636. self.listLoading = false;
  637. if (0 == e.data.code) {
  638. self.course_dir_list.push(...e.data.data);
  639. } else {
  640. this.$message({
  641. message: e.data.msg,
  642. type: 'error'
  643. });
  644. }
  645. }).catch(e => {
  646. this.$message({
  647. message: '网络错误',
  648. type: 'error'
  649. });
  650. });
  651. },
  652. handleSelectionChange(val) {
  653. this.multipleSelection = val
  654. },
  655. /* 单元格点击编辑 start */
  656. tableRowClassName({
  657. row,
  658. rowIndex
  659. }) {
  660. // 把每一行的索引放进row
  661. row.index = rowIndex
  662. },
  663. // 添加明细原因 row 当前行 column 当前列
  664. tabClick(row, column, cell, event) {
  665. switch (column.label) {
  666. case '排序':
  667. this.tabClickIndex = row.index;
  668. this.tabClickLabel = column.label;
  669. this.before_edit_sort = row.sort;
  670. this.before_edit_index = row.index;
  671. break;
  672. default:
  673. return
  674. }
  675. console.log('点击排序编辑', this.tabClickIndex, row, column, cell, event)
  676. },
  677. // 失去焦点初始化
  678. sortValueChange(data) {
  679. // this.listLoading = true;
  680. this.tabClickIndex = null;
  681. this.tabClickLabel = '';
  682. var self = this;
  683. // console.log(self.before_edit_index);
  684. // console.log(self.before_edit_sort);
  685. request({
  686. params: {
  687. r: 'course/chapter/edit-sort'
  688. },
  689. data: {
  690. id: data.id,
  691. 'sort': data.sort
  692. },
  693. method: 'post'
  694. }).then(e => {
  695. self.listLoading = false;
  696. if (0 != e.data.code) {
  697. self.list[self.before_edit_index].sort = self.before_edit_sort;
  698. self.$message.error(e.data.msg)
  699. } else {
  700. self.$message.success(e.data.msg);
  701. }
  702. }).catch(e => {
  703. self.$message.error('网络错误');
  704. });
  705. },
  706. /* 单元格点击编辑 end */
  707. // 选取节点
  708. selectNode(data, node, el) {
  709. // console.log(data, node, el);
  710. var self = this;
  711. self.listLoading = true;
  712. this.dir_id = data.id
  713. this.parent_id = data.parent_id
  714. request({
  715. params: {
  716. r: 'course/default/chapters',
  717. course_id: data.course_id,
  718. dir_id: data.id,
  719. parent_id: data.parent_id
  720. },
  721. method: 'get'
  722. }).then(e => {
  723. // console.log(e);
  724. self.listLoading = false;
  725. self.list = e.data.data.list;
  726. self.pageCount = e.data.data.page_count;
  727. }).catch(e => {
  728. console.log(e);
  729. });
  730. },
  731. // 下架课程
  732. switchCourseStatus(course_id, status) {
  733. var self = this;
  734. if (0 == status) {
  735. status = 1;
  736. } else if (1 == status) {
  737. status = 0;
  738. }
  739. request({
  740. params: {
  741. r: 'course/course/switch-status'
  742. },
  743. method: 'post',
  744. data: {
  745. id: course_id,
  746. status: status
  747. }
  748. }).then(e => {
  749. if (0 == e.data.code) {
  750. self.$message.success(e.data.msg);
  751. self.course_info.status = status;
  752. } else {
  753. self.$message.error(e.data.msg);
  754. }
  755. }).catch(e => {
  756. console.log(e);
  757. });
  758. },
  759. //复制链接
  760. copyLink(course_id) {
  761. // console.log(course_id);
  762. //复制链接
  763. // console.log("host:", window.location)
  764. var url = localStorage.getItem('h5_domain');
  765. var clipboard = new ClipboardJS('.copy_btn', {
  766. text: function() {
  767. return url + 'plugins/course/details?courseId=' + course_id + '&sign=' + localStorage.getItem('mall_sign');
  768. }
  769. });
  770. var self = this;
  771. clipboard.on('success', function(e) {
  772. console.log("success")
  773. self.$message.success('复制成功');
  774. e.clearSelection();
  775. clipboard.destroy()
  776. });
  777. clipboard.on('error', function(e) {
  778. console.log("error")
  779. self.$message.error('复制失败,请手动复制');
  780. });
  781. },
  782. // 课程联动获取目录列表
  783. getDirList(course_id) {
  784. var self = this;
  785. self.listLoading = true;
  786. // console.log('getDirList course_id: ', course_id);
  787. request({
  788. params: {
  789. r: 'course/directory/list',
  790. course_id: course_id,
  791. list_type: 2
  792. },
  793. method: 'get',
  794. }).then(e => {
  795. // console.log('dir list:', ...e.data.data.tree);return null;
  796. self.listLoading = false;
  797. if (0 == e.data.code) {
  798. self.directory_list = [];
  799. self.directory_list.push(...e.data.data.tree);
  800. // 给每个目录赋值一个下标位置
  801. let uncategorized = self.directory_list.filter(v => v.id == 0).length;
  802. let maxLength = self.directory_list.length;
  803. if (uncategorized > 0) {
  804. maxLength = self.directory_list.length - 1;
  805. }
  806. self.directory_list.forEach((v, i) => {
  807. if (v.id != 0) {
  808. self.$set(v, "sort", i);
  809. if (!v.children) {
  810. self.$set(v, "children", []);
  811. }
  812. if (maxLength == i + 1) {
  813. self.$set(v, "end", 1); //是否在最底部
  814. } else {
  815. self.$set(v, "end", 0);
  816. }
  817. if (v.children) {
  818. v.children.forEach((vv, j) => {
  819. self.$set(vv, "sort", j);
  820. if (v.children.length == j + 1) {
  821. self.$set(vv, "end", 1);
  822. } else {
  823. self.$set(vv, "end", 0);
  824. }
  825. })
  826. }
  827. }
  828. })
  829. // console.info(self.directory_list);
  830. self.chapter_all_count = e.data.data.all_count;
  831. } else {
  832. this.$message({
  833. message: e.data.msg,
  834. type: 'error'
  835. });
  836. }
  837. }).catch(e => {
  838. this.$message({
  839. message: '网络错误',
  840. type: 'error'
  841. });
  842. });
  843. },
  844. handleSelected(res) {
  845. // console.log('视频信息:', res);
  846. // console.log("视频首图地址:", res[0].thumb_url)
  847. if (res.length) {
  848. this.ruleForm.thumb_url = res[0].thumb_url;
  849. this.selectedVideo = '已选择: ' + res[0].name;
  850. } else {
  851. this.ruleForm.thumb_url = '';
  852. this.selectedVideo = '';
  853. }
  854. },
  855. search() {
  856. this.page = 1;
  857. this.getList();
  858. },
  859. pagination(currentPage) {
  860. let self = this;
  861. self.page = currentPage;
  862. self.getList();
  863. },
  864. // 0.1 获取章节列表
  865. getList() {
  866. let self = this;
  867. self.listLoading = true;
  868. var course_id = getQuery('id');
  869. var params = {
  870. r: 'course/default/chapters',
  871. page: self.page,
  872. keyword: this.keyword
  873. }
  874. if (course_id) {
  875. params.course_id = course_id;
  876. }
  877. if (this.dir_id) {
  878. params.dir_id = this.dir_id;
  879. }
  880. if (this.parent_id) {
  881. params.parent_id = this.parent_id;
  882. }
  883. // console.log("params :", params)
  884. request({
  885. params: params,
  886. method: 'get',
  887. }).then(e => {
  888. // console.log(e);
  889. self.listLoading = false;
  890. if (e.data.code == 0) {
  891. self.list = e.data.data.list;
  892. self.course_info = e.data.data.course_info;
  893. self.pageCount = e.data.data.page_count;
  894. } else {
  895. this.$message({
  896. message: e.data.msg,
  897. type: 'error'
  898. });
  899. }
  900. }).catch(e => {
  901. console.log(e);
  902. });
  903. },
  904. //删除单个章节
  905. chapterDelete(row, index) {
  906. let self = this;
  907. self.$confirm('删除该章节, 是否继续?', '提示', {
  908. confirmButtonText: '确定',
  909. cancelButtonText: '取消',
  910. type: 'warning'
  911. }).then(() => {
  912. self.listLoading = true;
  913. request({
  914. params: {
  915. r: 'course/chapter/delete',
  916. },
  917. method: 'post',
  918. data: {
  919. chapter_id: row.id,
  920. course_id: row.course_id
  921. }
  922. }).then(e => {
  923. self.listLoading = false;
  924. if (e.data.code === 0) {
  925. self.$message.success(e.data.msg);
  926. self.list.splice(index, 1);
  927. self.getDirList(getQuery('id'));
  928. } else {
  929. self.$message.error(e.data.msg);
  930. }
  931. }).catch(e => {
  932. console.log(e);
  933. });
  934. }).catch(() => {
  935. self.$message.info('已取消删除')
  936. });
  937. },
  938. // 批量删除章节
  939. multipleChapterDelete(course_id) {
  940. // console.log('multipleChapterDelete: ', this.multipleSelection);
  941. var chapter_ids = [];
  942. for (i in this.multipleSelection) {
  943. chapter_ids.push(this.multipleSelection[i].id);
  944. }
  945. var course_id = this.course_info.id;
  946. // console.log('multipleChapterDelete ids:', chapter_ids);
  947. request({
  948. params: {
  949. r: 'course/chapter/delete',
  950. },
  951. method: 'post',
  952. data: {
  953. chapter_id: chapter_ids,
  954. course_id: course_id
  955. }
  956. }).then(e => {
  957. var self = this;
  958. // self.listLoading = true;
  959. if (0 == e.data.code) {
  960. this.$message.success(e.data.msg);
  961. setTimeout(() => {
  962. self.getList();
  963. self.getDirList(getQuery('id'));
  964. }, 1000);
  965. } else {
  966. this.$message.error(e.data.msg);
  967. }
  968. }).catch(e => {
  969. console.log(e);
  970. });
  971. },
  972. switchStatus(id, can_see) {
  973. let obj = {
  974. id: id,
  975. can_see: can_see,
  976. }
  977. this.dialogLoading2 = true;
  978. //console.log("请求前得参数="+JSON.stringify(obj))
  979. request({
  980. method: 'post',
  981. params: {
  982. r: 'course/chapter/switch-status',
  983. },
  984. data: obj
  985. }).then(e => {
  986. this.dialogVisible = false;
  987. this.dialogLoading2 = false;
  988. //console.log("请求结果="+JSON.stringify(e))
  989. //this.getList();
  990. if (e.data.code === 0) {
  991. this.$message.success(e.data.msg);
  992. } else {
  993. this.$message.error(e.data.msg);
  994. }
  995. }).catch(e => {});
  996. },
  997. // 查看不可编辑
  998. toLook(row, index) {
  999. // console.log(row, index);
  1000. this.selectIndex = index;
  1001. this.selectRow = row;
  1002. this.dialogFormVisible = true;
  1003. for (key in row) {
  1004. for (key1 in this.ruleForm) {
  1005. if (key1 == key) {
  1006. this.ruleForm[key1] = row[key]
  1007. }
  1008. }
  1009. }
  1010. if (index == 0) {
  1011. console.log("add");
  1012. let self = this;
  1013. self.listLoading = true;
  1014. self.ruleForm = {
  1015. goods_list: [],
  1016. goods: [],
  1017. sort: 1,
  1018. name: '',
  1019. video_url: '',
  1020. type: 1,
  1021. can_see: 0,
  1022. course_id: "",
  1023. id: 0,
  1024. };
  1025. self.ruleForm.goods_list = []
  1026. self.ruleForm.goods = []
  1027. self.dialogText = '创建章节';
  1028. request({
  1029. params: {
  1030. r: 'course/chapter/storage',
  1031. page: self.page,
  1032. keyword: this.keyword
  1033. },
  1034. method: 'get',
  1035. }).then(e => {
  1036. self.listLoading = false;
  1037. self.courseList = e.data.data.courseList;
  1038. self.courseDirList(self.course_info.id);
  1039. self.ruleForm.course_id = self.course_info.id;
  1040. }).catch(e => {
  1041. console.log(e);
  1042. });
  1043. } else {
  1044. // console.log("edit");
  1045. let self = this;
  1046. self.listLoading = true;
  1047. self.dialogText = '编辑章节';
  1048. self.ruleForm = row;
  1049. // console.log("goods_list:", self.ruleForm.goods_list)
  1050. // console.log("goods:", self.ruleForm.goods)
  1051. self.ruleForm.goods_list = []
  1052. self.ruleForm.goods = []
  1053. request({
  1054. params: {
  1055. r: 'course/chapter/storage',
  1056. id: row.id,
  1057. course_id: row.course_id
  1058. },
  1059. method: 'get',
  1060. }).then(e => {
  1061. self.listLoading = false;
  1062. self.courseList = e.data.data.courseList;
  1063. self.ruleForm.goods = e.data.data.goods;
  1064. // console.log("goods:", self.ruleForm.goods, " type:", typeof self.ruleForm.goods)
  1065. self.ruleForm.goods_list = e.data.data.goods_list;
  1066. // console.log("goods_list:", self.ruleForm.goods_list, "type:", typeof self.ruleForm.goods_list)
  1067. // console.log(self.ruleForm, '11');
  1068. self.dir_list = e.data.data.directory_list;
  1069. }).catch(e => {
  1070. console.log(e);
  1071. });
  1072. }
  1073. return false;
  1074. },
  1075. deleteGoods(index) {
  1076. this.ruleForm.goods.splice(index, 1);
  1077. // console.log("goods_list:", this.ruleForm.goods_list, " typeof :", typeof this.ruleForm.goods_list)
  1078. this.ruleForm.goods_list.splice(index, 1);
  1079. // console.log("deleteGoods:", this.ruleForm.goods_list)
  1080. },
  1081. goodsSelect(list) {
  1082. // console.log("goodsSelect:", list)
  1083. for (let j in list) {
  1084. let item = list[j];
  1085. if (this.ruleForm.goods_list.length >= 5) {
  1086. this.$message.error('指定商品不能大于5个');
  1087. return;
  1088. }
  1089. let flag = true;
  1090. for (let i in this.ruleForm.goods_list) {
  1091. if (this.ruleForm.goods_list[i] == item.id) {
  1092. flag = false;
  1093. break;
  1094. }
  1095. }
  1096. if (flag) {
  1097. this.ruleForm.goods_list.push(item.id);
  1098. // console.log("goods:", this.ruleForm.goods, " typeof:", typeof this.ruleForm.goods)
  1099. this.ruleForm.goods.push({
  1100. id: item.id,
  1101. name: item.goods_name,
  1102. cover_pic: item.cover_pic,
  1103. });
  1104. }
  1105. }
  1106. },
  1107. editSave() {
  1108. if (this.ruleForm.video_url == '' && this.ruleForm.audio_url == '') {
  1109. this.$message.error('请上传视频文件或音频文件');
  1110. return;
  1111. }
  1112. if (this.ruleForm.can_see === 1 && (this.ruleForm.can_see_time <= 0 || isEmpty(this.ruleForm.can_see_time))) {
  1113. this.$message.error('请设置试看时长');
  1114. return;
  1115. }
  1116. if (!this.ruleForm.dir_id) {
  1117. this.ruleForm.dir_id = 0;
  1118. }
  1119. this.editBtnLoading = true;
  1120. var params = {};
  1121. var id = this.ruleForm.id;
  1122. if (id == 0) {
  1123. params = {
  1124. r: 'course/chapter/storage',
  1125. };
  1126. } else {
  1127. params = {
  1128. r: 'course/chapter/storage',
  1129. id: id,
  1130. };
  1131. }
  1132. var self = this;
  1133. self.editBtnLoading = true;
  1134. request({
  1135. params: params,
  1136. method: 'post',
  1137. data: this.ruleForm
  1138. }).then(response => {
  1139. self.editBtnLoading = false;
  1140. self.selectedVideo = '';
  1141. if (response.data.code == 0) {
  1142. self.$message.success(response.data.msg);
  1143. self.dialogFormVisible = false;
  1144. self.ruleForm = {
  1145. goods_list: [],
  1146. goods: [],
  1147. sort: 1,
  1148. name: '',
  1149. video_url: '',
  1150. audio_url: '',
  1151. can_see: 0,
  1152. course_id: 0,
  1153. id: 0,
  1154. }
  1155. self.goods = null;
  1156. self.level_list = [];
  1157. self.editCancel();
  1158. self.$emit('success', true);
  1159. self.getList();
  1160. self.getDirList(getQuery('id'));
  1161. } else {
  1162. self.$message.error(response.data.msg);
  1163. }
  1164. }).catch(response => {
  1165. self.editbtnLoading = false;
  1166. });
  1167. },
  1168. editCancel() {
  1169. this.$emit('input', false);
  1170. },
  1171. // 添加一级目录
  1172. addDirectory() {
  1173. let title = "新增目录";
  1174. let label = "目录名称";
  1175. let value = '';
  1176. this.$prompt(label, title, {
  1177. inputValue: value,
  1178. confirmButtonText: '确定',
  1179. cancelButtonText: '取消',
  1180. inputValidator: data => {
  1181. return data != null && (data + "").trim().length > 0;
  1182. },
  1183. inputErrorMessage: '名称不能为空'
  1184. }).then(({
  1185. value
  1186. }) => {
  1187. var self = this;
  1188. self.editBtnLoading = true;
  1189. request({
  1190. params: {
  1191. r: 'course/directory/add-dir'
  1192. },
  1193. method: 'post',
  1194. data: {
  1195. course_id: getQuery('id'),
  1196. name: value,
  1197. dir_type: 1,
  1198. }
  1199. }).then(response => {
  1200. self.editBtnLoading = false;
  1201. if (response.data.code == 0) {
  1202. self.$message.success(response.data.msg);
  1203. self.getDirList(getQuery('id'));
  1204. } else {
  1205. self.$message.error(response.data.msg);
  1206. }
  1207. }).catch(response => {
  1208. this.edit.btnLoading = false;
  1209. self.$message.error('网络错误');
  1210. });
  1211. }).catch(() => {
  1212. /* this.$message({
  1213. type: 'info',
  1214. message: '取消输入'
  1215. }); */
  1216. });
  1217. },
  1218. // 添加子目录
  1219. addChild(data, node, type) {
  1220. // console.log('add child type:', type);return null;
  1221. // console.info(data, node);return null;
  1222. let title = "新增子目录";
  1223. let label = "子目录名称";
  1224. let value = '';
  1225. if (type == 2) {
  1226. // 编辑
  1227. title = "子目录重命名";
  1228. value = data.label;
  1229. }
  1230. let id = 100;
  1231. this.$prompt(label, title, {
  1232. inputValue: value,
  1233. confirmButtonText: '确定',
  1234. cancelButtonText: '取消',
  1235. inputValidator: data => {
  1236. return data != null && (data + "").trim().length > 0;
  1237. },
  1238. inputErrorMessage: '名称不能为空'
  1239. }).then(({
  1240. value
  1241. }) => {
  1242. var self = this;
  1243. self.editBtnLoading = true;
  1244. var params = {};
  1245. var data_submit = {};
  1246. if (1 == type) {
  1247. // 添加子级目录
  1248. params = {
  1249. r: 'course/directory/add-dir'
  1250. };
  1251. data_submit = {
  1252. parent_id: data.id,
  1253. course_id: data.course_id,
  1254. name: value,
  1255. dir_type: 2,
  1256. };
  1257. } else if (2 == type) {
  1258. // 重命名子级目录
  1259. params = {
  1260. r: 'course/directory/rename'
  1261. };
  1262. data_submit = {
  1263. id: data.id,
  1264. name: value,
  1265. course_id: data.course_id,
  1266. };
  1267. }
  1268. // console.log('add child params+data: ', params, data_submit);return null;
  1269. request({
  1270. params: params,
  1271. method: 'post',
  1272. data: data_submit
  1273. }).then(response => {
  1274. self.editBtnLoading = false;
  1275. if (response.data.code == 0) {
  1276. self.$message.success(response.data.msg);
  1277. self.getDirList(data.course_id);
  1278. } else {
  1279. self.$message.error(response.data.msg);
  1280. }
  1281. }).catch(response => {
  1282. self.edit.btnLoading = false;
  1283. self.$message.error('网络错误');
  1284. });
  1285. // if (type == 2) {
  1286. // const parent = node.parent;
  1287. // const children = parent.data.children || parent.data;
  1288. // const index = children.findIndex(d => d.id === data.id);
  1289. // let newChild = children[index];
  1290. // newChild.label = value;
  1291. // children.splice(index, 1, newChild);
  1292. // } else {
  1293. // const newChild = {
  1294. // id: id++,
  1295. // label: value,
  1296. // children: []
  1297. // };
  1298. // if (!data.children) {
  1299. // this.$set(data, 'children', []);
  1300. // }
  1301. // data.children.push(newChild);
  1302. // }
  1303. // console.log(newChild);
  1304. // return null;
  1305. }).catch(() => {
  1306. /* this.$message({
  1307. type: 'info',
  1308. message: '取消输入'
  1309. }); */
  1310. });
  1311. },
  1312. // 删除目录
  1313. removeChild(data, node) {
  1314. var self = this;
  1315. self.editBtnLoading = true;
  1316. this.$confirm('是否永久删除 "' + data.label + '" 目录?', '提示', {
  1317. confirmButtonText: '删除',
  1318. cancelButtonText: '取消',
  1319. type: 'warning'
  1320. }).then(() => {
  1321. request({
  1322. params: {
  1323. r: 'course/directory/delete'
  1324. },
  1325. method: 'post',
  1326. data: {
  1327. id: data.id
  1328. }
  1329. }).then(response => {
  1330. self.editBtnLoading = false;
  1331. if (response.data.code == 0) {
  1332. // self.$message.success(response.data.msg);
  1333. const parent = node.parent;
  1334. const children = parent.data.children || parent.data;
  1335. const index = children.findIndex(d => d.id === data.id);
  1336. children.splice(index, 1);
  1337. this.$message({
  1338. type: 'success',
  1339. message: '删除成功!'
  1340. });
  1341. } else {
  1342. self.$message.error(response.data.msg);
  1343. }
  1344. }).catch(response => {
  1345. this.edit.btnLoading = false;
  1346. self.$message.error('网络错误');
  1347. });
  1348. }).catch(() => {
  1349. console.log('已取消删除');
  1350. });
  1351. },
  1352. /*
  1353. * 移动目录,改变排序
  1354. * type: 1(上移) 2(下移)
  1355. */
  1356. moveChild(data, node, type) {
  1357. // console.log('moveChild: ');
  1358. // console.info(data, node, type, node.id);
  1359. // console.info(this.directory_list);
  1360. const parent = node.parent;
  1361. const children = parent.data.children || parent.data;
  1362. const index = children.findIndex(d => d.id === data.id);
  1363. let info = children[index];
  1364. let uncategorized = this.directory_list.filter(v => v.id == 0).length;
  1365. directoryListLength = this.directory_list.length - 1;
  1366. if (uncategorized) {
  1367. directoryListLength = this.directory_list.length - 2;
  1368. }
  1369. if (data.children) {
  1370. // 一级目录
  1371. let info = children[index];
  1372. let byIndex = -1;
  1373. if (type == 2) {
  1374. byIndex = index + 1;
  1375. } else {
  1376. byIndex = index - 1;
  1377. }
  1378. // debugger;
  1379. if (type == 2 && index + 1 == directoryListLength) {
  1380. // 跟最后一个位置替换
  1381. children[index].end = 1;
  1382. children[byIndex].end = 0;
  1383. } else if (index == directoryListLength) {
  1384. children[index].end = 0;
  1385. children[byIndex].end = 1;
  1386. }
  1387. // debugger;
  1388. if (type == 2) {
  1389. children[index].sort += 1;
  1390. children[byIndex].sort -= 1;
  1391. children.splice(index, 1, children[byIndex]);
  1392. children.splice(byIndex, 1, info);
  1393. } else {
  1394. children[index].sort -= 1;
  1395. children[byIndex].sort += 1;
  1396. children.splice(index, 1, children[byIndex]);
  1397. children.splice(byIndex, 1, info);
  1398. }
  1399. this.directory_list = [];
  1400. this.directory_list.push(...children);
  1401. } else {
  1402. // 二级目录换位置;
  1403. let directory = this.directory_list.filter(v => v.id == data.parent_id)[0]; //获取父元素
  1404. let copyDirectory = JSON.parse(JSON.stringify(directory)); //由于删除children对象,directory的children也会被删,所以备份一份
  1405. let parentIndex = this.directory_list.findIndex(d => d.id === directory.id); //获取父元素的下标
  1406. let byIndex = -1;
  1407. if (type == 2) {
  1408. byIndex = index + 1;
  1409. } else {
  1410. byIndex = index - 1;
  1411. }
  1412. // debugger;
  1413. let childrenInfo = copyDirectory.children[byIndex];
  1414. if (type == 2 && index + 1 == copyDirectory.children.length - 1) {
  1415. childrenInfo.end = 0;
  1416. info.end = 1;
  1417. } else if (index == copyDirectory.children.length - 1) {
  1418. childrenInfo.end = 1;
  1419. info.end = 0;
  1420. }
  1421. if (type == 2) {
  1422. childrenInfo.sort -= 1;
  1423. info.sort += 1;
  1424. // console.info(byIndex,copyDirectory.children.length - 1);
  1425. copyDirectory.children.splice(index, 1, childrenInfo);
  1426. copyDirectory.children.splice(byIndex, 1, info);
  1427. } else {
  1428. childrenInfo.sort += 1;
  1429. info.sort -= 1;
  1430. copyDirectory.children.splice(index, 1, childrenInfo);
  1431. copyDirectory.children.splice(byIndex, 1, info);
  1432. }
  1433. this.$delete(this.directory_list[parentIndex], "children");
  1434. this.$set(this.directory_list[parentIndex], "children", copyDirectory.children);
  1435. }
  1436. console.log(data.id, type);
  1437. var self = this;
  1438. self.lableLoading = true;
  1439. request({
  1440. params: {
  1441. r: 'course/directory/sort-dir',
  1442. id: data.id,
  1443. type: type
  1444. },
  1445. method: 'get'
  1446. }).then(e => {
  1447. self.lableLoading = false;
  1448. if (0 !== e.data.code) {
  1449. self.getDirList(data.course_id);
  1450. }
  1451. }).catch(e => {
  1452. // console.log(e);
  1453. self.$message.error('网络错误');
  1454. });
  1455. },
  1456. // 打开移动对话框
  1457. moveToDirectory(course_id) {
  1458. if (this.multipleSelection.length == 0) {
  1459. this.$message.error('请先选择章节');
  1460. return;
  1461. }
  1462. this.shiftVisible = true;
  1463. this.checkDirectoryId = -1;
  1464. },
  1465. // 选中目录触发
  1466. handleNodeClick(val) {
  1467. this.checkDirectoryId = val.id;
  1468. },
  1469. // 移动--确定
  1470. subShifVisible() {
  1471. // 判断是否有选中目录
  1472. if (this.checkDirectoryId == -1) {
  1473. this.$message.error('请选择目录');
  1474. return;
  1475. }
  1476. // 获取表格选中的章节
  1477. let ids = [];
  1478. this.multipleSelection.forEach(v => {
  1479. ids.push(v.id);
  1480. });
  1481. // console.info(ids,this.checkDirectoryId, this.course_info.id);
  1482. var self = this;
  1483. request({
  1484. params: {
  1485. r: 'course/directory/move-chapters'
  1486. },
  1487. method: 'post',
  1488. data: {
  1489. course_id: self.course_info.id,
  1490. chapter_id: ids,
  1491. target_dir_id: self.checkDirectoryId
  1492. }
  1493. }).then(e => {
  1494. this.shiftVisible = false;
  1495. if (0 == e.data.code) {
  1496. self.getList();
  1497. self.getDirList(self.course_info.id);
  1498. self.$message.success(e.data.msg);
  1499. } else {
  1500. self.$message.error(e.data.msg);
  1501. }
  1502. }).catch(e => {
  1503. // console.log(e);
  1504. self.$message.error('网络错误');
  1505. });
  1506. },
  1507. // 跳转课程编辑页面
  1508. editCourse(course_id) {
  1509. navigateTo({
  1510. r: 'course/course/course-edit',
  1511. id: course_id,
  1512. });
  1513. },
  1514. onAllNode() {
  1515. this.dir_id = 0
  1516. this.parent_id = 0
  1517. this.getList()
  1518. }
  1519. },
  1520. mounted: function() {
  1521. this.getList();
  1522. this.getDirList(getQuery('id'));
  1523. }
  1524. });
  1525. </script>