detail.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. <!-- 音乐专辑 详情 -->
  2. <template>
  3. <div class="app-container">
  4. <el-form class="form" :model="form" ref="form" :rules="rules" label-width="100px" :disabled="disabled">
  5. <el-form-item label="专辑名称:" prop="name">
  6. <el-input v-model="form.name" placeholder="请输入专辑名称" />
  7. </el-form-item>
  8. <el-form-item label="专辑介绍" prop="description">
  9. <el-input v-model="form.description" type="textarea" :autosize="{ minRows: 5, maxRows: 10 }" maxlength="300"
  10. show-word-limit placeholder="请输入专辑介绍" />
  11. </el-form-item>
  12. <el-form-item label="专辑类型:" prop="albumType">
  13. <el-select v-model="form.albumType" placeholder="请选择专辑类型">
  14. <el-option v-for="item in albumTypeOptions" :key="item.value" :value="item.value" :label="item.label" />
  15. </el-select>
  16. </el-form-item>
  17. <el-form-item label="资源平台:" prop="platformId">
  18. <el-select v-model="form.platformId" placeholder="请选择资源平台" :disabled="disabledPlatformId(form.platformId)">
  19. <el-option v-for="item in platformOptions" :key="item.value" :value="item.value" :label="item.label"
  20. :disabled="disabledJoinType(item.joinType)" />
  21. </el-select>
  22. </el-form-item>
  23. <el-form-item label="付费类型:" prop="payType">
  24. <el-select v-model="form.payType" placeholder="请选择付费类型">
  25. <el-option v-for="item in payTypeOptions" :key="item.value" :value="item.value" :label="item.label" />
  26. </el-select>
  27. </el-form-item>
  28. <el-form-item v-if="form.payType !== 1" label="原价:" prop="price">
  29. <el-input-number v-model="form.price" placeholder="请输入原价" :min="1" :precision="2" :controls="false" />
  30. </el-form-item>
  31. <el-form-item v-if="form.payType !== 1" label="折扣价:" prop="discount">
  32. <el-input-number v-model="form.discount" placeholder="请输入折扣价" :min="1" :precision="2" :controls="false" />
  33. </el-form-item>
  34. <el-form-item label="专辑封面:" prop="coverUrl">
  35. <Upload listType="picture-card" :url="form.coverUrl" @upload="upload($event, 'coverUrl')"
  36. :disabled="disabled" />
  37. </el-form-item>
  38. <el-form-item label="歌曲列表:" style="width: 100%">
  39. <el-button type="primary" icon="el-icon-plus" @click="getDialog">添加歌曲</el-button>
  40. <!-- 列表 -->
  41. <el-table :data="form.programList" v-loading="form_loading">
  42. <el-table-column label="ID" prop="id" align="center" />
  43. <el-table-column label="歌曲名称" prop="name" align="center" show-overflow-tooltip />
  44. <el-table-column label="歌手名称" prop="singerName" align="center" show-overflow-tooltip />
  45. <el-table-column label="播放时长" prop="playTime" align="center" />
  46. <el-table-column label="当前状态" prop="status" align="center" :formatter="statusFormatter" />
  47. <el-table-column label="序号" align="center">
  48. <template slot-scope="scope">
  49. <div v-if="currentEditIndex !== scope.$index">
  50. <span :style="{ marginRight: (canOrder) ? '0px' : '8px' }">
  51. {{ (dialogForm.pageNum - 1) * dialogForm.pageSize + scope.$index + 1 }}
  52. </span>
  53. <svg-icon v-if="canOrder" icon-class="edit" @click.native="handleEditClick(scope.row, scope.$index)" />
  54. </div>
  55. <el-input v-else v-model="editData.sortIndex" size="mini" style="width:60px;" type="number"
  56. @blur="onNumberBlur(scope.row, scope.$index)" placeholder="序号" ref="numberInput" />
  57. </template>
  58. </el-table-column>
  59. <el-table-column label="操作" align="center">
  60. <template slot-scope="scope">
  61. <Audio :src="scope.row.progaramUrl" />
  62. <el-button type="delete" :disabled="disabled" @click="getDelete(scope.$index)">删除</el-button>
  63. <!-- 向上移动 -->
  64. <el-button type="text" icon="el-icon-caret-top" @click="getChange(true, scope.$index, scope.$index - 1)"
  65. :disabled="(scope.$index < 1 && !disabled) ||
  66. disabledPlatformId(form.platformId)
  67. " />
  68. <!-- 向下移动 -->
  69. <el-button type="text" icon="el-icon-caret-bottom"
  70. @click="getChange(false, scope.$index, scope.$index + 1)" :disabled="(scope.$index > form.programList.length - 2 && !disabled) ||
  71. disabledPlatformId(form.platformId)
  72. " />
  73. </template>
  74. </el-table-column>
  75. </el-table>
  76. </el-form-item>
  77. </el-form>
  78. <div class="form-btn">
  79. <el-button @click="cancel">取消</el-button>
  80. <el-button v-if="!disabled" type="primary" @click="getSubmit">确定</el-button>
  81. </div>
  82. <!-- 弹窗 -->
  83. <el-dialog :visible.sync="dialogVisible" title="添加歌曲" width="1100px">
  84. <el-form inline size="mini" style="width: 100%">
  85. <el-form-item label="歌曲名称:">
  86. <el-input v-model="dialogForm.name" placeholder="请输入歌曲名称" clearable />
  87. </el-form-item>
  88. <el-form-item label="歌手名称:">
  89. <el-input v-model="dialogForm.singerName" placeholder="请输入歌手名称" clearable />
  90. </el-form-item>
  91. <el-form-item label="资源平台:">
  92. <el-select v-model="dialogForm.platformId" placeholder="请选择资源平台">
  93. <el-option v-for="item in platformOptions.filter(
  94. (i) => !i.joinType.includes('1')
  95. )" :key="item.value" :value="item.value" :label="item.label" />
  96. </el-select>
  97. </el-form-item>
  98. <el-form-item>
  99. <el-button type="primary" icon="el-icon-search" @click="getSearch">搜索</el-button>
  100. <el-button icon="el-icon-refresh" @click="getRefresh">重置</el-button>
  101. </el-form-item>
  102. </el-form>
  103. <el-table :data="tableData" ref="multipleTable" :row-key="tableKey" v-loading="loading"
  104. @selection-change="handleSelectionChange">
  105. <el-table-column type="selection" align="center" key="selection" reserve-selection />
  106. <el-table-column label="ID" prop="id" align="center" />
  107. <el-table-column label="歌曲名称" prop="name" align="center" show-overflow-tooltip />
  108. <el-table-column label="歌手名称" prop="singerName" align="center" show-overflow-tooltip />
  109. <el-table-column label="播放时长" prop="playTime" align="center" />
  110. <!-- <el-table-column label="操作" align="center">
  111. <template slot-scope="scope">
  112. <el-button
  113. type="text"
  114. @click="getChecked(scope.row)"
  115. :disabled="
  116. form.programList.findIndex((i) => i.id === scope.row.id) === -1
  117. ? false
  118. : true
  119. "
  120. >
  121. 选择
  122. </el-button>
  123. </template>
  124. </el-table-column> -->
  125. </el-table>
  126. <pagination v-show="total > 0" :total="total" :page.sync="dialogForm.pageNum" :limit.sync="dialogForm.pageSize"
  127. @pagination="getList" />
  128. </el-dialog>
  129. </div>
  130. </template>
  131. <script>
  132. import { list } from "@/api/music/list";
  133. import { detail, submit } from "@/api/music/menu";
  134. import Audio from "@/components/Audio/index.vue";
  135. import {
  136. albumTypeMixin,
  137. onOrOffMixin,
  138. payTypeMixin,
  139. platformMixin,
  140. } from "@/mixin/index";
  141. export default {
  142. name: "musicAlbumDetail",
  143. mixins: [platformMixin, onOrOffMixin, payTypeMixin, albumTypeMixin],
  144. components: {
  145. Audio,
  146. },
  147. data() {
  148. // 判断原价是否大于折扣价
  149. var checkPrice = (rule, value, callback) => {
  150. if (!value) {
  151. callback(new Error("请输入原价"));
  152. } else {
  153. if (this.form.discount && value <= this.form.discount) {
  154. callback(new Error("原价必须大于折扣价"));
  155. }
  156. callback();
  157. }
  158. };
  159. // 判断折扣价是否小于原价
  160. var checkDiscount = (rule, value, callback) => {
  161. if (this.form.price && value >= this.form.price) {
  162. callback(new Error("折扣价必须小于原价"));
  163. } else {
  164. callback();
  165. }
  166. };
  167. return {
  168. // 遮罩层
  169. form_loading: false,
  170. loading: false,
  171. // 表单
  172. form: {
  173. programList: [], // 歌曲列表
  174. status: 1,
  175. type: 1,
  176. },
  177. editData: {},
  178. currentEditIndex: -1,
  179. // 校验
  180. rules: {
  181. name: [
  182. {
  183. required: true,
  184. message: "请输入歌单名称",
  185. trigger: "blur",
  186. },
  187. ],
  188. description: [
  189. {
  190. required: true,
  191. message: "请输入歌单介绍",
  192. trigger: "blur",
  193. },
  194. ],
  195. albumType: [
  196. {
  197. required: true,
  198. message: "请选择专辑类型",
  199. trigger: "blur",
  200. },
  201. ],
  202. avatarNickName: [
  203. {
  204. required: true,
  205. message: "请输入歌单创建者名称",
  206. trigger: "blur",
  207. },
  208. ],
  209. platformId: [
  210. {
  211. required: true,
  212. message: "请选择资源平台",
  213. trigger: "change",
  214. },
  215. ],
  216. payType: [
  217. {
  218. required: true,
  219. message: "请选择付费类型",
  220. trigger: "change",
  221. },
  222. ],
  223. price: [
  224. {
  225. required: true,
  226. validator: checkPrice,
  227. trigger: "blur",
  228. },
  229. ],
  230. discount: [
  231. {
  232. validator: checkDiscount,
  233. trigger: "blur",
  234. },
  235. ],
  236. coverUrl: [
  237. {
  238. required: true,
  239. message: "请上传歌单封面",
  240. trigger: "change",
  241. },
  242. ],
  243. avatarNickHead: [
  244. {
  245. required: true,
  246. message: "请上传创建者头像",
  247. trigger: "change",
  248. },
  249. ],
  250. },
  251. // 弹窗
  252. dialogVisible: false,
  253. // 弹窗表单
  254. dialogForm: {
  255. pageNum: 1,
  256. pageSize: 10,
  257. status: 1,
  258. platformId: null,
  259. },
  260. // 总数据
  261. total: 0,
  262. // 弹窗列表
  263. tableData: [],
  264. // 只读
  265. disabled: false,
  266. // 是否已选
  267. disabledChecked: false,
  268. ///被选中数据是否加载完
  269. isLoad: false,
  270. ///是否可以调整顺序
  271. canOrder: true,
  272. };
  273. },
  274. mounted() {
  275. // 获取资源平台
  276. this.getPlatform({
  277. audioType: 15,
  278. });
  279. if (this.$route.query.id) {
  280. this.form.id = this.$route.query.id;
  281. this.disabled = Boolean(this.$route.query.disabled);
  282. this.getDetail();
  283. }
  284. },
  285. methods: {
  286. tableKey(row) {
  287. return row.id;
  288. },
  289. // 输入框失去焦点时隐藏
  290. onNumberBlur(row, index) {
  291. let newValue = Number(this.editData.sortIndex);
  292. const maxLen = this.form.programList.length;
  293. if (isNaN(newValue) || newValue === null || newValue === undefined) {
  294. this.currentEditIndex = -1;
  295. console.log('序号未修改:', newValue);
  296. return;
  297. }
  298. if (newValue < 1) {
  299. this.$message.warning('序号必须大于1');
  300. this.currentEditIndex = -1;
  301. return;
  302. }
  303. if (newValue > maxLen) {
  304. // 超出就是最后一位
  305. newValue = maxLen
  306. }
  307. if (newValue === -1 || newValue === '') {
  308. // 新值为空时处理
  309. this.currentEditIndex = -1;
  310. console.log('序号未修改:', newValue);
  311. return
  312. }
  313. console.log('序号修改:', newValue, '当前索引:', index, this.currentEditIndex);
  314. // 计算目标下标
  315. const targetIndex = newValue - 1;
  316. if (targetIndex === index) {
  317. this.currentEditIndex = -1;
  318. return;
  319. }
  320. // 交换两个元素
  321. // ...existing code...
  322. const movingItem = this.form.programList.splice(index, 1)[0];
  323. this.form.programList.splice(targetIndex, 0, movingItem);
  324. this.currentEditIndex = -1;
  325. this.$message.success("操作成功!");
  326. },
  327. // 点击编辑图标显示输入框
  328. handleEditClick(row, index) {
  329. if (!this.canOrder) {
  330. console.log('编辑功能已禁用', this.disabled, this.canOrder);
  331. return;
  332. }
  333. this.editData = {
  334. sortIndex: row.index,
  335. };
  336. this.currentEditIndex = index;
  337. this.$nextTick(() => {
  338. this.$refs.numberInput.focus();
  339. });
  340. },
  341. handleSelectionChange(val) {
  342. if (this.isLoad) {
  343. if (this.form.programList.length == 0) {
  344. this.form.programList = JSON.parse(JSON.stringify(val));
  345. } else {
  346. ///查找dialogTableData里面有的
  347. var tempDialogHas = [];
  348. for (var i = 0; i < this.tableData.length; i++) {
  349. for (var j = 0; j < val.length; j++) {
  350. if (this.tableData[i].id === val[j].id) {
  351. tempDialogHas.push(this.tableData[i]);
  352. break;
  353. }
  354. }
  355. }
  356. ///查找dialogTableData里面没有的
  357. var tempDialogNot = [];
  358. if (tempDialogHas.length == 0) {
  359. tempDialogNot = JSON.parse(JSON.stringify(this.tableData));
  360. } else {
  361. for (var i = 0; i < this.tableData.length; i++) {
  362. var has = false;
  363. for (var j = 0; j < tempDialogHas.length; j++) {
  364. if (this.tableData[i].id === tempDialogHas[j].id) {
  365. has = true;
  366. break;
  367. }
  368. }
  369. if (!has) {
  370. tempDialogNot.push(this.tableData[i]);
  371. }
  372. }
  373. }
  374. ///减少val没有的
  375. if (tempDialogNot.length > 0) {
  376. for (var i = 0; i < tempDialogNot.length; i++) {
  377. for (var j = 0; j < this.form.programList.length; j++) {
  378. if (tempDialogNot[i].id === this.form.programList[j].id) {
  379. this.form.programList.splice(j, 1);
  380. break;
  381. }
  382. }
  383. }
  384. }
  385. ///添加adminPodCastProgramDetailResp没有的
  386. for (var i = 0; i < val.length; i++) {
  387. var isHas = false;
  388. for (var j = 0; j < this.form.programList.length; j++) {
  389. if (val[i].id === this.form.programList[j].id) {
  390. isHas = true;
  391. break;
  392. }
  393. }
  394. if (!isHas) {
  395. this.form.programList.push(val[i]);
  396. }
  397. }
  398. }
  399. this.form.programList = this.form.programList.filter((i) => i);
  400. this.$message.success("操作成功!");
  401. }
  402. },
  403. //是否展示排序
  404. // isShowSort() {
  405. // if (this.form) {
  406. // if (!disabledPlatformId(form.platformId)) {
  407. // return ture;
  408. // }
  409. // }
  410. // return false;
  411. // },
  412. // 排序
  413. getChange(top, index, laterIndex) {
  414. var row = this.form.programList[index];
  415. var laterRow = this.form.programList[laterIndex];
  416. if (top) {
  417. this.form.programList[index] = laterRow;
  418. this.form.programList[laterIndex] = row;
  419. } else {
  420. this.form.programList[laterIndex] = row;
  421. this.form.programList[index] = laterRow;
  422. }
  423. this.form.programList = this.form.programList.filter((i) => i);
  424. },
  425. // 详情
  426. getDetail() {
  427. this.form_loading = true;
  428. detail(this.form.id).then((res) => {
  429. if (res.code === 0) {
  430. this.form = res.data;
  431. ///qq音乐和喜马拉雅
  432. if (this.form.platformId == 6 || this.form.platformId == 12) {
  433. this.canOrder = false;
  434. }
  435. this.form_loading = false;
  436. }
  437. });
  438. },
  439. // 上传
  440. upload(e, key) {
  441. this.form[key] = e.file;
  442. },
  443. // 添加歌曲
  444. getDialog() {
  445. this.dialogVisible = true;
  446. this.dialogForm.platformId = this.platformOptions.filter(
  447. (i) => !i.joinType.includes("1")
  448. )[0].value;
  449. this.getList();
  450. },
  451. // 列表
  452. getList() {
  453. this.loading = true;
  454. list(this.dialogForm).then((res) => {
  455. if (res.code === 0) {
  456. this.tableData = res.data.records;
  457. this.total = res.data.total;
  458. this.loading = false;
  459. this.isLoad = false;
  460. this.$refs.multipleTable.clearSelection();
  461. if (this.form.programList.length > 0) {
  462. var temp = [];
  463. for (var i = 0; i < this.tableData.length; i++) {
  464. for (var j = 0; j < this.form.programList.length; j++) {
  465. if (this.form.programList[j].id === this.tableData[i].id) {
  466. temp.push(this.tableData[i]);
  467. break;
  468. }
  469. }
  470. }
  471. if (temp.length > 0) {
  472. temp.forEach((item) => {
  473. this.$refs.multipleTable.toggleRowSelection(item, true);
  474. });
  475. }
  476. }
  477. this.isLoad = true;
  478. }
  479. });
  480. },
  481. // 搜索
  482. getSearch() {
  483. this.dialogForm.pageNum = 1;
  484. this.getList();
  485. },
  486. // 重置
  487. getRefresh() {
  488. this.dialogForm = {
  489. pageNum: 1,
  490. pageSize: 10,
  491. status: 1,
  492. platformId: this.platformOptions[0].value,
  493. };
  494. this.getList();
  495. },
  496. // 选择
  497. getChecked(row) {
  498. this.form.programList.push({
  499. id: row.id,
  500. name: row.name,
  501. singerName: row.singerName,
  502. playTime: row.playTime,
  503. status: row.status,
  504. progaramUrl: row.progaramUrl,
  505. });
  506. this.$message.success("添加成功!");
  507. },
  508. // 删除已选歌曲
  509. getDelete(index) {
  510. this.form.programList.splice(index, 1);
  511. },
  512. // 确定
  513. getSubmit() {
  514. this.$refs.form.validate((valid) => {
  515. if (valid) {
  516. if (this.form.programList) {
  517. let arr = [];
  518. this.form.programList.map((i) => {
  519. arr.push(i.id);
  520. });
  521. this.form.programList = arr;
  522. }
  523. this.form_loading = true;
  524. let title = this.form.id ? "编辑成功!" : "新增成功!";
  525. submit(this.form).then((res) => {
  526. if (res.code === 0) {
  527. this.$message.success(title);
  528. this.cancel();
  529. }
  530. // if (res.code === 0) {
  531. // this.$message.success(`${title}`);
  532. // if (!this.form.id) {
  533. // this.cancel();
  534. // } else {
  535. // this.getDetail();
  536. // }
  537. // }
  538. });
  539. } else {
  540. return false;
  541. }
  542. });
  543. },
  544. // 取消
  545. cancel() {
  546. this.$tab.closeOpenPage("/music/musicAlbum");
  547. },
  548. // 字典翻译
  549. statusFormatter(row) {
  550. return this.selectDictLabel(this.onOrOffOptions, row.status);
  551. },
  552. },
  553. };
  554. </script>
  555. <style lang="scss" scoped>
  556. .form {
  557. .el-form-item {
  558. width: 500px;
  559. }
  560. }
  561. </style>