split.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <template>
  2. <div class="split-root">
  3. <div class="p-2 flex">
  4. <!-- <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">-->
  5. <!-- <div v-show="showSearch" class="mb-[10px]"></div>-->
  6. <!-- 左侧示意图 -->
  7. <div class="w-1/3 p-2 border-r">示意图</div>
  8. <!-- 中间 Table -->
  9. <div class="w-1/3 p-2 border-r table-container">
  10. <el-radio-group v-model="screenNum" @change="screenChange">
  11. <el-radio-button label="第一屏" value="1" v-if="splitScreen !== 4" />
  12. <el-radio-button label="第二屏" value="2" v-if="splitScreen !== 4" />
  13. <el-radio-button label="第三屏" value="3" v-if="splitScreen === 3" />
  14. <el-radio-button label="播放框" value="4" v-if="splitScreen === 4" />
  15. </el-radio-group>
  16. <el-table :data="minioDataList" ref="minioTable"
  17. @selection-change="handleSelectionFile"
  18. @select="handleSelect"
  19. @select-all="handleSelectAll"
  20. style="margin-top: 20px">
  21. <el-table-column type="selection" width="55" align="center" />
  22. <el-table-column label="原名" align="left" prop="originalName" width="150" :show-overflow-tooltip="true" />
  23. <el-table-column label="类型" align="center" prop="type" width="80">
  24. <template #default="scope">
  25. <dict-tag :options="smsb_source_type" :value="scope.row.type" />
  26. </template>
  27. </el-table-column>
  28. <el-table-column label="大小" align="center" prop="size" />
  29. <el-table-column label="时长" align="center" prop="duration" />
  30. <el-table-column label="截图" align="center" prop="screenshot">
  31. <template #default="scope">
  32. <image-preview :src="scope.row.screenshot" style="width: 40px; height: 40px; cursor: pointer" />
  33. </template>
  34. </el-table-column>
  35. </el-table>
  36. <pagination v-show="fileTotal > 0" :total="fileTotal" v-model:page="dialogQueryParams.pageNum"
  37. v-model:limit="dialogQueryParams.pageSize" @pagination="getFileList" />
  38. </div>
  39. <!-- 右侧内容 -->
  40. <div class="w-1/3 p-2">
  41. <div v-if="screenNum === '1'" class="table-container">
  42. <el-table ref="selectedTable" :data="selectedFiles1" border>
  43. <!-- 显示排序数字 -->
  44. <el-table-column label="排序" width="80">
  45. <template #default="{ row }">
  46. <span class="order-number">{{ row.order }}</span>
  47. </template>
  48. </el-table-column>
  49. <el-table-column label="文件名">
  50. <template #default="{ row }">
  51. <span>{{ row.name }}</span>
  52. </template>
  53. </el-table-column>
  54. <el-table-column label="播放时长">
  55. <template #default="{ row }">
  56. <el-input-number v-model="row.duration" :min="1" :max="300"></el-input-number>
  57. </template>
  58. </el-table-column>
  59. </el-table>
  60. </div>
  61. <div v-if="screenNum === '2'" class="table-container">
  62. <el-table ref="selectedTable" :data="selectedFiles2" border>
  63. <!-- 显示排序数字 -->
  64. <el-table-column label="排序" width="80">
  65. <template #default="{ row }">
  66. <span class="order-number">{{ row.order }}</span>
  67. </template>
  68. </el-table-column>
  69. <el-table-column label="文件名">
  70. <template #default="{ row }">
  71. <span>{{ row.name }}</span>
  72. </template>
  73. </el-table-column>
  74. <el-table-column label="播放时长">
  75. <template #default="{ row }">
  76. <el-input-number v-model="row.duration" :min="1" :max="300"></el-input-number>
  77. </template>
  78. </el-table-column>
  79. </el-table>
  80. </div>
  81. <div v-if="screenNum === '3'" class="table-container">
  82. <el-table ref="selectedTable" :data="selectedFiles3" border>
  83. <!-- 显示排序数字 -->
  84. <el-table-column label="排序" width="80">
  85. <template #default="{ row }">
  86. <span class="order-number">{{ row.order }}</span>
  87. </template>
  88. </el-table-column>
  89. <el-table-column label="文件名">
  90. <template #default="{ row }">
  91. <span>{{ row.name }}</span>
  92. </template>
  93. </el-table-column>
  94. <el-table-column label="播放时长">
  95. <template #default="{ row }">
  96. <el-input-number v-model="row.duration" :min="1" :max="300"></el-input-number>
  97. </template>
  98. </el-table-column>
  99. </el-table>
  100. </div>
  101. <div v-if="screenNum === '4'" class="table-container">
  102. <el-table ref="selectedTable" :data="selectedFiles4" border>
  103. <!-- 显示排序数字 -->
  104. <el-table-column label="排序" width="80">
  105. <template #default="{ row }">
  106. <span class="order-number">{{ row.order }}</span>
  107. </template>
  108. </el-table-column>
  109. <el-table-column label="文件名">
  110. <template #default="{ row }">
  111. <span>{{ row.name }}</span>
  112. </template>
  113. </el-table-column>
  114. <el-table-column label="播放时长">
  115. <template #default="{ row }">
  116. <el-input-number v-model="row.duration" :min="1" :max="300"></el-input-number>
  117. </template>
  118. </el-table-column>
  119. </el-table>
  120. </div>
  121. </div>
  122. </div>
  123. <div class="button-container">
  124. <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
  125. <el-button @click="cancel">关 闭</el-button>
  126. </div>
  127. <div class="button-container">
  128. <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
  129. <el-button @click="cancel">关 闭</el-button>
  130. </div>
  131. </div>
  132. </template>
  133. <script setup name="ItemSplit" lang="ts">
  134. import { MinioDataQuery, MinioDataVO } from '@/api/smsb/source/minioData_type';
  135. import { splitItemInfo, updateItem, updateItemSplit } from '@/api/smsb/source/item';
  136. import { listMinioData } from '@/api/smsb/source/minioData';
  137. import { ItemSplitScreenVO } from '@/api/smsb/source/item_split_screen_type';
  138. import { ElTable } from 'element-plus';
  139. import { SplitUploadForm } from '@/api/smsb/source/item_type';
  140. const route = useRoute();
  141. const minioTable = ref(ElTable);
  142. // 选中的文件
  143. const selectedFiles1 = ref<{ id: number; name: string; duration: number; order: number }[]>([]);
  144. const selectedFiles2 = ref<{ id: number; name: string; duration: number; order: number }[]>([]);
  145. const selectedFiles3 = ref<{ id: number; name: string; duration: number; order: number }[]>([]);
  146. const selectedFiles4 = ref<{ id: number; name: string; duration: number; order: number }[]>([]);
  147. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  148. const { smsb_source_type } = toRefs<any>(proxy?.useDict('smsb_source_type'));
  149. const dialogData = reactive<DialogPageData<MinioDataQuery>>({
  150. dialogQueryParams: {
  151. pageNum: 1,
  152. pageSize: 10,
  153. params: {}
  154. }
  155. });
  156. const minioDataList = ref<MinioDataVO[]>([]);
  157. const screenNum = ref<string>();
  158. const itemSplitVo = ref<ItemSplitScreenVO>();
  159. const splitScreen = ref(0);
  160. const buttonLoading = ref(false);
  161. const itemId = ref<string>();
  162. const fileTotal = ref(0);
  163. const { dialogQueryParams } = toRefs(dialogData);
  164. const uploadForm = reactive<SplitUploadForm>({
  165. itemId: undefined,
  166. selectedFiles1: undefined,
  167. selectedFiles2: undefined,
  168. selectedFiles3: undefined,
  169. selectedFiles4: undefined
  170. });
  171. const screenChange = () => {
  172. console.log(screenNum.value);
  173. // minioTable.value.clearSelection();
  174. };
  175. const getParamItemId = () => {
  176. itemId.value = route.params.itemId as string;
  177. console.log(itemId.value);
  178. getItemInfo();
  179. };
  180. const getItemInfo = async () => {
  181. const res = await splitItemInfo(itemId.value);
  182. console.log(res.data);
  183. itemSplitVo.value = res.data;
  184. splitScreen.value = res.data.splitScreen;
  185. if (splitScreen.value === 4) {
  186. screenNum.value = '4';
  187. } else {
  188. screenNum.value = '1';
  189. }
  190. };
  191. // 多选框选中文件数据(与 index.vue 保持一致,支持增量、去重、排序)
  192. const handleSelectionFile = (selection: MinioDataVO[]) => {
  193. let selectedFilesRef;
  194. if (screenNum.value === '1') selectedFilesRef = selectedFiles1;
  195. if (screenNum.value === '2') selectedFilesRef = selectedFiles2;
  196. if (screenNum.value === '3') selectedFilesRef = selectedFiles3;
  197. if (screenNum.value === '4') selectedFilesRef = selectedFiles4;
  198. if (!selectedFilesRef) return;
  199. selection.forEach((item) => {
  200. if (!selectedFilesRef.value.some((f) => String(f.id) === String(item.id))) {
  201. selectedFilesRef.value.push({
  202. id: item.id,
  203. name: item.originalName,
  204. type: item.type,
  205. duration: item.type === 1 ? 10 : item.duration,
  206. order: 0
  207. });
  208. }
  209. });
  210. // 重新排序
  211. selectedFilesRef.value = selectedFilesRef.value.map((f, idx) => ({ ...f, order: idx + 1 }));
  212. };
  213. // 取消单个选中
  214. const handleSelect = (selection: MinioDataVO[], row: MinioDataVO) => {
  215. let selectedFilesRef;
  216. if (screenNum.value === '1') selectedFilesRef = selectedFiles1;
  217. if (screenNum.value === '2') selectedFilesRef = selectedFiles2;
  218. if (screenNum.value === '3') selectedFilesRef = selectedFiles3;
  219. if (screenNum.value === '4') selectedFilesRef = selectedFiles4;
  220. if (!selectedFilesRef) return;
  221. if (!selection.some((item) => String(item.id) === String(row.id))) {
  222. selectedFilesRef.value = selectedFilesRef.value.filter((f) => String(f.id) !== String(row.id));
  223. selectedFilesRef.value = selectedFilesRef.value.map((f, idx) => ({ ...f, order: idx + 1 }));
  224. }
  225. };
  226. // 取消全选
  227. const handleSelectAll = (selection: MinioDataVO[]) => {
  228. let selectedFilesRef;
  229. if (screenNum.value === '1') selectedFilesRef = selectedFiles1;
  230. if (screenNum.value === '2') selectedFilesRef = selectedFiles2;
  231. if (screenNum.value === '3') selectedFilesRef = selectedFiles3;
  232. if (screenNum.value === '4') selectedFilesRef = selectedFiles4;
  233. if (!selectedFilesRef) return;
  234. const currentPageIds = new Set(minioDataList.value.map((item) => String(item.id)));
  235. const selectedIds = new Set(selection.map((item) => String(item.id)));
  236. selectedFilesRef.value = selectedFilesRef.value.filter((f) => !currentPageIds.has(String(f.id)) || selectedIds.has(String(f.id)));
  237. selectedFilesRef.value = selectedFilesRef.value.map((f, idx) => ({ ...f, order: idx + 1 }));
  238. };
  239. /** 查询文件资源列表 */
  240. const getFileList = async () => {
  241. const res = await listMinioData(dialogQueryParams.value);
  242. minioDataList.value = res.rows.map((data) => ({
  243. ...data,
  244. size: (parseFloat(data.size) / 1024).toFixed(3) + 'MB'
  245. }));
  246. fileTotal.value = res.total;
  247. // 加载后自动恢复选中(与 index.vue 保持一致)
  248. nextTick(() => {
  249. let selectedFilesRef;
  250. if (screenNum.value === '1') selectedFilesRef = selectedFiles1;
  251. if (screenNum.value === '2') selectedFilesRef = selectedFiles2;
  252. if (screenNum.value === '3') selectedFilesRef = selectedFiles3;
  253. if (screenNum.value === '4') selectedFilesRef = selectedFiles4;
  254. if (!selectedFilesRef) return;
  255. if (selectedFilesRef.value?.length) {
  256. const selectedIds = new Set(selectedFilesRef.value.map((f) => f.id));
  257. minioDataList.value.forEach((row) => {
  258. if (selectedIds.has(row.id)) {
  259. minioTable.value?.toggleRowSelection(row, true);
  260. }
  261. });
  262. }
  263. });
  264. };
  265. /** 提交按钮 */
  266. const submitForm = async () => {
  267. buttonLoading.value = true;
  268. uploadForm.itemId = itemId.value;
  269. uploadForm.selectedFiles1 = selectedFiles1.value;
  270. uploadForm.selectedFiles2 = selectedFiles2.value;
  271. uploadForm.selectedFiles3 = selectedFiles3.value;
  272. uploadForm.selectedFiles4 = selectedFiles4.value;
  273. console.log(uploadForm);
  274. await updateItemSplit(uploadForm).finally(() => (buttonLoading.value = false));
  275. proxy?.$modal.msgSuccess('编辑成功');
  276. // 跳转页面进行数据关联
  277. proxy.$router.push('/source/item');
  278. };
  279. const cancel = () => {
  280. proxy.$router.push('/source/item');
  281. };
  282. onMounted(() => {
  283. getParamItemId();
  284. getFileList();
  285. });
  286. </script>
  287. <style scoped>
  288. .table-container {
  289. height: 900px;
  290. /* 设置固定高度,根据需要调整 */
  291. overflow-y: auto;
  292. /* 当内容超出时显示滚动条 */
  293. }
  294. .button-container {
  295. display: flex;
  296. justify-content: center;
  297. position: absolute;
  298. bottom: 0;
  299. left: 0;
  300. right: 0;
  301. padding: 10px 0;
  302. background-color: white;
  303. /* 可选:根据需要设置背景色 */
  304. box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
  305. /* 可选:添加阴影效果 */
  306. }
  307. </style>