2026-03-31 10:14:20 +08:00
|
|
|
<!-- SidePanelItem.vue -->
|
|
|
|
|
<template>
|
|
|
|
|
<div class="qgc-side-pannel-item">
|
|
|
|
|
<div class="qgc_title">
|
|
|
|
|
<div class="title_left">
|
2026-05-09 17:04:48 +08:00
|
|
|
<span class="texttitle">{{ title }}</span>
|
2026-03-31 10:14:20 +08:00
|
|
|
<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>
|
2026-05-15 18:08:29 +08:00
|
|
|
<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>
|
2026-03-31 10:14:20 +08:00
|
|
|
</div>
|
|
|
|
|
<div class="title_right">
|
|
|
|
|
<div v-if="select.show">
|
2026-05-12 08:47:27 +08:00
|
|
|
<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>
|
2026-03-31 10:14:20 +08:00
|
|
|
</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">
|
2026-05-12 08:47:27 +08:00
|
|
|
<a-tree-select v-model:value="moreSelectValue" show-search
|
2026-03-31 10:14:20 +08:00
|
|
|
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" placeholder="Please select"
|
|
|
|
|
allow-clear tree-default-expand-all :tree-data="moreSelect.options"
|
|
|
|
|
tree-node-filter-prop="label">
|
|
|
|
|
</a-tree-select>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="datetimePicker.show">
|
|
|
|
|
<!-- 添加 locale 属性来设置语言 -->
|
|
|
|
|
<a-date-picker v-model:value="datetimeValue" show-time
|
2026-05-15 18:08:29 +08:00
|
|
|
:style="{ width: datetimePicker.picker === 'year' ? '80px' : '120px' }"
|
2026-03-31 10:14:20 +08:00
|
|
|
:format="datetimePicker.format !== null ? datetimePicker.format : undefined"
|
2026-05-12 08:47:27 +08:00
|
|
|
:picker="datetimePicker.picker" placeholder=" " @change="handleDateTimeChange"
|
|
|
|
|
:size="'small'" />
|
2026-03-31 10:14:20 +08:00
|
|
|
<!-- 修改为 locale 变量 -->
|
|
|
|
|
</div>
|
2026-05-12 08:47:27 +08:00
|
|
|
<div v-if="scopeDate.show" class="title_scopeDate">
|
2026-04-20 16:57:54 +08:00
|
|
|
<a-range-picker v-model:value="scopeDateValue" :picker="scopeDate.picker"
|
2026-05-12 08:47:27 +08:00
|
|
|
:style="{ width: scopeDate.picker === 'year' ? '80px' : (scopeDate.picker === 'month' ? '150px' : '') }"
|
|
|
|
|
:format="scopeDate.format" :range-separator="' 至 '" :size="'small'" />
|
|
|
|
|
</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>
|
2026-03-31 10:14:20 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="body">
|
|
|
|
|
<slot v-if="isExpand" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
import { ref, onMounted } 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;
|
2026-05-15 18:08:29 +08:00
|
|
|
icon?: string;
|
2026-03-31 10:14:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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: '',
|
|
|
|
|
})
|
|
|
|
|
},
|
2026-05-15 18:08:29 +08:00
|
|
|
iconmap: {//自定义图标浮动
|
|
|
|
|
type: Object as () => PromptConfig,
|
|
|
|
|
default: () => ({
|
|
|
|
|
show: false,
|
|
|
|
|
value: '',
|
|
|
|
|
icon:'iconfont icon-time',
|
|
|
|
|
})
|
|
|
|
|
},
|
2026-03-31 10:14:20 +08:00
|
|
|
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,
|
2026-05-12 08:47:27 +08:00
|
|
|
format: null, //YYYY-MM-DD HH
|
2026-03-31 10:14:20 +08:00
|
|
|
picker: 'month' //date | week | month | quarter | year
|
|
|
|
|
})
|
|
|
|
|
},
|
2026-05-12 08:47:27 +08:00
|
|
|
tabs: {
|
|
|
|
|
type: Object,
|
|
|
|
|
default: () => ({
|
|
|
|
|
show: false,
|
|
|
|
|
value: 'one',
|
|
|
|
|
})
|
|
|
|
|
}
|
2026-03-31 10:14:20 +08:00
|
|
|
});
|
2026-05-12 08:47:27 +08:00
|
|
|
const emit = defineEmits(['tab-change']);
|
2026-03-31 10:14:20 +08:00
|
|
|
const isExpand = ref(true);
|
|
|
|
|
const selectValue = ref(props.select.value)
|
|
|
|
|
const moreSelectValue = ref(props.select.value)
|
|
|
|
|
const datetimeValue = ref<Dayjs | null>(props.datetimePicker.value ? dayjs(props.datetimePicker.value) : null);
|
2026-05-12 08:47:27 +08:00
|
|
|
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)
|
2026-03-31 10:14:20 +08:00
|
|
|
// // 定义 locale 变量
|
|
|
|
|
// const locale = zhCN;
|
|
|
|
|
|
|
|
|
|
// console.log(locale, "zhCN");
|
|
|
|
|
// 下拉选择框事件处理
|
|
|
|
|
const handleChange = (value: string) => {
|
|
|
|
|
console.log(`selected ${value}`);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleBlur = () => {
|
|
|
|
|
console.log('blur');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleFocus = () => {
|
|
|
|
|
console.log('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) => {
|
|
|
|
|
console.log('Selected DateTime:', date, dateString);
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-12 08:47:27 +08:00
|
|
|
const handleTabClick = (value: string) => {
|
|
|
|
|
tabsValue.value = value;
|
|
|
|
|
// 向父组件传递参数
|
|
|
|
|
emit('tab-change', {
|
|
|
|
|
tabValue: value,
|
|
|
|
|
tabLabel: value === 'one' ? '图片' : '视频'
|
|
|
|
|
});
|
|
|
|
|
};
|
2026-03-31 10:14:20 +08:00
|
|
|
// 页面加载时执行的逻辑
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
console.log(props.select);
|
|
|
|
|
});
|
|
|
|
|
</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;
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
|
|
|
.texttitle {
|
2026-05-09 17:04:48 +08:00
|
|
|
display: inline-block;
|
2026-05-12 08:47:27 +08:00
|
|
|
//width:180px;
|
2026-05-09 17:04:48 +08:00
|
|
|
}
|
2026-05-12 08:47:27 +08:00
|
|
|
|
2026-03-31 10:14:20 +08:00
|
|
|
.title_icon {
|
|
|
|
|
display: inline-block;
|
|
|
|
|
margin-left: 5px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
2026-05-12 08:47:27 +08:00
|
|
|
|
2026-03-31 10:14:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.title_right {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
|
|
|
div {
|
|
|
|
|
|
2026-05-09 17:04:48 +08:00
|
|
|
margin-right: 2px;
|
|
|
|
|
}
|
2026-03-31 10:14:20 +08:00
|
|
|
}
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
|
|
|
.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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-31 10:14:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-12 08:47:27 +08:00
|
|
|
|
|
|
|
|
.title_scopeDate {
|
|
|
|
|
:deep(.ant-picker-range-separator) {
|
|
|
|
|
padding: 0px !important;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-20 16:57:54 +08:00
|
|
|
</style>
|