nursing_unit_vue/src/views/services/serviceDirective/ConfigServiceDirectiveList.vue

1080 lines
35 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="p-2">
<!--查询区域-->
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol"
:wrapper-col="wrapperCol">
<a-row :gutter="24">
<!-- <a-col :lg="6">
<a-form-item name="instructionTagId">
<template #label><span title="分类标签">分类标签</span></template>
<j-dict-select-tag v-model:value="queryParam.instructionTagId"
:dictCode="`nu_config_service_instruction_tag,instruction_name,id,del_flag = 0 order by sort asc`"
placeholder="请选择分类标签" allowClear :ignoreDisabled="true" />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="categoryId">
<template #label><span title="服务类别">服务类别</span></template>
<j-dict-select-tag type="list" v-model:value="queryParam.categoryId"
:dictCode="`nu_config_service_category,category_name,id,del_flag = 0 and instruction_id = '${queryParam.instructionTagId || ''}' order by sort asc`"
placeholder="请选择服务类别" allowClear :ignoreDisabled="true" />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="typeId">
<template #label><span title="服务类型">服务类型</span></template>
<j-dict-select-tag type="list" v-model:value="queryParam.typeId"
:dictCode="`nu_config_service_type,type_name,id,del_flag = 0 and category_id = '${queryParam.categoryId || ''}' order by sort asc`"
placeholder="请选择服务类型" allowClear :ignoreDisabled="true" />
</a-form-item>
</a-col> -->
<a-col :lg="6">
<a-form-item name="directiveName">
<template #label><span title="服务指令">服务指令</span></template>
<JInput v-model:value="queryParam.directiveName" placeholder="请输入服务指令名称" allowClear />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="bodyTags">
<template #label><span title="体型标签">体型标签</span></template>
<j-dict-select-tag type='list' v-model:value="queryParam.bodyTags"
:dictCode="`nu_config_body_tag,tag_name,id,del_flag = '0' order by sort asc`" :ignoreDisabled="true"
placeholder="请选择体型标签" allowClear />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="emotionTags">
<template #label><span title="情绪标签">情绪标签</span></template>
<j-dict-select-tag type="list" v-model:value="queryParam.emotionTags"
:dictCode="`nu_config_emotion_tag,tag_name,id,del_flag = '0' order by sort asc`" :ignoreDisabled="true"
placeholder="请选择情绪标签" allowClear />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="izEnabled">
<template #label><span title="是否启用">是否启用</span></template>
<j-dict-select-tag type='list' v-model:value="queryParam.izEnabled" dictCode="iz_enabled"
:ignoreDisabled="true" placeholder="请选择是否启用" allowClear />
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="6">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset"
style="margin-left: 8px">重置</a-button>
</a-col>
</span>
</a-col>
</a-row>
</a-form>
</div>
<div>
<div style="width:350px;float: left;max-height:77vh; overflow:auto;">
<a-empty v-if="treeLoading" />
<a-button v-else-if="!treeLoading && treeData.length < 1" type="link" class="btnPrivate" @click="addInstruction"
preIcon="ant-design:plus-outlined">新增分类标签</a-button>
<a-tree v-else :tree-data="treeData" v-model:expandedKeys="expandedKeys" expandAction="click"
@select="handleTreeSelect">
<template #title="{ data }">
<!-- @click.stop="openMenu(data, data.children, $event)" -->
<!-- @contextmenu.prevent="openMenu(data, data.children, $event)" -->
<span class="node-title" @mouseenter="onNodeEnter(data, data.children, $event)"
@mouseleave="onNodeLeave(data)">
<div v-if="data.level == 5">
<div><strong>体型标签:</strong>{{data?.bodyTagList?.map(tag => tag.tagName).join('、') || '-'}}</div>
<div><strong>情绪标签:</strong>{{data?.emotionTagList?.map(tag => tag.tagName).join('、') || '-'}}</div>
</div>
<span v-else-if="data.level == 4">{{ data?.title + '(' + data?.cycleTypeName + ')' }}</span>
<span v-else>{{ data?.title }}</span>
<span v-if="data?.izEnabled == '1'" style="color:red;">(已停用)</span>
<!-- 下拉菜单 -->
<a-dropdown :open="menuState[data?.key]?.open" @openChange="onMenuOpenChange(data.key, $event)">
<template #overlay>
<a-menu>
<a-menu-item v-for="item in menuItems(data)" :key="item.key"
@click="() => { closeAllMenus(); item.action(data) }">
<Icon style="color:#1890FF;" :icon="item.icon" class="action-icon"></Icon>
<span style=" color:#1890FF;margin-left: 5px;">{{ item.label }}</span>
</a-menu-item>
</a-menu>
</template>
<!-- 图标 -->
<Icon v-show="data.showIcon && data.level != 5" style="color:#1890FF;" :icon="iconClass(data.level)"
class="action-icon" @mouseenter="onNodeIconEnter(data, data.children)"
@mouseleave="onNodeIconLeave(data)" />
</a-dropdown>
</span>
</template>
</a-tree>
</div>
<div style="width:calc(100% - 360px);float: left;margin-left: 10px;">
<!--引用表格-->
<BasicTable @register="registerTable">
<!--插槽:table标题-->
<template #tableTitle>
<!-- <a-button type="primary" class="btnPrivate" @click="handleinstructionTag"
preIcon="tabler:settings">配置分类标签</a-button>
<a-button type="primary" class="btnPrivate" @click="handleCategory"
preIcon="tabler:settings">配置服务类别</a-button>
<a-button type="primary" class="btnPrivate" @click="handleType" preIcon="tabler:settings">配置服务类型</a-button> -->
<a-button type="primary" class="btnPrivate" @click="handleBodyTag"
preIcon="tabler:settings">配置体型标签</a-button>
<a-button type="primary" class="btnPrivate" @click="handleEmotionTag"
preIcon="tabler:settings">配置情绪标签</a-button>
<!-- <a-button type="primary" class="btnPrivate" @click="handleAdd"
preIcon="ant-design:plus-outlined">新增服务指令</a-button> -->
<a-button type="primary" class="btnPrivate" @click="handleDirectiveMainOpen" v-show="isShowDM"
preIcon="ant-design:profile-outlined">指令库</a-button>
</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>
<a-button v-else type="link" class="btnPrivate" @click="openAudioModal(text)">播放</a-button>
</template>
<!-- <template v-if="column.dataIndex === 'mp3File'">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
<div v-else style="display: flex; align-items: center; gap: 8px;">
<audio ref="audioPlayer" :src="getFileAccessHttpUrl(text)" hidden></audio>
<a-button v-if="!currentPlayingAudio || currentPlayingAudio !== text" type="link" @click="playAudio(text)"
preIcon="ant-design:play-circle-outlined">
播放
</a-button>
<template v-else>
<a-button v-if="isPlaying" type="link" @click="pauseAudio" preIcon="ant-design:pause-circle-outlined">
暂停
</a-button>
<a-button v-else type="link" @click="resumeAudio" preIcon="ant-design:play-circle-outlined">
播放
</a-button>
<a-button type="link" @click="restartAudio" preIcon="ant-design:reload-outlined">
重播
</a-button>
<a-button type="link" @click="stopAudio" preIcon="ant-design:stop-outlined">
停止
</a-button>
</template>
</div>
</template> -->
<template v-if="column.dataIndex === 'mp4File'">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
<a-button v-else type="link" class="btnPrivate" @click="openVideoModal(text)">播放</a-button>
</template>
<template v-if="column.dataIndex === 'bodyTagList'">
<span :title="text.map((item) => item.tagName).join('、')">{{text.map((item) =>
item.tagName).join('、')}}</span>
</template>
<template v-if="column.dataIndex === 'emotionTagList'">
<span :title="text.map((item) => item.tagName).join('、')">{{text.map((item) =>
item.tagName).join('、')}}</span>
</template>
</template>
</BasicTable>
</div>
</div>
<!-- 表单区域 -->
<ConfigServiceDirectiveModal ref="registerModal" @success="handleSuccess">
</ConfigServiceDirectiveModal>
</div>
<!-- 分类标签 -->
<a-drawer title="分类标签" width="60vw" :open="insTagOpen" @close="onInsTagClose">
<template #footer>
<a-button type="primary" @click="onInsTagClose" style="float: right;">关闭</a-button>
</template>
<InstructionTag v-if="insTagOpen"></InstructionTag>
</a-drawer>
<!-- 服务类别 -->
<a-drawer title="服务类别" width="60vw" :open="categoryOpen" @close="onCategoryClose">
<template #footer>
<a-button type="primary" @click="onCategoryClose" style="float: right;">关闭</a-button>
</template>
<ConfigServiceCategoryList v-if="categoryOpen"></ConfigServiceCategoryList>
</a-drawer>
<!-- 服务类型 -->
<a-drawer title="服务类型" width="60vw" :open="typeOpen" @close="onTypeClose">
<template #footer>
<a-button type="primary" @click="onTypeClose" style="float: right;">关闭</a-button>
</template>
<ConfigServiceTypeList v-if="typeOpen"></ConfigServiceTypeList>
</a-drawer>
<!-- 体型标签 -->
<a-drawer title="体型标签" width="60vw" :open="bodyTagOpen" @close="onBodyTagClose" bodyStyle="background: url(../../resource/img/modalback.png);">
<template #footer>
<a-button type="primary" @click="onBodyTagClose" style="float: right;">关闭</a-button>
</template>
<BodyTagList v-if="bodyTagOpen" ></BodyTagList>
</a-drawer>
<!-- 情绪标签 -->
<a-drawer title="情绪标签" width="60vw" :open="emotionTagOpen" @close="onEmotionTagClose" bodyStyle="background: url(../../resource/img/modalback.png);">
<template #footer>
<a-button type="primary" @click="onEmotionTagClose" style="float: right;">关闭</a-button>
</template>
<EmotionTagList v-if="emotionTagOpen" ></EmotionTagList>
</a-drawer>
<!-- 音频播放 -->
<a-modal v-model:visible="showAudioModal" title="音频播放" :footer="null" @cancel="closeAudioModal"
:bodyStyle="{ padding: '0', maxHeight: '80vh', overflow: 'auto' }" :keyboard="true">
<audio ref="audioPlayer" controls style="width: 100%; display: block; margin: 20px auto;">
<source :src="audioUrl">
您的浏览器不支持音频播放。
</audio>
</a-modal>
<!-- 视频播放 -->
<a-modal v-model:visible="showVideoModal" title="视频播放" :footer="null" @cancel="closeVideoModal"
:bodyStyle="{ padding: '0', maxHeight: '80vh', overflow: 'auto' }">
<video ref="videoPlayer" controls style="width: 100%; max-height: 70vh; display: block; margin: 0 auto;">
<source :src="videoUrl">
您的浏览器不支持视频播放
</video>
</a-modal>
<!-- 分类标签 -->
<InstructionTagModal ref="insRegisterModal" @success="reloadTree"></InstructionTagModal>
<ConfigServiceCategoryModal ref="catRegisterModal" @success="reloadTree"></ConfigServiceCategoryModal>
<ConfigServiceTypeModal ref="typRegisterModal" @success="reloadTree"></ConfigServiceTypeModal>
</template>
<script lang="ts" name="serviceDirective-configServiceDirective" setup>
import { ref, reactive, watch, onMounted, computed } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, superQuerySchema } from './ConfigServiceDirective.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl, tree } from './ConfigServiceDirective.api';
import ConfigServiceDirectiveModal from './components/ConfigServiceDirectiveModal.vue'
import { useUserStore } from '/@/store/modules/user';
import JInput from "/@/components/Form/src/jeecg/components/JInput.vue";
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import { cloneDeep } from "lodash-es";
import ConfigServiceCategoryList from '../serviceCategory/ConfigServiceCategoryList.vue';
import InstructionTag from '../instructiontag/InstructionTag.vue';
import ConfigServiceTypeList from '../serviceType/ConfigServiceTypeList.vue';
import BodyTagList from '/@/views/services/directivetag/bodytag/BodyTagList.vue';
import EmotionTagList from '/@/views/services/directivetag/emotiontag/EmotionTagList.vue';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { Empty } from 'ant-design-vue';
import InstructionTagModal from '/@/views/services/InstructionTag/components/InstructionTagModal.vue'
import ConfigServiceCategoryModal from '/@/views/services/serviceCategory/components//ConfigServiceCategoryModal.vue'
import ConfigServiceTypeModal from '/@/views/services/serviceType/components//ConfigServiceTypeModal.vue'
import { queryByKey } from '/@/views/admin/sysconfig/SysConfig.api'
import { getOrgInfo } from '@/api/common/api'
const insRegisterModal = ref();
const catRegisterModal = ref();
const typRegisterModal = ref();
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
const formRef = ref();
const queryParam = reactive<any>({
instructionTagId: '',
categoryId: '',
typeId: '',
});
watch(
() => queryParam.instructionTagId,
() => {
queryParam.categoryId = ''
queryParam.typeId = ''
}
)
// 当服务类别变动,清空服务类型
watch(
() => queryParam.categoryId,
() => {
queryParam.typeId = ''
}
)
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
const treeData = ref<any>([]);
const userStore = useUserStore();
const isShowDM = ref(false)//是否展示指令库功能
//注册table数据
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: '服务指令',
api: list,
columns,
canResize: false,
useSearchForm: false,
showIndexColumn: true,
scroll: { y: '58vh' },
pagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '20', '50', '100'],
},
actionColumn: {
width: 200,
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;
const labelCol = reactive({
xs: 24,
sm: 4,
xl: 6,
xxl: 4
});
const wrapperCol = reactive({
xs: 24,
sm: 20,
});
// 高级查询配置
const superQueryConfig = reactive(superQuerySchema);
const insTagOpen = ref(false)//分类标签抽屉
const categoryOpen = ref(false)//服务类别抽屉
const typeOpen = ref(false)//服务类型抽屉
const bodyTagOpen = ref(false)//体型标签抽屉
const emotionTagOpen = ref(false)//情绪标签抽屉
const mainOrgCode = ref()//指令库编码
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
searchQuery();
}
/**
* 新增事件
*/
function handleAdd() {
registerModal.value.disableSubmit = false;
registerModal.value.opeType = 'add';
registerModal.value.add();
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
registerModal.value.disableSubmit = false;
registerModal.value.opeType = 'edit';
registerModal.value.edit(record);
}
/**
* 编辑指令资源
*/
function handleMedia(record: Recordable) {
registerModal.value.disableSubmit = false;
registerModal.value.opeType = 'editMedia';
registerModal.value.editMedia(record);
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
registerModal.value.disableSubmit = true;
registerModal.value.opeType = 'look';
registerModal.value.edit(record);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
reloadTree()
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
},
// {
// label: '编辑',
// onClick: handleEdit.bind(null, record)
// },
// {
// label: '指令资源',
// onClick: handleMedia.bind(null, record)
// },
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
]
}
function expandTreeNodeToLevel4(directiveData: any) {
// 清空之前展开的节点
expandedKeys.value = [];
// 递归查找并展开相应的节点
const findAndExpandNode = (nodes: any[], level: number, directiveData: any) => {
for (const node of nodes) {
// 判断当前节点的 level 是否与 directiveData 的级别匹配
if (level === 1 && node.instructionId === directiveData.instructionTagId) {
expandedKeys.value.push(node.key);
if (node.children && node.children.length > 0) {
findAndExpandNode(node.children, 2, directiveData);
}
} else if (level === 2 && node.categoryId === directiveData.categoryId) {
expandedKeys.value.push(node.key);
if (node.children && node.children.length > 0) {
findAndExpandNode(node.children, 3, directiveData);
}
} else if (level === 3 && node.typeId === directiveData.typeId) {
expandedKeys.value.push(node.key);
if (node.children && node.children.length > 0) {
findAndExpandNode(node.children, 4, directiveData);
}
} else if (level === 4 && node.key === directiveData.id) {
expandedKeys.value.push(node.key);
}
}
};
// 调用递归方法,从树的根节点开始查找
findAndExpandNode(treeData.value, 1, directiveData);
}
/**
* 查询
*/
function searchQuery(reloadTree = true) {
if (!!queryParam.directiveName || !!queryParam.bodyTags || !!queryParam.emotionTags || !!queryParam.izEnabled) {
queryParam.instructionTagId = '';
queryParam.categoryId = '';
queryParam.typeId = '';
}
reload().then(() => {
if (reloadTree) {
initTree();
}
})
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields(); // 重置表单字段
selectedRowKeys.value = []; // 清空选中的行
// 清空 queryParam 中相关字段
queryParam.instructionTagId = '';
queryParam.categoryId = '';
queryParam.typeId = '';
queryParam.directiveName = ''; // 如果你有其他需要清除的字段,也可以加到这里
queryParam.bodyTags = '';
queryParam.emotionTags = '';
queryParam.izEnabled = '';
// 刷新数据
reload().then(() => {
initTree();
});
}
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;
}
//分类标签抽屉打开
function handleinstructionTag() {
insTagOpen.value = true
}
//服务类别抽屉打开
function handleCategory() {
categoryOpen.value = true
}
//服务类型抽屉打开
function handleType() {
typeOpen.value = true
}
//体型标签抽屉打开
function handleBodyTag() {
bodyTagOpen.value = true
}
//情绪标签抽屉打开
function handleEmotionTag() {
emotionTagOpen.value = true
}
//分类标签抽屉关闭
function onInsTagClose() {
insTagOpen.value = false
}
//服务类别抽屉关闭
function onCategoryClose() {
categoryOpen.value = false
}
//服务类型抽屉关闭
function onTypeClose() {
typeOpen.value = false
}
//体型标签抽屉关闭
function onBodyTagClose() {
bodyTagOpen.value = false
}
//体型标签抽屉关闭
function onEmotionTagClose() {
emotionTagOpen.value = false
}
const showAudioModal = ref(false); // 控制音频模态框显示
const audioUrl = ref(''); // 音频 URL
const audioPlayer = ref(null);
// 打开音频模态框
const openAudioModal = (url) => {
audioUrl.value = getFileAccessHttpUrl(url);
showAudioModal.value = true;
};
// 关闭音频模态框
const closeAudioModal = () => {
if (audioPlayer.value) {
audioPlayer.value.pause(); // 暂停音频播放
audioPlayer.value.currentTime = 0; // 可选:重置播放进度
}
showAudioModal.value = false;
audioUrl.value = '';
};
const showVideoModal = ref(false); // 控制模态框显示
const videoUrl = ref(''); // 视频 URL
const videoPlayer = ref(null);
// 打开视频模态框
const openVideoModal = (url) => {
videoUrl.value = getFileAccessHttpUrl(url);
showVideoModal.value = true;
};
// 关闭视频模态框
const closeVideoModal = () => {
if (videoPlayer.value) {
videoPlayer.value.pause(); // 暂停视频播放
videoPlayer.value.currentTime = 0; // 可选:将播放进度重置到开始
}
showVideoModal.value = false;
videoUrl.value = '';
};
// 添加以下响应式变量
const currentPlayingAudio = ref<string | null>(null);
const isPlaying = ref(false);
// 添加音频控制方法
const playAudio = (url: string) => {
if (currentPlayingAudio.value && currentPlayingAudio.value !== url) {
// 如果正在播放其他音频,先停止
stopAudio();
}
currentPlayingAudio.value = url;
isPlaying.value = true;
// 确保audio元素存在
if (audioPlayer.value) {
audioPlayer.value.src = getFileAccessHttpUrl(url);
audioPlayer.value.play().catch(e => {
isPlaying.value = false;
currentPlayingAudio.value = null;
});
}
};
const pauseAudio = () => {
if (audioPlayer.value) {
audioPlayer.value.pause();
isPlaying.value = false;
}
};
const resumeAudio = () => {
if (audioPlayer.value) {
audioPlayer.value.play().catch(e => {
});
isPlaying.value = true;
}
};
const restartAudio = () => {
if (audioPlayer.value) {
audioPlayer.value.currentTime = 0;
audioPlayer.value.play().catch(e => {
});
isPlaying.value = true;
}
};
const stopAudio = () => {
if (audioPlayer.value) {
audioPlayer.value.pause();
audioPlayer.value.currentTime = 0;
isPlaying.value = false;
currentPlayingAudio.value = null;
}
};
const clickCount = ref(0);
const treeChildData = ref<any>([]);
const expandedKeys = ref<string[]>([]);
// 为每个 node 维护一个菜单状态和 hover 定时器
const menuState = reactive<Record<string, { timer?: number, openedByClick: boolean, open: boolean }>>({
})
function onNodeEnter(node, level, event) {
node.showIcon = true
}
function onNodeLeave(node) {
node.showIcon = false
}
function onNodeIconEnter(node, level) {
// 检查当前节点是否已经展开,如果是,则跳过关闭所有菜单的操作
const key = node.key;
const currentMenuState = menuState[key];
if (currentMenuState?.open) {
// 当前菜单已经展开,直接返回
return;
}
// 如果没有菜单状态,则初始化
if (!menuState[key]) {
menuState[key] = { openedByClick: false, open: false };
}
// 只有前三级需要自动展开
if (level <= 3 && !menuState[key].openedByClick) {
menuState[key].timer = window.setTimeout(() => {
menuState[key].open = true;
}, 2000);
}
}
function onNodeIconLeave(node) {
const s = menuState[node.key]
if (s?.timer) {
clearTimeout(s.timer)
delete s.timer
}
}
// 用户点击图标手动打开
function openMenu(node, level, ev) {
closeAllMenus();
const key = node.key
if (!menuState[key]) menuState[key] = { openedByClick: false, open: false }
menuState[key].openedByClick = true
menuState[key].open = true
}
// 当 Dropdown 自身触发 openChange比如点击外部关闭同步状态
function onMenuOpenChange(key: string, open: boolean) {
if (!menuState[key]) menuState[key] = { open: false, openedByClick: false }
menuState[key].open = open
// 如果是外部关闭,则重置 clicked 状态
if (!open) menuState[key].openedByClick = false
}
// 关闭所有菜单工具函数
function closeAllMenus() {
Object.keys(menuState).forEach(k => {
menuState[k].open = false
menuState[k].openedByClick = false
})
}
// 根据层级返回图标 class
function iconClass(level: number) {
switch (level) {
case 1: return 'ant-design:setting-twotone'
case 2: return 'ant-design:setting-twotone'
case 3: return 'ant-design:setting-twotone'
case 4: return 'ant-design:setting-outlined'
default: return 'ant-design:setting-outlined'
}
}
//新增分类标签
function addInstruction() {
insRegisterModal.value.disableSubmit = false;
insRegisterModal.value.add();
}
//启用分类标签
function usingInstruction(data) {
insRegisterModal.value.usingOrStop(data.instructionId, '0')
}
//停用分类标签
function stopInstruction(data) {
insRegisterModal.value.usingOrStop(data.instructionId, '1')
}
//新增服务类别
function addCategory(data) {
catRegisterModal.value.disableSubmit = false;
catRegisterModal.value.edit({ instructionId: data.instructionId });
}
//启用服务类别
function usingCategory(data) {
catRegisterModal.value.usingOrStop(data.categoryId, '0')
}
//停用服务类别
function stopCategory(data) {
catRegisterModal.value.usingOrStop(data.categoryId, '1')
}
//新增服务类型
function addType(data) {
typRegisterModal.value.disableSubmit = false;
typRegisterModal.value.edit({ instructionId: data.instructionId, categoryId: data.categoryId });
}
//启用服务类型
function usingType(data) {
typRegisterModal.value.usingOrStop(data.typeId, '0')
}
//停用服务类型
function stopType(data) {
typRegisterModal.value.usingOrStop(data.typeId, '1')
}
//新增服务指令
function addDirective(data) {
registerModal.value.disableSubmit = false;
registerModal.value.opeType = 'add';
registerModal.value.edit({ instructionTagId: data.instructionId, categoryId: data.categoryId, typeId: data.typeId });
}
//编辑务指令
function editDirective(data) {
registerModal.value.disableSubmit = false;
registerModal.value.opeType = 'edit';
registerModal.value.queryByIdFunc(data.key);
}
//指令资源
function editMedia(data) {
registerModal.value.disableSubmit = false;
registerModal.value.opeType = 'editMedia';
registerModal.value.queryAndEditMedia(data.key);
}
//启用服务指令
function usingDirective(data) {
registerModal.value.usingOrStop(data.key, '0');
}
//停用服务指令
function stopDirective(data) {
registerModal.value.usingOrStop(data.key, '1');
}
//查看体型标签
function bodyTagsDetail(data) {
}
//查看情绪标签
function emotionTagsDetail(data) {
}
// 根据层级返回菜单项
function menuItems(data) {
if (data.level === 1) {
const items = [
{ key: 'addIns', label: '新增分类标签', icon: 'ant-design:plus-outlined', action: addInstruction },
]
if (data.canAdd) {
items.push({ key: 'addCat', label: '新增服务类别', icon: 'ant-design:plus-outlined', action: addCategory })
}
if (data.izEnabled === '1') {
items.push({ key: 'usingIns', label: '启用分类标签', icon: 'ant-design:check-circle-outlined', action: usingInstruction })
} else if (data.izEnabled === '0') {
items.push({ key: 'stopIns', label: '停用分类标签', icon: 'ant-design:stop-outlined', action: stopInstruction })
}
return items
}
else if (data.level === 2) {
const items = [
{ key: 'addCat', label: '新增服务类别', icon: 'ant-design:plus-outlined', action: addCategory },
]
if (data.canAdd) {
items.push({ key: 'addTyp', label: '新增服务类型', icon: 'ant-design:plus-outlined', action: addType })
}
if (data.izEnabled === '1') {
items.push({ key: 'usingCat', label: '启用服务类别', icon: 'ant-design:check-circle-outlined', action: usingCategory })
} else if (data.izEnabled === '0') {
items.push({ key: 'stopCat', label: '停用服务类别', icon: 'ant-design:stop-outlined', action: stopCategory })
}
return items
}
else if (data.level === 3) {
const items = [
{ key: 'addTyp', label: '新增服务类型', icon: 'ant-design:plus-outlined', action: addType },
]
if (data.canAdd) {
items.push({ key: 'addDir', label: '新增服务指令', icon: 'ant-design:plus-outlined', action: addDirective })
}
if (data.izEnabled === '1') {
items.push({ key: 'usingTyp', label: '启用服务类型', icon: 'ant-design:check-circle-outlined', action: usingType })
} else if (data.izEnabled === '0') {
items.push({ key: 'stopTyp', label: '停用服务类型', icon: 'ant-design:stop-outlined', action: stopType })
}
return items
}
else if (data.level === 4) {
const items = [
{ key: 'editDir', label: '编辑服务指令', icon: 'ant-design:edit-outlined', action: editDirective },
{ key: 'editMedia', label: '编辑指令资源', icon: 'ant-design:edit-outlined', action: editMedia },
]
// if (data.canAdd) {
// items.push({ key: 'addDir', label: '新增服务指令', icon: 'ant-design:plus-outlined', action: addDirective })
// }
if (data.izEnabled === '1') {
items.push({ key: 'usingDir', label: '启用服务指令', icon: 'ant-design:check-circle-outlined', action: usingDirective })
} else if (data.izEnabled === '0') {
items.push({ key: 'stopDir', label: '停用服务指令', icon: 'ant-design:stop-outlined', action: stopDirective })
}
if (data?.bodyTagList?.length > 0) {
items.push({ key: 'bodyTagsDetail', label: '查看体型标签', icon: 'ant-design:stop-outlined', action: bodyTagsDetail })
}
if (data?.emotionTagList?.length > 0) {
items.push({ key: 'emotionTagsDetail', label: '查看情绪标签', icon: 'ant-design:stop-outlined', action: emotionTagsDetail })
}
return items
}
return []
}
// 递归取每级第一个 key
function setDefaultExpanded(nodes: any[]) {
expandedKeys.value.push(nodes[0].key)
expandedKeys.value.push(nodes[0]?.children?.[0]?.key)
expandedKeys.value.push(nodes[0]?.children?.[0]?.children?.[0]?.key)
}
const treeLoading = ref(false)
function reloadTree() {
tree().then(res => {
treeData.value = res;
})
}
function handleTreeSelect(selectedKeys: string[], { node }: any) {
const level = node.level;
// 清空不必要的查询条件
queryParam.directiveName = '';
queryParam.bodyTags = '';
queryParam.emotionTags = '';
queryParam.izEnabled = '';
// 根据节点级别设置查询条件
switch (level) {
case 1: // 分类标签
queryParam.instructionTagId = node.instructionId;
queryParam.categoryId = '';
queryParam.typeId = '';
break;
case 2: // 服务类别
queryParam.instructionTagId = node.instructionId;
queryParam.categoryId = node.categoryId;
queryParam.typeId = '';
break;
case 3: // 服务类型
queryParam.instructionTagId = node.instructionId;
queryParam.categoryId = node.categoryId;
queryParam.typeId = node.typeId;
break;
case 4: // 服务指令
// 四级节点特殊处理:设置指令名称
queryParam.instructionTagId = node.instructionId;
queryParam.categoryId = node.categoryId;
queryParam.typeId = node.typeId;
queryParam.directiveName = node.title;
break;
}
if (level == 5) return
// 触发查询
searchQuery(false);
}
function initTree() {
treeLoading.value = true
tree().then(res => {
treeData.value = res;
expandedKeys.value = []
//默认展开每级第一个
setDefaultExpanded(res)
})
.finally(() => {
treeLoading.value = false
})
}
/**
* 查看指令库
*/
function handleDirectiveMainOpen() {
registerModal.value?.openDM(mainOrgCode.value)
}
async function getDirectiveMainOrgCode() {
let { orgCode } = await getOrgInfo()
let { configValue } = await queryByKey({ key: 'directive_main_org_code' })
mainOrgCode.value = configValue
if (orgCode != configValue) isShowDM.value = true
}
// 添加音频结束监听
onMounted(() => {
if (audioPlayer.value) {
audioPlayer.value.addEventListener('ended', () => {
isPlaying.value = false;
});
}
initTree()
getDirectiveMainOrgCode()
});
</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;
}
.btnPrivate {
height: 34px;
margin-left: 4px;
}
.node-title {
display: inline-flex;
align-items: center;
}
.action-icon {
margin-left: 4px;
cursor: pointer;
}
:deep(.centered-dropdown) {
position: fixed;
left: 50% !important;
top: 50% !important;
transform: translate(-50%, -50%) !important;
max-height: 80vh;
overflow-y: auto;
.ant-dropdown-menu {
max-height: 70vh;
overflow-y: auto;
}
}
.backClass{
background: url(../../resource/img/modalback.png);
}
</style>