811 lines
25 KiB
Vue
811 lines
25 KiB
Vue
<!-- SidePanelItem.vue -->
|
||
<template>
|
||
<div class="qgc-side-pannel-item">
|
||
<div class="qgc_title">
|
||
<div class="title_left">
|
||
<span class="texttitle">{{ title }}</span>
|
||
<span v-if="prompt.show" class="title_icon">
|
||
<a-tooltip placement="top" :title="prompt.value" :get-popup-container="getPopupContainer">
|
||
<QuestionCircleOutlined />
|
||
</a-tooltip>
|
||
</span>
|
||
<span v-if="clickprompt.show" class="title_icon">
|
||
<a-tooltip placement="top" trigger="click" :title="clickprompt.value"
|
||
:get-popup-container="getPopupContainer">
|
||
<InfoCircleOutlined />
|
||
</a-tooltip>
|
||
</span>
|
||
<span v-if="iconmap.show" class="title_icon">
|
||
<a-tooltip placement="top" :title="iconmap.value" :get-popup-container="getPopupContainer">
|
||
<span :class="iconmap.icon"></span>
|
||
</a-tooltip>
|
||
</span>
|
||
</div>
|
||
<div class="title_right">
|
||
<div v-if="select.show">
|
||
<a-select v-model:value="selectValue" show-search placeholder="请选择" :size="'small'"
|
||
style="width: 120px" :options="select.options" :filter-option="filterOption"
|
||
@focus="handleFocus" @blur="handleBlur" @change="handleChange"></a-select>
|
||
</div>
|
||
<div v-if="shrink" class="title_shrink" @click="isExpand = !isExpand">
|
||
<img v-if="isExpand" src="@/assets/components/arrow-up.png" alt="">
|
||
<img v-else src="@/assets/components/arrow-down.png" alt="">
|
||
</div>
|
||
<div v-if="moreSelect.show">
|
||
<a-tree-select v-model:value="moreSelectValue" v-model:tree-expanded-keys="treeExpandedKeys"
|
||
show-search :size="'small'" style="width: 110px"
|
||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto', minWidth: '180px' }" placeholder=" "
|
||
:tree-data="processedMoreSelectOptions"
|
||
:field-names="{ label: 'title', value: 'value', children: 'children' }"
|
||
tree-node-filter-prop="label" popup-class-name="no-wrap-tree-select" @select="handleTreeSelect"
|
||
@expand="handleTreeExpand">
|
||
</a-tree-select>
|
||
</div>
|
||
<div v-if="datetimePicker.show">
|
||
<!-- 添加 locale 属性来设置语言 -->
|
||
<a-date-picker v-model:value="datetimeValue" show-time
|
||
:style="{ width: datetimePicker.picker === 'year' ? '80px' : datetimePicker.picker === 'month' ? '90px' : '130px' }"
|
||
:format="datetimePicker.format !== null ? datetimePicker.format : undefined"
|
||
:picker="datetimePicker.picker" :allowClear="false" placeholder=" "
|
||
@change="handleDateTimeChange" :size="'small'"
|
||
:disabledDate="createDisabledDateFn(datetimePicker.picker)"
|
||
:disabledTime="disabledTimeForSinglePicker" />
|
||
<!-- 修改为 locale 变量 -->
|
||
</div>
|
||
<div v-if="scopeDate.show" class="title_scopeDate">
|
||
<a-range-picker v-model:value="scopeDateValue" :picker="scopeDate.picker" :allowClear="false"
|
||
:style="{ width: scopeDate.picker === 'year' ? '80px' : (scopeDate.picker === 'month' ? '180px' : '') }"
|
||
:format="scopeDate.format" :range-separator="' 至 '" :size="'small'"
|
||
:presets="computedScopeDatePresets" :disabledDate="createDisabledDateFn(scopeDate.picker)" />
|
||
</div>
|
||
<div v-if="tabs.show" class="typeOne">
|
||
<div @click="handleTabClick('one')" :class="tabsValue == 'one' ? 'typezhong' : ''">图片</div>
|
||
<div @click="handleTabClick('two')" :class="tabsValue == 'two' ? 'typezhong' : ''">视频</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="body">
|
||
<slot v-if="isExpand" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref, onMounted, watch, computed, nextTick } from 'vue';
|
||
import {
|
||
QuestionCircleOutlined,
|
||
InfoCircleOutlined
|
||
} from '@ant-design/icons-vue';
|
||
import type { SelectProps } from 'ant-design-vue';
|
||
// 导入 dayjs
|
||
import dayjs, { Dayjs } from 'dayjs';
|
||
|
||
// 定义类型接口
|
||
interface PromptConfig {
|
||
show: boolean;
|
||
value: string;
|
||
icon?: string;
|
||
}
|
||
|
||
interface SelectConfig {
|
||
picker: any;
|
||
format: any;
|
||
show: boolean;
|
||
value: string | undefined;
|
||
options: SelectProps['options'];
|
||
}
|
||
|
||
// 定义组件名(便于调试和递归)
|
||
defineOptions({
|
||
name: 'SidePanelItem'
|
||
});
|
||
|
||
// 定义props
|
||
const props = defineProps({
|
||
title: { // 标题
|
||
type: String,
|
||
default: ''
|
||
},
|
||
shrink: { // 是否显示收缩
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
prompt: { // 浮动提示
|
||
type: Object as () => PromptConfig,
|
||
default: () => ({
|
||
show: false,
|
||
value: '',
|
||
})
|
||
},
|
||
clickprompt: { // 点击提示
|
||
type: Object as () => PromptConfig,
|
||
default: () => ({
|
||
show: false,
|
||
value: '',
|
||
})
|
||
},
|
||
iconmap: {//自定义图标浮动
|
||
type: Object as () => PromptConfig,
|
||
default: () => ({
|
||
show: false,
|
||
value: '',
|
||
icon: 'iconfont icon-time',
|
||
})
|
||
},
|
||
select: { // 选择框
|
||
type: Object as () => SelectConfig,
|
||
default: () => ({
|
||
show: false,
|
||
value: undefined,
|
||
options: []
|
||
})
|
||
},
|
||
moreSelect: {//树选择框
|
||
type: Object as () => SelectConfig,
|
||
default: () => ({
|
||
show: false,
|
||
value: undefined,
|
||
options: []
|
||
})
|
||
},
|
||
datetimePicker: { // 时间选择框
|
||
type: Object as () => SelectConfig,
|
||
default: () => ({
|
||
show: false,
|
||
value: undefined,
|
||
format: null, //YYYY-MM-DD HH
|
||
picker: 'date' //date | week | month | quarter | year
|
||
})
|
||
},
|
||
scopeDate: { // 时间选择框
|
||
type: Object as () => SelectConfig,
|
||
default: () => ({
|
||
show: false,
|
||
value: undefined,
|
||
format: null, //YYYY-MM-DD HH
|
||
picker: 'month' //date | week | month | quarter | year
|
||
})
|
||
},
|
||
tabs: {
|
||
type: Object,
|
||
default: () => ({
|
||
show: false,
|
||
value: 'one',
|
||
})
|
||
}
|
||
});
|
||
const emit = defineEmits(['tab-change', 'update-values']);
|
||
const isExpand = ref(true);
|
||
const selectValue = ref(props.select.value)
|
||
const moreSelectValue = ref(props.moreSelect.value)
|
||
const datetimeValue = ref<Dayjs | null>(props.datetimePicker.value ? dayjs(props.datetimePicker.value) : null);
|
||
const scopeDateValue = ref<[Dayjs, Dayjs] | undefined>(
|
||
props.scopeDate.value && Array.isArray(props.scopeDate.value)
|
||
? [dayjs(props.scopeDate.value[0]), dayjs(props.scopeDate.value[1])]
|
||
: undefined
|
||
);
|
||
const tabsValue = ref(props.tabs.value)
|
||
|
||
// 树形选择器展开状态管理
|
||
const treeExpandedKeys = ref<string[]>([])
|
||
const nodeMap = new Map<string, { node: any; parentKey: string | null }>()
|
||
|
||
/**
|
||
* 创建针对不同 picker 类型的日期禁用函数
|
||
* @param pickerType - 选择器类型: year | month | quarter | week | date
|
||
* @returns disabledDate 回调函数
|
||
*/
|
||
const createDisabledDateFn = (pickerType: string) => {
|
||
return (current: Dayjs) => {
|
||
if (!current) return false
|
||
|
||
const now = dayjs()
|
||
|
||
switch (pickerType) {
|
||
case 'year':
|
||
// 年份选择器:禁用 > 当前年份
|
||
return current.year() > now.year()
|
||
|
||
case 'month':
|
||
// 月份选择器:禁用 > 当前年月
|
||
return current.isAfter(now, 'month')
|
||
|
||
case 'quarter':
|
||
// 季度选择器:禁用 > 当前季度
|
||
return current.isAfter(now, 'quarter')
|
||
|
||
case 'week':
|
||
// 周选择器:禁用 > 当前周
|
||
return current.isAfter(now, 'week')
|
||
|
||
case 'date':
|
||
default:
|
||
// 日期选择器:禁用 > 当前日期
|
||
return current.isAfter(now, 'day')
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 单日期选择器的时间禁用函数(针对 show-time)
|
||
* 精确限制到当前时刻的时分秒
|
||
*/
|
||
const disabledTimeForSinglePicker = () => {
|
||
// 只在 datetimePicker 显示且为 date 类型时生效
|
||
if (!props.datetimePicker.show || props.datetimePicker.picker !== 'date') {
|
||
return undefined
|
||
}
|
||
|
||
const now = dayjs()
|
||
const selectedDate = datetimeValue.value
|
||
|
||
// 如果未选择日期,或选择的不是今天,则不限制时间
|
||
if (!selectedDate || !selectedDate.isSame(now, 'day')) {
|
||
return {}
|
||
}
|
||
|
||
// 辅助函数:生成从 start 到 end-1 的数组
|
||
const range = (start: number, end: number) => {
|
||
const result: number[] = []
|
||
for (let i = start; i < end; i++) {
|
||
result.push(i)
|
||
}
|
||
return result
|
||
}
|
||
|
||
return {
|
||
// 禁用当前小时之后的所有小时
|
||
disabledHours: () => {
|
||
return range(now.hour() + 1, 24)
|
||
},
|
||
|
||
// 禁用当前分钟之后的所有分钟(仅在当前小时)
|
||
disabledMinutes: (selectedHour: number) => {
|
||
if (selectedHour === now.hour()) {
|
||
return range(now.minute() + 1, 60)
|
||
}
|
||
return []
|
||
},
|
||
|
||
// 禁用当前秒数之后的所有秒数(仅在当前小时和分钟)
|
||
disabledSeconds: (selectedHour: number, selectedMinute: number) => {
|
||
if (selectedHour === now.hour() && selectedMinute === now.minute()) {
|
||
return range(now.second() + 1, 60)
|
||
}
|
||
return []
|
||
}
|
||
}
|
||
}
|
||
|
||
// // 定义 locale 变量
|
||
// const locale = zhCN;
|
||
|
||
// console.log(locale, "zhCN");
|
||
|
||
/**
|
||
* 递归处理树数据,为父节点添加 selectable: false
|
||
* @param data 原始树数据
|
||
* @returns 处理后的树数据
|
||
*/
|
||
const processTreeData = (data: any[]): any[] => {
|
||
if (!data || !Array.isArray(data)) return [];
|
||
|
||
return data.map(item => {
|
||
const newItem = { ...item };
|
||
|
||
// 如果有子项,标记为不可选中
|
||
if (newItem.children && newItem.children.length > 0) {
|
||
newItem.selectable = false;
|
||
// 递归处理子项
|
||
newItem.children = processTreeData(newItem.children);
|
||
} else {
|
||
// 叶子节点默认可选中(显式声明更清晰)
|
||
newItem.selectable = true;
|
||
}
|
||
|
||
return newItem;
|
||
});
|
||
};
|
||
|
||
// 计算属性:处理后的树数据
|
||
const processedMoreSelectOptions = computed(() => {
|
||
return processTreeData(props.moreSelect.options || []);
|
||
});
|
||
|
||
/**
|
||
* 构建树节点映射(建立父子关系)
|
||
* @param treeData 树形数据
|
||
* @param parentKey 父节点key
|
||
*/
|
||
const buildNodeMap = (treeData: any[], parentKey: string | null = null) => {
|
||
if (!treeData || !Array.isArray(treeData)) return
|
||
|
||
treeData.forEach(node => {
|
||
// 存储当前节点及其父节点信息
|
||
nodeMap.set(node.value, {
|
||
node,
|
||
parentKey
|
||
})
|
||
|
||
// 递归处理子节点
|
||
if (node.children && node.children.length > 0) {
|
||
buildNodeMap(node.children, node.value)
|
||
}
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 获取目标节点的所有父节点keys
|
||
* @param targetValue 目标节点value
|
||
* @returns 父节点keys数组(从根到直接父节点)
|
||
*/
|
||
const getParentKeys = (targetValue: string): string[] => {
|
||
const parentKeys: string[] = []
|
||
let currentKey: string | null = targetValue
|
||
|
||
// 向上追溯所有父节点
|
||
while (currentKey !== null && currentKey !== undefined) {
|
||
const nodeInfo = nodeMap.get(currentKey)
|
||
|
||
// 如果节点不存在或已到达根节点,停止追溯
|
||
if (!nodeInfo || nodeInfo.parentKey === null || nodeInfo.parentKey === undefined) {
|
||
break
|
||
}
|
||
|
||
// 将父节点插入到数组开头(保持从根到叶的顺序)
|
||
parentKeys.unshift(nodeInfo.parentKey)
|
||
currentKey = nodeInfo.parentKey
|
||
}
|
||
|
||
return parentKeys
|
||
}
|
||
|
||
/**
|
||
* 计算属性:根据 picker 类型动态生成快捷日期选项
|
||
*/
|
||
const computedScopeDatePresets = computed(() => {
|
||
const now = dayjs();
|
||
const presets: Array<{ label: string; value: [Dayjs, Dayjs] }> = [];
|
||
|
||
// 根据 picker 类型生成对应的快捷选项
|
||
switch (props.scopeDate.picker) {
|
||
case 'year':
|
||
// 年份选择器:只显示今年
|
||
presets.push({
|
||
label: '今年',
|
||
value: [now.startOf('year'), now]
|
||
});
|
||
break;
|
||
|
||
case 'month':
|
||
// 月份选择器:显示今天、昨天、最近七天、最近一个月、最近三个月、今年
|
||
presets.push(
|
||
{
|
||
label: '今天',
|
||
value: [now.startOf('day'), now.endOf('day')]
|
||
},
|
||
{
|
||
label: '昨天',
|
||
value: [now.subtract(1, 'day').startOf('day'), now.subtract(1, 'day').endOf('day')]
|
||
},
|
||
{
|
||
label: '最近七天',
|
||
value: [now.subtract(6, 'day').startOf('day'), now.endOf('day')]
|
||
},
|
||
{
|
||
label: '最近一个月',
|
||
value: [now.subtract(1, 'month').startOf('day'), now.endOf('day')]
|
||
},
|
||
{
|
||
label: '最近三个月',
|
||
value: [now.subtract(3, 'month').startOf('day'), now.endOf('day')]
|
||
},
|
||
{
|
||
label: '今年',
|
||
value: [now.startOf('year'), now.endOf('day')]
|
||
}
|
||
);
|
||
break;
|
||
|
||
case 'quarter':
|
||
// 季度选择器:显示最近一季度、今年
|
||
presets.push(
|
||
{
|
||
label: '最近一季度',
|
||
value: [now.subtract(1, 'quarter').startOf('quarter'), now.endOf('quarter')]
|
||
},
|
||
{
|
||
label: '今年',
|
||
value: [now.startOf('year'), now.endOf('quarter')]
|
||
}
|
||
);
|
||
break;
|
||
|
||
case 'week':
|
||
// 周选择器:显示本周、上周、最近四周
|
||
presets.push(
|
||
{
|
||
label: '本周',
|
||
value: [now.startOf('week'), now.endOf('week')]
|
||
},
|
||
{
|
||
label: '上周',
|
||
value: [now.subtract(1, 'week').startOf('week'), now.subtract(1, 'week').endOf('week')]
|
||
},
|
||
{
|
||
label: '最近四周',
|
||
value: [now.subtract(3, 'week').startOf('week'), now.endOf('week')]
|
||
}
|
||
);
|
||
break;
|
||
|
||
case 'date':
|
||
default:
|
||
// 日期选择器:显示所有常用选项
|
||
presets.push(
|
||
{
|
||
label: '今天',
|
||
value: [now.startOf('day'), now.endOf('day')]
|
||
},
|
||
{
|
||
label: '昨天',
|
||
value: [now.subtract(1, 'day').startOf('day'), now.subtract(1, 'day').endOf('day')]
|
||
},
|
||
{
|
||
label: '最近七天',
|
||
value: [now.subtract(6, 'day').startOf('day'), now.endOf('day')]
|
||
},
|
||
{
|
||
label: '最近一个月',
|
||
value: [now.subtract(1, 'month').startOf('day'), now.endOf('day')]
|
||
},
|
||
{
|
||
label: '最近三个月',
|
||
value: [now.subtract(3, 'month').startOf('day'), now.endOf('day')]
|
||
},
|
||
{
|
||
label: '今年',
|
||
value: [now.startOf('year'), now.endOf('day')]
|
||
}
|
||
);
|
||
break;
|
||
}
|
||
|
||
return presets;
|
||
});
|
||
|
||
/**
|
||
* 处理树节点选择事件
|
||
* 由于父节点已设置 selectable: false,这里只会接收到叶子节点
|
||
* @param selectedKeys 选中的键值(可能是字符串或数组)
|
||
* @param info 节点信息对象(本身就是节点,不是包含 node 的对象)
|
||
*/
|
||
const handleTreeSelect = (selectedKeys: string | string[], info: any) => {
|
||
// selectedKeys 可能是字符串(单选模式)或数组(多选模式)
|
||
let selectedValue: string;
|
||
|
||
if (typeof selectedKeys === 'string') {
|
||
// 单选模式:selectedKeys 直接就是字符串
|
||
selectedValue = selectedKeys;
|
||
} else if (Array.isArray(selectedKeys)) {
|
||
// 多选模式:取第一个元素
|
||
selectedValue = selectedKeys[0];
|
||
} else {
|
||
// 兜底:尝试从 info 中获取
|
||
selectedValue = info?.value || '';
|
||
}
|
||
|
||
moreSelectValue.value = selectedValue;
|
||
};
|
||
|
||
/**
|
||
* 处理树节点展开/收起事件
|
||
* @param keys 展开的节点键值数组
|
||
*/
|
||
const handleTreeExpand = (keys: string[]) => {
|
||
// 保留事件处理函数以维持组件接口完整性
|
||
};
|
||
|
||
// 下拉选择框事件处理
|
||
const handleChange = (value: string) => {
|
||
// Handle change
|
||
};
|
||
|
||
const handleBlur = () => {
|
||
// Handle blur
|
||
};
|
||
|
||
const handleFocus = () => {
|
||
// Handle focus
|
||
};
|
||
|
||
const filterOption = (input: string, option?: { value: string }) => {
|
||
if (!option) return false;
|
||
return option.value.toLowerCase().includes(input.toLowerCase());
|
||
};
|
||
|
||
// 文字提示容器
|
||
const getPopupContainer = (trigger: HTMLElement) => {
|
||
return trigger.parentElement;
|
||
};
|
||
|
||
//时间选择框事件处理
|
||
const handleDateTimeChange = (date: any | null, dateString: string) => {
|
||
// Handle date time change
|
||
};
|
||
|
||
const handleTabClick = (value: string) => {
|
||
tabsValue.value = value;
|
||
// 向父组件传递参数
|
||
emit('tab-change', {
|
||
tabValue: value,
|
||
tabLabel: value === 'one' ? '图片' : '视频'
|
||
});
|
||
};
|
||
|
||
// 统一收集并发送所有控件的值
|
||
const emitAllValues = () => {
|
||
const payload: any = {
|
||
select: selectValue.value,
|
||
moreSelect: moreSelectValue.value,
|
||
tabs: tabsValue.value,
|
||
};
|
||
|
||
// 处理单个时间选择器
|
||
if (datetimeValue.value) {
|
||
// 使用传入的 format,如果没有则根据 picker 类型设置默认格式
|
||
const format = props.datetimePicker.format || getDefaultFormat(props.datetimePicker.picker);
|
||
payload.datetime = datetimeValue.value.format(format);
|
||
} else {
|
||
payload.datetime = null;
|
||
}
|
||
|
||
// 处理时间范围选择器
|
||
if (scopeDateValue.value && Array.isArray(scopeDateValue.value)) {
|
||
// 使用传入的 format,如果没有则根据 picker 类型设置默认格式
|
||
const format = props.scopeDate.format || getDefaultFormat(props.scopeDate.picker);
|
||
payload.scopeDate = scopeDateValue.value.map(d => d ? d.format(format) : null);
|
||
} else {
|
||
payload.scopeDate = [];
|
||
}
|
||
|
||
emit('update-values', payload);
|
||
};
|
||
|
||
// 根据 picker 类型获取默认格式
|
||
const getDefaultFormat = (picker: string): string => {
|
||
switch (picker) {
|
||
case 'year':
|
||
return 'YYYY';
|
||
case 'month':
|
||
return 'YYYY-MM';
|
||
case 'quarter':
|
||
return 'YYYY-[Q]Q';
|
||
case 'week':
|
||
return 'YYYY-wo';
|
||
case 'date':
|
||
default:
|
||
return 'YYYY-MM-DD';
|
||
}
|
||
};
|
||
|
||
// 监听各个变量的变化
|
||
watch([selectValue, moreSelectValue, datetimeValue, scopeDateValue, tabsValue], () => {
|
||
emitAllValues();
|
||
});
|
||
|
||
// 监听 props 变化,实现父子组件数据同步
|
||
watch(
|
||
() => props.select.value,
|
||
(newVal) => {
|
||
if (newVal !== selectValue.value) {
|
||
selectValue.value = newVal;
|
||
}
|
||
}
|
||
);
|
||
|
||
// 监听 moreSelectValue 的变化,移除了自动展开逻辑
|
||
watch(
|
||
() => props.moreSelect.value,
|
||
(newVal) => {
|
||
if (newVal !== moreSelectValue.value) {
|
||
moreSelectValue.value = newVal;
|
||
}
|
||
}
|
||
);
|
||
|
||
watch(
|
||
() => props.datetimePicker.value,
|
||
(newVal) => {
|
||
const newDayjs = newVal ? dayjs(newVal) : null;
|
||
if (!datetimeValue.value || !newDayjs || !datetimeValue.value.isSame(newDayjs)) {
|
||
datetimeValue.value = newDayjs;
|
||
}
|
||
}
|
||
);
|
||
|
||
watch(
|
||
() => props.scopeDate.value,
|
||
(newVal) => {
|
||
if (newVal && Array.isArray(newVal) && newVal.length === 2) {
|
||
const newRange: [Dayjs, Dayjs] = [dayjs(newVal[0]), dayjs(newVal[1])];
|
||
const currentRange = scopeDateValue.value;
|
||
|
||
// 检查是否需要更新(避免不必要的触发)
|
||
if (!currentRange ||
|
||
!currentRange[0].isSame(newRange[0]) ||
|
||
!currentRange[1].isSame(newRange[1])) {
|
||
scopeDateValue.value = newRange;
|
||
}
|
||
} else {
|
||
if (scopeDateValue.value) {
|
||
scopeDateValue.value = undefined;
|
||
}
|
||
}
|
||
}
|
||
);
|
||
|
||
watch(
|
||
() => props.tabs.value,
|
||
(newVal) => {
|
||
if (newVal !== tabsValue.value) {
|
||
tabsValue.value = newVal;
|
||
}
|
||
}
|
||
);
|
||
|
||
// 监听 moreSelectValue 变化(包括默认值和用户选择)
|
||
watch(() => moreSelectValue.value, (newValue) => {
|
||
console.log('moreSelectValue 变化:', newValue)
|
||
|
||
if (newValue && nodeMap.size > 0) {
|
||
// 只有当 nodeMap 已构建时才执行
|
||
const parentKeys = getParentKeys(newValue as string)
|
||
treeExpandedKeys.value = parentKeys
|
||
console.log('自动展开父节点:', parentKeys)
|
||
} else {
|
||
treeExpandedKeys.value = []
|
||
}
|
||
}, { immediate: true }) // immediate: true 确保默认值也能触发
|
||
|
||
// 监听树数据变化,重新构建映射
|
||
watch(() => processedMoreSelectOptions.value, (newData) => {
|
||
console.log('树数据变化,重新构建映射')
|
||
|
||
if (newData && newData.length > 0) {
|
||
// 清空旧映射
|
||
nodeMap.clear()
|
||
// 重新构建映射
|
||
buildNodeMap(newData)
|
||
|
||
// 数据加载完成后,如果已有默认值,重新触发一次
|
||
if (moreSelectValue.value) {
|
||
nextTick(() => {
|
||
const parentKeys = getParentKeys(moreSelectValue.value as string)
|
||
treeExpandedKeys.value = parentKeys
|
||
console.log('数据加载后自动展开父节点:', parentKeys)
|
||
})
|
||
}
|
||
}
|
||
}, { deep: true })
|
||
|
||
// 页面加载时执行的逻辑
|
||
onMounted(() => {
|
||
// 初始化时发送一次默认值
|
||
emitAllValues();
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.qgc-side-pannel-item {
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
flex-direction: column;
|
||
|
||
.qgc_title {
|
||
width: 100%;
|
||
background-color: #e5edf3;
|
||
border-radius: 2px;
|
||
font-size: 16px;
|
||
color: #2f6b98;
|
||
line-height: 36px;
|
||
padding-left: 16px;
|
||
padding-right: 8px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
position: relative;
|
||
font-weight: 500;
|
||
|
||
.title_shrink {
|
||
cursor: pointer;
|
||
}
|
||
|
||
.title_left {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.texttitle {
|
||
display: inline-block;
|
||
//width:180px;
|
||
}
|
||
|
||
.title_icon {
|
||
display: inline-block;
|
||
margin-left: 5px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
}
|
||
|
||
.title_right {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
div {
|
||
|
||
margin-right: 2px;
|
||
}
|
||
}
|
||
|
||
.typeOne {
|
||
display: flex;
|
||
// width: 84px;
|
||
height: 24px;
|
||
box-sizing: border-box;
|
||
cursor: pointer;
|
||
|
||
div {
|
||
width: 38px;
|
||
height: 24px;
|
||
font-size: 14px;
|
||
line-height: 24px;
|
||
text-align: center;
|
||
background: #fff;
|
||
margin: 0px;
|
||
color: rgba(0, 0, 0, .85);
|
||
}
|
||
|
||
.typezhong {
|
||
background: #40a9ff;
|
||
color: #fff;
|
||
}
|
||
}
|
||
}
|
||
|
||
.qgc_title:before {
|
||
position: absolute;
|
||
content: "";
|
||
display: inline-block;
|
||
left: 0;
|
||
width: 2px;
|
||
background-color: #005293;
|
||
top: 2px;
|
||
height: 32px;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.body {
|
||
width: 100%;
|
||
font-size: 14px;
|
||
line-height: 22px;
|
||
padding: 16px 0 0;
|
||
margin-bottom: 16px;
|
||
text-overflow: ellipsis;
|
||
overflow: hidden;
|
||
height: calc(100% - 36px);
|
||
box-sizing: border-box;
|
||
|
||
|
||
p {
|
||
text-indent: 2em;
|
||
}
|
||
}
|
||
}
|
||
|
||
.title_scopeDate {
|
||
:deep(.ant-picker-range-separator) {
|
||
padding: 0px !important;
|
||
}
|
||
}
|
||
</style> |