| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875 |
- <template>
- <div class="p-2">
- <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
- :leave-active-class="proxy?.animate.searchAnimate.leave">
- <div v-show="showSearch" class="mb-[10px]">
- <el-card shadow="hover" :style="{ height: '70px' }">
- <el-row :gutter="20" align="middle">
- <!-- 节目总数 -->
- <el-col :span="8" class="statistic-col">
- <el-statistic :value="totalNum">
- <template #title>
- <div class="stat-title">节目总数</div>
- </template>
- </el-statistic>
- </el-col>
- <!-- 轮播总数 -->
- <el-col :span="8" class="statistic-col">
- <el-statistic :value="lbNum">
- <template #title>
- <div class="stat-title">轮播总数</div>
- </template>
- </el-statistic>
- </el-col>
- <!-- 分屏总数 -->
- <el-col :span="8" class="statistic-col">
- <el-statistic :value="jmNum">
- <template #title>
- <div class="stat-title">分屏总数</div>
- </template>
- </el-statistic>
- </el-col>
- </el-row>
- </el-card>
- <el-card shadow="hover" :style="{ marginTop: '10px', height: '60px' }">
- <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="40px">
- <el-form-item label="名称" prop="itemName">
- <el-input v-model="queryParams.itemName" style="width: 150px" placeholder="请输入名称" clearable
- @keyup.enter="handleQuery" />
- </el-form-item>
- <!-- <el-form-item label="类型" prop="itemType">
- <el-select v-model="queryParams.itemType" style="width: 150px" placeholder="请选择类型" clearable>
- <el-option v-for="dict in smsb_item_type" :key="dict.value" :label="dict.label" :value="dict.value" />
- </el-select>
- </el-form-item>-->
- <el-form-item label="时间" style="width: 250px">
- <el-date-picker v-model="dateRangeCreateTime" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
- range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
- :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker>
- </el-form-item>
- <el-form-item>
- <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
- <el-button icon="Refresh" @click="resetQuery">重置</el-button>
- <el-button type="primary" plain icon="Plus" @click="handleAddL" v-hasPermi="['source:item:add']"> 新增轮播组
- </el-button>
- <!-- <el-button type="primary" plain icon="Plus" @click="handleAddJ" v-hasPermi="['source:item:add']"> 新增分屏组
- </el-button>-->
- <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
- v-hasPermi="['source:item:edit']">修改
- </el-button>
- <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()"
- v-hasPermi="['source:item:remove']">删除
- </el-button>
- <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['source:item:export']">
- 导出
- </el-button>
- </el-form-item>
- </el-form>
- </el-card>
- </div>
- </transition>
- <el-card shadow="never">
- <div class="table-content">
- <el-table v-loading="mainLoading" :data="itemList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="ID" align="left" prop="id" v-if="true" width="180" :show-overflow-tooltip="true" />
- <el-table-column label="名称" align="left" prop="itemName" />
- <el-table-column label="类型" align="center" prop="itemType" width="120">
- <template #default="scope">
- <dict-tag :options="smsb_item_type" :value="scope.row.itemType" />
- </template>
- </el-table-column>
- <!-- <el-table-column label="分屏" align="center" prop="splitScreen" width="120">
- <template #default="scope">
- <span v-if="scope.row.splitScreen == 0"> --- </span>
- <dict-tag v-else :options="smsb_split_screen" :value="scope.row.splitScreen" />
- </template>
- </el-table-column>-->
- <el-table-column label="资源数量" align="center" prop="sourceNum" width="100" />
- <el-table-column label="创建人" align="left" prop="createUser" width="120" :show-overflow-tooltip="true" />
- <el-table-column label="创建时间" align="left" prop="createTime" width="160" />
- <el-table-column label="更新时间" align="left" prop="updateTime" width="160" />
- <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
- <template #default="scope">
- <el-tooltip content="修改" placement="top">
- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
- v-hasPermi="['source:item:edit']"></el-button>
- </el-tooltip>
- <el-tooltip content="删除" placement="top">
- <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
- v-hasPermi="['source:item:remove']"></el-button>
- </el-tooltip>
- <el-tooltip content="编辑历史" placement="top">
- <el-button link type="primary" icon="Clock" @click="onShowEditHistory(scope.row)"></el-button>
- </el-tooltip>
- </template>
- </el-table-column>
- <!-- 编辑历史弹窗 -->
- <el-dialog title="编辑历史" v-model="editHistoryDialog.visible" width="800px" append-to-body>
- <div class="edit-history-container" v-html="editHistoryDialog.tableHtml"></div>
- </el-dialog>
- </el-table>
- </div>
- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
- v-model:limit="queryParams.pageSize" @pagination="getList" />
- </el-card>
- <!-- 添加或修改轮播组对话框 -->
- <el-dialog :title="dialog.title" v-model="dialog.visible" width="1400px" append-to-body @close="onDialogClose">
- <div class="dialog-container">
- <!-- 左侧文件列表 -->
- <div class="table-container">
- <!-- 界面名称输入框 -->
- <el-input v-model="itemName" placeholder="请输入轮播组名称" class="interface-input"></el-input>
- <el-table v-loading="dialogLoading" ref="fileTable" :data="minioDataList" reserve-selection row-key="id"
- @selection-change="handleSelectionFile" @select="handleSelect" @select-all="handleSelectAll">
- <el-table-column type="selection" width="55" header-align="center" />
- <el-table-column label="类型" header-align="center" prop="type" width="80">
- <template #default="scope">
- <dict-tag :options="smsb_source_type" :value="scope.row.type" />
- </template>
- </el-table-column>
- <el-table-column label="原名" header-align="left" prop="originalName" width="150"
- :show-overflow-tooltip="true" />
- <el-table-column label="大小" header-align="center" prop="size" />
- <el-table-column label="时长" header-align="center" prop="duration" />
- <el-table-column label="截图" header-align="center" prop="screenshot">
- <template #default="scope">
- <image-preview :src="scope.row.screenshot" style="width: 40px; height: 40px; cursor: pointer" />
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="fileTotal > 0" :total="fileTotal" v-model:page="dialogQueryParams.pageNum"
- v-model:limit="dialogQueryParams.pageSize" @pagination="getFileList" />
- </div>
- <!-- 右侧选中文件列表 -->
- <div class="selected-container">
- <!-- 自定义表头 -->
- <div class="draggable-header"
- style="display: flex; align-items: center; background: #fafafa; border-bottom: 1px solid #eee; min-height: 48px; font-weight: bold">
- <span style="width: 80px; text-align: center">排序</span>
- <span style="flex: 1">文件名</span>
- <span style="width: 120px; margin-left: 8px">播放时长</span>
- </div>
- <!-- 拖拽列表体 -->
- <draggable v-model="selectedFiles" item-key="id" @end="onSelectedFilesDragEnd" :animation="200" tag="div">
- <template #item="{ element, index }">
- <div class="draggable-row" :draggable="true"
- style="display: flex; align-items: center; border-bottom: 1px solid #eee; min-height: 48px; cursor: move">
- <span class="order-number" style="width: 80px; text-align: center">{{ element.order }}</span>
- <el-tooltip effect="dark" :content="element.name" placement="top">
- <span style="
- flex: 1;
- max-width: 380px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- display: inline-block;
- vertical-align: middle;
- ">{{ element.name }}</span>
- </el-tooltip>
- <el-input-number :disabled="element.type !== 1" v-model="element.duration" :min="1" :max="300"
- style="width: 120px; margin-left: 8px" />
- </div>
- </template>
- </draggable>
- <!-- 空数据提示 -->
- <div v-if="selectedFiles.length === 0" style="text-align: center; color: #999; padding: 16px 0">暂无数据</div>
- </div>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 添加或修改分屏组对话框 -->
- <el-dialog :title="splitDialog.title" v-model="splitDialog.visible" width="1200px" append-to-body>
- <div class="dialog-container">
- <!-- 左侧示意图 -->
- <div class="table-container">示意图</div>
- <!-- 右侧基础信息 -->
- <div class="selected-container">
- <el-form ref="itemFormRef" :model="form" :rules="rules" label-width="60px">
- <el-form-item label="名称" prop="itemName">
- <el-input v-model="form.itemName" placeholder="请输入分屏组名称" />
- </el-form-item>
- <el-row>
- <el-col :span="10">
- <el-form-item label="分辨率" prop="width">
- <el-input-number v-model="form.width" controls-position="right" placeholder="请输入宽度" :min="0"
- style="width: 180px" maxlength="6" />
- </el-form-item>
- </el-col>
- <el-col :span="10">
- <el-form-item label="" prop="height" width="10px">
- <el-input-number v-model="form.height" controls-position="right" placeholder="请输入高度" :min="0"
- style="width: 180px" maxlength="6" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="分屏" prop="splitScreen">
- <el-radio-group v-model="form.splitScreen">
- <el-radio v-for="dict in smsb_split_screen" :key="dict.value" :value="parseInt(dict.value)">
- {{ dict.label }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="坐标" prop="position">
- <el-row>
- <el-col :span="12">
- <el-input-number v-model="position1" controls-position="right" placeholder="请输入坐标1" :min="0"
- style="width: 180px" maxlength="6" />
- </el-col>
- <el-col :span="12">
- <el-input-number v-model="position2" controls-position="right" placeholder="请输入坐标2" :min="0"
- style="width: 180px; margin-left: 15px" maxlength="6" v-if="form.splitScreen !== 2" />
- </el-col>
- </el-row>
- </el-form-item>
- <el-form-item label="宽高" prop="position" v-if="form.splitScreen === 4">
- <el-row>
- <el-col :span="12">
- <el-input-number v-model="positionW" controls-position="right" placeholder="请输入坐标1" :min="0"
- style="width: 180px" maxlength="6" />
- </el-col>
- <el-col :span="12">
- <el-input-number v-model="positionH" controls-position="right" placeholder="请输入坐标2" :min="0"
- style="width: 180px; margin-left: 15px" maxlength="6" />
- </el-col>
- </el-row>
- </el-form-item>
- <el-row>
- <el-col :span="12">
- <el-form-item label="跑马灯" prop="hasPmd">
- <el-radio-group v-model="form.hasPmd">
- <el-radio v-for="dict in smsb_yes_no" :key="dict.value" :value="parseInt(dict.value)">{{ dict.label
- }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="位置" prop="positionPmd">
- <el-radio-group v-model="form.positionPmd">
- <el-radio-button label="上方" value="1" />
- <el-radio-button label="下方" value="2" />
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="内容" prop="contentPmd">
- <el-input v-model="form.contentPmd" type="textarea" placeholder="请输入跑马灯内容" />
- </el-form-item>
- <el-row>
- <el-col :span="12">
- <el-form-item label="天气" prop="hasWeather">
- <el-radio-group v-model="form.hasWeather">
- <el-radio v-for="dict in smsb_yes_no" :key="dict.value" :value="parseInt(dict.value)">{{ dict.label
- }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="时间" prop="hasTime">
- <el-radio-group v-model="form.hasTime">
- <el-radio v-for="dict in smsb_yes_no" :key="dict.value" :value="parseInt(dict.value)">{{ dict.label
- }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- </div>
- </div>
- <template #footer>
- <div class="dialog-footer">
- <el-button :loading="buttonLoading" type="primary" @click="submitSplit">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup name="Item" lang="ts">
- import draggable from 'vuedraggable';
- import { onActivated, reactive } from 'vue';
- import { getEditHistory } from '@/api/smsb/source/item';
- import type { EditHistoryVo, ItemVO, ItemForm } from '@/api/smsb/source/item_type';
- // 编辑历史弹窗数据
- const editHistoryDialog = reactive({
- visible: false,
- list: [] as EditHistoryVo[],
- type: 1 as 1 | 2,
- tableHtml: ref('')
- });
- /**
- * 打开编辑历史弹窗
- * @param row 当前行数据
- */
- function onShowEditHistory(row: ItemVO) {
- editHistoryDialog.visible = true;
- editHistoryDialog.list = [];
- // type: 1=轮播组, 2=分屏组
- const type = row.itemType === 1 ? 1 : 2;
- editHistoryDialog.type = type;
- getEditHistory(row.id, type).then((res) => {
- console.log('编辑历史数据:', res.data);
- let list = res.data || [];
- if (type === 1) {
- // 轮播组过滤掉无selectedFiles的异常数据(第一条保留)
- list = list.filter((item: any, idx: number, arr: any[]) => {
- if (idx === 0) return true;
- try {
- const curr = JSON.parse(item.operParam || '{}');
- const prev = idx > 0 ? JSON.parse(arr[idx - 1].operParam || '{}') : {};
- // 没有selectedFiles字段直接过滤
- if (!Array.isArray(curr.selectedFiles)) return false;
- // diff结果为无变化也过滤
- const diff = diffSelectedFiles({ selectedFiles: prev.selectedFiles || [] }, { selectedFiles: curr.selectedFiles || [] }, 'selectedFiles');
- return diff && diff !== '无变化';
- } catch {
- return false;
- }
- });
- }
- editHistoryDialog.list = list;
- // 使用新的渲染函数生成表格HTML
- editHistoryDialog.tableHtml = renderOperHistoryTable(list, type);
- console.log('编辑历史数据处理后:', list);
- });
- }
- function getFileNameSet(selectedFiles?: any[]): Set<string> {
- if (!Array.isArray(selectedFiles)) return new Set();
- return new Set(selectedFiles.map((f) => f.name));
- }
- function diffSelectedFiles(prev: any, curr: any, key: string) {
- const prevSet = getFileNameSet(prev?.[key]);
- const currSet = getFileNameSet(curr?.[key]);
- const added = [...currSet].filter((x) => !prevSet.has(x));
- const removed = [...prevSet].filter((x) => !currSet.has(x));
- let result = '';
- if (added.length) result += `新增:${added.join(',')}`;
- if (removed.length) result += `${added.length ? ' ' : ''}减少:${removed.join(',')}`;
- return result || '无变化';
- }
- function renderOperParam(row: EditHistoryVo, index: number, list: EditHistoryVo[], type: 1 | 2) {
- // 轮播组和分屏组都采用diff方式展示
- let curr, prev;
- // 轮播组只处理selectedFiles字段,分屏组处理每一屏
- if (type === 1) {
- try {
- curr = JSON.parse(row.operParam || '{}');
- } catch {
- curr = {};
- }
- try {
- prev = index > 0 ? JSON.parse(list[index - 1].operParam || '{}') : {};
- } catch {
- prev = {};
- }
- // 只要没有selectedFiles字段就视为异常数据,不显示
- if (!Array.isArray(curr.selectedFiles)) {
- return '';
- }
- const currFiles = curr.selectedFiles || [];
- const prevFiles = prev.selectedFiles || [];
- if (index === 0) {
- // 第一条记录,全部按“创建”显示
- return `<span style='color:#409EFF;font-weight:bold;'>创建</span>`;
- }
- const diff = diffSelectedFiles({ selectedFiles: prevFiles }, { selectedFiles: currFiles }, 'selectedFiles');
- if (diff && diff !== '无变化') {
- let styled = diff
- .replace(/新增:/g, "<span style='color:#67C23A;font-weight:bold;'>新增:</span>")
- .replace(/减少:/g, "<span style='color:#F56C6C;font-weight:bold;'>减少:</span>");
- return `<span style='font-weight:bold;'>文件</span>:${styled}`;
- }
- return '';
- }
- // 分屏组diff逻辑修正,严格一一对应
- const screenFields = ['selectedFiles1', 'selectedFiles2', 'selectedFiles3', 'selectedFiles4'];
- const screenNames = ['第一屏', '第二屏', '第三屏', '第四屏'];
- try {
- curr = JSON.parse(row.operParam || '{}');
- } catch {
- curr = {};
- }
- try {
- prev = index > 0 ? JSON.parse(list[index - 1].operParam || '{}') : {};
- } catch {
- prev = {};
- }
- if (index === 0) {
- // 第一条记录,固定显示“创建”
- return `<span style='color:#409EFF;font-weight:bold;'>创建</span>`;
- }
- const diffs = screenFields.map((field, idx) => {
- const currFiles = curr[field] || [];
- const prevFiles = prev[field] || [];
- if (!Array.isArray(currFiles) && !Array.isArray(prevFiles)) return '';
- const diff = diffSelectedFiles({ selectedFiles: prevFiles }, { selectedFiles: currFiles }, 'selectedFiles');
- if (diff && diff !== '无变化') {
- let styled = diff
- .replace(/新增:/g, "<span style='color:#67C23A;font-weight:bold;'>新增:</span>")
- .replace(/减少:/g, "<span style='color:#F56C6C;font-weight:bold;'>减少:</span>");
- return `<span style='font-weight:bold;'>${screenNames[idx]}</span>:${styled}`;
- }
- return '';
- }).filter(Boolean);
- return diffs.length ? diffs.join('<br/>') : '';
- }
- import { listItem, getItem, delItem, addItem, updateItem, itemStatistics } from '@/api/smsb/source/item';
- import { MinioDataQuery, MinioDataVO } from '@/api/smsb/source/minioData_type';
- import { listMinioData } from '@/api/smsb/source/minioData';
- import { renderOperHistoryTable } from './renderOperHistoryTable';
- import { nextTick } from 'vue';
- import type { ElTable } from 'element-plus';
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const { smsb_item_type, smsb_split_screen, smsb_source_type, smsb_yes_no } = toRefs<any>(
- proxy?.useDict('smsb_item_type', 'smsb_split_screen', 'smsb_source_type', 'smsb_yes_no')
- );
- const itemList = ref<ItemVO[]>([]);
- const buttonLoading = ref(false);
- const mainLoading = ref(true); // 主表 loading
- const dialogLoading = ref(false); // dialog loading
- const showSearch = ref(true);
- const ids = ref<Array<string | number>>([]);
- const single = ref(true);
- const multiple = ref(true);
- const total = ref(0);
- const fileTotal = ref(0);
- const totalNum = ref(0);
- const lbNum = ref(0);
- const jmNum = ref(0);
- const position1 = ref(0);
- const position2 = ref(0);
- const positionW = ref(0);
- const positionH = ref(0);
- const itemName = ref<string>('');
- const queryFormRef = ref<ElFormInstance>();
- const itemFormRef = ref<ElFormInstance>();
- const fileTable = ref<InstanceType<typeof ElTable>>();
- const minioDataList = ref<MinioDataVO[]>([]);
- const dateRangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
- // 选中的文件
- const selectedFiles = ref<{ id: number; name: string; duration: number; order: number; type: number }[]>([]);
- const dialog = reactive<DialogOption>({
- visible: false,
- title: ''
- });
- const splitDialog = reactive<DialogOption>({
- visible: false,
- title: ''
- });
- const initFormData: ItemForm = {
- itemName: undefined,
- itemType: undefined,
- splitScreen: 2,
- selectedFiles: undefined,
- width: undefined,
- height: undefined,
- background: undefined,
- position: undefined,
- hasPmd: 0,
- positionPmd: '1',
- contentPmd: undefined,
- hasWeather: 0,
- hasTime: 0
- };
- const queryParams = ref({
- pageNum: 1,
- pageSize: 10,
- itemName: undefined,
- itemType: 1,
- splitScreen: undefined,
- createUser: undefined,
- params: {}
- });
- const form = ref({ ...initFormData });
- const rules = {
- itemName: [{ required: true, message: '请输入名称', trigger: 'blur' }],
- itemType: [{ required: true, message: '请选择类型', trigger: 'change' }]
- // 可按需补充其它字段校验
- };
- const dialogQueryParams = ref({
- pageNum: 1,
- pageSize: 10,
- params: {}
- });
- /** 查询节目管理列表 */
- const getList = async () => {
- mainLoading.value = true;
- try {
- const res = await listItem(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, 'CreateTime'));
- console.log('getList result:', res);
- itemList.value = res.rows;
- total.value = res.total;
- } catch (e: any) {
- proxy?.$modal.msgError(e?.message || '获取列表失败');
- } finally {
- mainLoading.value = false;
- }
- };
- /** 查询文件资源列表 */
- const getFileList = async () => {
- dialogLoading.value = true;
- try {
- // console.log('分页参数:', dialogQueryParams.value);
- const res = await listMinioData(dialogQueryParams.value);
- minioDataList.value = res.rows.map((data) => ({
- ...data,
- size: (parseFloat(data.size) / 1024).toFixed(3) + 'MB'
- }));
- fileTotal.value = res.total;
- // After data loads, restore selections
- await nextTick();
- if (selectedFiles.value?.length) {
- const selectedIds = new Set(selectedFiles.value.map((f) => f.id));
- minioDataList.value.forEach((row) => {
- if (selectedIds.has(row.id)) {
- fileTable.value?.toggleRowSelection(row, true);
- }
- });
- // console.log('本页高亮选中:', [...selectedIds]);
- }
- } finally {
- dialogLoading.value = false;
- }
- };
- /** 多选框选中文件数据 */
- // selection-change 只做新增
- const handleSelectionFile = (selection: MinioDataVO[]) => {
- selection.forEach((item) => {
- if (!selectedFiles.value.some((f) => String(f.id) === String(item.id))) {
- selectedFiles.value.push({
- id: item.id,
- name: item.originalName,
- type: item.type,
- duration: item.type === 1 ? 10 : item.duration,
- order: 0
- });
- }
- });
- // 重新排序
- selectedFiles.value = selectedFiles.value.map((f, idx) => ({ ...f, order: idx + 1 }));
- };
- // 取消单个选中
- const handleSelect = (selection: MinioDataVO[], row: MinioDataVO) => {
- if (!selection.some((item) => String(item.id) === String(row.id))) {
- selectedFiles.value = selectedFiles.value.filter((f) => String(f.id) !== String(row.id));
- selectedFiles.value = selectedFiles.value.map((f, idx) => ({ ...f, order: idx + 1 }));
- }
- };
- // 取消全选
- const handleSelectAll = (selection: MinioDataVO[]) => {
- const currentPageIds = new Set(minioDataList.value.map((item) => String(item.id)));
- const selectedIds = new Set(selection.map((item) => String(item.id)));
- selectedFiles.value = selectedFiles.value.filter((f) => !currentPageIds.has(String(f.id)) || selectedIds.has(String(f.id)));
- selectedFiles.value = selectedFiles.value.map((f, idx) => ({ ...f, order: idx + 1 }));
- };
- const cancel = () => {
- reset();
- dialog.visible = false;
- splitDialog.visible = false;
- onDialogClose();
- };
- /** 新建轮播组弹窗关闭时清空选中文件 */
- const onDialogClose = () => {
- selectedFiles.value = [];
- };
- /** 表单重置 */
- const reset = () => {
- form.value = { ...initFormData };
- itemName.value = '';
- itemFormRef.value?.resetFields();
- };
- /** 搜索按钮操作 */
- const handleQuery = () => {
- queryParams.value.pageNum = 1;
- getList();
- };
- /** 重置按钮操作 */
- const resetQuery = () => {
- queryFormRef.value?.resetFields();
- handleQuery();
- };
- /** 多选框选中数据 */
- const handleSelectionChange = (selection: ItemVO[]) => {
- ids.value = selection.map((item) => item.id);
- single.value = selection.length != 1;
- multiple.value = !selection.length;
- };
- /** 新增轮播按钮操作 */
- const handleAddL = () => {
- reset();
- dialog.visible = true;
- dialog.title = '新增轮播组';
- form.value.itemType = 1;
- getFileList();
- };
- /** 新增节目按钮操作 */
- const handleAddJ = () => {
- reset();
- splitDialog.visible = true;
- splitDialog.title = '新增分屏组';
- form.value.itemType = 2;
- };
- /** 修改按钮操作 */
- const handleUpdate = async (row?: ItemVO) => {
- reset();
- try {
- const _id = row?.id || ids.value[0];
- const res = await getItem(_id);
- if (1 === res.data.itemType) {
- Object.assign(form.value, res.data);
- itemName.value = res.data.itemName || '';
- dialog.visible = true;
- dialog.title = '修改节目管理';
- // 资源ID列表字段,改为fileIdList
- const fileIds = Array.isArray(res.data.fileIdList) ? res.data.fileIdList : [];
- if (fileIds.length > 0) {
- const fileRes = await listMinioData({ ids: fileIds });
- selectedFiles.value = fileIds
- .map((id: string | number, idx: number) => {
- const file = fileRes.rows.find((f: any) => String(f.id) === String(id));
- return file
- ? {
- id: file.id,
- name: file.originalName,
- type: file.type,
- duration: file.type === 1 ? 10 : Number(file.duration),
- order: idx + 1
- }
- : null;
- })
- .filter(Boolean);
- } else {
- selectedFiles.value = [];
- }
- // 打开弹窗后刷新分页列表
- await getFileList();
- } else {
- // 跳转页面进行数据关联
- proxy.$router.push('/source/split/edit/' + res.data.id);
- }
- } catch (e: any) {
- proxy?.$modal.msgError(e?.message || '获取详情失败');
- }
- };
- /** 提交按钮 */
- const submitForm = async () => {
- buttonLoading.value = true;
- try {
- if (form.value.id) {
- if (form.value.itemType === 1) {
- form.value.selectedFiles = selectedFiles.value;
- form.value.fileIdList = selectedFiles.value.map(f => f.id);
- form.value.itemName = itemName.value;
- }
- await updateItem(form.value);
- } else {
- if (form.value.itemType === 1) {
- form.value.selectedFiles = selectedFiles.value;
- form.value.fileIdList = selectedFiles.value.map(f => f.id);
- form.value.itemName = itemName.value;
- }
- await addItem(form.value);
- }
- proxy?.$modal.msgSuccess('操作成功');
- dialog.visible = false;
- await getList();
- } catch (e: any) {
- proxy?.$modal.msgError(e?.message || '提交失败');
- } finally {
- buttonLoading.value = false;
- }
- };
- const submitSplit = async () => {
- buttonLoading.value = true;
- try {
- // 根据分辨率判断横屏还是竖屏
- const isWidth = form.value.width > form.value.height;
- // 2分屏的坐标
- if (form.value.splitScreen === 2) {
- if (isWidth) {
- form.value.position = '(0,' + position1.value + '),(' + form.value.height + ',' + position1.value + ')';
- } else {
- form.value.position = '(0,' + position1.value + '),(' + form.value.width + ',' + position1.value + ')';
- }
- }
- // 3分屏的坐标
- if (form.value.splitScreen === 3) {
- if (isWidth) {
- const xy1 = '(0,' + position1.value + '),(' + form.value.height + ',' + position1.value + ')';
- const xy2 = '(0,' + position2.value + '),(' + form.value.height + ',' + position2.value + ')';
- form.value.position = xy1 + ',' + xy2;
- } else {
- const xy1 = '(0,' + position1.value + '),(' + form.value.width + ',' + position1.value + ')';
- const xy2 = '(0,' + position2.value + '),(' + form.value.width + ',' + position2.value + ')';
- form.value.position = xy1 + ',' + xy2;
- }
- }
- // 播放框
- if (form.value.splitScreen === 4) {
- const xy1 = '(' + (position1.value - positionW.value / 2) + ',' + (position2.value + positionH.value / 2) + ')';
- const xy2 = '(' + (position1.value + positionW.value / 2) + ',' + (position2.value + positionH.value / 2) + ')';
- const xy3 = '(' + (position1.value - positionW.value / 2) + ',' + (position2.value - positionH.value / 2) + ')';
- const xy4 = '(' + (position1.value + positionW.value / 2) + ',' + (position2.value - positionH.value / 2) + ')';
- form.value.position = xy1 + ',' + xy2 + ',' + xy3 + ',' + xy4;
- }
- const res = await addItem(form.value);
- proxy?.$modal.msgSuccess('操作成功');
- splitDialog.visible = false;
- const itemId = res.data;
- // 跳转页面进行数据关联
- proxy.$router.push('/source/split/edit/' + itemId);
- } catch (e: any) {
- proxy?.$modal.msgError(e?.message || '提交分屏失败');
- } finally {
- buttonLoading.value = false;
- }
- };
- /** 删除按钮操作 */
- const handleDelete = async (row?: ItemVO) => {
- loading.value = true;
- try {
- const _ids = row?.id || ids.value;
- await proxy?.$modal.confirm('是否确认删除节目管理编号为"' + _ids + '"的数据项?');
- await delItem(_ids);
- proxy?.$modal.msgSuccess('删除成功');
- await getList();
- } catch (e: any) {
- proxy?.$modal.msgError(e?.message || '删除失败');
- } finally {
- loading.value = false;
- }
- };
- /** 导出按钮操作 */
- const handleExport = () => {
- proxy?.download(
- 'source/item/export',
- {
- ...queryParams.value
- },
- `item_${new Date().getTime()}.xlsx`
- );
- };
- const getItemStatistics = async () => {
- try {
- const res = await itemStatistics();
- totalNum.value = res.data.totalNum;
- lbNum.value = res.data.lbNum;
- jmNum.value = res.data.jmNum;
- } catch (e: any) {
- proxy?.$modal.msgError(e?.message || '获取统计数据失败');
- }
- };
- /** 拖拽排序结束时,重排 order 字段 */
- const onSelectedFilesDragEnd = () => {
- selectedFiles.value = selectedFiles.value.map((f, idx) => ({ ...f, order: idx + 1 }));
- };
- onMounted(() => {
- getList();
- getItemStatistics();
- });
- onActivated(() => {
- getList();
- getItemStatistics();
- });
- </script>
- <style scoped>
- .dialog-container {
- display: flex;
- gap: 20px;
- }
- .table-container {
- flex: 1;
- }
- .selected-container {
- flex: 1;
- }
- .interface-input {
- margin-bottom: 10px;
- }
- .order-number {
- display: inline-block;
- width: 30px;
- text-align: center;
- font-weight: bold;
- }
- .stat-title {
- display: inline-flex;
- align-items: center;
- }
- .statistic-col {
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .edit-history-param {
- line-height: 1.8;
- font-size: 14px;
- word-break: break-all;
- }
- .edit-history-user {
- font-size: 18px;
- color: #222;
- }
- .edit-history-time {
- font-size: 14px;
- color: #999;
- }
- </style>
|