1
0
mirror of synced 2025-12-07 22:08:16 +08:00

增加日历组件

This commit is contained in:
李帅武
2025-06-05 17:17:24 +08:00
parent 15f02c44c9
commit 183e7f2863
6 changed files with 605 additions and 0 deletions

View File

@@ -173,6 +173,8 @@ export default {
return this.piechartFn(params.chartProperties, data);
} else if (chartType == "widget-text") {
return this.widgettext(params.chartProperties, data)
} else if (chartType == "widget-calendar") {
return this.widgetcalendar(params.chartProperties, data)
} else if (chartType == "widget-stackchart") {
return this.stackChartFn(params.chartProperties, data)
} else if (chartType == "widget-coord") {
@@ -285,6 +287,9 @@ export default {
}
return analysisData;
},
widgetcalendar (chartProperties, data) {
return data
},
// 坐标系数据解析
coordChartFn(chartProperties, data) {
const analysisData = {};

View File

@@ -0,0 +1,223 @@
/*
* @Descripttion: 日历组件json
* @version:
* @Author: lishuaiwu
* @Date: 2025-06-05 13:44:32
*/
export const widgetCalendar = {
code: 'widget-calendar',
type: 'text',
tabName: '文本栏',
label: '日历',
icon: 'iconbiaoge',
options: {
// 配置
setup: [
{
type: 'el-input-text',
label: '图层名称',
name: 'layerName',
required: false,
placeholder: '',
value: '日历',
},
[
{
name: '日历样式',
list: [
{
type: 'vue-color',
label: '边框线颜色',
name: 'borderColor',
required: false,
placeholder: '',
value: 'rgb(221, 221, 221)'
},
{
type: 'vue-color',
label: '头部背景颜色',
name: 'headerBackground',
required: false,
placeholder: '',
value: 'rgb(10, 115, 255)'
},
{
type: 'vue-color',
label: '头部文字颜色',
name: 'headerTextColor',
required: false,
placeholder: '',
value: 'rgb(255, 255, 255)'
},
{
type: 'vue-color',
label: '头部按钮颜色',
name: 'headerBtnBackground',
required: false,
placeholder: '',
value: 'rgb(10, 115, 255)'
},
{
type: 'vue-color',
label: '头部按钮文字',
name: 'headerBtnTextColor',
required: false,
placeholder: '',
value: 'rgb(255, 255, 255)'
},
{
type: 'vue-color',
label: '星期背景色',
name: 'weekBackground',
required: false,
placeholder: '',
value: 'rgb(10, 39, 50)'
},
{
type: 'vue-color',
label: '星期文字颜色',
name: 'weekTextColor',
required: false,
placeholder: '',
value: 'rgb(255, 255, 255)'
},
{
type: 'vue-color',
label: '日期背景色',
name: 'dayBackground',
required: false,
placeholder: '',
value: 'rgb(0, 59, 81)'
},
{
type: 'vue-color',
label: '日期文字颜色',
name: 'dayTextColor',
required: false,
placeholder: '',
value: 'rgb(255, 255, 255)'
},
{
type: 'vue-color',
label: '当日背景色',
name: 'todayBackground',
required: false,
placeholder: '',
value: 'rgba(0, 59, 81, .5)'
},
{
type: 'vue-color',
label: '当日文字颜色',
name: 'todayTextColor',
required: false,
placeholder: '',
value: 'rgb(0, 0, 0)'
},
{
type: 'el-switch',
label: '按钮显隐',
name: 'isButton',
required: false,
placeholder: '',
value: true,
},
]
}
]
],
data: [
{
type: 'el-radio-group',
label: '数据类型',
name: 'dataType',
require: false,
placeholder: '',
selectValue: true,
selectOptions: [
{
code: 'staticData',
name: '静态数据',
},
{
code: 'dynamicData',
name: '动态数据',
},
],
value: 'staticData',
},
{
type: 'el-input-number',
label: '刷新时间(毫秒)',
name: 'refreshTime',
relactiveDom: 'dataType',
relactiveDomValue: 'dynamicData',
value: 600000
},
{
type: 'el-button',
label: '静态数据',
name: 'staticData',
required: false,
placeholder: '',
relactiveDom: 'dataType',
relactiveDomValue: 'staticData',
value: [
{
"date": "2025-06-01",
"data": '2单'
},
{
"date": "2025-06-02",
"data": '10单'
}
],
},
{
type: 'dycustComponents',
label: '',
name: 'dynamicData',
required: false,
placeholder: '',
relactiveDom: 'dataType',
relactiveDomValue: 'dynamicData',
chartType: 'widget-calendar',
dictKey: 'TEXT_PROPERTIES',
value: '',
}
],
position: [
{
type: 'el-input-number',
label: '左边距',
name: 'left',
required: false,
placeholder: '',
value: 0,
},
{
type: 'el-input-number',
label: '上边距',
name: 'top',
required: false,
placeholder: '',
value: 0,
},
{
type: 'el-input-number',
label: '宽度',
name: 'width',
required: false,
placeholder: '该容器在1920px大屏中的宽度',
value: 600,
},
{
type: 'el-input-number',
label: '高度',
name: 'height',
required: false,
placeholder: '该容器在1080px大屏中的高度',
value: 400,
},
]
}
}

View File

@@ -17,6 +17,7 @@ import {widgetSliders} from "./configure/texts/widget-slider"
import {widgetVideo} from "./configure/texts/widget-video"
import {widgetTable} from "./configure/texts/widget-table"
import {widgetIframe} from "./configure/texts/widget-iframe"
import {widgetCalendar} from "./configure/texts/widget-calendar"
import {widgetUniversal} from "./configure/widget-universal"
import {widgetBarchart} from "./configure/barCharts/widget-barchart"
import {widgetGradientBarchart} from "./configure/barCharts/widget-gradient-barchart"
@@ -70,6 +71,7 @@ export const widgetTool = [
widgetVideo,
widgetTable,
widgetIframe,
widgetCalendar,
// widgetUniversal,
widgetBarchart,
widgetGradientBarchart,

View File

@@ -19,6 +19,7 @@ import widgetImage from "./texts/widgetImage.vue";
import widgetSlider from "./texts/widgetSlider.vue";
import widgetVideo from "./texts/widgetVideo.vue";
import WidgetIframe from "./texts/widgetIframe.vue";
import widgetCalendar from "./texts/widgetCalendar.vue";
import widgetBarchart from "./bar/widgetBarchart.vue";
import widgetLinechart from "./line/widgetLinechart.vue";
import widgetBarlinechart from "./barline/widgetBarlinechart";
@@ -72,6 +73,7 @@ export default {
widgetSlider,
widgetVideo,
WidgetIframe,
widgetCalendar,
widgetBarchart,
widgetGradientColorBarchart,
widgetLinechart,

View File

@@ -0,0 +1,371 @@
<template>
<div class="calendar-container full-box" :style="styleObj">
<div class="calendar-header" :style="headerStyle">
<button class="nav-button" :style="headerBtnStyle" @click="prevMonth" v-if="showButton">&lt;</button>
<div class="current-month-title">{{ currentMonthTitle }}</div>
<button class="nav-button" :style="headerBtnStyle" @click="nextMonth" v-if="showButton">&gt;</button>
</div>
<div class="calendar-month">
<div class="weekdays" :style="weekStyle">
<div class="weekday" v-for="day in weekdays" :key="day">{{ day }}</div>
</div>
<div class="days-grid" :style="dayStyle">
<div
class="day-cell"
v-for="day in currentMonthDays"
:key="day.date"
:class="{
'out-of-range': day.isOutOfRange,
'current-month': day.isCurrentMonth,
'today': day.isToday
}"
:style="cellStyle(day.isToday)"
>
<slot name="day" :day="day">
<div class="day-number">{{ day.day }}</div>
<div class="day-content" v-html="text[day.date] || ''"></div>
</slot>
</div>
</div>
</div>
</div>
</template>
<script>
import moment from 'moment'
import { targetWidgetLinkageLogic } from "@/views/bigscreenDesigner/designer/linkageLogic";
export default {
name: 'widgetCalendar',
props: {
value: Object,
ispreview: Boolean,
},
data() {
return {
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
currentMonth: moment().startOf('month'),
startDate: moment().format('YYYY-MM-DD'),
endDate: moment().format('YYYY-MM-DD'),
options: {},
optionsSetUp: {},
optionsPosition: {},
optionsData: {},
text: ''
}
},
computed: {
momentStartDate() {
return moment(this.startDate, 'YYYY-MM-DD').startOf('day')
},
momentEndDate() {
return moment(this.endDate, 'YYYY-MM-DD').endOf('day')
},
showButton () {
return this.optionsSetUp.isButton;
},
styleObj() {
const allStyle = this.optionsPosition;
return {
position: this.ispreview ? "absolute" : "static",
width: allStyle.width + "px",
height: allStyle.height + "px",
left: allStyle.left + "px",
top: allStyle.top + "px",
background: this.optionsSetUp.tableBgColor,
borderColor: this.optionsSetUp.borderColor
};
},
headerStyle () {
return {
background: this.optionsSetUp.headerBackground,
color: this.optionsSetUp.headerTextColor,
justifyContent: this.optionsSetUp.isButton ? 'space-between' : 'center'
};
},
headerBtnStyle () {
return {
background: this.optionsSetUp.headerBtnBackground,
color: this.optionsSetUp.headerBtnTextColor
};
},
weekStyle () {
return {
background: this.optionsSetUp.weekBackground,
color: this.optionsSetUp.weekTextColor
};
},
dayStyle () {
return {
backgroundColor: this.optionsSetUp.borderColor
}
},
currentMonthTitle() {
return `${this.currentMonth.year()}${this.currentMonth.month() + 1}`
},
currentMonthDays() {
const daysInMonth = this.currentMonth.daysInMonth()
const firstDayOfMonth = moment(this.currentMonth).startOf('month')
const startingDayOfWeek = firstDayOfMonth.day()
const days = []
// 添加上个月的日期
const daysFromPrevMonth = startingDayOfWeek
const prevMonth = moment(this.currentMonth).subtract(1, 'month')
for (let i = 0; i < daysFromPrevMonth; i++) {
const day = prevMonth.daysInMonth() - daysFromPrevMonth + i + 1
const date = moment(prevMonth).date(day)
days.push(this.createDayObject(date, false))
}
// 添加当前月的日期
for (let day = 1; day <= daysInMonth; day++) {
const date = moment(this.currentMonth).date(day)
days.push(this.createDayObject(date, true))
}
// 添加下个月的日期
const totalCells = daysFromPrevMonth + daysInMonth
const remainingCells = totalCells % 7 === 0 ? 0 : 7 - (totalCells % 7)
const nextMonth = moment(this.currentMonth).add(1, 'month')
for (let i = 1; i <= remainingCells; i++) {
const date = moment(nextMonth).date(i)
days.push(this.createDayObject(date, false))
}
return days
}
},
watch: {
value: {
handler(val) {
this.options = val;
this.optionsSetUp = val.setup;
this.optionsPosition = val.position;
this.optionsData = val.data;
this.setOptionsData();
},
deep: true
}
},
mounted() {
this.options = this.value;
this.optionsSetUp = this.value.setup;
this.optionsPosition = this.value.position;
this.optionsData = this.value.data;
targetWidgetLinkageLogic(this);
this.setOptionsData();
},
methods: {
// 数据解析
setOptionsData(e, paramsConfig) {
const optionsData = this.optionsData; // 数据类型 静态 or 动态
// 联动接收者逻辑开始
optionsData.dynamicData = optionsData.dynamicData || {}; // 兼容 dynamicData undefined
const myDynamicData = optionsData.dynamicData;
clearInterval(this.flagInter); // 不管咋,先干掉上一次的定时任务,避免多跑
if (
e &&
optionsData.dataType !== "staticData" &&
Object.keys(myDynamicData.contextData).length
) {
const keyArr = Object.keys(myDynamicData.contextData);
paramsConfig.forEach((conf) => {
if (keyArr.includes(conf.targetKey)) {
myDynamicData.contextData[conf.targetKey] = e[conf.originKey];
}
});
}
// 联动接收者逻辑结束
if (optionsData.dataType === "dynamicData") {
this.dynamicDataFn(optionsData.dynamicData, optionsData.refreshTime);
} else {
const data = this.objToOne(this.options).staticData
let obj = {}
data.forEach(e => {
obj[e.date] = e.data
});
this.text = obj
};
},
dynamicDataFn(val, refreshTime) {
if (!val) return;
if (this.ispreview) {
this.getEchartData(val);
this.flagInter = setInterval(() => {
this.getEchartData(val);
}, refreshTime);
} else {
this.getEchartData(val);
}
},
getEchartData(val) {
const data = this.queryEchartsData(val);
data.then(res => {
let obj = {}
res.forEach(e => {
obj[e.date] = e.data
});
this.text = obj
this.$forceUpdate();
});
},
cellStyle (isToday) {
return {
backgroundColor: isToday ? this.optionsSetUp.todayBackground : this.optionsSetUp.dayBackground,
color: isToday ? this.optionsSetUp.todayTextColor : this.optionsSetUp.dayTextColor,
}
},
prevMonth() {
this.currentMonth = moment(this.currentMonth).subtract(1, 'month')
},
nextMonth() {
this.currentMonth = moment(this.currentMonth).add(1, 'month')
},
createDayObject(date, isCurrentMonth) {
const isToday = date.isSame(moment(), 'day')
const isBeforeRange = date.isBefore(this.momentStartDate, 'day')
const isAfterRange = date.isAfter(this.momentEndDate, 'day')
const isDisabled = isBeforeRange || isAfterRange
return {
date: date.format('YYYY-MM-DD'),
year: date.year(),
month: date.month(), // 0-11
day: date.date(), // 1-31
weekday: date.day(), // 0-6 (0是周日)
isCurrentMonth,
isOutOfRange: !isCurrentMonth,
isToday,
isBeforeRange,
isAfterRange,
isDisabled,
fullDate: date.toDate()
}
}
}
}
</script>
<style scoped lang="scss">
.calendar-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
border: 1px solid #ddd;
}
.full-box {
height: 100%;
.calendar-month {
height: 100%;
display: flex;
flex-direction: column;
.days-grid {
flex: 1;
}
}
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: rgb(10, 115, 255);
color: #ffffff;
}
.current-month-title {
font-size: 18px;
font-weight: bold;
}
.nav-button {
background: none;
border: 1px solid #ddd;
border-radius: 4px;
padding: 5px 10px;
cursor: pointer;
font-size: 16px;
color: #ffffff;
&:hover {
opacity: .5;
}
}
.weekdays {
display: grid;
grid-template-columns: repeat(7, 1fr);
background-color: rgb(10, 39, 50);
color: #ffffff;
}
.weekday {
text-align: center;
padding: 8px 0;
font-weight: bold;
}
.days-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-gap: 1px;
background-color: rgb(221, 221, 221);
flex: 1;
}
.day-cell {
min-height: 60px;
background-color: rgb(0, 59, 81);
padding: 5px;
position: relative;
width: calc(100% - 0px);
display: flex;
flex-direction: column;
}
/* 当前月份的日期 */
.day-cell.current-month {
background-color: rgb(0, 59, 81);
color: #ffffff;
}
/* 非当前月份的日期 */
.day-cell:not(.current-month) {
background-color: rgba(0, 59, 81, .5);
color: #ffffff;
}
/* 今天日期 */
.day-cell.today {
background-color: #e6f7ff;
color: #000;
}
/* 日期范围外的单元格 */
.day-cell.disabled-day {
background-color: #e0e0e0;
color: #999;
cursor: not-allowed;
}
.day-number {
font-weight: bold;
width: 30px;
}
.day-content {
text-align: left;
padding: 0 10px;
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
}
</style>

View File

@@ -26,6 +26,7 @@ import widgetImage from "./texts/widgetImage.vue";
import widgetSlider from "./texts/widgetSlider.vue";
import widgetVideo from "./texts/widgetVideo.vue";
import WidgetIframe from "./texts/widgetIframe.vue";
import widgetCalendar from "./texts/widgetCalendar.vue";
import widgetBarchart from "./bar/widgetBarchart.vue";
import widgetScatter from "./scatter/widgetScatter.vue";
import widgetGradientColorBarchart from "./bar/widgetGradientColorBarchart.vue";
@@ -79,6 +80,7 @@ export default {
widgetSlider,
widgetVideo,
WidgetIframe,
widgetCalendar,
widgetBarchart,
widgetGradientColorBarchart,
widgetLinechart,