数据同步-服务指令同步
This commit is contained in:
parent
8118cc5639
commit
3962fc6536
|
@ -9,32 +9,32 @@ export const columns: BasicColumn[] = [
|
|||
title: '服务类别',
|
||||
align: 'center',
|
||||
dataIndex: 'categoryId_dictText',
|
||||
customCell: (record, index, column) => {
|
||||
if (record.categoryRowSpan != null) {
|
||||
return { rowSpan: record.categoryRowSpan };
|
||||
}
|
||||
},
|
||||
// customCell: (record, index, column) => {
|
||||
// if (record.categoryRowSpan != null) {
|
||||
// return { rowSpan: record.categoryRowSpan };
|
||||
// }
|
||||
// },
|
||||
},
|
||||
{
|
||||
title: '服务类型',
|
||||
align: 'center',
|
||||
dataIndex: 'typeId_dictText',
|
||||
customCell: (record, index, column) => {
|
||||
if (record.typeRowSpan != null) {
|
||||
return { rowSpan: record.typeRowSpan };
|
||||
}
|
||||
},
|
||||
// customCell: (record, index, column) => {
|
||||
// if (record.typeRowSpan != null) {
|
||||
// return { rowSpan: record.typeRowSpan };
|
||||
// }
|
||||
// },
|
||||
},
|
||||
{
|
||||
title: '分类标签',
|
||||
align: 'center',
|
||||
dataIndex: 'instructionTagId_dictText',
|
||||
width: 100,
|
||||
customCell: (record, index, column) => {
|
||||
if (record.instructionRowSpan != null) {
|
||||
return { rowSpan: record.instructionRowSpan };
|
||||
}
|
||||
},
|
||||
// customCell: (record, index, column) => {
|
||||
// if (record.instructionRowSpan != null) {
|
||||
// return { rowSpan: record.instructionRowSpan };
|
||||
// }
|
||||
// },
|
||||
},
|
||||
{
|
||||
title: '服务指令名称',
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
<template>
|
||||
<div class="p-2">
|
||||
<BasicTable
|
||||
@register="registerTable"
|
||||
:scroll="{ y: '55vh' }"
|
||||
:rowClassName="getRowClassName"
|
||||
>
|
||||
<template #tableTitle></template>
|
||||
|
||||
<template #action="{ record }">
|
||||
<TableAction
|
||||
:actions="getTableAction(record)"
|
||||
:dropDownActions="getDropDownAction(record)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-slot:bodyCell="{ column, record, index, text }">
|
||||
<template v-if="column.dataIndex === 'mp3File'">
|
||||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
|
||||
<audio controls v-else style="width: 100%; max-width: 300px; height: 40px;">
|
||||
<source :src="getFileAccessHttpUrl(text)">
|
||||
</audio>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'mp4File'">
|
||||
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
|
||||
<template v-else>
|
||||
<a-button type="primary" @click="openVideoModal(text)">播放视频</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<ConfigServiceDirectiveModal ref="registerModal" @success="handleSuccess"></ConfigServiceDirectiveModal>
|
||||
|
||||
<a-modal
|
||||
v-model:visible="showVideoModal"
|
||||
title="视频播放"
|
||||
:footer="null"
|
||||
@cancel="closeVideoModal"
|
||||
:bodyStyle="{ padding: '0', maxHeight: '80vh', overflow: 'auto' }"
|
||||
>
|
||||
<video controls style="width: 100%; max-height: 70vh; display: block; margin: 0 auto;">
|
||||
<source :src="videoUrl">
|
||||
您的浏览器不支持视频播放。
|
||||
</video>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="serviceDirective-configServiceDirective" setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { columns, superQuerySchema } from './ConfigServiceDirective.data';
|
||||
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './ConfigServiceDirective.api';
|
||||
import ConfigServiceDirectiveModal from './components/ConfigServiceDirectiveModal.vue'
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||
|
||||
const emit = defineEmits(['select-change']);
|
||||
const queryParam = reactive<any>({});
|
||||
const registerModal = ref();
|
||||
const selectedRowIds = ref<Set<string | number>>(new Set());
|
||||
const allSelectedItems = ref<Map<string | number, any>>(new Map());
|
||||
|
||||
// 行类名函数
|
||||
const getRowClassName = (record) => {
|
||||
return selectedRowIds.value.has(record.id) ? 'selected-row' : '';
|
||||
};
|
||||
|
||||
// 切换选择状态
|
||||
const toggleSelect = (record) => {
|
||||
if (selectedRowIds.value.has(record.id)) {
|
||||
selectedRowIds.value.delete(record.id);
|
||||
allSelectedItems.value.delete(record.id);
|
||||
} else {
|
||||
selectedRowIds.value.add(record.id);
|
||||
allSelectedItems.value.set(record.id, record);
|
||||
}
|
||||
updateSelectedItems();
|
||||
};
|
||||
|
||||
// 移除选中项
|
||||
const removeSelected = (record) => {
|
||||
selectedRowIds.value.delete(record.id);
|
||||
allSelectedItems.value.delete(record.id);
|
||||
updateSelectedItems();
|
||||
};
|
||||
|
||||
// 暴露给父组件的方法
|
||||
const removeSelectedItem = (id: string | number) => {
|
||||
selectedRowIds.value.delete(id);
|
||||
allSelectedItems.value.delete(id);
|
||||
updateSelectedItems();
|
||||
};
|
||||
|
||||
// 更新已选择项并通知父组件
|
||||
const updateSelectedItems = () => {
|
||||
emit('select-change', new Map(allSelectedItems.value));
|
||||
};
|
||||
|
||||
function handleSuccess() {
|
||||
(selectedRowKeys.value = []) && reload();
|
||||
}
|
||||
|
||||
// 注册表格
|
||||
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
|
||||
tableProps: {
|
||||
title: '服务指令',
|
||||
api: list,
|
||||
columns,
|
||||
size: 'small',
|
||||
showTableSetting: false,
|
||||
canResize: false,
|
||||
useSearchForm: false,
|
||||
showIndexColumn: true,
|
||||
actionColumn: {
|
||||
width: 120,
|
||||
fixed: 'right',
|
||||
},
|
||||
beforeFetch: async (params) => {
|
||||
params.column = 'createTime'
|
||||
params.order = 'desc'
|
||||
let rangerQuery = await setRangeQuery();
|
||||
return Object.assign(params, rangerQuery);
|
||||
},
|
||||
},
|
||||
exportConfig: {
|
||||
name: "服务指令",
|
||||
url: getExportUrl,
|
||||
params: queryParam,
|
||||
},
|
||||
importConfig: {
|
||||
url: getImportUrl,
|
||||
success: handleSuccess
|
||||
},
|
||||
});
|
||||
|
||||
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
function handleDetail(record: Recordable) {
|
||||
registerModal.value.disableSubmit = true;
|
||||
registerModal.value.edit(record);
|
||||
}
|
||||
|
||||
function getTableAction(record) {
|
||||
const actions = [
|
||||
{
|
||||
label: '详情',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
}
|
||||
];
|
||||
|
||||
if (selectedRowIds.value.has(record.id)) {
|
||||
actions.push({
|
||||
label: '移除',
|
||||
color: 'error',
|
||||
onClick: () => {
|
||||
removeSelected(record);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
actions.push({
|
||||
label: '选择',
|
||||
onClick: () => {
|
||||
toggleSelect(record);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
function getDropDownAction(record) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let rangeField = 'tollPrice,comPrice,';
|
||||
|
||||
async function setRangeQuery() {
|
||||
let queryParamClone = cloneDeep(queryParam);
|
||||
if (rangeField) {
|
||||
let fieldsValue = rangeField.split(',');
|
||||
fieldsValue.forEach(item => {
|
||||
if (queryParamClone[item]) {
|
||||
let range = queryParamClone[item];
|
||||
queryParamClone[item + '_begin'] = range[0];
|
||||
queryParamClone[item + '_end'] = range[1];
|
||||
delete queryParamClone[item];
|
||||
} else {
|
||||
queryParamClone[item + '_begin'] = '';
|
||||
queryParamClone[item + '_end'] = '';
|
||||
}
|
||||
})
|
||||
}
|
||||
return queryParamClone;
|
||||
}
|
||||
|
||||
const showVideoModal = ref(false);
|
||||
const videoUrl = ref('');
|
||||
|
||||
const openVideoModal = (url) => {
|
||||
videoUrl.value = getFileAccessHttpUrl(url);
|
||||
showVideoModal.value = true;
|
||||
};
|
||||
|
||||
const closeVideoModal = () => {
|
||||
showVideoModal.value = false;
|
||||
videoUrl.value = '';
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
removeSelectedItem
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.jeecg-basic-table-form-container {
|
||||
padding: 0;
|
||||
|
||||
.table-page-search-submitButtons {
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.query-group-cust {
|
||||
min-width: 100px !important;
|
||||
}
|
||||
|
||||
.query-group-split-cust {
|
||||
width: 30px;
|
||||
display: inline-block;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
.ant-form-item:not(.ant-form-item-with-help) {
|
||||
margin-bottom: 16px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
:deep(.ant-picker),
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
audio::-webkit-media-controls-timeline {
|
||||
display: none;
|
||||
}
|
||||
|
||||
audio::-webkit-media-controls-current-time-display,
|
||||
audio::-webkit-media-controls-time-remaining-display {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.ant-table-title) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep(.selected-row) {
|
||||
background-color: #e6f7ff !important;
|
||||
|
||||
&:hover td {
|
||||
background-color: #e6f7ff !important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,269 @@
|
|||
<template>
|
||||
<div class="p-2">
|
||||
<a-card @click="toggleSearchStatus = true" :class="{ 'base-con-class': toggleSearchStatus == false }">
|
||||
<a-row>
|
||||
<a-col :span="23">
|
||||
<span>机构信息</span>
|
||||
</a-col>
|
||||
<a-divider v-show="toggleSearchStatus" />
|
||||
<a-col :span="24" v-show="toggleSearchStatus">
|
||||
<span>筛选条件及功能操作按钮</span>
|
||||
<a-form></a-form>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<a-card>
|
||||
<a-row>
|
||||
<a-col :span="5" :push="19">
|
||||
<a-radio-group v-model:value="splitVal" button-style="solid" size="small"
|
||||
@change="splitScreenChanged">
|
||||
<a-radio-button value="sc">源数据</a-radio-button>
|
||||
<a-radio-button value="sc2sed1">分屏1</a-radio-button>
|
||||
<a-radio-button value="sc1sed1">分屏2</a-radio-button>
|
||||
<a-radio-button value="sc1sed2">分屏3</a-radio-button>
|
||||
<a-radio-button value="sed">已选择</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-col>
|
||||
<a-col :span="1" :push="18">
|
||||
<a @click="toggleSearchStatus = !toggleSearchStatus"
|
||||
style="margin-left: 20px; display: inline-flex; align-items: center; gap: 4px">
|
||||
{{ toggleSearchStatus ? '拉伸' : '压缩' }}
|
||||
<Icon
|
||||
:icon="toggleSearchStatus ? 'humbleicons:align-objects-top' : 'humbleicons:align-objects-bottom'" />
|
||||
</a>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row>
|
||||
<a-col :span="sourceScreenSpan">
|
||||
<ConfigServiceDirectiveListCom @select-change="handleSelectChange" ref="listComRef" />
|
||||
</a-col>
|
||||
<a-col :span="selectedScreenSpan">
|
||||
<a-card size="small" :bordered="false" class="selected-list-container">
|
||||
<a-table size="small" :columns="selectedColumns"
|
||||
:dataSource="Array.from(selectedItems.values())" :pagination="false"
|
||||
:scroll="{ y: '55vh' }">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-button type="link" danger size="small" @click="handleRemoveFromRight(record.id)">
|
||||
移除
|
||||
</a-button>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'mp3File'">
|
||||
<span v-if="!record.mp3File" style="font-size: 12px;font-style: italic;">无文件</span>
|
||||
<audio controls v-else style="width: 100%; max-width: 300px; height: 40px;">
|
||||
<source :src="getFileAccessHttpUrl(record.mp3File)">
|
||||
</audio>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'mp4File'">
|
||||
<span v-if="!record.mp4File" style="font-size: 12px;font-style: italic;">无文件</span>
|
||||
<a-button v-else type="primary" size="small"
|
||||
@click="openVideoModal(record.mp4File)">
|
||||
播放视频
|
||||
</a-button>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'tagList'">
|
||||
<span v-if="!record.tagList || record.tagList.length === 0"
|
||||
style="font-size: 12px;font-style: italic;">-</span>
|
||||
<template v-else>
|
||||
{{record.tagList.map(item => item.tagName).join('、')}}
|
||||
</template>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'previewFile'">
|
||||
<span v-if="!record.previewFile"
|
||||
style="font-size: 12px;font-style: italic;">无图片</span>
|
||||
<img v-else :src="getFileAccessHttpUrl(record.previewFile)"
|
||||
style="max-width: 100px; max-height: 60px;" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'immediateFile'">
|
||||
<span v-if="!record.immediateFile"
|
||||
style="font-size: 12px;font-style: italic;">无图片</span>
|
||||
<img v-else :src="getFileAccessHttpUrl(record.immediateFile)"
|
||||
style="max-width: 100px; max-height: 60px;" />
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</div>
|
||||
|
||||
<a-modal v-model:visible="showVideoModal" title="视频播放" :footer="null" @cancel="closeVideoModal"
|
||||
:bodyStyle="{ padding: '0', maxHeight: '80vh', overflow: 'auto' }">
|
||||
<video controls style="width: 100%; max-height: 70vh; display: block; margin: 0 auto;">
|
||||
<source :src="videoUrl">
|
||||
您的浏览器不支持视频播放。
|
||||
</video>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="synchronization-directive" setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import ConfigServiceDirectiveListCom from '@/views/serviceDirective/serviceDirective/ConfigServiceDirectiveListCom.vue'
|
||||
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
|
||||
const toggleSearchStatus = ref<boolean>(true);
|
||||
const splitVal = ref<string>('sc1sed1');
|
||||
const sourceScreenSpan = ref(12);
|
||||
const selectedScreenSpan = ref(12);
|
||||
|
||||
function splitScreenChanged(val) {
|
||||
let v_ = val.target.value;
|
||||
if (v_ == 'sc') {
|
||||
sourceScreenSpan.value = 24;
|
||||
selectedScreenSpan.value = 0;
|
||||
}
|
||||
if (v_ == 'sc2sed1') {
|
||||
sourceScreenSpan.value = 16;
|
||||
selectedScreenSpan.value = 8;
|
||||
}
|
||||
if (v_ == 'sc1sed1') {
|
||||
sourceScreenSpan.value = 12;
|
||||
selectedScreenSpan.value = 12;
|
||||
}
|
||||
if (v_ == 'sc1sed2') {
|
||||
sourceScreenSpan.value = 8;
|
||||
selectedScreenSpan.value = 16;
|
||||
}
|
||||
if (v_ == 'sed') {
|
||||
sourceScreenSpan.value = 0;
|
||||
selectedScreenSpan.value = 24;
|
||||
}
|
||||
}
|
||||
|
||||
const selectedItems = ref(new Map<string | number, any>());
|
||||
const listComRef = ref();
|
||||
|
||||
const selectedColumns = [
|
||||
{
|
||||
title: '服务类别',
|
||||
align: 'center',
|
||||
dataIndex: 'categoryId_dictText',
|
||||
width: 100 // 添加固定宽度
|
||||
},
|
||||
{
|
||||
title: '服务类型',
|
||||
align: 'center',
|
||||
dataIndex: 'typeId_dictText',
|
||||
width: 120 // 添加固定宽度
|
||||
},
|
||||
{
|
||||
title: '分类标签',
|
||||
align: 'center',
|
||||
dataIndex: 'instructionTagId_dictText',
|
||||
width: 90,
|
||||
},
|
||||
{
|
||||
title: '服务指令名称',
|
||||
align: 'center',
|
||||
dataIndex: 'directiveName',
|
||||
width: 150 // 添加固定宽度
|
||||
},
|
||||
{
|
||||
title: '指令标签',
|
||||
align: 'center',
|
||||
dataIndex: 'tagList',
|
||||
width: 150,
|
||||
ellipsis: true // 确保内容过长时显示省略号
|
||||
},
|
||||
{
|
||||
title: '周期类型',
|
||||
align: 'center',
|
||||
dataIndex: 'cycleType_dictText',
|
||||
width: 100 // 添加固定宽度
|
||||
},
|
||||
{
|
||||
title: '服务时长(分钟)',
|
||||
align: 'center',
|
||||
dataIndex: 'serviceDuration',
|
||||
width: 135,
|
||||
},
|
||||
{
|
||||
title: '是否启用',
|
||||
align: 'center',
|
||||
dataIndex: 'izEnabled_dictText',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '语音文件',
|
||||
align: 'center',
|
||||
dataIndex: 'mp3File',
|
||||
width: 200 // 添加固定宽度
|
||||
},
|
||||
{
|
||||
title: '视频文件',
|
||||
align: 'center',
|
||||
dataIndex: 'mp4File',
|
||||
width: 120 // 添加固定宽度
|
||||
},
|
||||
{
|
||||
title: '预览图片',
|
||||
align: 'center',
|
||||
dataIndex: 'previewFile',
|
||||
width: 120 // 添加固定宽度
|
||||
},
|
||||
{
|
||||
title: '即时指令图片',
|
||||
align: 'center',
|
||||
dataIndex: 'immediateFile',
|
||||
width: 150 // 添加固定宽度
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
width: 60,
|
||||
fixed: 'right'
|
||||
}
|
||||
];
|
||||
|
||||
const handleSelectChange = (items: Map<string | number, any>) => {
|
||||
selectedItems.value = new Map(items);
|
||||
};
|
||||
|
||||
const handleRemoveFromRight = (key: string | number) => {
|
||||
console.log("🌊 ~ handleRemoveFromRight ~ selectedItems.value:", selectedItems.value)
|
||||
selectedItems.value.delete(key);
|
||||
listComRef.value?.removeSelectedItem?.(key); // 添加了额外的安全调用
|
||||
};
|
||||
|
||||
const showVideoModal = ref(false);
|
||||
const videoUrl = ref('');
|
||||
|
||||
const openVideoModal = (url: string) => {
|
||||
videoUrl.value = getFileAccessHttpUrl(url);
|
||||
showVideoModal.value = true;
|
||||
};
|
||||
|
||||
const closeVideoModal = () => {
|
||||
showVideoModal.value = false;
|
||||
videoUrl.value = '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.base-con-class {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-2px);
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.selected-list-container {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
:deep(.ant-table-small) {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-table-cell) {
|
||||
padding: 8px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue