Переглянути джерело

V0.2
1、添加了《新增特殊日》弹窗

Apple 3 місяців тому
батько
коміт
9e0305677f
76 змінених файлів з 4501 додано та 767 видалено
  1. 1 1
      External
  2. 72 31
      TransmitterSwitch/AddItem/addnormalitem.cpp
  3. 21 3
      TransmitterSwitch/AddItem/addnormalitem.h
  4. 277 261
      TransmitterSwitch/AddItem/addnormalitem.ui
  5. 101 40
      TransmitterSwitch/AddItem/addspecialitem.cpp
  6. 90 0
      TransmitterSwitch/AddItem/addspecialitem.h
  7. 358 0
      TransmitterSwitch/AddItem/addspecialitem.ui
  8. 0 61
      TransmitterSwitch/AddItem__/addnormalitem.h
  9. 0 299
      TransmitterSwitch/AddItem__/addnormalitem.ui
  10. 192 0
      TransmitterSwitch/ItemData/ItemData.cpp
  11. 45 0
      TransmitterSwitch/ItemData/ItemData.h
  12. 87 15
      TransmitterSwitch/ItemData/oneitem.cpp
  13. 29 6
      TransmitterSwitch/ItemData/oneitem.h
  14. 21 2
      TransmitterSwitch/ItemData/oneitem.ui
  15. BIN
      TransmitterSwitch/Resource/ICON/Close_Dark.png
  16. BIN
      TransmitterSwitch/Resource/ICON/DownArrow_Dark.png
  17. BIN
      TransmitterSwitch/Resource/ICON/date_dark.png
  18. BIN
      TransmitterSwitch/Resource/ICON/date_light.png
  19. 25 1
      TransmitterSwitch/Resource/QSS/AddNormalItem_Light.qss
  20. 282 0
      TransmitterSwitch/Resource/QSS/AddSpecialItem_Light.qss
  21. 176 0
      TransmitterSwitch/Resource/QSS/OneItem_dark.qss
  22. 12 0
      TransmitterSwitch/Resource/QSS/TransmitterSwitch_dark.qss
  23. 4 1
      TransmitterSwitch/Resource/TransSwitch.qrc
  24. BIN
      TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/.DS_Store
  25. BIN
      TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/._.DS_Store
  26. BIN
      TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/._下拉箭头@2x.png
  27. BIN
      TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/._关闭默认@2x.png
  28. BIN
      TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/._动环监测选中@2x.png
  29. 1 0
      TransmitterSwitch/TransmitterSwitchInfo.cpp
  30. 2 0
      TransmitterSwitch/TransmitterSwitchInfo.h
  31. 28 0
      TransmitterSwitch/common/DropShadow/dropshadowmgr.cpp
  32. 46 0
      TransmitterSwitch/common/DropShadow/dropshadowmgr.h
  33. 83 0
      TransmitterSwitch/common/DropShadow/idropshadowable.cpp
  34. 82 0
      TransmitterSwitch/common/DropShadow/idropshadowable.h
  35. 187 0
      TransmitterSwitch/common/PaintHelper/painthelper.cpp
  36. 75 0
      TransmitterSwitch/common/PaintHelper/painthelper.h
  37. 109 29
      TransmitterSwitch/common/SelectTime/timewidget.cpp
  38. 21 3
      TransmitterSwitch/common/SelectTime/timewidget.h
  39. 150 0
      TransmitterSwitch/common/StyleManager/lhstylemanager.cpp
  40. 44 0
      TransmitterSwitch/common/StyleManager/lhstylemanager.h
  41. 19 0
      TransmitterSwitch/common/date/CMakeLists.txt
  42. 6 0
      TransmitterSwitch/common/date/CalendarHeader.qss
  43. 50 0
      TransmitterSwitch/common/date/CalendarNav.qss
  44. 34 0
      TransmitterSwitch/common/date/calendardtedit.cpp
  45. 21 0
      TransmitterSwitch/common/date/calendardtedit.h
  46. 187 0
      TransmitterSwitch/common/date/calendarex.cpp
  47. 66 0
      TransmitterSwitch/common/date/calendarex.h
  48. 36 0
      TransmitterSwitch/common/date/calendarheader.cpp
  49. 26 0
      TransmitterSwitch/common/date/calendarheader.h
  50. 139 0
      TransmitterSwitch/common/date/calendarheader.ui
  51. 67 0
      TransmitterSwitch/common/date/calendarnav.cpp
  52. 30 0
      TransmitterSwitch/common/date/calendarnav.h
  53. 140 0
      TransmitterSwitch/common/date/calendarnav.ui
  54. 373 0
      TransmitterSwitch/common/date/calendarwidgetex.cpp
  55. 84 0
      TransmitterSwitch/common/date/calendarwidgetex.h
  56. 112 0
      TransmitterSwitch/common/date/cdate.cpp
  57. 54 0
      TransmitterSwitch/common/date/cdate.h
  58. BIN
      TransmitterSwitch/common/date/nextMonth.png
  59. BIN
      TransmitterSwitch/common/date/nextMonth_hover.png
  60. BIN
      TransmitterSwitch/common/date/nextYear.png
  61. BIN
      TransmitterSwitch/common/date/nextYear_hover.png
  62. BIN
      TransmitterSwitch/common/date/preMonth.png
  63. BIN
      TransmitterSwitch/common/date/preMonth_hover.png
  64. BIN
      TransmitterSwitch/common/date/preYear.png
  65. BIN
      TransmitterSwitch/common/date/preYear_hover.png
  66. 13 0
      TransmitterSwitch/common/date/rescalendar.qrc
  67. 63 0
      TransmitterSwitch/common/date/scopecalendarbtn.cpp
  68. 33 0
      TransmitterSwitch/common/date/scopecalendarbtn.h
  69. 34 0
      TransmitterSwitch/common/date/scopeselectionmodel.cpp
  70. 26 0
      TransmitterSwitch/common/date/scopeselectionmodel.h
  71. 228 9
      TransmitterSwitch/transmitterswitch.cpp
  72. 21 2
      TransmitterSwitch/transmitterswitch.h
  73. 6 0
      show1/CMakeLists.txt
  74. 9 3
      show1/main.cpp
  75. 3 0
      show1/widget.h
  76. BIN
      归档.zip

+ 1 - 1
External

@@ -1 +1 @@
-Subproject commit a456f702471f2b50626afa54366d4896fcefdbcc
+Subproject commit 065b3651fa3bc23f4540ed042d29912cb105526b

+ 72 - 31
TransmitterSwitch/AddItem/addnormalitem.cpp

@@ -5,11 +5,14 @@
 #include <QDebug>
 #include <QListView>
 #include <QFile>
+#include <QApplication>
+#include <QDesktopWidget>
 
 #include "common/combobox/customcombobox.h"
 #include "LHQLogAPI.h"
 #include "transmitterswitchinfo.h"
 #include "common/SelectTime/timewidget.h"
+#include "ItemData.h"
 
 AddNormalItem::AddNormalItem(QWidget *parent) :
     QDialog(parent),
@@ -38,30 +41,33 @@ AddNormalItem::AddNormalItem(QWidget *parent) :
     ui->comBox_actionSelect->setViewShadowEffect();
 
 
-    /* 获取父指针 */
-    // m_p = dynamic_cast<ExecPlan*>(parent);
-
-
     ui->label_timeWarn->hide();
     ui->label_devWarn->hide();
     ui->label_actionWarn->hide();
 
+    /* 获取屏幕大小 */
+    m_rectScreen = QApplication::desktop()->availableGeometry();
+    this->resize(m_rectScreen.width(), m_rectScreen.height());
+    /* 设置默认时间 */
+    m_time.setHMS(0, 0, 0);
+
     /* 连接信号和槽 */
-    connect(ui->pBtn_Close,&QPushButton::clicked,this,&QDialog::close);
-    connect(ui->pBtn_cancel,&QPushButton::clicked,this,&QDialog::close);
-    connect(ui->pBtn_ok,&QPushButton::clicked,this,&AddNormalItem::do_ok);
-    connect(ui->pBtn_cancel,&QPushButton::clicked,this,&AddNormalItem::close);
+    connect(ui->pBtn_Close, &QPushButton::clicked, this, &QDialog::close);
+    connect(ui->pBtn_cancel, &QPushButton::clicked, this, &QDialog::close);
+    connect(ui->pBtn_ok, &QPushButton::clicked, this, &AddNormalItem::do_ok);
+    connect(ui->pBtn_cancel, &QPushButton::clicked, this, &AddNormalItem::close);
 
     /* 设备选择 */
     connect(ui->comBox_devSelect, QOverload<const QString&>::of(&QComboBox::currentTextChanged), this, &AddNormalItem::do_selectDev);
     /* 动作选择 */
     connect(ui->comBox_actionSelect,QOverload<const QString&>::of(&QComboBox::currentTextChanged),this, &AddNormalItem::do_selectAction);
-    /* 设置默认时间 */
-    ui->timeEdit->setTime("00:00:00");
-
-    /* 注册事件过滤器 */
+    /* 打开时间选择器 */
+    connect(ui->pBtn_selectTime, &QPushButton::clicked, this, &AddNormalItem::do_selectTime);
+    
+    /* 设置事件过滤器 */
     ui->comBox_actionSelect->installEventFilter(this);
     ui->comBox_devSelect->installEventFilter(this);
+
 }
 
 AddNormalItem::~AddNormalItem()
@@ -72,9 +78,8 @@ AddNormalItem::~AddNormalItem()
 /* 设置父指针,时间选择器需要使用 */
 void AddNormalItem::setParentPointer(QWidget* p)
 {
-    /* 设置时间选择器 */
-    ui->timeEdit->setTimeAreaWidth(132);
-    ui->timeEdit->SetMainWindow(this);
+    m_parent = p;
+    // m_parent->installEventFilter(this);
 }
 
 /* 添加可选设备 */
@@ -91,6 +96,16 @@ void AddNormalItem::setDevice(QMap<QString, DeviceInfo>& mapDev)
     setAction(m_devName);
 }
 
+/* 设置周几 */
+void AddNormalItem::setWeekDay(int week)
+{
+    if(week < 0 || week > 6)
+    {
+        return;
+    }
+    m_week = week;
+}
+
 
 /* 进行查重和关闭页面 */
 void AddNormalItem::do_ok()
@@ -117,9 +132,7 @@ void AddNormalItem::do_ok()
         ui->label_actionWarn->show();
         setComboBoxWarning(ui->comBox_actionSelect, true);
     }
-
-    /* 时间赋值 */
-    m_time = ui->timeEdit->getFormTime();
+    
     /* 检查时间是否为空 */
     if(m_time.isNull())
     {
@@ -130,13 +143,17 @@ void AddNormalItem::do_ok()
     }
     /* 进行设备查重 */
     // bool ret = m_p->judgeTimeRepetition(*m_p->m_vecItem[m_p->m_stack->currentIndex()],m_devName,m_time);
-    // if(ret)
-    // {
-    //     ui->label_timeWarn->setText("一个时间点,单个设备仅能执行一个操作!");
-    //     ui->label_timeWarn->show();
-    //     setTimeEditWarning(true);
-    //     return;
-    // }
+    bool ret = IData.judgeTimeRepetitionWithAdd(m_week, m_devName, m_time);
+    if(ret)
+    {
+        ui->label_timeWarn->setText("一个时间点,单个设备仅能执行一个操作!");
+        ui->label_timeWarn->show();
+        setTimeEditWarning(true);
+        return;
+    }
+    m_isAddDev = true;
+    /* 添加一项计划 */
+    LH_WRITE_LOG_DEBUG(QString("添加一项计划: 设备:%1, 动作:%2, 时间:%3").arg(m_devName).arg(m_action).arg(m_time.toString("hh:mm:ss")));
 
     /* 发送信号 */
     emit signal_addNormalItem(m_devName,m_action,m_time);
@@ -157,6 +174,31 @@ void AddNormalItem::do_selectAction()
     m_action = ui->comBox_actionSelect->currentText();
 }
 
+/* 点击了时间选择按钮,打开时间选择器 */
+void AddNormalItem::do_selectTime()
+{
+    // LH_WRITE_LOG_DEBUG("选择时间");
+    std::shared_ptr<TimeWidget> tw = std::make_shared<TimeWidget>(this, TimeWidget::ShowType::Dialog);
+    /* 设置图标 */
+    tw->setIcon(":/ICON/ICON/Time.png");
+    tw->setIconShow(true);
+    tw->setIconSize(16, 16);
+    /* 重新设置大小 */
+    tw->setEditLine(ui->pBtn_selectTime->width(), ui->pBtn_selectTime->height());
+    /* 设置选择框大小 */
+    tw->setTimeAreaWidth(140);
+    /* 移动位置,覆盖显示时间的按钮,获取的坐标是相对于Dialog的位置 */
+    auto pos = ui->pBtn_selectTime->mapTo(this, QPoint(0, 0));
+    tw->move(pos);
+    /* 设置默认的时间 */
+    tw->setTime(m_time);
+
+    tw->execShow();
+    m_time = tw->getTime();
+    // LH_WRITE_LOG_DEBUG(QString("选择时间:%1").arg(m_time.toString("hh:mm:ss")));
+    ui->pBtn_selectTime->setText(m_time.toString("hh:mm:ss"));
+}
+
 /* 设置选择框报警 */
 void AddNormalItem::setComboBoxWarning(QComboBox* bo, bool flag)
 {
@@ -179,15 +221,15 @@ void AddNormalItem::setTimeEditWarning(bool flag)
 {
     if(flag)
     {
-        ui->timeEdit->setProperty("Warn", true);
+        ui->pBtn_selectTime->setProperty("Warn", true);
     }
     else
     {
-        ui->timeEdit->setProperty("Warn", false);
+        ui->pBtn_selectTime->setProperty("Warn", false);
     }
 
-    ui->timeEdit->style()->unpolish(ui->timeEdit);
-    ui->timeEdit->style()->polish(ui->timeEdit);
+    ui->pBtn_selectTime->style()->unpolish(ui->pBtn_selectTime);
+    ui->pBtn_selectTime->style()->polish(ui->pBtn_selectTime);
 }
 
 /* 设置动作 */
@@ -205,7 +247,6 @@ void AddNormalItem::setAction(const QString& devName)
     }
 }
 
-
 /* 事件过滤器 */
 bool AddNormalItem::eventFilter(QObject *watched, QEvent *event)
 {
@@ -223,6 +264,6 @@ bool AddNormalItem::eventFilter(QObject *watched, QEvent *event)
             return true;
         }
     }
-    return QDialog::eventFilter(watched,event);
+    return QDialog::eventFilter(watched, event);
 }
 

+ 21 - 3
TransmitterSwitch/AddItem/addnormalitem.h

@@ -24,19 +24,31 @@ public:
     void setParentPointer(QWidget* p);
     /* 添加可选设备 */
     void setDevice(QMap<QString, DeviceInfo>& mapDev);
+    /* 设置周几 */
+    void setWeekDay(int week);
+
+    /* 获取设别名称 */
+    QString getDevName() const { return m_devName; }
+    /* 获取动作 */
+    QString getAction() const { return m_action; }
+    /* 获取时间 */
+    QTime getTime() const { return m_time; }
+    /* 判断是否添加设备 */
+    bool isAddDev() const { return m_isAddDev; }
 
 signals:
     /* 添加正常日期的项 */
     void signal_addNormalItem(QString dev,QString action,QTime time);
 
 private slots:
-//    void do_selectTime();                           /* 选择时间 */
     /* 进行查重和关闭页面 */
     void do_ok();
     /* 选择了设备,设置其对应的动作 */
     void do_selectDev();
     /* 选择了动作 */
     void do_selectAction();
+    /* 点击了时间选择按钮,打开时间选择器 */
+    void do_selectTime();
 
 private:
     /* 设置选择框报警 */
@@ -47,15 +59,21 @@ private:
 
 protected:
     /* 事件过滤器 */
-    bool eventFilter(QObject *watched, QEvent *event);
+    bool eventFilter(QObject *watched, QEvent *event) override;
     
 private:
     Ui::AddNormalItem *ui;
 
-    // ExecPlan* m_p = nullptr;                        /* 设置父类指针 */
+    QWidget* m_parent = nullptr;                    /* 父类指针 */
+    QRect m_rectScreen;                             /* 屏幕大小 */
+    int m_week = -1;                                /* 周几 */
+    bool m_isAddDev = false;                        /* 是否添加设备 */
+
     QString m_devName;                              /* 选择的设备 */
     QString m_action;                               /* 选择的动作 */
     QTime m_time;                                   /* 执行的时间 */
+
+    TimeWidget* m_timeWidget = nullptr;             /* 时间选择器 */
 };
 
 #endif // ADDNORMALITEM_H

+ 277 - 261
TransmitterSwitch/AddItem/addnormalitem.ui

@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>436</width>
-    <height>349</height>
+    <width>1920</width>
+    <height>1080</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -18,278 +18,294 @@
     <number>0</number>
    </property>
    <property name="leftMargin">
-    <number>10</number>
+    <number>0</number>
    </property>
    <property name="topMargin">
-    <number>10</number>
+    <number>0</number>
    </property>
    <property name="rightMargin">
-    <number>10</number>
+    <number>0</number>
    </property>
    <property name="bottomMargin">
-    <number>10</number>
+    <number>0</number>
    </property>
    <item>
-    <widget class="QWidget" name="widget_background" native="true">
-     <property name="styleSheet">
-      <string notr="true"/>
-     </property>
-     <widget class="QLabel" name="label_NC1">
-      <property name="geometry">
-       <rect>
-        <x>32</x>
-        <y>18</y>
-        <width>80</width>
-        <height>18</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>添加计划</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC2_x">
-      <property name="geometry">
-       <rect>
-        <x>32</x>
-        <y>154</y>
-        <width>7</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC3">
-      <property name="geometry">
-       <rect>
-        <x>40</x>
-        <y>154</y>
-        <width>70</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>时间选择:</string>
-      </property>
-     </widget>
-     <widget class="QPushButton" name="pBtn_Close">
-      <property name="geometry">
-       <rect>
-        <x>368</x>
-        <y>12</y>
-        <width>32</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string/>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC4">
-      <property name="geometry">
-       <rect>
-        <x>0</x>
-        <y>56</y>
-        <width>416</width>
-        <height>1</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string/>
-      </property>
-     </widget>
-     <widget class="QPushButton" name="pBtn_cancel">
-      <property name="geometry">
-       <rect>
-        <x>248</x>
-        <y>265</y>
-        <width>60</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>取消</string>
-      </property>
-     </widget>
-     <widget class="QPushButton" name="pBtn_ok">
-      <property name="geometry">
-       <rect>
-        <x>324</x>
-        <y>265</y>
-        <width>60</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>确定</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_iconTime">
-      <property name="geometry">
-       <rect>
-        <x>359</x>
-        <y>153</y>
-        <width>16</width>
-        <height>16</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string/>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_timeWarn">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>180</y>
-        <width>250</width>
-        <height>18</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>TextLabel</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC8_x">
-      <property name="geometry">
-       <rect>
-        <x>32</x>
-        <y>98</y>
-        <width>7</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC9">
-      <property name="geometry">
-       <rect>
-        <x>40</x>
-        <y>98</y>
-        <width>70</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>设备选择:</string>
-      </property>
-     </widget>
-     <widget class="CustomComboBox" name="comBox_devSelect">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>89</y>
-        <width>274</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="currentText">
-       <string/>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC8_x_2">
-      <property name="geometry">
-       <rect>
-        <x>32</x>
-        <y>210</y>
-        <width>7</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-      </property>
-     </widget>
-     <widget class="CustomComboBox" name="comBox_actionSelect">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>201</y>
-        <width>274</width>
-        <height>32</height>
-       </rect>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC9_2">
-      <property name="geometry">
-       <rect>
-        <x>40</x>
-        <y>210</y>
-        <width>70</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>动作选择:</string>
-      </property>
-     </widget>
-     <widget class="TimeWidget" name="timeEdit">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>145</y>
-        <width>274</width>
-        <height>32</height>
-       </rect>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_devWarn">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>126</y>
-        <width>250</width>
-        <height>18</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>TextLabel</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_actionWarn">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>238</y>
-        <width>250</width>
-        <height>18</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>TextLabel</string>
-      </property>
-     </widget>
-     <zorder>label_iconTime</zorder>
-     <zorder>label_NC1</zorder>
-     <zorder>label_NC2_x</zorder>
-     <zorder>label_NC3</zorder>
-     <zorder>pBtn_Close</zorder>
-     <zorder>label_NC4</zorder>
-     <zorder>pBtn_cancel</zorder>
-     <zorder>pBtn_ok</zorder>
-     <zorder>label_timeWarn</zorder>
-     <zorder>label_NC8_x</zorder>
-     <zorder>label_NC9</zorder>
-     <zorder>comBox_devSelect</zorder>
-     <zorder>label_NC8_x_2</zorder>
-     <zorder>comBox_actionSelect</zorder>
-     <zorder>label_NC9_2</zorder>
-     <zorder>label_devWarn</zorder>
-     <zorder>label_actionWarn</zorder>
-     <zorder>timeEdit</zorder>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0">
+       <widget class="QWidget" name="widget_background" native="true">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>416</width>
+          <height>309</height>
+         </size>
+        </property>
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <widget class="QLabel" name="label_NC1">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>18</y>
+           <width>80</width>
+           <height>18</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>添加计划</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC2_x">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>154</y>
+           <width>7</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC3">
+         <property name="geometry">
+          <rect>
+           <x>40</x>
+           <y>154</y>
+           <width>70</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>时间选择:</string>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_Close">
+         <property name="geometry">
+          <rect>
+           <x>368</x>
+           <y>12</y>
+           <width>32</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC4">
+         <property name="geometry">
+          <rect>
+           <x>0</x>
+           <y>56</y>
+           <width>416</width>
+           <height>1</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_cancel">
+         <property name="geometry">
+          <rect>
+           <x>248</x>
+           <y>265</y>
+           <width>60</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>取消</string>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_ok">
+         <property name="geometry">
+          <rect>
+           <x>324</x>
+           <y>265</y>
+           <width>60</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>确定</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_iconTime">
+         <property name="geometry">
+          <rect>
+           <x>359</x>
+           <y>153</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_timeWarn">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>180</y>
+           <width>281</width>
+           <height>18</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>TextLabel</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC8_x">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>98</y>
+           <width>7</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC9">
+         <property name="geometry">
+          <rect>
+           <x>40</x>
+           <y>98</y>
+           <width>70</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>设备选择:</string>
+         </property>
+        </widget>
+        <widget class="CustomComboBox" name="comBox_devSelect">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>89</y>
+           <width>274</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="currentText">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC8_x_2">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>210</y>
+           <width>7</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+        </widget>
+        <widget class="CustomComboBox" name="comBox_actionSelect">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>201</y>
+           <width>274</width>
+           <height>32</height>
+          </rect>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC9_2">
+         <property name="geometry">
+          <rect>
+           <x>40</x>
+           <y>210</y>
+           <width>70</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>动作选择:</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_devWarn">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>126</y>
+           <width>281</width>
+           <height>18</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>TextLabel</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_actionWarn">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>238</y>
+           <width>281</width>
+           <height>18</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>TextLabel</string>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_selectTime">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>145</y>
+           <width>274</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>00:00:00</string>
+         </property>
+        </widget>
+        <zorder>label_iconTime</zorder>
+        <zorder>label_NC1</zorder>
+        <zorder>label_NC2_x</zorder>
+        <zorder>label_NC3</zorder>
+        <zorder>pBtn_Close</zorder>
+        <zorder>label_NC4</zorder>
+        <zorder>pBtn_cancel</zorder>
+        <zorder>pBtn_ok</zorder>
+        <zorder>label_timeWarn</zorder>
+        <zorder>label_NC8_x</zorder>
+        <zorder>label_NC9</zorder>
+        <zorder>comBox_devSelect</zorder>
+        <zorder>label_NC8_x_2</zorder>
+        <zorder>comBox_actionSelect</zorder>
+        <zorder>label_NC9_2</zorder>
+        <zorder>label_devWarn</zorder>
+        <zorder>label_actionWarn</zorder>
+        <zorder>pBtn_selectTime</zorder>
+       </widget>
+      </item>
+     </layout>
     </widget>
    </item>
   </layout>
  </widget>
  <customwidgets>
-  <customwidget>
-   <class>TimeWidget</class>
-   <extends>QTimeEdit</extends>
-   <header location="global">timewidget.h</header>
-  </customwidget>
   <customwidget>
    <class>CustomComboBox</class>
    <extends>QComboBox</extends>

+ 101 - 40
TransmitterSwitch/AddItem__/addnormalitem.cpp → TransmitterSwitch/AddItem/addspecialitem.cpp

@@ -1,19 +1,23 @@
-#include "addnormalitem.h"
-#include "ui_addnormalitem.h"
+#include "addspecialitem.h"
+#include "ui_addspecialitem.h"
 
 #include <memory>
 #include <QDebug>
 #include <QListView>
 #include <QFile>
+#include <QApplication>
+#include <QDesktopWidget>
 
 #include "common/combobox/customcombobox.h"
 #include "LHQLogAPI.h"
 #include "transmitterswitchinfo.h"
 #include "common/SelectTime/timewidget.h"
+#include "common/date/calendardtedit.h"
+#include "ItemData.h"
 
-AddNormalItem::AddNormalItem(QWidget *parent) :
+AddSpecialItem::AddSpecialItem(QWidget *parent) :
     QDialog(parent),
-    ui(new Ui::AddNormalItem)
+    ui(new Ui::AddSpecialItem)
 {
     ui->setupUi(this);
 
@@ -23,7 +27,7 @@ AddNormalItem::AddNormalItem(QWidget *parent) :
     this->setAttribute(Qt::WA_TranslucentBackground);
 
     /* 加载QSS */
-    QFile file(":/QSS/QSS/AddNormalItem_Light.qss");
+    QFile file(":/QSS/QSS/AddSpecialItem_Light.qss");
     if(file.open(QIODevice::ReadOnly))
     {
         QString stylesheet = file.readAll();
@@ -38,44 +42,51 @@ AddNormalItem::AddNormalItem(QWidget *parent) :
     ui->comBox_actionSelect->setViewShadowEffect();
 
 
-    /* 获取父指针 */
-    // m_p = dynamic_cast<ExecPlan*>(parent);
-
-
     ui->label_timeWarn->hide();
     ui->label_devWarn->hide();
     ui->label_actionWarn->hide();
 
+    /* 获取屏幕大小 */
+    m_rectScreen = QApplication::desktop()->availableGeometry();
+    this->resize(m_rectScreen.width(), m_rectScreen.height());
+    /* 设置默认时间 */
+    m_time.setHMS(0, 0, 0);
+    m_date = QDate::currentDate();
+
     /* 连接信号和槽 */
     connect(ui->pBtn_Close, &QPushButton::clicked, this, &QDialog::close);
     connect(ui->pBtn_cancel, &QPushButton::clicked, this, &QDialog::close);
-    connect(ui->pBtn_ok, &QPushButton::clicked, this, &AddNormalItem::do_ok);
-    connect(ui->pBtn_cancel, &QPushButton::clicked, this, &AddNormalItem::close);
+    connect(ui->pBtn_ok, &QPushButton::clicked, this, &AddSpecialItem::do_ok);
+    connect(ui->pBtn_cancel, &QPushButton::clicked, this, &AddSpecialItem::close);
 
     /* 设备选择 */
-    connect(ui->comBox_devSelect, QOverload<const QString&>::of(&QComboBox::currentTextChanged), this, &AddNormalItem::do_selectDev);
+    connect(ui->comBox_devSelect, QOverload<const QString&>::of(&QComboBox::currentTextChanged), this, &AddSpecialItem::do_selectDev);
     /* 动作选择 */
-    connect(ui->comBox_actionSelect,QOverload<const QString&>::of(&QComboBox::currentTextChanged),this, &AddNormalItem::do_selectAction);
+    connect(ui->comBox_actionSelect,QOverload<const QString&>::of(&QComboBox::currentTextChanged),this, &AddSpecialItem::do_selectAction);
     /* 打开时间选择器 */
-    connect(ui->pBtn_selectTime, &QPushButton::clicked, this, &AddNormalItem::do_selectTime);
-    /* 设置默认时间 */
-    m_time.setHMS(0, 0, 0);
+    connect(ui->pBtn_selectTime, &QPushButton::clicked, this, &AddSpecialItem::do_selectTime);
+    
+    /* 设置事件过滤器 */
+    ui->comBox_actionSelect->installEventFilter(this);
+    ui->comBox_devSelect->installEventFilter(this);
+
 }
 
-AddNormalItem::~AddNormalItem()
+AddSpecialItem::~AddSpecialItem()
 {
     delete ui;
 }
 
+
 /* 设置父指针,时间选择器需要使用 */
-void AddNormalItem::setParentPointer(QWidget* p)
+void AddSpecialItem::setParentPointer(QWidget* p)
 {
-    /* 设置时间选择器 */
-
+    m_parent = p;
+    // m_parent->installEventFilter(this);
 }
 
 /* 添加可选设备 */
-void AddNormalItem::setDevice(QMap<QString, DeviceInfo>& mapDev)
+void AddSpecialItem::setDevice(QMap<QString, DeviceInfo>& mapDev)
 {
     ui->comBox_devSelect->clear();
     for(const auto& it : mapDev)
@@ -88,9 +99,19 @@ void AddNormalItem::setDevice(QMap<QString, DeviceInfo>& mapDev)
     setAction(m_devName);
 }
 
+/* 设置周几 */
+void AddSpecialItem::setWeekDay(int week)
+{
+    if(week < 0 || week > 6)
+    {
+        return;
+    }
+    m_week = week;
+}
+
 
 /* 进行查重和关闭页面 */
-void AddNormalItem::do_ok()
+void AddSpecialItem::do_ok()
 {
     ui->label_timeWarn->hide();
     ui->label_devWarn->hide();
@@ -114,8 +135,6 @@ void AddNormalItem::do_ok()
         ui->label_actionWarn->show();
         setComboBoxWarning(ui->comBox_actionSelect, true);
     }
-
-    /* 时间赋值 */
     
     /* 检查时间是否为空 */
     if(m_time.isNull())
@@ -127,44 +146,64 @@ void AddNormalItem::do_ok()
     }
     /* 进行设备查重 */
     // bool ret = m_p->judgeTimeRepetition(*m_p->m_vecItem[m_p->m_stack->currentIndex()],m_devName,m_time);
-    // if(ret)
-    // {
-    //     ui->label_timeWarn->setText("一个时间点,单个设备仅能执行一个操作!");
-    //     ui->label_timeWarn->show();
-    //     setTimeEditWarning(true);
-    //     return;
-    // }
+    bool ret = IData.judgeTimeRepetitionWithAdd(m_week, m_devName, m_time);
+    if(ret)
+    {
+        ui->label_timeWarn->setText("一个时间点,单个设备仅能执行一个操作!");
+        ui->label_timeWarn->show();
+        setTimeEditWarning(true);
+        return;
+    }
+    m_isAddDev = true;
+    /* 添加一项计划 */
+    LH_WRITE_LOG_DEBUG(QString("添加一项计划: 设备:%1, 动作:%2, 时间:%3").arg(m_devName).arg(m_action).arg(m_time.toString("hh:mm:ss")));
 
     /* 发送信号 */
-    emit signal_addNormalItem(m_devName,m_action,m_time);
+    emit signal_AddSpecialItem(m_devName, m_action, m_date, m_time);
     close();
 }
 
 
 /* 选择了设备,设置其对应的动作 */
-void AddNormalItem::do_selectDev()
+void AddSpecialItem::do_selectDev()
 {
     m_devName = ui->comBox_devSelect->currentText();
     setAction(m_devName);
 }
 
 /* 选择了动作 */
-void AddNormalItem::do_selectAction()
+void AddSpecialItem::do_selectAction()
 {
     m_action = ui->comBox_actionSelect->currentText();
 }
 
 /* 点击了时间选择按钮,打开时间选择器 */
-void AddNormalItem::do_selectTime()
+void AddSpecialItem::do_selectTime()
 {
-    LH_WRITE_LOG_DEBUG("选择时间");
+    // LH_WRITE_LOG_DEBUG("选择时间");
     std::shared_ptr<TimeWidget> tw = std::make_shared<TimeWidget>(this, TimeWidget::ShowType::Dialog);
+    /* 设置图标 */
+    tw->setIcon(":/ICON/ICON/Time.png");
+    tw->setIconShow(true);
+    tw->setIconSize(16, 16);
+    /* 重新设置大小 */
+    tw->setEditLine(ui->pBtn_selectTime->width(), ui->pBtn_selectTime->height());
+    /* 设置选择框大小 */
+    tw->setTimeAreaWidth(140);
+    /* 移动位置,覆盖显示时间的按钮,获取的坐标是相对于Dialog的位置 */
+    auto pos = ui->pBtn_selectTime->mapTo(this, QPoint(0, 0));
+    tw->move(pos);
+    /* 设置默认的时间 */
+    tw->setTime(m_time);
 
-    tw->showTimeEditArea();
+    tw->execShow();
+    m_time = tw->getTime();
+    // LH_WRITE_LOG_DEBUG(QString("选择时间:%1").arg(m_time.toString("hh:mm:ss")));
+    ui->pBtn_selectTime->setText(m_time.toString("hh:mm:ss"));
 }
 
 /* 设置选择框报警 */
-void AddNormalItem::setComboBoxWarning(QComboBox* bo, bool flag)
+void AddSpecialItem::setComboBoxWarning(QComboBox* bo, bool flag)
 {
     if(flag)
     {
@@ -181,7 +220,7 @@ void AddNormalItem::setComboBoxWarning(QComboBox* bo, bool flag)
 }
 
 /* 设置时间报警 */
-void AddNormalItem::setTimeEditWarning(bool flag)
+void AddSpecialItem::setTimeEditWarning(bool flag)
 {
     if(flag)
     {
@@ -197,7 +236,7 @@ void AddNormalItem::setTimeEditWarning(bool flag)
 }
 
 /* 设置动作 */
-void AddNormalItem::setAction(const QString& devName)
+void AddSpecialItem::setAction(const QString& devName)
 {
     QMap<int, QString> devAction;
     if(!DeviceContainer.getDevAction(devName, devAction))
@@ -211,3 +250,25 @@ void AddNormalItem::setAction(const QString& devName)
     }
 }
 
+/* 事件过滤器 */
+bool AddSpecialItem::eventFilter(QObject *watched, QEvent *event)
+{
+    if(watched == ui->comBox_devSelect)
+    {
+        if(event->type() == QEvent::Wheel)
+        {
+            return true;
+        }
+    }
+    else if(watched == ui->comBox_actionSelect)
+    {
+        if(event->type() == QEvent::Wheel)
+        {
+            return true;
+        }
+    }
+    return QDialog::eventFilter(watched, event);
+}
+
+
+

+ 90 - 0
TransmitterSwitch/AddItem/addspecialitem.h

@@ -0,0 +1,90 @@
+#ifndef ADDSPECIALITEM_H
+#define ADDSPECIALITEM_H
+
+/**
+ * 注意事:
+ *  1、这里的日期用的提升方式,提升为CalendarTEdit,日期图标
+ *     直接设置的箭头图标,如果想显示出来,需要设置setCalendarPopup为true
+*/
+
+#include <QDialog>
+#include <QTime>
+#include <QDate>
+#include <QComboBox>
+
+class TimeWidget;
+class DeviceInfo;
+
+namespace Ui {
+class AddSpecialItem;
+}
+
+class AddSpecialItem : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit AddSpecialItem(QWidget *parent = nullptr);
+    ~AddSpecialItem();
+
+    /* 设置父指针,时间选择器需要使用 */
+    void setParentPointer(QWidget* p);
+    /* 添加可选设备 */
+    void setDevice(QMap<QString, DeviceInfo>& mapDev);
+    /* 设置周几 */
+    void setWeekDay(int week);
+
+    /* 获取设别名称 */
+    QString getDevName() const { return m_devName; }
+    /* 获取动作 */
+    QString getAction() const { return m_action; }
+    /* 获取时间 */
+    QTime getTime() const { return m_time; }
+    /* 获取日期 */
+    QDate getDate() const { return m_date; }
+    /* 判断是否添加设备 */
+    bool isAddDev() const { return m_isAddDev; }
+
+signals:
+    /* 添加特殊日期项 */
+    void signal_AddSpecialItem(QString dev, QString action, QDate date, QTime time);
+
+private slots:
+    /* 进行查重和关闭页面 */
+    void do_ok();
+    /* 选择了设备,设置其对应的动作 */
+    void do_selectDev();
+    /* 选择了动作 */
+    void do_selectAction();
+    /* 点击了时间选择按钮,打开时间选择器 */
+    void do_selectTime();
+
+private:
+    /* 设置选择框报警 */
+    void setComboBoxWarning(QComboBox* bo,bool flag);
+    /* 设置时间报警 */
+    void setTimeEditWarning(bool flag);
+    void setAction(const QString& devName);
+
+protected:
+    /* 事件过滤器 */
+    bool eventFilter(QObject *watched, QEvent *event) override;
+
+
+private:
+    Ui::AddSpecialItem *ui;
+    
+    QWidget* m_parent = nullptr;                    /* 父类指针 */
+    QRect m_rectScreen;                             /* 屏幕大小 */
+    int m_week = -1;                                /* 周几 */
+    bool m_isAddDev = false;                        /* 是否添加设备 */
+
+    QString m_devName;                              /* 选择的设备 */
+    QString m_action;                               /* 选择的动作 */
+    QTime m_time;                                   /* 执行的时间 */
+    QDate m_date;                                   /* 执行的日期 */
+
+    TimeWidget* m_timeWidget = nullptr;             /* 时间选择器 */
+};
+
+#endif // ADDSPECIALITEM_H

+ 358 - 0
TransmitterSwitch/AddItem/addspecialitem.ui

@@ -0,0 +1,358 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AddSpecialItem</class>
+ <widget class="QDialog" name="AddSpecialItem">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1150</width>
+    <height>771</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QGridLayout" name="gridLayout">
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <property name="spacing">
+       <number>0</number>
+      </property>
+      <item row="0" column="0">
+       <widget class="QWidget" name="widget_background" native="true">
+        <property name="minimumSize">
+         <size>
+          <width>416</width>
+          <height>385</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>416</width>
+          <height>385</height>
+         </size>
+        </property>
+        <property name="styleSheet">
+         <string notr="true"/>
+        </property>
+        <widget class="QLabel" name="label_NC1">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>18</y>
+           <width>80</width>
+           <height>18</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>添加计划</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC2_x">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>210</y>
+           <width>7</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC3">
+         <property name="geometry">
+          <rect>
+           <x>40</x>
+           <y>210</y>
+           <width>70</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>时间选择:</string>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_Close">
+         <property name="geometry">
+          <rect>
+           <x>368</x>
+           <y>12</y>
+           <width>32</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC4">
+         <property name="geometry">
+          <rect>
+           <x>0</x>
+           <y>56</y>
+           <width>416</width>
+           <height>1</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_cancel">
+         <property name="geometry">
+          <rect>
+           <x>248</x>
+           <y>321</y>
+           <width>60</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>取消</string>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_ok">
+         <property name="geometry">
+          <rect>
+           <x>324</x>
+           <y>321</y>
+           <width>60</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>确定</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_timeWarn">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>236</y>
+           <width>250</width>
+           <height>18</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>TextLabel</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC8_x">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>98</y>
+           <width>7</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC9">
+         <property name="geometry">
+          <rect>
+           <x>40</x>
+           <y>98</y>
+           <width>70</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>设备选择:</string>
+         </property>
+        </widget>
+        <widget class="CustomComboBox" name="comBox_devSelect">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>89</y>
+           <width>274</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="currentText">
+          <string/>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC12_x">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>266</y>
+           <width>7</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+        </widget>
+        <widget class="CustomComboBox" name="comBox_actionSelect">
+         <property name="geometry">
+          <rect>
+           <x>108</x>
+           <y>257</y>
+           <width>274</width>
+           <height>32</height>
+          </rect>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC9_2">
+         <property name="geometry">
+          <rect>
+           <x>40</x>
+           <y>266</y>
+           <width>70</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>动作选择:</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC10">
+         <property name="geometry">
+          <rect>
+           <x>40</x>
+           <y>154</y>
+           <width>70</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>日期选择:</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_NC2_x_2">
+         <property name="geometry">
+          <rect>
+           <x>32</x>
+           <y>154</y>
+           <width>7</width>
+           <height>14</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+        </widget>
+        <widget class="CalendarDTEdit" name="dateEdit">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>145</y>
+           <width>274</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="calendarPopup">
+          <bool>true</bool>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_devWarn">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>126</y>
+           <width>250</width>
+           <height>18</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>TextLabel</string>
+         </property>
+        </widget>
+        <widget class="QLabel" name="label_actionWarn">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>296</y>
+           <width>250</width>
+           <height>18</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>TextLabel</string>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_selectTime">
+         <property name="geometry">
+          <rect>
+           <x>110</x>
+           <y>201</y>
+           <width>274</width>
+           <height>32</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string>00:00:00</string>
+         </property>
+        </widget>
+        <widget class="QPushButton" name="pBtn_iconTime">
+         <property name="geometry">
+          <rect>
+           <x>359</x>
+           <y>209</y>
+           <width>16</width>
+           <height>16</height>
+          </rect>
+         </property>
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>CustomComboBox</class>
+   <extends>QComboBox</extends>
+   <header location="global">customcombobox.h</header>
+  </customwidget>
+  <customwidget>
+   <class>CalendarDTEdit</class>
+   <extends>QDateEdit</extends>
+   <header location="global">calendardtedit.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>

+ 0 - 61
TransmitterSwitch/AddItem__/addnormalitem.h

@@ -1,61 +0,0 @@
-#ifndef ADDNORMALITEM_H
-#define ADDNORMALITEM_H
-
-#include <QDialog>
-#include <QTime>
-#include <QComboBox>
-
-class TimeWidget;
-class DeviceInfo;
-
-namespace Ui {
-class AddNormalItem;
-}
-
-class AddNormalItem : public QDialog
-{
-    Q_OBJECT
-
-public:
-    explicit AddNormalItem(QWidget *parent = nullptr);
-    ~AddNormalItem();
-
-    /* 设置父指针,时间选择器需要使用 */
-    void setParentPointer(QWidget* p);
-    /* 添加可选设备 */
-    void setDevice(QMap<QString, DeviceInfo>& mapDev);
-
-signals:
-    /* 添加正常日期的项 */
-    void signal_addNormalItem(QString dev,QString action,QTime time);
-
-private slots:
-//    void do_selectTime();                           /* 选择时间 */
-    /* 进行查重和关闭页面 */
-    void do_ok();
-    /* 选择了设备,设置其对应的动作 */
-    void do_selectDev();
-    /* 选择了动作 */
-    void do_selectAction();
-    /* 点击了时间选择按钮,打开时间选择器 */
-    void do_selectTime();
-
-private:
-    /* 设置选择框报警 */
-    void setComboBoxWarning(QComboBox* bo,bool flag);
-    /* 设置时间报警 */
-    void setTimeEditWarning(bool flag);
-    void setAction(const QString& devName);
-    
-private:
-    Ui::AddNormalItem *ui;
-
-    // ExecPlan* m_p = nullptr;                        /* 设置父类指针 */
-    QString m_devName;                              /* 选择的设备 */
-    QString m_action;                               /* 选择的动作 */
-    QTime m_time;                                   /* 执行的时间 */
-
-    TimeWidget* m_timeWidget = nullptr;             /* 时间选择器 */
-};
-
-#endif // ADDNORMALITEM_H

+ 0 - 299
TransmitterSwitch/AddItem__/addnormalitem.ui

@@ -1,299 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>AddNormalItem</class>
- <widget class="QDialog" name="AddNormalItem">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>436</width>
-    <height>349</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <property name="spacing">
-    <number>0</number>
-   </property>
-   <property name="leftMargin">
-    <number>10</number>
-   </property>
-   <property name="topMargin">
-    <number>10</number>
-   </property>
-   <property name="rightMargin">
-    <number>10</number>
-   </property>
-   <property name="bottomMargin">
-    <number>10</number>
-   </property>
-   <item>
-    <widget class="QWidget" name="widget_background" native="true">
-     <property name="styleSheet">
-      <string notr="true"/>
-     </property>
-     <widget class="QLabel" name="label_NC1">
-      <property name="geometry">
-       <rect>
-        <x>32</x>
-        <y>18</y>
-        <width>80</width>
-        <height>18</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>添加计划</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC2_x">
-      <property name="geometry">
-       <rect>
-        <x>32</x>
-        <y>154</y>
-        <width>7</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC3">
-      <property name="geometry">
-       <rect>
-        <x>40</x>
-        <y>154</y>
-        <width>70</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>时间选择:</string>
-      </property>
-     </widget>
-     <widget class="QPushButton" name="pBtn_Close">
-      <property name="geometry">
-       <rect>
-        <x>368</x>
-        <y>12</y>
-        <width>32</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string/>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC4">
-      <property name="geometry">
-       <rect>
-        <x>0</x>
-        <y>56</y>
-        <width>416</width>
-        <height>1</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string/>
-      </property>
-     </widget>
-     <widget class="QPushButton" name="pBtn_cancel">
-      <property name="geometry">
-       <rect>
-        <x>248</x>
-        <y>265</y>
-        <width>60</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>取消</string>
-      </property>
-     </widget>
-     <widget class="QPushButton" name="pBtn_ok">
-      <property name="geometry">
-       <rect>
-        <x>324</x>
-        <y>265</y>
-        <width>60</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>确定</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_iconTime">
-      <property name="geometry">
-       <rect>
-        <x>359</x>
-        <y>153</y>
-        <width>16</width>
-        <height>16</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string/>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_timeWarn">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>180</y>
-        <width>250</width>
-        <height>18</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>TextLabel</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC8_x">
-      <property name="geometry">
-       <rect>
-        <x>32</x>
-        <y>98</y>
-        <width>7</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC9">
-      <property name="geometry">
-       <rect>
-        <x>40</x>
-        <y>98</y>
-        <width>70</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>设备选择:</string>
-      </property>
-     </widget>
-     <widget class="CustomComboBox" name="comBox_devSelect">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>89</y>
-        <width>274</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="currentText">
-       <string/>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC8_x_2">
-      <property name="geometry">
-       <rect>
-        <x>32</x>
-        <y>210</y>
-        <width>7</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff0000;&quot;&gt;*&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
-      </property>
-     </widget>
-     <widget class="CustomComboBox" name="comBox_actionSelect">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>201</y>
-        <width>274</width>
-        <height>32</height>
-       </rect>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_NC9_2">
-      <property name="geometry">
-       <rect>
-        <x>40</x>
-        <y>210</y>
-        <width>70</width>
-        <height>14</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>动作选择:</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_devWarn">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>126</y>
-        <width>250</width>
-        <height>18</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>TextLabel</string>
-      </property>
-     </widget>
-     <widget class="QLabel" name="label_actionWarn">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>238</y>
-        <width>250</width>
-        <height>18</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>TextLabel</string>
-      </property>
-     </widget>
-     <widget class="QPushButton" name="pBtn_selectTime">
-      <property name="geometry">
-       <rect>
-        <x>110</x>
-        <y>145</y>
-        <width>274</width>
-        <height>32</height>
-       </rect>
-      </property>
-      <property name="text">
-       <string>00:00:00</string>
-      </property>
-     </widget>
-     <zorder>label_iconTime</zorder>
-     <zorder>label_NC1</zorder>
-     <zorder>label_NC2_x</zorder>
-     <zorder>label_NC3</zorder>
-     <zorder>pBtn_Close</zorder>
-     <zorder>label_NC4</zorder>
-     <zorder>pBtn_cancel</zorder>
-     <zorder>pBtn_ok</zorder>
-     <zorder>label_timeWarn</zorder>
-     <zorder>label_NC8_x</zorder>
-     <zorder>label_NC9</zorder>
-     <zorder>comBox_devSelect</zorder>
-     <zorder>label_NC8_x_2</zorder>
-     <zorder>comBox_actionSelect</zorder>
-     <zorder>label_NC9_2</zorder>
-     <zorder>label_devWarn</zorder>
-     <zorder>label_actionWarn</zorder>
-     <zorder>pBtn_selectTime</zorder>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>CustomComboBox</class>
-   <extends>QComboBox</extends>
-   <header location="global">customcombobox.h</header>
-  </customwidget>
- </customwidgets>
- <resources/>
- <connections/>
-</ui>

+ 192 - 0
TransmitterSwitch/ItemData/ItemData.cpp

@@ -1,3 +1,195 @@
 #include "ItemData/ItemData.h"
 
+ItemData::ItemData()
+{
+    /* 创建8个List */
+    for(int i = 0; i < 8; ++i)
+    {
+        QList<OneItem*>* list = new QList<OneItem*>;
+        m_mapItem.insert(i, list);
+    }
+}
+
+
+ItemData::~ItemData()
+{
+    // for(auto it = m_mapItem.begin(); it != m_mapItem.end(); ++it)
+    // {
+    //     for(auto it1 = it.value()->begin(); it1 != it.value()->end(); ++it1)
+    //     {
+    //         delete *it1;
+    //     }
+    //     it.value()->clear();
+    //     delete it.value();
+    // }
+    // m_mapItem.clear();
+}
+
+
+/* 添加一项计划 */
+void ItemData::addOneItem(int week, OneItem* item)
+{
+    if(m_mapItem.find(week) == m_mapItem.end())
+    {
+        return;
+    }
+    m_mapItem[week]->append(item);
+}
+
+/* 删除一项计划 */
+void ItemData::deleteOneItem(int week, int num)
+{
+    if(m_mapItem.find(week) == m_mapItem.end())
+    {
+        return;
+    }
+    auto list = m_mapItem[week];
+
+    for(auto& it : *list)
+    {
+        if(it->getNum() == num)
+        {
+            auto tmpPtr = it;
+            list->removeOne(it);
+            delete tmpPtr;
+            break;
+        }
+    }
+
+}
+
+
+/* 查找有没有这个项 */
+bool ItemData::findItem(OneItem* item)
+{
+    for(auto it = m_mapItem.begin(); it != m_mapItem.end(); ++it)
+    {
+        QList<OneItem*>* list = it.value();
+        for(const auto& item1 : *list)
+        {
+            if(item1 == item)
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+/* 查找有没有这个项 */
+bool ItemData::findItem(int week, OneItem* item)
+{
+    if(m_mapItem.find(week) == m_mapItem.end())
+    {
+        return false;
+    }
+    QList<OneItem*>* list = m_mapItem[week];
+    for(const auto& it : *list)
+    {
+        if(it == item)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+/* 获取一天的容器 */
+QList<OneItem*>* ItemData::getOneDay(int week)
+{
+    if(m_mapItem.find(week) == m_mapItem.end())
+    {
+        return nullptr;
+    }
+    return m_mapItem[week];
+}
+
+
+/* 新增判断是否有重复 */
+bool ItemData::judgeTimeRepetitionWithAdd(int weekDay, const QString& devName, const QTime& time)
+{
+    /* 先查找周几对应的列表 */
+    if(m_mapItem.find(weekDay) == m_mapItem.end())
+    {
+        return false;
+    }
+    auto list = m_mapItem[weekDay];
+    for(const auto& it : *list)
+    {
+        if(it->getDevName() == devName)
+        {
+            if(it->getExecTime() == time)
+            {
+                return true;
+            }
+        }
+    }
+    /* 所有设备都判断完了,没有相同的 */
+    return false;
+}
+
+
+/* 判断已有的项修改时间后和其他项是否重复 */
+bool ItemData::judgeTimeRepetitionWithEdit(int weekDay, OneItem* item, const QTime& newTime)
+{
+    if(m_mapItem.find(weekDay) == m_mapItem.end())
+    {
+        return false;
+    }
+    auto list = m_mapItem[weekDay];
+
+    for(const auto& it : *list)
+    {
+        /* 先判断名称是否相等 */
+        if(it->getDevName() == item->getDevName())
+        {
+            /* 判断是否是同一个项 */
+            if(it->getUUID() == item->getUUID())
+            {
+                continue;
+            }
+            /* 判断时间是否相同 */
+            if(it->getExecTime() == newTime)
+            {
+                return true;
+            }
+        }
+    }
+    /* 所有设备都判断完了 */
+    return false;
+}
+
+/* 判断特殊日的已有项修改时间后和其他项是否重复 */
+bool ItemData::judgeDateTimeRepetitionWithEdit(int weekDay, OneItem* item, const QDate& newDate, const QTime& newTime)
+{
+    if(m_mapItem.find(weekDay) == m_mapItem.end())
+    {
+        return false;
+    }
+    auto list = m_mapItem[weekDay];
+
+    for(const auto& it : *list)
+    {
+        /* 先判断名称是否相等 */
+        if(it->getDevName() == item->getDevName())
+        {
+            /* 判断是否是同一个项 */
+            if(it->getUUID() == item->getUUID())
+            {
+                continue;
+            }
+            /* 判断日期是否相等 */
+            if(it->getDate() == newDate)
+            {
+                /* 判断时间是否相同 */
+                if(it->getExecTime() == newTime)
+                {
+                    return true;
+                }
+            }
+        }
+    }
+    /* 所有设备都判断完了 */
+    return false;
+}
 

+ 45 - 0
TransmitterSwitch/ItemData/ItemData.h

@@ -1,8 +1,53 @@
 #ifndef ITEMDATA_H
 #define ITEMDATA_H
 
+#include "oneitem.h"
 
 
+#define IData ItemData::getInstance()
+
+/**
+ * @brief 存储创建的Item
+ * 
+ */
+class ItemData
+{
+    ItemData();
+    ItemData(const ItemData&) = delete;
+    ItemData& operator=(const ItemData&) = delete;
+
+public:
+    ~ItemData();
+
+    static ItemData& getInstance()
+    {
+        static ItemData instance;
+        return instance;
+    }
+
+    /* 添加一项计划 */
+    void addOneItem(int week, OneItem* item);
+    /* 删除一项计划 */
+    void deleteOneItem(int week, int num);
+    /* 查找有没有这个项 */
+    bool findItem(OneItem* item);
+    bool findItem(int week, OneItem* item);
+    /* 获取一天的容器 */
+    QList<OneItem*>* getOneDay(int week);
+
+    /* 新增判断是否有重复 */
+    bool judgeTimeRepetitionWithAdd(int weekDay, const QString& devName, const QTime& time);
+    /* 判断已有的项修改时间后和其他项是否重复 */
+    bool judgeTimeRepetitionWithEdit(int weekDay, OneItem* item, const QTime& newTime);
+    /* 判断特殊日的已有项修改时间后和其他项是否重复 */
+    bool judgeDateTimeRepetitionWithEdit(int weekDay, OneItem* item, const QDate& newDate, const QTime& newTime);
+    
+
+private:
+    QMap<int, QList<OneItem*>*> m_mapItem;           /* int是周几 */
+
+
+};
 
 
 

+ 87 - 15
TransmitterSwitch/ItemData/oneitem.cpp

@@ -4,7 +4,8 @@
 #include <QFile>
 
 #include "LHQLogAPI.h"
-
+#include "TransmitterSwitchInfo.h"
+#include "customcombobox.h"
 
 OneItem::OneItem(QWidget *parent, bool isSpecial) :
     QWidget(parent), m_isSpecial(isSpecial),
@@ -23,17 +24,29 @@ OneItem::OneItem(QWidget *parent, bool isSpecial) :
     {
         LH_WRITE_ERROR(QString("打开文件失败:%1").arg(file.fileName()));
     }
+    /* 设置背景透明 */
+    this->setAttribute(Qt::WA_TranslucentBackground);
+    /* 设置无边框 */
+    this->setWindowFlags(Qt::FramelessWindowHint);
 
     /* 设置定时器 */
     m_warnTimer.setTimerType(Qt::PreciseTimer);
     m_warnTimer.setSingleShot(true);
-    connect(&m_warnTimer,&QTimer::timeout,this,[this](){
-        ui->label_warnning->hide();
-    });
+    connect(&m_warnTimer, &QTimer::timeout, this, &OneItem::hideWarn);
+
+    /* 初始化变量 */
+    m_uuid = QUuid::createUuid();
+    setExecTime(QTime(0,0,0));
+    setDate(QDate(1970,1,1));
+
 
     /* 根据是否是特殊日移动位置 */
     layoutInit();
 
+    /* 设置下拉框背景 */
+    ui->comboBox_devName->setViewShadowEffect();
+    ui->comboBox_action->setViewShadowEffect();
+
     /* 注册事件过滤器 */
     ui->comboBox_devName->installEventFilter(this);
     ui->comboBox_action->installEventFilter(this);
@@ -42,7 +55,10 @@ OneItem::OneItem(QWidget *parent, bool isSpecial) :
     connect(ui->comboBox_devName,QOverload<const QString&>::of(&QComboBox::currentTextChanged),this,&OneItem::do_devChanged);
     connect(ui->comboBox_action,QOverload<const QString&>::of(&QComboBox::currentTextChanged),this,&OneItem::do_actionChanged);
     connect(ui->pBtn_execTime,&QPushButton::clicked,this,&OneItem::do_pBtn_execTime_clicked);
+    connect(ui->pBtn_iconTime,&QPushButton::clicked,this,&OneItem::do_pBtn_execTime_clicked);
     connect(ui->pBtn_execDate,&QPushButton::clicked,this,&OneItem::do_pBtn_execDate_clicked);
+    connect(ui->pBtn_iconDate,&QPushButton::clicked,this,&OneItem::do_pBtn_execDate_clicked);
+    connect(ui->pBtn_close, &QPushButton::clicked, this, &OneItem::do_pBtn_close_clicked);
 }
 
 OneItem::~OneItem()
@@ -54,37 +70,40 @@ OneItem::~OneItem()
 /* 设置序号 */
 void OneItem::setNum(int num)
 {
+    m_num = num;
     ui->label_num->setText(QString::number(num));
 }
 
 /* 获取序号 */
 int OneItem::getNum()
 {
-    return ui->label_num->text().toInt();
+    return m_num;
 }
 
 /* 设置日期 */
 void OneItem::setDate(const QDate& date)
 {
+    m_date = date;
     ui->pBtn_execDate->setText(date.toString("yyyy-MM-dd"));
 }
 
 /* 获取日期 */
 QDate OneItem::getDate()
 {
-    return QDate::fromString(ui->pBtn_execDate->text(),"yyyy-MM-dd");
+    return m_date;
 }
 
 /* 设置执行时间 */
 void OneItem::setExecTime(const QTime& time)
 {
+    m_time = time;
     ui->pBtn_execTime->setText(time.toString("hh:mm:ss"));
 }
 
 /* 获取执行时间 */
 QTime OneItem::getExecTime()
 {
-    return QTime::fromString(ui->pBtn_execTime->text(),"hh:mm:ss");
+    return m_time;
 }
 
 /* 设置设备名称 */
@@ -99,10 +118,18 @@ QString OneItem::getDevName()
     return ui->comboBox_devName->currentText();
 }
 
-/* 通过动作名称设置动作 */
-void OneItem::setActionName(const QString &action)
+/* 添加设备支持的动作 */
+void OneItem::addActions()
 {
-    ui->comboBox_action->setCurrentText(action);
+    auto acts = DevTypeContainer.getDevType(m_devInfo.PTTypeCode);
+    ui->comboBox_action->clear();
+    if(acts.PTTypeCode > 0)
+    {
+        for(auto it = acts.devAction.begin();it != acts.devAction.end();it++)
+        {
+            ui->comboBox_action->addItem(it.value(), it.key());
+        }
+    }
 }
 
 /* 获取动作名称 */
@@ -118,8 +145,9 @@ int OneItem::getActionNum()
 }
 
 /* 添加设备 */
-void OneItem::addDevice(const QMap<QString, DeviceInfo>& mapDev)
+void OneItem::addDevice()
 {
+    auto& mapDev = DeviceContainer.getMapDevice();
     ui->comboBox_devName->clear();
     for(const auto& it : mapDev)
     {
@@ -127,7 +155,7 @@ void OneItem::addDevice(const QMap<QString, DeviceInfo>& mapDev)
     }
     /* 设置显示第一个设备,并设置可选的动作 */
     ui->comboBox_devName->setCurrentIndex(0);
-    setActionName(ui->comboBox_devName->currentText());
+    addActions();
 }
 
 /* 获取日期类型 */
@@ -145,12 +173,50 @@ void OneItem::setWarningText(QString str, int ms)
     {
         m_warnTimer.start(ms);
     }
+    /* 设置红框 */
+    ui->pBtn_execTime->setProperty("Warn",true);
+    ui->pBtn_execTime->style()->unpolish(ui->pBtn_execTime);
+    ui->pBtn_execTime->style()->polish(ui->pBtn_execTime);
+    ui->pBtn_execDate->setProperty("Warn",true);
+    ui->pBtn_execDate->style()->unpolish(ui->pBtn_execDate);
+    ui->pBtn_execDate->style()->polish(ui->pBtn_execDate);
 }
 
 /* 隐藏警告 */
 void OneItem::hideWarn()
 {
-    ui->label_warnning->hide();
+    ui->label_warnning->clear();
+    /* 取消红框 */
+    ui->pBtn_execTime->setProperty("Warn", false);
+    ui->pBtn_execTime->style()->unpolish(ui->pBtn_execTime);
+    ui->pBtn_execTime->style()->polish(ui->pBtn_execTime);
+    ui->pBtn_execDate->setProperty("Warn", false);
+    ui->pBtn_execDate->style()->unpolish(ui->pBtn_execDate);
+    ui->pBtn_execDate->style()->polish(ui->pBtn_execDate);
+}
+
+/* 获取执行时间的位置 */
+QPoint OneItem::getExecTimePos()
+{
+    return ui->pBtn_execTime->pos();
+}
+
+/* 获取执行日期的位置 */
+QPoint OneItem::getExecDatePos()
+{
+    return ui->pBtn_execDate->pos();
+}
+
+/* 获取执行时间按钮的大小 */
+QSize OneItem::getExecTimeSize()
+{
+    return ui->pBtn_execTime->size();
+}
+
+/* 获取执行日期按钮的大小 */
+QSize OneItem::getExecDateSize()
+{
+    return ui->pBtn_execDate->size();
 }
 
 /* 设备改变了 */
@@ -192,6 +258,12 @@ void OneItem::do_pBtn_execDate_clicked()
     emit signal_dateClicked(getDate());
 }
 
+/* 关闭按钮被点击了 */
+void OneItem::do_pBtn_close_clicked()
+{
+    emit signal_OneItemDelete(m_weekDay, m_num);
+}
+
 
 /* 根据日期类型布局 */
 void OneItem::layoutInit()
@@ -206,7 +278,7 @@ void OneItem::layoutInit()
         /* 设备名称 */
         ui->comboBox_devName->move(114, 0);
         /* 执行时间 */
-        ui->pBtn_execTime->move(390, 40);
+        ui->pBtn_execTime->move(390, 0);
         /* 执行时间图标 */
         ui->pBtn_iconTime->move(498, 8);
         /* 动作 */
@@ -226,7 +298,7 @@ void OneItem::layoutInit()
         /* 执行日期图标 */
         ui->pBtn_iconDate->move(498, 8);
         /* 执行时间 */
-        ui->pBtn_execTime->move(539, 40);
+        ui->pBtn_execTime->move(539, 0);
         /* 执行时间图标 */
         ui->pBtn_iconTime->move(646, 8);
         /* 动作 */

+ 29 - 6
TransmitterSwitch/ItemData/oneitem.h

@@ -3,6 +3,8 @@
 
 #include <QWidget>
 #include <QTimer>
+#include <QUuid>
+
 #include "TransmitterSwitchInfo.h"
 
 namespace Ui {
@@ -17,6 +19,12 @@ public:
     explicit OneItem(QWidget *parent = nullptr, bool isSpecial = false);
     ~OneItem();
 
+    /* 获取UUID */
+    QUuid getUUID() { return m_uuid; }
+    /* 设置周几 */
+    void setWeekDay(int week) { m_weekDay = week; }
+    /* 获取周几 */
+    int getWeekDay() { return m_weekDay; }
     /* 设置序号 */
     void setNum(int num);
     /* 获取序号 */
@@ -33,14 +41,14 @@ public:
     void setDevName(const QString& dev);
     /* 获取设备名称 */
     QString getDevName();
-    /* 通过动作名称设置动作 */
-    void setActionName(const QString &action);
+    /* 添加设备支持的动作 */
+    void addActions();
     /* 获取动作名称 */
     QString getActionName();
     /* 获取动作类型 */
     int getActionNum();
-    /* 添加设备 */
-    void addDevice(const QMap<QString, DeviceInfo>& mapDev);
+    /* 添加所有设备 */
+    void addDevice();
 
     /* 获取日期类型 */
     bool getDateType();
@@ -48,10 +56,18 @@ public:
     void setWarningText(QString str,int ms = 3000);
     /* 隐藏警告 */
     void hideWarn();
+    /* 获取执行时间的位置,相对于该项的位置 */
+    QPoint getExecTimePos();
+    /* 获取执行日期的位置 */
+    QPoint getExecDatePos();
+    /* 获取执行时间按钮的大小 */
+    QSize getExecTimeSize();
+    /* 获取执行日期按钮的大小 */
+    QSize getExecDateSize();
 
 signals:
     /* 一个OneItem被删除了 */
-    void signal_OneItemDelete(int num);
+    void signal_OneItemDelete(int week, int num);
     /* 日期被点击了 */
     void signal_dateClicked(QDate date);
     /* 执行时间被点击了 */
@@ -68,6 +84,8 @@ private slots:
     void do_pBtn_execTime_clicked();
     /* 执行日期被点击了 */
     void do_pBtn_execDate_clicked();
+    /* 关闭按钮被点击了 */
+    void do_pBtn_close_clicked();
 
 private:
     /* 根据日期类型布局 */
@@ -79,10 +97,15 @@ protected:
 
 private:
     Ui::OneItem *ui;
-
+    QUuid m_uuid;               /* 项的唯一识别号,做判断的时候使用 */
     bool m_isSpecial = false;
     QTimer m_warnTimer;
     DeviceInfo m_devInfo;
+    
+    int m_weekDay = -1;
+    int m_num = -1;
+    QTime m_time;
+    QDate m_date;
 };
 
 #endif // ONEITEM_H

+ 21 - 2
TransmitterSwitch/ItemData/oneitem.ui

@@ -116,7 +116,7 @@
           <string>序号</string>
          </property>
         </widget>
-        <widget class="QComboBox" name="comboBox_devName">
+        <widget class="CustomComboBox" name="comboBox_devName">
          <property name="geometry">
           <rect>
            <x>114</x>
@@ -169,7 +169,7 @@
           <string/>
          </property>
         </widget>
-        <widget class="QComboBox" name="comboBox_action">
+        <widget class="CustomComboBox" name="comboBox_action">
          <property name="geometry">
           <rect>
            <x>686</x>
@@ -291,6 +291,18 @@
       </item>
       <item>
        <widget class="QLabel" name="label_warnning">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>16777215</width>
+          <height>16</height>
+         </size>
+        </property>
         <property name="text">
          <string/>
         </property>
@@ -301,6 +313,13 @@
    </item>
   </layout>
  </widget>
+ <customwidgets>
+  <customwidget>
+   <class>CustomComboBox</class>
+   <extends>QComboBox</extends>
+   <header location="global">customcombobox.h</header>
+  </customwidget>
+ </customwidgets>
  <resources/>
  <connections/>
 </ui>

BIN
TransmitterSwitch/Resource/ICON/Close_Dark.png


BIN
TransmitterSwitch/Resource/ICON/DownArrow_Dark.png


BIN
TransmitterSwitch/Resource/ICON/date_dark.png


BIN
TransmitterSwitch/Resource/ICON/date_light.png


+ 25 - 1
TransmitterSwitch/Resource/QSS/AddNormalItem_Light.qss

@@ -15,6 +15,12 @@ QWidget
     background: #FFFFFF;
 }
 
+QWidget#widget
+{
+    background: rgba(0,0,0,0.01);
+    /* background: rgba(255,255,255,1); */
+}
+
 QLabel#label_NC1
 {
     font-weight: bold;
@@ -224,7 +230,7 @@ TimeWidget:!enabled
     border: 1px solid #E6E9F4;
 }
 
-/* QPushButton#pBtn_selectTime
+QPushButton#pBtn_selectTime
 {
     background: transparent;
     border: 1px solid #E6E9F4;
@@ -254,5 +260,23 @@ QPushButton#pBtn_selectTime[Warn=true]
     border-radius: 4px;
     padding-left:12px;
     border: 1px solid #D21F21;
+}
+
+TimeWidget
+{
+    /* background: transparent; */
+    border-radius: 4px;
+    padding-left:12px;
+    border: 1px solid #4458FE;
+}
+
+/* TimeWidget QPushButton
+{
+    border-image: url(:/ICON/ICON/Time.png);
 } */
 
+QPushButton#btn_tip
+{
+    border-image: url(:/ICON/ICON/Time.png);
+}
+

+ 282 - 0
TransmitterSwitch/Resource/QSS/AddSpecialItem_Light.qss

@@ -0,0 +1,282 @@
+
+/* ==========================================================
+ *  通用样式
+ * ========================================================== */
+QWidget
+{
+    font-family: 思源黑体R;
+    font-weight: 400;
+    font-size: 14px;
+    color: #3A3F63;
+    line-height: 21px;
+    text-align: left;
+    font-style: normal;
+    border-radius: 8px;
+    background: #FFFFFF;
+}
+
+QWidget#widget
+{
+    background: rgba(0,0,0,0.01);
+    /* background: rgba(255,255,255,1); */
+}
+
+QLabel#label_NC1
+{
+    font-weight: bold;
+    font-size: 18px;
+    color: #3A3F63;
+    line-height: 27px;
+    text-align: left;
+    font-style: normal;
+    text-transform: uppercase;
+}
+QLabel#label_NC4
+{
+    background: #E6E9F4;
+}
+
+QPushButton
+{
+	text-align: center;
+	font-family: 思源黑体M;
+}
+
+QPushButton#pBtn_Close{
+	image: url(:/ICON/ICON/Dialog_close.png);
+}
+QPushButton#pBtn_Close:hover
+{
+	image: url(:/ICON/ICON/Dialog_close2.png);
+}
+
+/********* 普通方框按钮三种状态效果 *********/
+QPushButton#pBtn_cancel:enabled
+{
+    background: #FFFFFF;
+    border-radius: 16px;
+    border: 1px solid #E6E9F4;
+    color: #3A3F63;
+}
+QPushButton#pBtn_cancel:hover
+{
+    background: #FFFFFF;
+    border-radius: 16px;
+    border: 1px solid #4458FE;
+    color: #4458FE;
+}
+
+
+/********* 带有底色按钮三种状态效果 *********/
+QPushButton#pBtn_ok
+{
+    color:white;
+    background: qlineargradient( x0:1,x1:1,y1:0,y2:0,stop:1 #4F8AFF,stop:0 #4B5EFF);
+    border-radius: 16px;
+}
+
+QPushButton#pBtn_ok:hover
+{
+    color:white;
+    background: qlineargradient( x0:1,x1:1,y1:0,y2:0,stop:0 #5D73FF,stop:1 #6092FF);
+    border-radius: 16px;
+}
+
+
+QLabel#label_devWarn,QLabel#label_timeWarn,QLabel#label_actionWarn
+{
+    font-weight: 400;
+    font-size: 14px;
+    color: #D21F21;
+    line-height: 21px;
+    text-align: left;
+    font-style: normal;
+}
+
+/* ==========================================================
+ *  QComboBox(这个是在用的)
+ * ========================================================== */
+
+QComboBox:enabled
+{
+    background-color:#FFFFFF;
+    border: 1px solid #E6E9F4;
+    border-radius: 4px;
+    font-size:14px;
+    font-weight: 400;
+    color:#3A3F63;
+    padding-left: 12px;
+}
+
+/* 不能编辑的时候的样式,setEnable(false) */
+QComboBox:!enabled
+{
+    background:rgba(0,0,0,0.04);
+	border: 1px solid #E6E9F4;
+    border-radius: 4px;
+    font-size:14px;
+    font-weight: 400;
+    color:rgba(58,63,99,0.65);
+    padding-left: 12px;
+}
+
+QComboBox:hover
+{
+    border: 1px solid #4458FE;
+    border-radius: 4px;
+    background:transparent;
+}
+
+/* 下拉箭头所在的位置方框 */
+QComboBox::drop-down
+{
+    width: 24px;
+    border: none;
+}
+/* 下拉箭头图标 */
+QComboBox::down-arrow
+{
+    image: url(:/ICON/ICON/DownArrow.png);
+    height:16px;
+    width:16px;
+}
+
+/* 下拉条样式,就是view,整个下拉窗体的样式 */
+QComboBox QAbstractItemView
+{
+    background-color: #FFFFFF;
+    margin: 12px;
+    outline:0px;
+    font-size:14px;
+    color: #3A3F63;
+    border-radius: 4px;
+}
+
+/* 使下面两句生效,需要加上如下语句 */
+/* m_comBoxDev->setView(new QListView()); */
+QComboBox QAbstractItemView::item
+{
+    background-color: #FFFFFF;
+    border-radius:4px;
+    color: #3A3F63;
+    padding-left: 12px;
+    height: 32px;
+}
+
+QComboBox QAbstractItemView::item:hover
+{
+    border-radius:4px;
+    background-color: #EEF2FF;
+}
+
+/* QComboBox QAbstractItemView::item:selected
+{
+    border-radius:4px;
+    background-color: #EEF2FF;
+} */
+
+/******** combobox 滚动条  *********/
+QComboBox QScrollBar::vertical{ /*主体部分*/
+    width:8px;
+    background:transparent;
+    border:none;
+    border-radius:5px;
+}
+QComboBox QScrollBar::handle::vertical{ /*滑块主体*/
+    width: 8px;
+    background: #E2E2E2;
+    border-radius: 3px;
+    min-width: 8px;
+}
+QComboBox QScrollBar::handle::vertical::hover{
+    background:transparent;
+}
+QComboBox QScrollBar::add-line::vertical{/*上箭头*/
+    border:none;
+}
+QComboBox QScrollBar::sub-line::vertical{/*下箭头*/
+    border:none;
+}
+
+
+/* ==========================================================
+ *  时间报警红框
+ * ========================================================== */
+
+QLabel#label_iconTime
+{
+	border-image: url(:/ICON/ICON/Time.png);
+}
+
+TimeWidget
+{
+	background: transparent;
+    border-radius: 4px;
+    padding-left:12px;
+    border: 1px solid #E6E9F4;
+}
+
+TimeWidget[Warn=true]
+{
+	background: transparent;
+    border-radius: 4px;
+    padding-left:12px;
+    border: 1px solid #D21F21;
+}
+
+TimeWidget:!enabled
+{
+    background: rgba(0,0,0,0.04);
+    border: 1px solid #E6E9F4;
+}
+
+QPushButton#pBtn_selectTime
+{
+    background: transparent;
+    border: 1px solid #E6E9F4;
+    border-radius: 4px;
+    font-size: 14px;
+    font-weight: 400;
+    color: #3A3F63;
+    padding-left: 12px;
+    text-align: left;
+}
+
+QPushButton#pBtn_selectTime:hover
+{
+    background: transparent;
+    border: 1px solid #4458FE;
+    border-radius: 4px;
+    font-size: 14px;
+    font-weight: 400;
+    color: #4458FE;
+    padding-left: 12px;
+    text-align: left;
+}
+/* 报警红框 */
+QPushButton#pBtn_selectTime[Warn=true]
+{
+	background: transparent;
+    border-radius: 4px;
+    padding-left:12px;
+    border: 1px solid #D21F21;
+}
+
+TimeWidget
+{
+    /* background: transparent; */
+    border-radius: 4px;
+    padding-left:12px;
+    border: 1px solid #4458FE;
+}
+
+/* TimeWidget QPushButton
+{
+    border-image: url(:/ICON/ICON/Time.png);
+} */
+
+QPushButton#btn_tip
+{
+    border-image: url(:/ICON/ICON/Time.png);
+}
+

+ 176 - 0
TransmitterSwitch/Resource/QSS/OneItem_dark.qss

@@ -0,0 +1,176 @@
+
+QWidget
+{
+    font-family: 思源黑体R;
+    font-weight: 400;
+    font-size: 14px;
+    color: #D2D2D2;
+    line-height: 22px;
+    text-align: left;
+    font-style: normal;
+    text-transform: none;
+
+}
+
+QWidget#widget
+{
+    background: transparent;
+    border: 0px solid #313539;
+}
+
+QWidget#widget_content
+{
+    background: transparent;
+    border: 0px solid #313539;
+}
+
+
+/* 序号 */
+QLabel#label_num
+{
+    background: #313539;
+    border-radius: 2px 2px 2px 2px;
+    border: 1px solid #313539;
+    padding-left: 12px;
+}
+
+
+
+QPushButton#pBtn_close
+{
+    background-color: #313539;
+    border-radius: 2px 2px 2px 2px;
+    padding-left: 6px;
+
+    border: 1px solid #313539;
+    qproperty-icon: url(:/ICON/ICON/Close_Dark.png);
+    qproperty-iconSize: 20px 20px;
+}
+
+QPushButton#pBtn_close:hover
+{
+    background-color: #313539;
+    border-radius: 2px 2px 2px 2px;
+    padding-left: 6px;
+
+    border: 1px solid #438EFF;
+    qproperty-icon: url(:/ICON/ICON/Close_Dark.png);
+    qproperty-iconSize: 20px 20px;
+}
+
+/* 执行时间 */
+QPushButton#pBtn_execTime, #pBtn_execDate
+{
+    background-color: #313539;
+    border-radius: 2px 2px 2px 2px;
+    padding-left: 12px;
+
+    border: 1px solid #313539;
+}
+
+QPushButton#pBtn_execTime:hover, #pBtn_execDate:hover
+{
+    background-color: #313539;
+    border-radius: 2px 2px 2px 2px;
+    padding-left: 12px;
+
+    border: 1px solid #438EFF;
+}
+
+/* 时间图标 */ 
+QPushButton#pBtn_iconTime
+{
+    background: transparent;
+    border: none;
+    qproperty-icon: url(:/ICON/ICON/Time.png);
+    qproperty-iconSize: 16px 16px;
+}
+
+
+/*=====================================================================
+ * QComboBox下拉框
+ *==================================================================== */
+
+QComboBox
+{
+	background-color: #313539;
+	border-radius: 4px;
+	border: 1px solid #313539;
+	font-weight: 400;
+	font-size: 14px;
+	color: #D2D2D2;
+	padding-left: 12px;
+}
+QComboBox:hover, QComboBox:on 
+{
+	border: 1px solid #438EFF;
+}
+/*下拉箭头样式*/
+QComboBox::down-arrow
+{
+	height: 16px;
+	width: 16px;
+	image: url(:/ICON/ICON/DownArrow_Dark.png);
+}
+QComboBox::drop-down
+{
+    background-color:transparent;
+	padding-right:12px;
+}
+/* 下拉后,整个下拉窗体样式 */
+QComboBox QAbstractItemView
+{
+	margin: 12px;
+	font-size: 14px;
+	background-color: #5C5E61;
+	outline:0px;
+	border-radius: 4px;
+}
+/* 下拉后,整个下拉窗体每项的样式 */
+QComboBox QAbstractItemView::item 
+{
+    border-radius: 4px;
+	color: #D2D2D2;
+    height: 32px;
+	background-color: #5C5E61;
+	font-weight: 400;
+	font-size: 14px;
+	padding-left: 12px;
+}
+QComboBox QAbstractItemView::item:hover 
+{
+	font-weight: 400;
+    color: #FFFFFF;
+	background-color: #438EFF;
+}
+QComboBox QAbstractItemView::item:selected 
+{
+	font-weight: 400;
+    color: #FFFFFF;
+	background-color: #438EFF;
+}
+
+
+/*=====================================================================
+ * 报警文字和报警框
+ *==================================================================== */
+
+QLabel#label_warnning
+{
+    font-weight: 400;
+    font-size: 14px;
+    color: #D21F21;
+    line-height: 21px;
+    text-align: left;
+    font-style: normal;
+    padding-left: 18px;
+}
+
+QPushButton#pBtn_execTime[Warn=true], #pBtn_execDate[Warn=true]
+{
+    background-color: #313539;
+    border-radius: 2px 2px 2px 2px;
+    padding-left: 12px;
+
+    border: 1px solid #D21F21;
+}

+ 12 - 0
TransmitterSwitch/Resource/QSS/TransmitterSwitch_dark.qss

@@ -221,3 +221,15 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
 
 
 
+/*===============================================================
+ * TimeWidget 时间选择器
+ *===============================================================*/
+
+TimeWidget
+{
+    /* background: transparent; */
+    border-radius: 4px;
+    padding-left:12px;
+    border: 1px solid #438EFF;
+}
+

+ 4 - 1
TransmitterSwitch/Resource/TransSwitch.qrc

@@ -20,9 +20,12 @@
         <file>ICON/Tip_Dark.png</file>
         <file>ICON/Dialog_close.png</file>
         <file>ICON/Dialog_close2.png</file>
-        <file>ICON/Date.png</file>
         <file>ICON/Time.png</file>
+        <file>ICON/date_dark.png</file>
+        <file>ICON/date_light.png</file>
         <file>ICON/DownArrow.png</file>
+        <file>ICON/Close_Dark.png</file>
+        <file>ICON/DownArrow_Dark.png</file>
     </qresource>
     <qresource prefix="/Font">
         <file>font/SiYuanBlack_ttf/SiYuanBlack_Bold.ttf</file>

BIN
TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/.DS_Store


BIN
TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/._.DS_Store


BIN
TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/._下拉箭头@2x.png


BIN
TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/._关闭默认@2x.png


BIN
TransmitterSwitch/Resource/发射业务控制台切图@2x/发射业务控制台浅色@2x/._动环监测选中@2x.png


+ 1 - 0
TransmitterSwitch/TransmitterSwitchInfo.cpp

@@ -2,6 +2,7 @@
 
 
 
+
 ExecPlanItemInfo::ExecPlanItemInfo()
 {
     ExecType = -1;

+ 2 - 0
TransmitterSwitch/TransmitterSwitchInfo.h

@@ -9,6 +9,7 @@
 
 #define nJson nlohmann::json
 
+
 /**
  * @brief 支持的发射机类型
  * 
@@ -159,4 +160,5 @@ private:
 #define DeviceContainer MapDevice::getInstance()
 
 
+
 #endif /* TRANSMITTERSWITCHINFO_H */

+ 28 - 0
TransmitterSwitch/common/DropShadow/dropshadowmgr.cpp

@@ -0,0 +1,28 @@
+#include "dropshadowmgr.h"
+#include "idropshadowable.h"
+#include <QEvent>
+
+
+DropShadowMgr::DropShadowMgrGarbo DropShadowMgr::garbo;
+DropShadowMgr* DropShadowMgr::sm_pInstance = new DropShadowMgr(nullptr);     //初始化静态单例(饿汉):
+QList<BoxShadow> DropShadowMgr::sm_cacheShadows;
+
+/**
+ * @brief 绘制注册到这里的阴影效果
+ * @param watched
+ * @param event
+ * @return
+ */
+bool DropShadowMgr::eventFilter(QObject *watched, QEvent *event)
+{
+    IDropShadowable *pDropShadowableObj = dynamic_cast<IDropShadowable*>(watched);
+    if(pDropShadowableObj == nullptr)
+    {
+        return QObject::eventFilter(watched, event);
+    }
+    if(event->type() == QEvent::Paint)
+    {
+        pDropShadowableObj->PaintShadows();
+    }
+    return QObject::eventFilter(watched, event);
+}

+ 46 - 0
TransmitterSwitch/common/DropShadow/dropshadowmgr.h

@@ -0,0 +1,46 @@
+#ifndef DROPSHADOWMGR_H
+#define DROPSHADOWMGR_H
+
+#include <QObject>
+#include "idropshadowable.h"
+
+class DropShadowMgr : public QObject
+{
+    Q_OBJECT
+public:
+    static DropShadowMgr* Instance(){return sm_pInstance;}
+    ~DropShadowMgr() override {sm_pInstance = nullptr;}
+public:
+    //static QMap<BoxShadow, QImage> sm_cacheShadows;
+    static QList<BoxShadow> sm_cacheShadows;
+private:
+    DropShadowMgr(QObject *parent = nullptr):QObject(parent){}
+    //防拷贝, C++11
+    DropShadowMgr(DropShadowMgr const&) = delete;
+	DropShadowMgr& operator=(DropShadowMgr const&) = delete;
+    
+private:
+    static DropShadowMgr* sm_pInstance;     //单例实例
+public:
+    virtual bool eventFilter(QObject *watched, QEvent *event) override;
+    /*----------------------------------------------------------------
+     * 关于释放全局单例: 
+     * 一个妥善的方法是让这个类自己知道在合适的时候把自己删除; 或者说把删除自己的操作挂在系统中的某个合适的点上, 使其在恰当的时候自动被执行;
+     * 程序在结束的时候, 系统会自动析构所有的全局变量;事实上, 系统也会析构所有的类的静态成员变量, 就像这些静态成员也是全局变量一样;
+     * 利用这个特征, 我们可以在单例类中定义一个这样的静态成员变量, 而它的唯一工作就是在析构函数中删除单例类的实例;
+    ----------------------------------------------------------------*/
+private:
+    class DropShadowMgrGarbo
+    {
+    public:
+        ~DropShadowMgrGarbo()
+        {  
+            if(DropShadowMgr::sm_pInstance != nullptr)
+                delete DropShadowMgr::sm_pInstance;
+        }
+    };
+    static DropShadowMgrGarbo garbo;
+    /*----------------------------------------------------------------*/
+};
+
+#endif // DROPSHADOWMGR_H

+ 83 - 0
TransmitterSwitch/common/DropShadow/idropshadowable.cpp

@@ -0,0 +1,83 @@
+#include "idropshadowable.h"
+#include "dropshadowmgr.h"
+#include "../ImageBlur/imageblur.h"
+#include "PaintHelper/painthelper.h"
+#include <QDebug>
+
+/**
+ * @brief IDropShadowable::IDropShadowable
+ * @param selfWidget 阴影显示在这一层上
+ */
+IDropShadowable::IDropShadowable(QWidget *selfWidget)
+    : m_pSelfWidget(selfWidget)
+{
+    selfWidget->installEventFilter(DropShadowMgr::Instance());
+}
+/**
+ * @brief IDropShadowable::SetDropShadow
+ * @param boxShadow
+ * @param size 这个是阴影上面内容的大小
+ */
+void IDropShadowable::SetDropShadow(const BoxShadow &boxShadow, const QSize &size)
+{
+    /* 直接清除list,这单例阴影只能用在一个地方? */
+    ClearDropShadow();
+    DropShadowMgr::sm_cacheShadows.clear();
+    m_listShadows.append(boxShadow);
+    if(!DropShadowMgr::sm_cacheShadows.contains(boxShadow))
+    {
+        /* 一边阴影的宽度 */
+        int radius = boxShadow.radius;
+        /* 图片(阴影?)宽和高 */
+        int imageWidth = size.width()+radius*2;
+        int imageHeight = size.height()+radius*2;
+        QImage image(imageWidth, imageHeight, QImage::Format_ARGB32);
+        image.fill(boxShadow.color);
+        //边框设为透明
+        for(int x=0;x<image.width();x++)
+        {
+            for(int y=0;y<image.height();y++)
+            {
+                /* 设置阴影圈部分透明 */
+                if(x>=radius && x<(image.width()-radius) && y>=radius && y<(image.height()-radius)) continue;
+                image.setPixelColor(QPoint(x,y), Qt::transparent);
+            }
+        }
+        /* 通过高斯模糊来设置阴影 */
+        GaussBlur::Blur(image, boxShadow.radius);
+        /* 又创建一个? */
+        BoxShadow shadow_image(boxShadow);
+        shadow_image.image = image;
+        DropShadowMgr::sm_cacheShadows.append(shadow_image);
+    }
+    m_pSelfWidget->update();
+}
+
+void IDropShadowable::SetDropShadows(const QList<BoxShadow> &shadows, const QSize &size)
+{
+    Q_UNUSED(shadows)
+    Q_UNUSED(size)
+    //找到最大的radius, x偏移, y偏移
+    return;
+}
+
+void IDropShadowable::ClearDropShadow()
+{
+    m_listShadows.clear();
+    m_pSelfWidget->update();
+}
+/**
+ * @brief 绘制阴影
+ */
+void IDropShadowable::PaintShadows()
+{
+    PainterEx painter(m_pSelfWidget);
+    painter.setRenderHint(QPainter::Antialiasing);
+    for(const BoxShadow &boxShadow: m_listShadows)
+    {
+        int index = DropShadowMgr::sm_cacheShadows.indexOf(boxShadow);
+        if(index == -1) continue;
+        QImage image = DropShadowMgr::sm_cacheShadows.at(index).image;
+        painter.drawImage(image.rect(), image, image.rect());
+    }
+}

+ 82 - 0
TransmitterSwitch/common/DropShadow/idropshadowable.h

@@ -0,0 +1,82 @@
+#ifndef IDROPSHADOWABLE_H
+#define IDROPSHADOWABLE_H
+
+#include <QList>
+#include <QSize>
+#include <QColor>
+#include <QWidget>
+#include <QDebug>
+
+/**
+ * @brief 这是个数据结构,存储阴影相关的参数
+ */
+struct BoxShadow
+{
+    int x;
+    int y;
+    int radius;                 /* 一边阴影的宽度 */
+    int spread;                 /*  */
+    QColor color;
+    QSize boxSize;
+    QImage image;
+    //BoxShadow():x(0),y(0),radius(0),spread(0),color(QColor()),boxSize(QSize()){}
+    bool operator==(const BoxShadow &rhs) const
+    {
+        return (this->radius == rhs.radius)
+                &&(this->spread == rhs.spread)
+                &&(this->color == rhs.color)
+                &&(this->boxSize == rhs.boxSize);
+    }
+    bool operator<(const BoxShadow &rhs) const
+    {
+        /*----------------------------------------------------------------
+         * QMap中通过<运算符来比较两个参数是否相等
+         * 即通过a<b来判断是否相等,若小于成立,则说明不相等,便会插入;
+         * 若小于不成立,则说明要么大于,要么等于;
+         * 然后再反过来比较一次,即b<a,若这次小于成立,则b>a,则说明它们不相等,便会插入,否则相等。
+        ----------------------------------------------------------------*/
+        if((this->radius == rhs.radius)
+            &&(this->spread == rhs.spread)
+            &&(this->color == rhs.color)
+            &&(this->boxSize == rhs.boxSize))
+        {
+            return false;
+        }
+        else 
+        {
+            return true;    
+        }
+        //return this->radius < rhs.radius;
+    }
+    friend QDebug operator<<(QDebug debug, const BoxShadow &boxShadow)
+    {
+//        QString info = QString("[x: %1][y: %2][radius: %3][spread: %4][size: (%5,%6)]")
+//                .arg(boxShadow.x).arg(boxShadow.y).arg(boxShadow.radius).arg(boxShadow.spread)
+//                .arg(boxShadow.boxSize.width()).arg(boxShadow.boxSize.height());
+        debug << QString("(%1,%2)").arg(boxShadow.x).arg(boxShadow.y)
+              <<boxShadow.color<<boxShadow.radius<<boxShadow.spread<<boxShadow.boxSize;
+        return debug;
+    }
+};
+Q_DECLARE_METATYPE(BoxShadow);
+
+/**
+ * @brief
+ */
+class IDropShadowable
+{
+public:
+    IDropShadowable(){}
+    IDropShadowable(QWidget *selfWidget);
+protected:
+    void SetDropShadow(const BoxShadow &boxShadow, const QSize &size);
+    void SetDropShadows(const QList<BoxShadow> &shadows, const QSize &size);
+    void ClearDropShadow();
+private:
+    QWidget *m_pSelfWidget;
+    QList<BoxShadow> m_listShadows;
+public:
+    void PaintShadows();
+};
+
+#endif // IDROPSHADOWABLE_H

+ 187 - 0
TransmitterSwitch/common/PaintHelper/painthelper.cpp

@@ -0,0 +1,187 @@
+#include "painthelper.h"
+#include <QPainterPath>
+
+FontEx::FontEx(const QString &family, int pixelSize, bool bold) : QFont(family)
+{
+    setPixelSize(pixelSize);
+    setBold(bold);
+}
+
+FontEx::FontEx(FontEx::NotoSansType type, int pixelSize)
+{
+    QString family = "黑体";
+    if(type == NotoSansType::Normal) family = "思源黑体 CN Normal";
+    if(type == NotoSansType::Medium) family = "思源黑体 CN Medium";
+    if(type == NotoSansType::Regular) family = "思源黑体 CN Regular";
+    if(type == NotoSansType::Bold) family = "思源黑体 CN Bold";
+    if(type == NotoSansType::Light) family = "思源黑体 CN Light";
+    setFamily(family);
+    setPixelSize(pixelSize);
+}
+
+PainterEx::PainterEx(QPaintDevice *device): QPainter(device)
+{
+    
+}
+
+
+void PainterEx::SetBrushOnly(const QColor &color)
+{
+    setPen(Qt::transparent);
+    setBrush(color);
+}
+
+void PainterEx::SetPenOnly(const QColor &color, qreal width, Qt::PenStyle style)
+{
+    setPen(QPen(color, width, style));
+    setBrush(Qt::transparent);
+}
+//------------------------------------------------------------------------
+//函    数:DrawCircle(QPointF center, double radius, const QColor &color = QColor())
+//
+//说    明:画圆的函数
+//
+//参    数:
+//[传入]center 中心点
+//[传入]radius 半径
+//
+//返 回 值:
+//------------------------------------------------------------------------
+void PainterEx::DrawCircle(QPointF center, double radius, const QColor &brush, const QPen &pen)
+{
+    save();
+    setRenderHint(QPainter::Antialiasing);
+    setPen(pen);
+    setBrush(brush.isValid()?brush:QColor(0,0,0,0));
+    translate(center - QPointF(radius, radius));
+    drawEllipse(QRectF(0, 0, radius*2, radius*2));
+    restore();
+}
+//------------------------------------------------------------------------
+//函    数:DrawTextTwice(const QRectF &textRect, const QString &text, const QColor &color = QColor(), Qt::Alignment flags = Qt::AlignHCenter|Qt::AlignVCenter);
+//
+//说    明:思源黑体连续绘制两次, 否则会有点失真
+//
+//参    数:
+//[传入]textRect 
+//[传入]text 
+//[传入]color 
+//[传入]flags 
+//
+//返 回 值:
+//------------------------------------------------------------------------
+void PainterEx::DrawTextTwice(const QRectF &textRect, const QString &text, const QColor &color, Qt::Alignment flags)
+{
+    save();
+    if(color.isValid()) SetPenOnly(color);
+    drawText(textRect, static_cast<int>(flags), text);
+    drawText(textRect, static_cast<int>(flags), text);
+    restore();
+}
+void PainterEx::DrawText(const QRectF &textRect, const QString &text, const QColor &color, Qt::Alignment flags)
+{
+    save();
+    if(color.isValid()) SetPenOnly(color);
+    drawText(textRect, static_cast<int>(flags), text);
+    restore();
+}
+
+void PainterEx::DrawRoundedRect(const QRectF &rect, int radius, const QColor &color, RoundedCorners flags)
+{
+//    save();
+//    setRenderHint(QPainter::Antialiasing);
+//    if(color.isValid()) SetBrushOnly(color);
+//    //先画4个圆
+//    DrawCircle(QPointF(radius, radius), radius, color);
+//    DrawCircle(QPointF(textRect.width() - radius, radius), radius, color);
+//    DrawCircle(QPointF(radius, textRect.height() - radius), radius, color);
+//    DrawCircle(QPointF(textRect.width() - radius, textRect.height() - radius), radius, color);
+//    //再画2个矩形
+//    drawRect(textRect.adjusted(0, radius, 0, -radius));
+//    drawRect(textRect.adjusted(radius, 0, -radius, 0));
+//    restore();
+    
+    save();
+    setRenderHint(QPainter::Antialiasing);
+    if(color.isValid()) SetBrushOnly(color);
+    QRectF cornerRect(0, 0, radius*2, radius*2);
+    //下面arcTo都是逆时针画90°弧
+    QPainterPath roundPath; //圆角矩形
+    roundPath.setFillRule(Qt::WindingFill);
+    
+    //起点
+    QPointF topLeftPoint = flags.testFlag(RoundedCorner::TopLeft)?QPointF(radius, 0):QPointF(0, 0);
+    QPointF bottomLeftPoint = flags.testFlag(RoundedCorner::BottomLeft)?QPointF(0, rect.height()-radius):QPointF(0, rect.height());
+    QPointF bottomRightPoint = flags.testFlag(RoundedCorner::BottomRight)?QPointF(rect.width()-radius, rect.height()):QPointF(rect.width(), rect.height());
+    QPointF topRightPoint = flags.testFlag(RoundedCorner::TopRight)?QPointF(rect.width(), radius):QPointF(rect.width(), 0);
+    
+    roundPath.moveTo(topLeftPoint);//左上角
+    if(flags.testFlag(RoundedCorner::TopLeft)) roundPath.arcTo(cornerRect, 90, 90);
+    roundPath.lineTo(bottomLeftPoint);//左下角
+    if(flags.testFlag(RoundedCorner::BottomLeft)) roundPath.arcTo(cornerRect.translated(0, rect.height()-radius*2), 180, 90);
+    roundPath.lineTo(bottomRightPoint);//右下角
+    if(flags.testFlag(RoundedCorner::BottomRight)) roundPath.arcTo(cornerRect.translated(rect.width()-radius*2, rect.height()-radius*2), 270, 90);
+    roundPath.lineTo(topRightPoint);//右上角
+    if(flags.testFlag(RoundedCorner::TopRight)) roundPath.arcTo(cornerRect.translated(rect.width()-radius*2, 0), 360, 90);
+    roundPath.closeSubpath();
+    
+    translate(rect.topLeft());
+    drawPath(roundPath);
+    restore();
+}
+
+void PainterEx::DrawPixmap(const QRectF &rect, const QPixmap &pixmap)
+{
+    QRectF sourceRect(0.0, 0.0, pixmap.width(), pixmap.height());
+    drawPixmap(rect, pixmap, sourceRect);
+}
+
+void PainterEx::DrawPixmap(const QRectF &rect, const QString &srcPath, int alpha)
+{
+    save();
+    QPixmap pixmap(srcPath);
+    if(alpha != 255)
+    {//将pixmap处理成半透明
+        QPixmap temp(pixmap.size());
+        temp.fill(Qt::transparent);
+        QPainter p1(&temp);
+        p1.setCompositionMode(QPainter::CompositionMode_Source);
+        p1.drawPixmap(0, 0, pixmap);
+        p1.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+        p1.fillRect(temp.rect(), QColor(0, 0, 0, alpha));
+        p1.end();
+        pixmap = temp;
+    }
+    QRectF sourceRect(0.0, 0.0, pixmap.width(), pixmap.height());
+    drawPixmap(rect, pixmap, sourceRect);
+    restore();
+}
+
+void PainterEx::DrawBorder(const QRect &rect, const QPen &pen, RectBorders flags)
+{
+    save();
+    setPen(pen);
+    if(flags.testFlag(RectBorder::RectBorderLeft)) drawLine(rect.topLeft(), rect.bottomLeft());
+    if(flags.testFlag(RectBorder::RectBorderRight)) drawLine(rect.topRight(), rect.bottomRight());
+    if(flags.testFlag(RectBorder::RectBorderTop)) drawLine(rect.topLeft(), rect.topRight());
+    if(flags.testFlag(RectBorder::RectBorderBottom)) drawLine(rect.bottomLeft(), rect.bottomRight());
+    restore();
+}
+
+void PainterEx::DrawTriangle(const QRect &rect, bool isUp, const QColor &brush, const QPen &pen)
+{
+    save();
+    setRenderHint(QPainter::Antialiasing);
+    setPen(pen);
+    setBrush(brush.isValid()?brush:QColor(0,0,0,0));
+    QPainterPath roundPath;
+    roundPath.setFillRule(Qt::WindingFill);
+    
+    roundPath.moveTo(isUp?rect.bottomLeft():rect.topLeft()); //底边-左
+    roundPath.lineTo(isUp?rect.bottomRight():rect.topRight()); //底边-右
+    roundPath.lineTo(QPoint(rect.center().x(), isUp?rect.top():rect.bottom()));//头
+    roundPath.closeSubpath();
+    
+    drawPath(roundPath);
+    restore();
+}

+ 75 - 0
TransmitterSwitch/common/PaintHelper/painthelper.h

@@ -0,0 +1,75 @@
+#ifndef PAINTHELPER_H
+#define PAINTHELPER_H
+
+#include <QFont>
+#include <QPainter>
+
+class PainterEx : public QPainter
+{
+public:
+    enum RoundedCorner
+    {
+        None                = 0x0000,
+        TopLeft             = 0x0001,
+        TopRight            = 0x0002,
+        BottomLeft          = 0x0004,
+        BottomRight         = 0x0008,
+        Left                = TopLeft|BottomLeft,
+        Right               = TopRight|BottomRight,
+        Top                 = TopLeft|TopRight,
+        Bottom              = BottomLeft|BottomRight,
+        All                 = TopLeft|TopRight|BottomLeft|BottomRight,
+    };
+    Q_DECLARE_FLAGS(RoundedCorners, RoundedCorner)
+    enum RectBorder
+    {
+        RectBorderNone                = 0x0000,
+        RectBorderLeft                = 0x0001,
+        RectBorderRight               = 0x0002,
+        RectBorderTop                 = 0x0004,
+        RectBorderBottom              = 0x0008,
+        RectBorderAll                 = TopLeft|TopRight|BottomLeft|BottomRight,
+        RectBorderExceptLeft          = RectBorderAll & (~RectBorderLeft),
+        RectBorderExceptRight         = RectBorderAll & (~RectBorderRight),
+        RectBorderExceptTop           = RectBorderAll & (~RectBorderTop),
+        RectBorderExceptBottom        = RectBorderAll & (~RectBorderBottom),
+    };
+    Q_DECLARE_FLAGS(RectBorders, RectBorder)
+public:
+    explicit PainterEx(QPaintDevice *device);
+    void SetBrushOnly(const QColor &color);
+    void SetPenOnly(const QColor &color, qreal width = 1, Qt::PenStyle s = Qt::SolidLine);
+    void DrawCircle(QPointF center, double radius, const QColor &brush = QColor(), const QPen &pen = QPen(Qt::transparent));
+    void DrawTextTwice(const QRectF &textRect, const QString &text, const QColor &color = QColor(), Qt::Alignment flags = Qt::AlignHCenter|Qt::AlignVCenter);
+    void DrawText(const QRectF &textRect, const QString &text, const QColor &color, Qt::Alignment flags = Qt::AlignHCenter|Qt::AlignVCenter);
+    void DrawRoundedRect(const QRectF &rect, int radius, const QColor &color = QColor(), RoundedCorners flags = RoundedCorner::All);
+    void DrawPixmap(const QRectF &rect, const QPixmap &pixmap);
+    void DrawPixmap(const QRectF &rect, const QString &srcPath, int alpha = 255);
+    void DrawBorder(const QRect &rect, const QPen &pen, RectBorders flags = RectBorder::RectBorderAll);
+    void DrawTriangle(const QRect &rect, bool isUp, const QColor &brush = QColor(), const QPen &pen = QPen(Qt::transparent));
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(PainterEx::RoundedCorners)
+Q_DECLARE_OPERATORS_FOR_FLAGS(PainterEx::RectBorders)
+
+class FontEx : public QFont
+{
+public:
+    enum NotoSansType
+    {
+        Unkown,
+        Normal,
+        Regular,
+        Medium,
+        Light,
+        Bold
+    };
+public:
+    explicit FontEx(const QString &family, int pixelSize, bool bold = false);
+    explicit FontEx(NotoSansType type, int pixelSize);
+    
+signals:
+    
+public slots:
+};
+
+#endif // PAINTHELPER_H

+ 109 - 29
TransmitterSwitch/common/SelectTime/timewidget.cpp

@@ -3,6 +3,7 @@
 #include <QListWidgetItem>
 #include <QMouseEvent>
 #include <QDebug>
+#include <QSizePolicy>
 #include "timepartwidget.h"
 #include "shadowwidget.h"
 
@@ -14,36 +15,19 @@ TimeWidget::TimeWidget(QWidget *parent , ShowType type) :
     m_type(type)
 {
     ui->setupUi(this);
-    // InitUI
-    ui->dateTimeEdit->hide();
-    ui->dateTimeEdit->installEventFilter(this);
-    this->installEventFilter(this);
-    ui->lbl_tip->installEventFilter(this);
-    if (nullptr != m_pMainWindow) {
-        m_pMainWindow->installEventFilter(this);
-    }
-    ui->btn_tip->setProperty("selected", false);
+    Init();
+}
 
-    connect(ui->btn_tip, &QPushButton::clicked, this, &TimeWidget::onBtnTipClicked);
-    connect(ui->dateTimeEdit, &QDateTimeEdit::dateTimeChanged, this, &TimeWidget::onDateTimeChanged);
 
-    /* 判断显示类型,如果是弹窗直接显示编辑区 */
-    if(m_type == Dialog)
-    {
-        ui->btn_tip->hide();
-        this->resize(136,36);
-//        ShowTimeArea(false);
-        /* 设置编辑栏样式 */
-        this->setStyleSheet(R"(
-            TimeWidget
-            {
-                padding-left:15px;
-                background: #FFFFFF;
-                border-radius: 4px;
-                border: 1px solid #E6E9F4;
-            }
-        )");
-    }
+TimeWidget::TimeWidget(ShowType type) : 
+    QFrame(nullptr),
+    ui(new Ui::TimeWidget),
+    m_wdgTimeArea(nullptr),
+    m_pMainWindow(nullptr),
+    m_type(type)
+{
+    ui->setupUi(this);
+    Init();
 }
 
 TimeWidget::~TimeWidget()
@@ -89,11 +73,18 @@ void TimeWidget::SetMainWindow(QWidget* pWidget)
     m_pMainWindow = pWidget;
 }
 
+/* 返回时间 */
+QTime TimeWidget::getTime()
+{
+    return ui->dateTimeEdit->time();
+}
+
+
 /**
  * @brief 存在时间就返回hh:mm:ss.zzz格式字符串,否则返回提示信息
  * @return
  */
-QString TimeWidget::getTime()
+QString TimeWidget::getTimeStr()
 {
     QString ret(ui->lbl_tip->text());
     if (!ui->dateTimeEdit->isHidden()) {
@@ -161,6 +152,75 @@ void TimeWidget::showTimeEditArea()
     ShowTimeArea(true);
 }
 
+/* 以弹窗的模式模态显示 */
+void TimeWidget::execShow()
+{
+    QEventLoop loop;
+    connect (this, &TimeWidget::signal_close, &loop, &QEventLoop::quit);
+    this->show();
+    ShowTimeArea(true);
+    loop.exec();
+
+    deleteLater();
+}
+
+/* 设置时间图标 */
+void TimeWidget::setIcon(const QString& icon)
+{
+    /* 设置图片适应按钮大小 */
+    QString ss = QString("border-image: url(%1)").arg(icon);
+    ui->btn_tip->setStyleSheet(ss);
+    ui->btn_tip->show();
+}
+
+/* 设置图标显示 */
+void TimeWidget::setIconShow(bool isShow)
+{
+    if(isShow)
+    {
+        ui->btn_tip->show();
+    }else {
+        ui->btn_tip->hide();
+    }
+}
+
+/* 设置图标大小 */
+void TimeWidget::setIconSize(int w, int h)
+{
+    ui->btn_tip->setMinimumSize(w, h);
+    /* 设置为固定大小 */
+    ui->btn_tip->setFixedSize(w, h);
+    // ui->btn_tip->resize(w, h);
+}
+
+/* 设置默认的样式 */
+void TimeWidget::setDefaultStyle()
+{
+    /* 判断显示类型,如果是弹窗直接显示编辑区 */
+    if(m_type == Dialog)
+    {
+        ui->btn_tip->hide();
+        this->resize(136,36);
+//        ShowTimeArea(false);
+        /* 设置编辑栏样式 */
+        // this->setStyleSheet(R"(
+        //     TimeWidget
+        //     {
+        //         padding-left:15px;
+        //         background: #FFFFFF;
+        //         border-radius: 4px;
+        //         border: 1px solid #E6E9F4;
+        //     }
+        // )");
+    }
+}
+
+/* 设置编辑栏大小 */
+void TimeWidget::setEditLine(int w, int h)
+{
+    this->resize(w, h);
+}
+
 /**
  * @brief 点击提示信息
  */
@@ -363,6 +423,7 @@ void TimeWidget::ShowTimeArea(bool bShow)
             UpdatePopupTime(ui->dateTimeEdit->dateTime());
         } else {
             m_wdgTimeArea->hide();
+            emit signal_close();
         }
     }
 }
@@ -398,3 +459,22 @@ void TimeWidget::CreatePopupWidget()
         }
     }
 }
+
+/* 初始化函数 */
+void TimeWidget::Init()
+{
+    // InitUI
+    ui->dateTimeEdit->hide();
+    ui->dateTimeEdit->installEventFilter(this);
+    this->installEventFilter(this);
+    ui->lbl_tip->installEventFilter(this);
+    if (nullptr != m_pMainWindow) {
+        m_pMainWindow->installEventFilter(this);
+    }
+    ui->btn_tip->setProperty("selected", false);
+
+    connect(ui->btn_tip, &QPushButton::clicked, this, &TimeWidget::onBtnTipClicked);
+    connect(ui->dateTimeEdit, &QDateTimeEdit::dateTimeChanged, this, &TimeWidget::onDateTimeChanged);
+
+    setDefaultStyle();
+}

+ 21 - 3
TransmitterSwitch/common/SelectTime/timewidget.h

@@ -12,7 +12,7 @@
  *     创建出来,也可以在弹窗中直接显示出来,所以moveEvent事件就是用来移动m_wdgTimeArea的。
  *  3、在原来的基础上新添加了两个信号,在关闭的时候发送
  *  4、使用Dialog模式的时候,点击空白处隐藏就会close掉,然后发送新的时间信号
- *  5、使用Dialog模式,记得要调用showTimeEditArea()函数才会显示
+ *  5、使用Dialog模式,执行execShow()函数,会阻塞运行,直到关闭
 */
 
 
@@ -39,24 +39,40 @@ public:
         Dialog = 1,             /* 以弹窗的形式出现 */
     };
     explicit TimeWidget(QWidget *parent = nullptr , ShowType type = EditLine);
+    explicit TimeWidget(ShowType type = EditLine);
     ~TimeWidget();
 
     void CreateTimeVector(const QVector<int>& types);
     void ClearVector(QVector<TimePartWidget*>& vec);
     // 在父窗口无法容纳控件时,这是必要的
     void SetMainWindow(QWidget* pWidget);
-    QString getTime();
+    QTime getTime();
+    QString getTimeStr();
     QTime getFormTime() const;
     void setTime(const QString& t);
     void setTime(const QTime& t);
     void clearTime();
     QString tipText() const;
-    void setTimeAreaWidth(int w);                   /* 新增一个设置时间条宽度的函数 */
+    /* 新增一个设置时间条宽度的函数 */
+    void setTimeAreaWidth(int w);
     /***** 2024-05-25 添加两个信号 ******/
     void showTimeEditArea();
+    /* 以弹窗的模式模态显示 */
+    void execShow();
+    /* 设置时间图标 */
+    void setIcon(const QString& icon);
+    /* 设置图标显示 */
+    void setIconShow(bool isShow);
+    /* 设置图标大小 */
+    void setIconSize(int w, int h);
+    /* 设置默认的样式 */
+    void setDefaultStyle();
+    /* 设置编辑栏大小 */
+    void setEditLine(int w, int h);
 signals:
     void signal_nowTime(const QTime& time);
     void signal_formerTimer(const QTime& time);
+    void signal_close();
 
 protected:
     bool eventFilter(QObject* obj, QEvent* e) override;
@@ -72,6 +88,8 @@ private:
     void UpdatePopupTime(const QDateTime& dt);
     void ShowTimeArea(bool bShow);
     void CreatePopupWidget();
+    /* 初始化函数 */
+    void Init();
 private:
     const int TIME_AREA_WIDTH = 56;
     const int TIME_AREA_HEIGHT = 32;

+ 150 - 0
TransmitterSwitch/common/StyleManager/lhstylemanager.cpp

@@ -0,0 +1,150 @@
+#include "lhstylemanager.h"
+#include <QCoreApplication>
+#include <QStyle>
+#include <QDir>
+#include <QDebug>
+
+LHStyleManager* LHStyleManager::m_instance = nullptr;
+QMutex LHStyleManager::m_mtx;
+
+LHStyleManager::LHStyleManager(QObject *parent) : QObject(parent), m_bQss(true)
+{
+    m_nCurStyle = eBrightStyle;
+#ifdef QT_NO_DEBUG
+    QssToSkin();
+#endif
+}
+
+LHStyleManager::~LHStyleManager()
+{
+    if(m_instance) {
+        delete m_instance;
+    }
+}
+
+LHStyleManager *LHStyleManager::Instance()
+{
+    if (nullptr == m_instance) {
+        QMutexLocker lock(&m_mtx);
+        if (nullptr == m_instance) {
+            m_instance = new LHStyleManager;
+        }
+    }
+    return m_instance;
+}
+/**
+ * @brief 有个隐患:如果widget在外面已经销毁,此处不会消除,导致List越来越大
+ * @param widget
+ */
+void LHStyleManager::AddWidget(QWidget *widget)
+{
+    if(widget != nullptr && !m_widgetList.contains(widget)) {
+        m_widgetList.append(widget);
+        UpdateWidgetStyle(widget);
+    } else {
+        UpdateWidgetStyle(widget);
+    }
+}
+
+bool LHStyleManager::UpdateWidgetStyle(QWidget *widget)
+{
+    if(widget == nullptr) {
+        return false;
+    }
+    QString strBasePath = QCoreApplication::applicationDirPath();
+    QString strStylePath;
+    QString strName = widget->objectName();
+    if(m_nCurStyle == eBrightStyle) {
+        strStylePath = "skin/Bright";
+    } else if(m_nCurStyle == eDarkStyle) {
+        strStylePath = "skin/Dark";
+    }
+    // 从文件加载样式
+    QString strStyleFile = strBasePath + QString("/%1/%2.%3").arg(strStylePath, strName, m_bQss ? "qss" : "skin");
+    //qInfo() << strStyleFile;
+    // 从资源加载样式,缺点每次需要重新编译才生效
+    //QString strStyleFile = QString(":/%1/%2.qss").arg(strStylePath).arg(strName);
+    QFile file(strStyleFile);
+    if (file.open(QIODevice::ReadOnly)) {
+        QByteArray arrStyle = file.readAll();
+        widget->setStyleSheet(m_bQss ? arrStyle : qUncompress(arrStyle));
+        file.close();
+        return true;
+    }
+    return false;
+}
+
+void LHStyleManager::QssToSkin(bool reserve)
+{
+    // 遍历skin文件夹,存在qss就压缩成skin文件,并删除qss文件
+    QString skinPath(QString("%1/skin/%2/").arg(QCoreApplication::applicationDirPath(), GetCurSkinName()));
+    QDir directory(skinPath);
+    if (!directory.exists()) {
+        //qWarning("目录不存在: %s", qPrintable(skinPath));
+        return;
+    }
+
+    QStringList filters;
+    if (!reserve) {
+        filters << "*.qss";
+    } else {
+        filters << "*.shin";
+    }
+
+    QStringList fileNames = directory.entryList(filters, QDir::Files);
+    for (const QString& fileName : fileNames) {
+        QString filePath = directory.absoluteFilePath(fileName);
+        QFile qssFile(filePath);
+        if (!qssFile.open(QIODevice::ReadOnly)) {
+            //qWarning("打开Qss文件失败: %s", qPrintable(filePath));
+            continue;
+        }
+
+        QString skinFilePath = filePath;
+        if (!reserve) {
+            skinFilePath.replace(".qss", ".skin");
+        } else {
+            skinFilePath.replace(".skin", ".qss");
+        }
+
+        QFile skinFile(skinFilePath);
+        if (!skinFile.open(QIODevice::WriteOnly)) {
+            //qWarning("创建文件失败: %s", qPrintable(skinFilePath));
+            qssFile.close();
+            continue;
+        }
+
+        QByteArray strQss = qssFile.readAll();
+
+        skinFile.write(reserve ? qUncompress(strQss) : qCompress(strQss));
+        qssFile.close();
+        skinFile.close();
+
+        if (!QFile::remove(filePath)) {
+            //qWarning("移除文件失败: %s", qPrintable(filePath));
+        }
+    }
+    m_bQss = reserve;
+}
+
+
+void LHStyleManager::SetSkinStyle(const QString& style)
+{
+    if (style.isEmpty()) return;
+    SkinStyle skin{SkinStyle::eBrightStyle};
+    if (!style.compare("Bright")) {
+        skin = SkinStyle::eBrightStyle;
+    } else if (!style.compare("Dark")) {
+        skin = SkinStyle::eDarkStyle;
+    }
+    if(m_nCurStyle == skin) {
+        return;
+    }
+
+    m_nCurStyle = skin;
+    for(int i = 0; i < m_widgetList.size(); i++) {
+        QWidget* widget = m_widgetList.at(i);
+        if(widget == nullptr) continue;
+        UpdateWidgetStyle(widget);
+    }
+}

+ 44 - 0
TransmitterSwitch/common/StyleManager/lhstylemanager.h

@@ -0,0 +1,44 @@
+#ifndef LHSTYLEMANAGER_H
+#define LHSTYLEMANAGER_H
+#include <QWidget>
+#include <QList>
+#include <QMutex>
+
+enum SkinStyle{eBrightStyle, eDarkStyle};
+
+class LHStyleManager : public QObject
+{
+    Q_OBJECT
+public:
+    explicit LHStyleManager(QObject *parent = nullptr);
+    ~LHStyleManager();
+
+    static LHStyleManager* Instance();
+
+    void AddWidget(QWidget* widget);
+
+    void SetSkinStyle(const QString& style);
+
+    SkinStyle GetCurSkinStyle() const {return m_nCurStyle;}
+    QString GetCurSkinName() const {return m_nCurStyle == eBrightStyle ? QString("Bright") : QString("Dark");}
+signals:
+public slots:
+private:
+    bool UpdateWidgetStyle(QWidget* widget);
+    void QssToSkin(bool reserve = false);
+private:
+    //当前样式
+    SkinStyle m_nCurStyle;
+    //所有需要更改样式的widget
+    QWidgetList m_widgetList;
+    //白色样式表
+    QString m_strBrightStyle;
+    //黑色样式表
+    QString m_strDarkStyle;
+    bool m_bQss;
+
+    static LHStyleManager *m_instance;
+    static QMutex m_mtx;
+};
+
+#endif // LHSTYLEMANAGER_H

+ 19 - 0
TransmitterSwitch/common/date/CMakeLists.txt

@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.10)
+project(CDate)
+
+set(LIB_NAME CDate)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../common.cmake)
+
+file(GLOB SRC ${COMMON_SRC}
+            ${CMAKE_CURRENT_SOURCE_DIR}/*.qss
+            ${CMAKE_CURRENT_SOURCE_DIR}/date/*.qrc
+            ${CMAKE_CURRENT_SOURCE_DIR}/date/*.cpp
+            ${CMAKE_CURRENT_SOURCE_DIR}/date/*.ui
+        )
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/date
+                    ${COMMON_INC})
+set(LIBRARY_OUTPUT_PATH ${LIB_PATH})
+#add_library(${LIB_NAME} SHARED ${SRC})
+#target_link_libraries(${LIB_NAME} PRIVATE Qt5::Widgets)

+ 6 - 0
TransmitterSwitch/common/date/CalendarHeader.qss

@@ -0,0 +1,6 @@
+QLabel 
+{
+	font-size: 14px;
+	font-weight: 500;
+	color: #3A3F63;
+}

+ 50 - 0
TransmitterSwitch/common/date/CalendarNav.qss

@@ -0,0 +1,50 @@
+QPushButton#btnPrevYear::hover
+{
+	image: url(:/Calendar/preYear.png);
+	border:none;
+}
+QPushButton#btnPrevYear
+{
+	image: url(:/Calendar/preYear_hover.png);
+	border:none;
+}
+
+QPushButton#btnPrevMonth::hover
+{
+	image: url(:/Calendar/preMonth.png);
+	border:none;
+}
+QPushButton#btnPrevMonth
+{
+	image: url(:/Calendar/preMonth_hover.png);
+	border:none;
+}
+
+QPushButton#btnNextMonth::hover
+{
+	image: url(:/Calendar/nextMonth.png);
+	border:none;
+}
+QPushButton#btnNextMonth
+{
+	image: url(:/Calendar/nextMonth_hover.png);
+	border:none;
+}
+
+QPushButton#btnNextYear::hover
+{
+	image: url(:/Calendar/nextYear.png);
+	border:none;
+}
+QPushButton#btnNextYear
+{
+	image: url(:/Calendar/nextYear_hover.png);
+	border:none;
+}
+
+QLabel 
+{
+	font-size: 14px;
+	font-weight: 500;
+	color: #3A3F63;
+}

+ 34 - 0
TransmitterSwitch/common/date/calendardtedit.cpp

@@ -0,0 +1,34 @@
+#include "calendardtedit.h"
+#include <QDebug>
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QKeyEvent>
+#include "calendarex.h"
+
+CalendarDTEdit::CalendarDTEdit(QWidget *parent) : QDateTimeEdit(parent)
+{
+    setCalendarPopup(false);// 阻止自带的日历窗口
+}
+
+CalendarDTEdit::~CalendarDTEdit()
+{
+}
+
+void CalendarDTEdit::CloseCalendar()
+{
+
+}
+
+void CalendarDTEdit::mousePressEvent(QMouseEvent *e)
+{
+    Q_UNUSED(e);
+    CalendarEx *pC = new CalendarEx(date());
+    if (nullptr == pC) return;
+    connect(pC, &CalendarEx::sig_DateChanged, this, [this](const QDate& date){
+        if (date.isValid()) {
+            setDate(date);
+        }
+    });
+    pC->show();
+    pC->positionCalendarPopup(this);
+}

+ 21 - 0
TransmitterSwitch/common/date/calendardtedit.h

@@ -0,0 +1,21 @@
+#ifndef CALENDARDTEDIT_H
+#define CALENDARDTEDIT_H
+
+#include <QWidget>
+#include <QDateTimeEdit>
+
+class CalendarDTEdit : public QDateTimeEdit
+{
+    Q_OBJECT
+public:
+    explicit CalendarDTEdit(QWidget *parent = nullptr);
+    virtual ~CalendarDTEdit();
+    void SetCalendarAutoClose(bool value);
+    void CloseCalendar();
+signals:
+    void sig_SetCurrentPage(int year, int month);
+protected:
+    void mousePressEvent(QMouseEvent* e) override;
+};
+
+#endif // CALENDARDTEDIT_H

+ 187 - 0
TransmitterSwitch/common/date/calendarex.cpp

@@ -0,0 +1,187 @@
+#include "calendarex.h"
+#include <QEvent>
+#include <QScreen>
+#include <QKeyEvent>
+#include <QApplication>
+#include <QDesktopWidget>
+#include <QHBoxLayout>
+#include <QDebug>
+#include "scopeselectionmodel.h"
+#include "PaintHelper/painthelper.h"
+
+CalendarInterface::CalendarInterface(QWidget *parent)
+    : QWidget(parent)
+    , IDropShadowable(this)
+    , m_pLayout(new QHBoxLayout)
+{
+    setWindowFlag(Qt::Popup);
+    setWindowFlag(Qt::NoDropShadowWindowHint);
+    //设置无边框属性
+    setWindowFlag(Qt::FramelessWindowHint);
+    //设置背景透明属性
+    setAttribute(Qt::WA_TranslucentBackground, true);
+    //关闭对话框时,删除自身对象
+    setAttribute(Qt::WA_DeleteOnClose, true);
+}
+
+CalendarInterface::~CalendarInterface()
+{
+    //qDebug()<<"~ScopeCalendar";
+}
+
+/**
+ * @brief 这个只是坐标位移?
+ * @param q
+ */
+void CalendarInterface::positionCalendarPopup(QWidget *q)
+{
+    if (nullptr == m_pLayout) return;
+    QPoint pos = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().bottomRight() : q->rect().bottomLeft();
+    QPoint pos2 = (q->layoutDirection() == Qt::RightToLeft) ? q->rect().topRight() : q->rect().topLeft();
+    pos = q->mapToGlobal(pos);
+    pos2 = q->mapToGlobal(pos2);
+    QSize size = QSize(CALENDAR_WIDTH * m_pLayout->count() + 2 * SHADOW_RADIUS, CALENDAR_HEIGHT + 2 * SHADOW_RADIUS);
+    //QRect screen = QApplication::desktop()->availableGeometry(pos);
+    QRect screen = QGuiApplication::screenAt(pos)->availableGeometry();
+    //handle popup falling "off screen"
+    if (q->layoutDirection() == Qt::RightToLeft) {
+        pos.setX(pos.x()-size.width());
+        pos2.setX(pos2.x()-size.width());
+        if (pos.x() < screen.left())
+            pos.setX(qMax(pos.x(), screen.left()));
+        else if (pos.x()+size.width() > screen.right())
+            pos.setX(qMax(pos.x()-size.width(), screen.right()-size.width()));
+    } else {
+        if (pos.x()+size.width() > screen.right())
+            pos.setX(screen.right()-size.width());
+        pos.setX(qMax(pos.x(), screen.left()));
+    }
+    if (pos.y() + size.height() > screen.bottom())
+        pos.setY(pos2.y() - size.height());
+    else if (pos.y() < screen.top())
+        pos.setY(screen.top());
+    if (pos.y() < screen.top())
+        pos.setY(screen.top());
+    if (pos.y()+size.height() > screen.bottom())
+        pos.setY(screen.bottom()-size.height());
+    pos.setX(pos.rx() - SHADOW_RADIUS);
+    pos.setY(pos.ry() - SHADOW_RADIUS + SPACING);
+    move(pos);
+}
+
+CalendarEx::CalendarEx(const QDate& defaultDate, QWidget* parent) :
+    CalendarInterface(parent),
+    m_pCalendar(nullptr)
+{
+    QHBoxLayout* pLay = new QHBoxLayout(this);
+    QWidget* pMain = new QWidget(this);
+    pMain->setLayout(m_pLayout);
+
+    pLay->addWidget(pMain);
+    pLay->setMargin(SHADOW_RADIUS);
+
+    m_pCalendar = new CalendarWidgetEx(this);
+    m_pCalendar->setStyleSheet("QCalendarView{background-color: transparent;}");
+    m_pLayout->addWidget(m_pCalendar);
+    connect(m_pCalendar, &CalendarWidgetEx::clicked, this, [this](const QDate& date){
+        emit sig_DateChanged(date);
+        close();
+    });
+
+    m_pLayout->setMargin(0);
+    pMain->resize(CALENDAR_WIDTH, CALENDAR_HEIGHT);
+    SetCalendarSync(defaultDate);
+    /* 设置大小,包含阴影的大小 */
+    resize(CALENDAR_WIDTH + 2 * SHADOW_RADIUS, CALENDAR_HEIGHT + 2 * SHADOW_RADIUS);
+    /* 设置阴影 */
+    SetDropShadow(BoxShadow{0, 0, SHADOW_RADIUS, 0, QColor(0, 0, 0, 60), QSize(0, 0), QImage()}, pMain->size());
+}
+
+void CalendarEx::SetCalendarSync(const QDate &defaultDate)
+{
+    if (nullptr == m_pCalendar || !defaultDate.isValid()) return;
+
+    m_pCalendar->setCurrentPage(defaultDate.year(), defaultDate.month());
+    m_pCalendar->setSelectedDate(defaultDate);
+}
+
+ScopedCalendar::ScopedCalendar(const QDate &from, const QDate &to, QWidget *parent) :
+    CalendarInterface(parent),
+    m_pCalendar_L(nullptr),
+    m_pCalendar_R(nullptr)
+{
+    QHBoxLayout* pLay = new QHBoxLayout(this);
+    QWidget* pMain = new QWidget(this);
+    pMain->setLayout(m_pLayout);
+
+    pLay->addWidget(pMain);
+    pLay->setMargin(SHADOW_RADIUS);
+
+    ScopeSelectionModel *pDateScopeModel = new ScopeSelectionModel();
+    if(from.isValid() && to.isValid())
+    {
+        pDateScopeModel->dtFirst = from;
+        pDateScopeModel->dtSecond = to;
+        pDateScopeModel->bLocked = true;
+    }
+    m_pCalendar_L = new CalendarWidgetEx(this);
+    m_pCalendar_L->setStyleSheet("QCalendarView{background-color: transparent;}");
+    m_pCalendar_L->SetSelectMode(CalendarWidgetEx::Scope, pDateScopeModel);
+    m_pCalendar_L->hideNavigatioinButton(false, false, true, true);
+    m_pLayout->addWidget(m_pCalendar_L);
+
+    m_pCalendar_R = new CalendarWidgetEx(this);
+    m_pCalendar_R->setStyleSheet("QCalendarView{background-color: transparent;}");
+    m_pCalendar_R->SetSelectMode(CalendarWidgetEx::Scope, pDateScopeModel);
+    m_pCalendar_R->hideNavigatioinButton(true, true, false, false);
+    m_pLayout->addWidget(m_pCalendar_R);
+
+    m_pLayout->setSpacing(0);
+    m_pLayout->setMargin(0);
+    pMain->resize(2 * CALENDAR_WIDTH, CALENDAR_HEIGHT);
+    SetCalendarSync(from);
+
+    connect(pDateScopeModel, &ScopeSelectionModel::sig_ScopeSelected, this, &ScopedCalendar::OnScopeSelected);
+
+    resize(2 * CALENDAR_WIDTH + 2 * SHADOW_RADIUS, CALENDAR_HEIGHT + 2 * SHADOW_RADIUS);
+    SetDropShadow(BoxShadow{0, 0, SHADOW_RADIUS, 0, QColor(0, 0, 0, 60), QSize(0, 0), QImage()}, pMain->size());
+}
+
+void ScopedCalendar::SetMinimumDate(const QDate &date)
+{
+    if (nullptr == m_pCalendar_L || nullptr == m_pCalendar_R) return;
+
+    m_pCalendar_L->setMinimumDate(date);
+    m_pCalendar_R->setMinimumDate(date);
+}
+
+void ScopedCalendar::SetMaximumDate(const QDate &date)
+{
+    if (nullptr == m_pCalendar_L || nullptr == m_pCalendar_R) return;
+
+    m_pCalendar_L->setMaximumDate(date);
+    m_pCalendar_R->setMaximumDate(date);
+}
+
+void ScopedCalendar::OnScopeSelected(const QDate &from, const QDate &to)
+{
+    emit sig_ScopeSelected(from, to);
+    close();
+}
+
+void ScopedCalendar::SetCalendarSync(const QDate &defaultDate)
+{
+    if (nullptr == m_pCalendar_L || nullptr == m_pCalendar_R || !defaultDate.isValid()) return;
+
+    m_pCalendar_L->setCurrentPage(defaultDate.year(), defaultDate.month());
+    connect(m_pCalendar_L, &QCalendarWidget::currentPageChanged, this, [&](int year, int month) {
+        QDate nextMonth = QDate(year, month, 1).addMonths(1);
+        m_pCalendar_R->setCurrentPage(nextMonth.year(), nextMonth.month());
+    });
+
+    m_pCalendar_R->setCurrentPage(defaultDate.addMonths(1).year(), defaultDate.addMonths(1).month());
+    connect(m_pCalendar_R, &QCalendarWidget::currentPageChanged, this, [&](int year, int month) {
+        QDate prevMonth = QDate(year, month, 1).addMonths(-1);
+        m_pCalendar_L->setCurrentPage(prevMonth.year(), prevMonth.month());
+    });
+}

+ 66 - 0
TransmitterSwitch/common/date/calendarex.h

@@ -0,0 +1,66 @@
+#ifndef CALENDAREX_H
+#define CALENDAREX_H
+
+#include <QWidget>
+#include "calendarwidgetex.h"
+#include "DropShadow/idropshadowable.h"
+
+class QHBoxLayout;
+
+class CalendarInterface : public QWidget, public IDropShadowable
+{
+    Q_OBJECT
+public:
+    explicit CalendarInterface(QWidget *parent = nullptr);
+    virtual ~CalendarInterface();
+    /* 弹出位置? */
+    void positionCalendarPopup(QWidget *q);
+protected:
+     virtual void SetCalendarSync(const QDate &defaultDate) = 0;
+protected:
+     QHBoxLayout* m_pLayout;
+
+     const int SHADOW_RADIUS = 16;
+     const int SPACING = 8;
+     const int CALENDAR_WIDTH = 325;
+     const int CALENDAR_HEIGHT = 350;
+};
+/**
+ * @brief 带有阴影的日历
+ *
+ */
+class CalendarEx : public CalendarInterface
+{
+    Q_OBJECT
+public:
+    explicit CalendarEx(const QDate& defaultDate = QDate(), QWidget* parent = nullptr);
+    virtual ~CalendarEx() {}
+signals:
+    void sig_DateChanged(const QDate& date);
+private:
+    virtual void SetCalendarSync(const QDate &defaultDate);
+private:
+     CalendarWidgetEx *m_pCalendar;
+};
+
+class ScopedCalendar : public CalendarInterface
+{
+    Q_OBJECT
+public:
+    explicit ScopedCalendar(const QDate &from = QDate(), const QDate &to = QDate(), QWidget *parent = nullptr);
+    virtual ~ScopedCalendar() { };
+
+    void SetMinimumDate(const QDate &date);
+    void SetMaximumDate(const QDate &date);
+signals:
+    void sig_ScopeSelected(const QDate &from, const QDate &to);
+public slots:
+    void OnScopeSelected(const QDate &from, const QDate &to);
+private:
+    virtual void SetCalendarSync(const QDate &defaultDate);
+private:
+     CalendarWidgetEx *m_pCalendar_L;
+     CalendarWidgetEx *m_pCalendar_R;
+};
+
+#endif // CALENDAREX_H

+ 36 - 0
TransmitterSwitch/common/date/calendarheader.cpp

@@ -0,0 +1,36 @@
+#include "calendarheader.h"
+#include "ui_calendarheader.h"
+#include "PaintHelper/painthelper.h"
+#include "StyleManager/lhstylemanager.h"
+
+CalendarHeader::CalendarHeader(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::CalendarHeader)
+{
+    ui->setupUi(this);
+    LHStyleManager::Instance()->AddWidget(this);
+}
+
+CalendarHeader::~CalendarHeader()
+{
+    delete ui;
+}
+
+void CalendarHeader::SetFirstDayOfWeek(Qt::DayOfWeek dayOfWeek)
+{
+    ui->label1->setText(km_listWeeks.at((dayOfWeek-1+0)%km_listWeeks.count()));
+    ui->label2->setText(km_listWeeks.at((dayOfWeek-1+1)%km_listWeeks.count()));
+    
+    ui->label3->setText(km_listWeeks.at((dayOfWeek-1+2)%km_listWeeks.count()));
+    ui->label4->setText(km_listWeeks.at((dayOfWeek-1+3)%km_listWeeks.count()));
+    
+    ui->label5->setText(km_listWeeks.at((dayOfWeek-1+4)%km_listWeeks.count()));
+    ui->label6->setText(km_listWeeks.at((dayOfWeek-1+5)%km_listWeeks.count()));
+    
+    ui->label7->setText(km_listWeeks.at((dayOfWeek-1+6)%km_listWeeks.count()));
+}
+
+void CalendarHeader::paintEvent(QPaintEvent *)
+{
+    PainterEx painter(this);
+}

+ 26 - 0
TransmitterSwitch/common/date/calendarheader.h

@@ -0,0 +1,26 @@
+#ifndef CALENDARHEADER_H
+#define CALENDARHEADER_H
+
+#include <QWidget>
+
+namespace Ui {
+class CalendarHeader;
+}
+
+class CalendarHeader : public QWidget
+{
+    Q_OBJECT
+    
+public:
+    explicit CalendarHeader(QWidget *parent = nullptr);
+    ~CalendarHeader() override;
+    void SetFirstDayOfWeek(Qt::DayOfWeek dayOfWeek);
+    
+private:
+    Ui::CalendarHeader *ui;
+    const QList<QString> km_listWeeks = {"一","二","三","四","五","六","日"};
+protected:
+    void paintEvent(QPaintEvent *) override;
+};
+
+#endif // CALENDARHEADER_H

+ 139 - 0
TransmitterSwitch/common/date/calendarheader.ui

@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CalendarHeader</class>
+ <widget class="QWidget" name="CalendarHeader">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>361</width>
+    <height>19</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>0</width>
+    <height>16</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>19</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label1">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>日</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label2">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>一</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label3">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>二</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label4">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>三</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label5">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>四</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label6">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>五</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label7">
+     <property name="styleSheet">
+      <string notr="true"/>
+     </property>
+     <property name="text">
+      <string>六</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 67 - 0
TransmitterSwitch/common/date/calendarnav.cpp

@@ -0,0 +1,67 @@
+#include "calendarnav.h"
+#include "PaintHelper/painthelper.h"
+#include "ui_calendarnav.h"
+#include "StyleManager/lhstylemanager.h"
+#include <QDebug>
+#include <QFile>
+
+
+//#pragma execution_character_set("utf-8")
+CalendarNav::CalendarNav(QCalendarWidget *pCalendar, QWidget *parent)
+   : QWidget(parent)
+   , ui(new Ui::CalendarNav)
+   , m_pCalendar(pCalendar)
+{
+    ui->setupUi(this);
+
+    /* 加载qss */
+    QFile file = QString(":/Calendar/CalendarNav.qss");
+    if(!file.open(QIODevice::ReadOnly))
+    {
+        qDebug() << "CalendarNav.cpp:QSS打开失败";
+    }
+    QString  ss = file.readAll();
+
+    this->setStyleSheet(ss);
+
+    connect(ui->btnPrevYear, &QPushButton::clicked, m_pCalendar, &QCalendarWidget::showPreviousYear);
+    connect(ui->btnPrevMonth, &QPushButton::clicked, m_pCalendar, &QCalendarWidget::showPreviousMonth);
+    connect(ui->btnNextMonth, &QPushButton::clicked, m_pCalendar, &QCalendarWidget::showNextMonth);
+    connect(ui->btnNextYear, &QPushButton::clicked, m_pCalendar, &QCalendarWidget::showNextYear);
+    
+    connect(m_pCalendar, &QCalendarWidget::currentPageChanged, this, &CalendarNav::SetYearMonth);
+    
+    //默认显示当天, QCalendarWidget的默认选中日期也是当天
+    SetYearMonth(QDate::currentDate().year(), QDate::currentDate().month());
+    LHStyleManager::Instance()->AddWidget(this);
+}
+
+CalendarNav::~CalendarNav()
+{
+    delete ui;
+}
+
+void CalendarNav::hidePreYear(bool flag)
+{
+    ui->btnPrevYear->setVisible(!flag);
+}
+
+void CalendarNav::hidePreMonth(bool flag)
+{
+    ui->btnPrevMonth->setVisible(!flag);
+}
+
+void CalendarNav::hideNextYear(bool flag)
+{
+    ui->btnNextYear->setVisible(!flag);
+}
+
+void CalendarNav::hideNextMonth(bool flag)
+{
+    ui->btnNextMonth->setVisible(!flag);
+}
+
+void CalendarNav::SetYearMonth(int year, int month)
+{
+    ui->labelYearMonth->setText(QString("%1 年 %2 月").arg(year).arg(month));
+}

+ 30 - 0
TransmitterSwitch/common/date/calendarnav.h

@@ -0,0 +1,30 @@
+#ifndef CALENDARNAV_H
+#define CALENDARNAV_H
+
+#include <QWidget>
+#include <QCalendarWidget>
+
+namespace Ui {
+class CalendarNav;
+}
+
+class CalendarNav : public QWidget
+{
+    Q_OBJECT
+    
+public:
+    explicit CalendarNav(QCalendarWidget *pCalendar, QWidget *parent = nullptr);
+    ~CalendarNav() override;
+
+    void hidePreYear(bool);
+    void hidePreMonth(bool);
+    void hideNextYear(bool);
+    void hideNextMonth(bool);
+private:
+    Ui::CalendarNav *ui;
+    QCalendarWidget *m_pCalendar;
+private slots:
+    void SetYearMonth(int year, int month);
+};
+
+#endif // CALENDARNAV_H

+ 140 - 0
TransmitterSwitch/common/date/calendarnav.ui

@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CalendarNav</class>
+ <widget class="QWidget" name="CalendarNav">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>361</width>
+    <height>39</height>
+   </rect>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>0</width>
+    <height>39</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>39</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <property name="spacing">
+    <number>15</number>
+   </property>
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QPushButton" name="btnPrevYear">
+     <property name="minimumSize">
+      <size>
+       <width>12</width>
+       <height>12</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>12</width>
+       <height>12</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="btnPrevMonth">
+     <property name="minimumSize">
+      <size>
+       <width>12</width>
+       <height>12</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>12</width>
+       <height>12</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="labelYearMonth">
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="text">
+      <string>2020 年 8 月</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="btnNextMonth">
+     <property name="minimumSize">
+      <size>
+       <width>12</width>
+       <height>12</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>12</width>
+       <height>12</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="btnNextYear">
+     <property name="minimumSize">
+      <size>
+       <width>12</width>
+       <height>12</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>12</width>
+       <height>12</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 373 - 0
TransmitterSwitch/common/date/calendarwidgetex.cpp

@@ -0,0 +1,373 @@
+//qcustomcalendarwidget.cpp
+#include "calendarwidgetex.h"
+#include <QPainter>
+#include <QProxyStyle>
+#include <QTableView>
+#include <QHeaderView>
+#include <QLayout>
+#include <QPushButton>
+#include <QLabel>
+#include <QDebug>
+#include <QLayoutItem>
+#include <QKeyEvent>
+#include <QPainterPath>
+
+#include "scopeselectionmodel.h"
+#include "calendarheader.h"
+#include "calendarnav.h"
+#include "PaintHelper/painthelper.h"
+#include "StyleManager/lhstylemanager.h"
+//#include "utility/utility.h"
+
+CalendarWidgetEx::CalendarWidgetEx(QWidget *parent)
+    : QCalendarWidget(parent)
+    , m_modeSelection(Normal)
+    , m_pDateScopeModel(nullptr)
+    , m_nLineHeight(-1)
+    , m_hasTopSplitLine(false)
+{
+    setWindowFlag(Qt::NoDropShadowWindowHint);
+    setAttribute(Qt::WA_TranslucentBackground);
+    setWindowFlag(Qt::FramelessWindowHint);
+
+    //使用固定尺寸(无法通过resize控制日历大小, 日历整体大小由layout下的控件的fixSize决定)
+    //layout()->setSizeConstraint(QLayout::SetFixedSize);
+    //禁用原有的年月导航
+    setNavigationBarVisible(false);
+    //禁用横向纵向表头
+    setVerticalHeaderFormat(QCalendarWidget::NoVerticalHeader);
+    setHorizontalHeaderFormat(QCalendarWidget::NoHorizontalHeader);
+    //取消聚焦虚线框
+    setStyle(new NoFocusStyle(this));
+
+    QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
+    if(vBodyLayout == nullptr) return;
+
+    CalendarNav *pNav = new CalendarNav(this);
+    CalendarHeader *pHeader = new CalendarHeader(this);
+    setFirstDayOfWeek(Qt::Sunday);
+    pHeader->SetFirstDayOfWeek(Qt::Sunday);
+
+    vBodyLayout->insertWidget(0, pNav);
+    // 导航和星期标题间距
+    vBodyLayout->insertSpacing(1, 10);
+    vBodyLayout->insertWidget(2, pHeader);
+
+    vBodyLayout->setSpacing(10);
+    vBodyLayout->setContentsMargins(10,0,10,10);
+
+    m_nLineHeight = vBodyLayout->itemAt(4)->widget()->mapTo(this, QPoint(0,0)).y();
+    //qDebug()<<"m_nLineHeight"<<m_nLineHeight<<vBodyLayout->itemAt(3)->widget()->height();
+
+    //开启鼠标监测
+    QTableView *pCalendarView = dynamic_cast<QTableView*>(vBodyLayout->itemAt(4)->widget());
+    if (Q_NULLPTR != pCalendarView) {
+        pCalendarView->setMouseTracking(true);
+    }
+
+    //在构造函数里取消selectionChanged, clicked事件没用, 因为执行QDateTimeEdit的setCalendarWidget方法时, 会重新绑定
+    //所以必须等setCalendarWidget执行完后再取消事件
+    //calendarWidget->disconnect(calendarWidget, &QCalendarWidget::selectionChanged, 0, 0);
+    //calendarWidget->disconnect(calendarWidget, &QCalendarWidget::clicked, 0, 0);
+
+    setMouseTracking(true);
+
+    // 设置默认字体后,修复单元格变得很宽的问题
+    for (QWidget* f : findChildren<QWidget*>()) {
+        if(f->objectName() != "qt_calendar_calendarview") continue;
+        QTableView* pView = reinterpret_cast<QTableView*>(f);
+        if (nullptr != pView && nullptr != pView->horizontalHeader()) {
+            pView->horizontalHeader()->setMaximumSectionSize(WINDOW_WIDTH / 8);
+        }
+    }
+
+    connect(this, &QCalendarWidget::clicked, this, &CalendarWidgetEx::OnClicked);
+    initSkinColor();
+}
+
+
+void CalendarWidgetEx::SetSelectMode(SelectMode mode, ScopeSelectionModel *pDataModel)
+{
+    m_listMultiSelectDays.clear();
+    m_modeSelection = mode;
+    if(m_pDateScopeModel == nullptr)
+    {
+        m_pDateScopeModel = pDataModel;
+        connect(m_pDateScopeModel, &ScopeSelectionModel::sig_Update, this, static_cast<void(QWidget::*)()>(&QWidget::update));
+    }
+    update();
+}
+
+void CalendarWidgetEx::hideNavigatioinButton(bool bPreYear, bool bPreMon, bool bNextYear, bool bNextMon)
+{
+    QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
+    if(vBodyLayout == nullptr) return;
+    CalendarNav *pNav = qobject_cast<CalendarNav*>(vBodyLayout->itemAt(0)->widget());
+    if (nullptr != pNav) {
+        pNav->hideNextMonth(bNextMon);
+        pNav->hideNextYear(bNextYear);
+        pNav->hidePreMonth(bPreMon);
+        pNav->hidePreYear(bPreYear);
+    }
+}
+
+void CalendarWidgetEx::paintCell(QPainter *painter, const QRect &rect, const QDate &date) const
+{
+    PainterEx *painterEx = static_cast<PainterEx*>(painter);
+    painterEx->setRenderHint(QPainter::Antialiasing);
+
+    QColor textColor;
+    {//正常
+        textColor = m_normalTextColor;
+    }
+#if 0
+    // 周六,周日特殊颜色
+    int nWeek = date.dayOfWeek();
+    if (6 == nWeek || 7 == nWeek) {
+        textColor = QColor(255,149,0);
+    }
+#endif
+    //鼠标移入
+    if(date == m_dateMouseOver)
+    {
+        QPoint center = rect.center();
+        QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
+        painterEx->DrawRoundedRect(rc, 2.0, m_hoverBlockColor);
+        textColor = m_normalTextColor;
+    }
+    //当天
+    if(date == QDate::currentDate())
+    {
+        painter->save();
+        QPoint center = rect.center();
+        QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
+        painter->setPen(m_todayTextColor);
+        painter->setBrush(Qt::transparent);
+        painter->drawRoundedRect(rc, 2.0, 2.0);
+        textColor = m_todayTextColor;
+        painter->restore();
+    }
+    //选中
+    if(m_modeSelection == Multi && m_listMultiSelectDays.contains(date))
+    {
+        //painterEx->DrawCircle(QRectF(rect).center(), 9, QColor(9,109,217));
+        QPoint center = rect.center();
+        QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
+        painterEx->DrawRoundedRect(rc, 2.0, m_selectBlockColor);
+        textColor = m_selectTextColor;
+    }
+    if(m_modeSelection == Normal && date == selectedDate())
+    {
+        //painterEx->DrawCircle(QRectF(rect).center(), 9, QColor(9, 109, 217));
+        QPoint center = rect.center();
+        QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
+        painterEx->DrawRoundedRect(rc, 2.0, m_selectBlockColor);
+        textColor = m_selectTextColor;
+    }
+    if(m_modeSelection == Scope && m_pDateScopeModel != nullptr && m_pDateScopeModel->dtFirst.isValid() && m_pDateScopeModel->dtSecond.isValid())
+    {
+        QDate scopeStart = qMin(m_pDateScopeModel->dtFirst, m_pDateScopeModel->dtSecond);
+        QDate scopeEnd = qMax(m_pDateScopeModel->dtFirst, m_pDateScopeModel->dtSecond);
+        if(date == qBound(scopeStart, date, scopeEnd) && date.month() == monthShown())
+        {
+            painterEx->SetBrushOnly(m_hoverBlockColor);
+            if(date == scopeStart || date == scopeEnd)
+            {
+                textColor = m_selectTextColor;
+                QPoint center = rect.center();
+                QRect rc(center.x() - TEXT_WIDTH / 2, center.y() - TEXT_WIDTH / 2, TEXT_WIDTH, TEXT_WIDTH);
+                painterEx->DrawRoundedRect(rc, 2.0, m_selectBlockColor);
+            }
+            else
+            {
+                QRect r(0, 0, rect.width(), TEXT_WIDTH);
+                r.moveCenter(rect.center());
+                painterEx->drawRect(r);
+            }
+        }
+    }
+    //不可选的日期或非当月日期
+    if(date < minimumDate() || date > maximumDate() || date.month() != monthShown())
+    {
+        textColor = m_disableTextColor;
+    }
+
+    //当天且未选中, 加粗
+    bool isBold = (date == QDate::currentDate() && date != selectedDate());
+    QString strDay(QString("%1").arg(date.day(), 2, 10, QLatin1Char('0')));
+    painterEx->setFont(FontEx(font().family(), DEFAULT_FONT_SIZE, isBold));
+    QRect rc = rect.adjusted(-1, 0, 0, -3); // 矫正文字位置
+    painterEx->DrawText(rc, strDay, textColor, Qt::AlignCenter);
+}
+
+void CalendarWidgetEx::paintEvent(QPaintEvent *)
+{
+    PainterEx painter(this);
+
+    //边框和背景
+    painter.setPen(Qt::transparent);
+    painter.setBrush(QColor(255, 255, 255));
+    QRect rc(rect());
+    painter.DrawRoundedRect(rc, WINDOW_RADIUS);
+
+    QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
+    if(vBodyLayout != nullptr) {
+        // 画导航栏,绘制上圆角
+        QPainterPath path;
+        path.setFillRule(Qt::WindingFill);
+        QRectF tmpRc(1, 0, WINDOW_WIDTH - WINDOW_RADIUS, 40);
+        path.addRoundedRect(tmpRc, WINDOW_RADIUS, WINDOW_RADIUS);
+        path.addRect(QRectF(tmpRc.x(), tmpRc.y() + WINDOW_RADIUS, tmpRc.width(), tmpRc.height()));
+        painter.fillPath(path, QColor(255, 255, 255));
+        //分割线
+        QWidget* pNav = vBodyLayout->itemAt(0)->widget();
+        if (nullptr != pNav) {
+            int h = pNav->mapTo(this, pNav->rect().bottomRight()).y();
+            painter.SetPenOnly(QColor(0, 0, 0, 23));
+            painter.drawLine(QPoint(0, h), QPoint(width(), h));
+        }
+    }
+}
+
+QSize CalendarWidgetEx::minimumSizeHint() const
+{
+    return QSize(WINDOW_WIDTH, WINDOW_HEIGHT);
+}
+
+void CalendarWidgetEx::mouseMoveEvent(QMouseEvent *event)
+{
+    QCalendarWidget::mouseMoveEvent(event);
+
+    QVBoxLayout *vBodyLayout = qobject_cast<QVBoxLayout *>(layout());
+    if(vBodyLayout == nullptr) return;
+    QTableView *pCalendarView = dynamic_cast<QTableView*>(vBodyLayout->itemAt(4)->widget());
+    if(pCalendarView == nullptr) return;
+    QModelIndex index = pCalendarView->indexAt(pCalendarView->mapFromGlobal(event->globalPos()));
+    QDate dateMouseOver = dateForCell(index.row(), index.column());
+    if(m_dateMouseOver != dateMouseOver)
+    {
+        m_dateMouseOver = dateMouseOver;
+        if(m_pDateScopeModel != nullptr && !m_pDateScopeModel->bLocked && m_pDateScopeModel->dtFirst.isValid())
+        {
+            m_pDateScopeModel->dtSecond = dateMouseOver;
+            m_pDateScopeModel->Update();
+        }
+        update();
+    }
+}
+
+//仅适用于: 不显示纵向表头(第几周), 且不显示横向表头(周几)
+QDate CalendarWidgetEx::dateForCell(int row, int column) const
+{
+    if (row < 0 || row > 5 || column < 0 || column > 6)
+        return QDate();
+
+    const QDate refDate = referenceDate();
+    if (!refDate.isValid())
+        return QDate();
+
+    const int columnForFirstOfShownMonth = columnForFirstOfMonth(refDate);
+    if (columnForFirstOfShownMonth - 0/*m_firstColumn*/ < 1)
+        row -= 1;
+
+    const int requestedDay = 7 * (row - 0/*m_firstRow*/) + column - columnForFirstOfShownMonth - refDate.day() + 1;
+    return refDate.addDays(requestedDay);
+}
+
+QDate CalendarWidgetEx::referenceDate() const
+{
+    int refDay = 1;
+    while (refDay <= 31) {
+        QDate refDate(yearShown(), monthShown(), refDay);
+        if (refDate.isValid())
+            return refDate;
+        refDay += 1;
+    }
+    return QDate();
+}
+int CalendarWidgetEx::columnForFirstOfMonth(const QDate &date) const
+{
+    return (columnForDayOfWeek(date.dayOfWeek()) - (date.day() % 7) + 8) % 7;
+}
+int CalendarWidgetEx::columnForDayOfWeek(int day) const
+{
+    if (day < 1 || day > 7)
+        return -1;
+    int column = day - firstDayOfWeek();
+    if (column < 0)
+        column += 7;
+    return column;
+}
+
+void CalendarWidgetEx::initSkinColor()
+{
+    switch (LHStyleManager::Instance()->GetCurSkinStyle()) {
+    case eBrightStyle:
+        m_normalTextColor = NORMAL_TEXT_BRIGHT;
+        m_todayTextColor = TODAY_TEXT_BRIGHT;
+        m_selectTextColor = SELECT_TEXT_BRIGHT;
+        m_disableTextColor = DISABLE_TEXT_BRIGHT;
+        m_splitLineColor = SPLIT_LINE_BRIGHT;
+        m_selectBlockColor = SELECT_BRIGHT;
+        m_hoverBlockColor = HOVER_BRIGHT;
+        break;
+    case eDarkStyle:
+        break;
+    default:
+        break;
+    }
+}
+
+void CalendarWidgetEx::OnClicked(const QDate &date)
+{
+    if(m_modeSelection == Multi)
+    {
+        if(m_listMultiSelectDays.contains(date))
+        {
+            m_listMultiSelectDays.removeOne(date);
+        }
+        else
+        {
+            m_listMultiSelectDays.append(date);
+        }
+    }
+    if(m_modeSelection == Scope && m_pDateScopeModel != nullptr)
+    {
+        if(!m_pDateScopeModel->bLocked && m_pDateScopeModel->dtFirst.isValid())
+        {
+            m_pDateScopeModel->dtSecond = date;
+            m_pDateScopeModel->bLocked = true;
+            m_pDateScopeModel->Locked();
+        }
+        else
+        {
+            m_pDateScopeModel->dtFirst = date;
+            m_pDateScopeModel->dtSecond = date;
+            m_pDateScopeModel->bLocked = false;
+        }
+
+        m_pDateScopeModel->Update();
+    }
+    update();
+}
+
+void CalendarWidgetEx::leaveEvent(QEvent *)
+{
+    if(m_modeSelection != Scope)
+    {
+        //离开日历时, 清空鼠标移入状态
+        m_dateMouseOver = QDate();
+        update();
+    }
+}
+
+void NoFocusStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
+{
+    QStyleOption *viewOption = new QStyleOption(*option);
+    viewOption->state &= (~QStyle::State_HasFocus);
+    //if (element == PE_FrameFocusRect) return;
+    QProxyStyle::drawPrimitive(element, viewOption, painter, widget);
+    delete viewOption;
+}
+
+

+ 84 - 0
TransmitterSwitch/common/date/calendarwidgetex.h

@@ -0,0 +1,84 @@
+#ifndef QCUSTOMCALENDARWIDGET_H
+#define QCUSTOMCALENDARWIDGET_H
+
+#include <QCalendarWidget>
+#include <QPushButton>
+#include <QLabel>
+#include <QProxyStyle>
+
+class ScopeSelectionModel;
+
+class NoFocusStyle : public QProxyStyle
+{
+    Q_OBJECT
+public:
+    explicit NoFocusStyle(QObject *parent):QProxyStyle() { setParent(parent); }
+
+private:
+    void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+                       QPainter *painter, const QWidget *widget) const;
+};
+/**
+ * @brief The CalendarWidgetEx class
+ */
+class CalendarWidgetEx : public QCalendarWidget
+{
+    Q_OBJECT
+public:
+    enum SelectMode
+    {
+        Normal,
+        Multi,
+        Scope,
+    };
+public:
+    explicit CalendarWidgetEx(QWidget *parent = nullptr);
+    ~CalendarWidgetEx() override {}
+    void SetSelectMode(SelectMode mode, ScopeSelectionModel *pDataModel = nullptr);
+    QList<QDate> GetSelectDays(){return m_listMultiSelectDays;}
+
+    void hideNavigatioinButton(bool bPreYear, bool bPreMon, bool bNextYear, bool bNextMon);
+private:
+    QDate dateForCell(int row, int column) const;
+    QDate referenceDate() const;
+    int columnForFirstOfMonth(const QDate &date) const;
+    int columnForDayOfWeek(int day) const;
+    void initSkinColor();
+protected:
+    void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const override;
+    void paintEvent(QPaintEvent *) override;
+    void mouseMoveEvent(QMouseEvent *event) override;
+    void leaveEvent(QEvent *) override;
+public:
+    QSize minimumSizeHint() const override;
+private slots:
+    void OnClicked(const QDate &date);
+private:
+    const QColor NORMAL_TEXT_BRIGHT{QColor(58,63,99)};
+    const QColor TODAY_TEXT_BRIGHT{QColor(68,88,254)};
+    const QColor SELECT_TEXT_BRIGHT{Qt::white};
+    const QColor DISABLE_TEXT_BRIGHT{QColor(133, 142, 189)};
+    const QColor SPLIT_LINE_BRIGHT{QColor(0, 0, 0, 23)};
+    const QColor SELECT_BRIGHT{QColor(68, 88, 254)};
+    const QColor HOVER_BRIGHT{QColor(227, 238, 255)};
+    const int DEFAULT_FONT_SIZE = 14;
+    const int TEXT_WIDTH = 24;
+    const qreal WINDOW_RADIUS = 2.0;
+    const int WINDOW_WIDTH = 325;
+    const int WINDOW_HEIGHT = 350;
+
+    QDate m_dateMouseOver;
+    QList<QDate> m_listMultiSelectDays;
+    SelectMode m_modeSelection;
+    ScopeSelectionModel *m_pDateScopeModel;
+    int m_nLineHeight;      //星期和日之间的分割线的Y坐标
+    bool m_hasTopSplitLine; // 是否绘制顶部分割线
+    QColor m_normalTextColor;
+    QColor m_todayTextColor;
+    QColor m_selectTextColor;
+    QColor m_disableTextColor;
+    QColor m_splitLineColor;
+    QColor m_selectBlockColor;
+    QColor m_hoverBlockColor;
+};
+#endif // QCUSTOMCALENDARWIDGET_H

+ 112 - 0
TransmitterSwitch/common/date/cdate.cpp

@@ -0,0 +1,112 @@
+#include "cdate.h"
+
+#include <QHBoxLayout>
+#include <QPainter>
+#include <QEvent>
+#include <QDebug>
+#include <QMouseEvent>
+
+#include "calendarwidgetex.h"
+#include "oneshadow.h"
+
+CDate::CDate(const QDate& defaultDate,QWidget *parent,PopupType type) :
+    QWidget{parent},
+    m_parent(parent),
+    m_type(type)
+{
+    init(defaultDate);
+}
+
+CDate::CDate(QWidget *parent,PopupType type) :
+    QWidget{parent},
+    m_parent(parent),
+    m_type(type)
+{
+//    if(type == Popup)
+//    {
+//        setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
+//    }
+    init(QDate::currentDate());
+}
+
+void CDate::paintEvent(QPaintEvent *event)
+{
+    QPainter painter(this);
+    painter.setRenderHint(QPainter::Antialiasing);
+    painter.drawImage(QPoint(0,0),m_shadow->image());
+}
+/**
+ * @brief 在这里实现点击空白处隐藏或者关闭自身
+ * @param watched
+ * @param event
+ * @return
+ */
+bool CDate::eventFilter(QObject *watched, QEvent *event)
+{
+    auto me = dynamic_cast<QMouseEvent*>(event);
+    if(nullptr != me)
+    {
+        if(me->type() == QEvent::MouseButtonPress)
+        {
+            if(m_type == Popup)
+            {
+                /* 先将自身区域和鼠标坐标都转换成全局坐标 */
+                QPoint gTopLeft = this->mapToGlobal(this->rect().topLeft());
+                QRect gRect(gTopLeft.x(),gTopLeft.y(),this->width(),this->height());
+                /* 判断此时的鼠标坐标是否在这个控件中 */
+                if(!gRect.contains(me->globalPos()))
+                {
+//                    qDebug() << QTime::currentTime() << "CDate关闭了";
+                    /* 发送信号,关闭自身 */
+                    emit signal_close();
+                    emit signal_DateChanged(m_date);
+                    this->close();
+                }
+            }
+        }
+    }
+
+    return QWidget::eventFilter(watched,event);
+}
+
+
+void CDate::init(const QDate &defaultDate)
+{
+    /* 设置无边框 */
+    setWindowFlags(Qt::FramelessWindowHint);
+    /* 设置底层样式表,让最底层的透明 */
+    this->setAttribute(Qt::WA_TranslucentBackground);
+    /* 将父类的事件注册给自己 */
+    if(m_type == Popup && m_parent != nullptr)
+    {
+        m_parent->installEventFilter(this);
+    }
+    /* 设置布局,通过设置layout的Margin距离显示阴影 */
+    QHBoxLayout* layout = new QHBoxLayout(this);
+    this->setLayout(layout);
+    layout->setMargin(RADIUS);
+    this->resize(CALENDAR_WIDTH + RADIUS*2,CALENDAR_HEIGHT + RADIUS*2);
+
+    /* 设置日历组件 */
+    m_calendarEx = new CalendarWidgetEx(this);
+    m_calendarEx->resize(CALENDAR_WIDTH,CALENDAR_HEIGHT);
+    m_calendarEx->setCurrentPage(defaultDate.year(),defaultDate.month());
+    m_calendarEx->setSelectedDate(defaultDate);
+    layout->addWidget(m_calendarEx);
+
+
+    /* 设置自身时间 */
+    m_date = defaultDate;
+
+    /* 设置阴影 */
+    m_shadow = new OneShadow(QSize(m_calendarEx->width(),m_calendarEx->height()),RADIUS);
+
+
+    /* 信号和槽 */
+    connect(m_calendarEx,&CalendarWidgetEx::clicked,this,[this](const QDate& date){
+        m_date = date;
+        emit signal_DateChanged(date);
+        this->close();
+    });
+
+}

+ 54 - 0
TransmitterSwitch/common/date/cdate.h

@@ -0,0 +1,54 @@
+#ifndef CDATE_H
+#define CDATE_H
+
+
+/**
+ * 使用说明
+ *  1、这个是仿照TimeWidget做的一个可以点击空白处隐藏自身的日历控件
+ *  2、实现方式就是将父类的事件注册到这个控件上,拦截父类的鼠标点击,判断
+ *     是否在这个控件上进行隐藏,因此控件显示范围就依赖于父类空间大小了
+ *  3、使用方法:
+ *      1) 可以选择点击空白处隐藏或者不隐藏,设置PopuType类型就行
+ *
+*/
+
+#include <QDialog>
+#include <QWidget>
+#include <QDate>
+
+class CalendarWidgetEx;
+class OneShadow;
+
+class CDate : public QWidget
+{
+    Q_OBJECT
+
+    const int RADIUS = 16;              /* 阴影范围 */
+    const int CALENDAR_WIDTH = 325;     /* 日历大小 */
+    const int CALENDAR_HEIGHT = 350;
+public:
+    enum PopupType{
+        Popup = 0,
+        NoPopup = 1
+    };
+    CDate(const QDate& defaultDate,QWidget *parent = nullptr,PopupType type = Popup);
+    CDate(QWidget *parent = nullptr,PopupType type = Popup);
+signals:
+    void signal_DateChanged(const QDate& date);
+    void signal_close();
+
+protected:
+    void paintEvent(QPaintEvent *event);
+    bool eventFilter(QObject *watched, QEvent *event);
+
+private:
+    void init(const QDate& defaultDate);
+private:
+    QDate m_date;
+    CalendarWidgetEx* m_calendarEx = nullptr;
+    OneShadow* m_shadow = nullptr;
+    QWidget* m_parent = nullptr;
+    PopupType m_type;
+};
+
+#endif // CDATE_H

BIN
TransmitterSwitch/common/date/nextMonth.png


BIN
TransmitterSwitch/common/date/nextMonth_hover.png


BIN
TransmitterSwitch/common/date/nextYear.png


BIN
TransmitterSwitch/common/date/nextYear_hover.png


BIN
TransmitterSwitch/common/date/preMonth.png


BIN
TransmitterSwitch/common/date/preMonth_hover.png


BIN
TransmitterSwitch/common/date/preYear.png


BIN
TransmitterSwitch/common/date/preYear_hover.png


+ 13 - 0
TransmitterSwitch/common/date/rescalendar.qrc

@@ -0,0 +1,13 @@
+<RCC>
+    <qresource prefix="/Calendar">
+        <file>nextMonth.png</file>
+        <file>nextMonth_hover.png</file>
+        <file>nextYear.png</file>
+        <file>nextYear_hover.png</file>
+        <file>preMonth.png</file>
+        <file>preMonth_hover.png</file>
+        <file>preYear.png</file>
+        <file>preYear_hover.png</file>
+        <file>CalendarNav.qss</file>
+    </qresource>
+</RCC>

+ 63 - 0
TransmitterSwitch/common/date/scopecalendarbtn.cpp

@@ -0,0 +1,63 @@
+#include "scopecalendarbtn.h"
+#include "calendarex.h"
+#include <QDebug>
+
+ScopeCalendarBtn::ScopeCalendarBtn(QWidget *parent) 
+    : QPushButton(parent)
+    , m_dtFrom(QDate::currentDate())
+    , m_dtTo(QDate::currentDate())
+    , m_dtMin(QDate(1,1,1))
+    , m_dtMax(QDate(9999,12,31))
+    , m_strFormat("%1 - %2")
+{
+    connect(this, &QPushButton::clicked, this, &ScopeCalendarBtn::OnPopBtnClicked);
+    SetScope(m_dtFrom, m_dtTo);
+}
+
+void ScopeCalendarBtn::SetMinimumDate(const QDate &date)
+{
+    m_dtMin = date;
+    m_dtMax = qMax(m_dtMin, m_dtMax);
+    m_dtFrom = qMax(m_dtMin, m_dtFrom);
+    m_dtTo = qMax(m_dtMin, m_dtTo);
+}
+
+void ScopeCalendarBtn::SetMiaxmumDate(const QDate &date)
+{
+    m_dtMax = date;
+    m_dtMin = qMin(m_dtMax, m_dtMin);
+    m_dtFrom = qMin(m_dtMax, m_dtFrom);
+    m_dtTo = qMin(m_dtMax, m_dtTo);
+}
+
+void ScopeCalendarBtn::SetScope(const QDate &from, const QDate &to)
+{
+    m_dtFrom = qBound(m_dtMin, from, m_dtMax);
+    m_dtTo = qBound(m_dtMin, to, m_dtMax);
+    QString text = QString(m_strFormat).arg(m_dtFrom.toString("yyyy-MM-dd"), m_dtTo.toString("yyyy-MM-dd"));
+    setText(text);
+}
+
+void ScopeCalendarBtn::OnPopBtnClicked()
+{
+    ScopedCalendar *pC = new ScopedCalendar(m_dtFrom, m_dtTo);
+    pC->show();
+    pC->positionCalendarPopup(this);
+    if(m_dtMin.isValid()) pC->SetMinimumDate(m_dtMin);
+    if(m_dtMax.isValid()) pC->SetMaximumDate(m_dtMax);
+    connect(pC, &ScopedCalendar::sig_ScopeSelected, this, &ScopeCalendarBtn::OnScopeSelected);
+}
+
+void ScopeCalendarBtn::OnScopeSelected(const QDate &from, const QDate &to)
+{
+    SetScope(from, to);
+    emit sig_ScopeSelected(from, to);
+}
+
+void ScopeCalendarBtn::paintEvent(QPaintEvent *event)
+{
+//    PainterEx painter(this);
+//    painter.SetBrushOnly(Qt::gray);
+//    painter.drawRect(rect());
+    QPushButton::paintEvent(event);
+}

+ 33 - 0
TransmitterSwitch/common/date/scopecalendarbtn.h

@@ -0,0 +1,33 @@
+#ifndef CALENDARSCOPEBTN_H
+#define CALENDARSCOPEBTN_H
+
+#include <QDateTime>
+#include <QPushButton>
+
+class ScopeCalendarBtn : public QPushButton
+{
+    Q_OBJECT
+public:
+    explicit ScopeCalendarBtn(QWidget *parent = nullptr);
+    QDate From(){return m_dtFrom;}
+    QDate To(){return m_dtTo;}
+    void SetMinimumDate(const QDate &date);
+    void SetMiaxmumDate(const QDate &date);
+    void SetScope(const QDate &from, const QDate &to);
+    void SetFormat(const QString &format = "%1 - %2"){m_strFormat = format;}
+signals:
+    void sig_ScopeSelected(const QDate &from, const QDate &to);
+private slots:
+    void OnPopBtnClicked();
+    void OnScopeSelected(const QDate &from, const QDate &to);
+protected:
+    void paintEvent(QPaintEvent *event);
+private:
+    QDate m_dtFrom;
+    QDate m_dtTo;
+    QDate m_dtMin;
+    QDate m_dtMax;
+    QString m_strFormat;
+};
+
+#endif // CALENDARSCOPEBTN_H

+ 34 - 0
TransmitterSwitch/common/date/scopeselectionmodel.cpp

@@ -0,0 +1,34 @@
+#include "scopeselectionmodel.h"
+
+ScopeSelectionModel::ScopeSelectionModel(QObject *parent)
+    : QObject(parent)
+    , bLocked(false)
+{
+    
+}
+
+void ScopeSelectionModel::Clear()
+{
+    dtFirst = QDate();
+    dtSecond = QDate();
+    bLocked = false;
+}
+
+void ScopeSelectionModel::Update()
+{
+    emit sig_Update();
+}
+
+void ScopeSelectionModel::Locked()
+{
+    QDate from = qMin(dtFirst, dtSecond);
+    QDate to = qMax(dtFirst, dtSecond);
+    emit sig_ScopeSelected(from, to);
+}
+
+//void DateScopeModel::Lock(const QDate &date)
+//{
+//    if(bLocked || !dtFirst.isValid()) return;
+//    dtSecond = date;
+//    bLocked = true;
+//}

+ 26 - 0
TransmitterSwitch/common/date/scopeselectionmodel.h

@@ -0,0 +1,26 @@
+#ifndef DATESCOPEMODEL_H
+#define DATESCOPEMODEL_H
+
+#include <QDateTime>
+#include <QObject>
+
+class ScopeSelectionModel : public QObject
+{
+    Q_OBJECT
+public:
+    explicit ScopeSelectionModel(QObject *parent = nullptr);
+    void Clear();
+    void Update();
+    void Locked();
+signals:
+    void sig_Update();
+    void sig_ScopeSelected(const QDate &from, const QDate &to);
+    //void Lock(const QDate &date);
+public:
+    //QPair<QDate, QDate> m_pairDateScope;    //鼠标移动时的范围指示, key和value都是Qdate类型, 但是不一定哪个较大
+    QDate dtFirst;
+    QDate dtSecond;
+    bool bLocked;
+};
+
+#endif // DATESCOPEMODEL_H

+ 228 - 9
TransmitterSwitch/transmitterswitch.cpp

@@ -9,8 +9,12 @@
 #include "widgetitems.h"
 #include "UserData/pBtnUserData.h"
 #include "AddItem/addnormalitem.h"
+#include "AddItem/addspecialitem.h"
 #include "WebAPI/FromWebAPI.h"
 #include "transmitterswitchinfo.h"
+#include "oneitem.h"
+#include "ItemData.h"
+#include "timewidget.h"
 
 TransmitterSwitch::TransmitterSwitch(QWidget *parent) :
     QWidget(parent),
@@ -42,6 +46,7 @@ TransmitterSwitch::TransmitterSwitch(QWidget *parent) :
     /* 获取今天是周几,设置周几页面 */
     int day = QDate::currentDate().dayOfWeek() - 1;
     m_vecWeeks[day]->setChecked(true);
+    ui->stackedWidget_items->setCurrentIndex(day);
 
     /* 连接信号和槽 */
     connect(ui->pBtn_addPlan, &QPushButton::clicked, this, &TransmitterSwitch::do_pBtnAddExecPlan);
@@ -133,26 +138,121 @@ void TransmitterSwitch::do_pBtnAddExecPlan()
     {
         std::shared_ptr<AddNormalItem> atf = std::make_shared<AddNormalItem>(this);
         atf->setParentPointer(this);
-        connect(atf.get(),SIGNAL(signal_addNormalItem(QString,QString,QTime)),this,SLOT(do_addNormalOneItem(QString,QString,QTime)));
         /* 设置可选项 */
         atf->setDevice(DeviceContainer.getMapDevice());
+        /* 设置是周几 */
+        int weekDay = ui->stackedWidget_items->currentIndex();
+        atf->setWeekDay(weekDay);
         atf->exec();
-        // atf->setAttribute(Qt::WA_DeleteOnClose,true);
+        /* 判断是否需要添加计划 */
+        if(atf->isAddDev())
+        {
+            /* 添加计划 */
+            addNormalOneItem(weekDay, atf->getDevName(), atf->getAction(), atf->getTime());
+        }
     }
-    else        /* 特殊日 */
+    else
     {
-        // std::shared_ptr<AddSpecialItem> ast = std::make_shared<AddSpecialItem>(this);
-        // connect(ast.get(),SIGNAL(signal_AddSpecialItem(QString,QString,QDate,QTime)),this,SLOT(do_addSpecialOneItem(QString,QString,QDate,QTime)));
+        /* 特殊日 */
+        std::shared_ptr<AddSpecialItem> atf = std::make_shared<AddSpecialItem>(this);
+        atf->setParentPointer(this);
+        /* 设置可选项 */
+        atf->setDevice(DeviceContainer.getMapDevice());
+        /* 设置是周几 */
+        int weekDay = ui->stackedWidget_items->currentIndex();
+        atf->setWeekDay(weekDay);
+        atf->exec();
+        /* 判断是否需要添加计划 */
+        if(atf->isAddDev())
+        {
+            /* 添加计划 */
+            addSpecialOneItem(weekDay, atf->getDevName(), atf->getAction(), atf->getDate(), atf->getTime());
+        }
+    }
+}
 
-        // ast->exec();
-        // ast->setAttribute(Qt::WA_DeleteOnClose,true);
+
+/* 删除一项正常日计划 */
+void TransmitterSwitch::do_deleteOneItem(int week, int index)
+{
+    /* 删除该项 */
+    IData.deleteOneItem(week, index);
+    /* 重新排序 */
+    sortLayout(week);
+}
+
+/* 一个计划修改了设备 */
+void TransmitterSwitch::do_changeDev()
+{
+    /* 判断修改设备后时间是否冲突 */
+    auto one = qobject_cast<OneItem*>(sender());
+    if(one == nullptr)
+    {
+        return;
     }
+    if(one->getWeekDay() > 0 && one->getWeekDay() < 7)
+    {
+        if(IData.judgeTimeRepetitionWithEdit(one->getWeekDay(), one, one->getExecTime()))
+        {
+            /* 设置时间报警 */
+            one->setWarningText("设备执行时间冲突", -1);
+            return;
+        }
+    }
+    else if(one->getWeekDay() == 7)
+    {
+        if(IData.judgeDateTimeRepetitionWithEdit(one->getWeekDay(), one, one->getDate(), one->getExecTime()))
+        {
+            /* 设置时间报警 */
+            one->setWarningText("设备执行日期时间冲突", -1);
+            return;
+        }
+    }
+    /* 取消报警 */
+    one->hideWarn();
 }
 
-/* 添加一项正常日计划 */
-void TransmitterSwitch::do_addNormalOneItem(QString devName, QString action, QTime execTime)
+/* 点击修改执行时间 */
+void TransmitterSwitch::do_editExecTime(QTime t)
 {
+    /* 获取信号发送者 */
+    auto one = qobject_cast<OneItem*>(sender());
+    /* 创建时间选择控件 */
+    std::shared_ptr<TimeWidget> tw = std::make_shared<TimeWidget>(this, TimeWidget::ShowType::Dialog);
+    /* 设置图标 */
+    tw->setIcon(":/ICON/ICON/Time.png");
+    tw->setIconShow(true);
+    tw->setIconSize(16, 16);
+    /* 重新设置大小 */
+    tw->setEditLine(one->getExecTimeSize().width(), one->getExecTimeSize().height());
+    /* 设置选择框大小 */
+    tw->setTimeAreaWidth(140);
+    /* 移动位置,覆盖显示时间的按钮,获取的坐标是相对于Dialog的位置 */
+    auto pos = one->mapTo(this, one->getExecTimePos());
+    tw->move(pos);
+    /* 设置默认的时间 */
+    tw->setTime(t);
 
+    tw->execShow();
+    auto time = tw->getTime();
+    /* 判断时间有没有修改 */
+    if(time == t)
+    {
+        return;
+    }
+    LH_WRITE_LOG_DEBUG(QString("选择时间:%1").arg(time.toString("hh:mm:ss")));
+    one->setExecTime(time);
+    /* 判断时间是否重复 */
+    if(IData.judgeTimeRepetitionWithEdit(one->getWeekDay(), one, time))
+    {
+        /* 设置时间报警 */
+        one->setWarningText("设备执行时间冲突", -1);
+        return;
+    }
+    /* 取消报警 */
+    one->hideWarn();
+    /* 重新排序 */
+    sortLayout(one->getWeekDay());
 }
 
 /* 导入数据 */
@@ -226,6 +326,125 @@ void TransmitterSwitch::createWeekWidget()
     // LH_WRITE_LOG("StackedWidget count: " + QString::number(ui->stackedWidget_items->count()));
 }
 
+
+/* 添加一个正常日的计划 */
+void TransmitterSwitch::addNormalOneItem(int week, QString devName, QString action, QTime execTime)
+{
+    OneItem* one = new OneItem();
+    /* 添加可选的设备 */
+    one->addDevice();
+    /* 设置最小高度 */
+    // one->setMinimumHeight(48);
+    one->setDevName(devName);
+    one->setExecTime(execTime);
+    one->setWeekDay(week);
+
+    /* 连接删除项信号,执行时间改变信号 */
+    connect(one, &OneItem::signal_OneItemDelete, this, &TransmitterSwitch::do_deleteOneItem);
+    connect(one, &OneItem::signal_devChanged, this, &TransmitterSwitch::do_changeDev);
+    connect(one, &OneItem::signal_execTimeClicked, this, &TransmitterSwitch::do_editExecTime);
+
+    /* 添加到容器中 */
+    IData.addOneItem(week, one);
+    /* 重新排序 */
+    sortLayout(week);
+}
+
+/* 添加一项特殊日计划 */
+void TransmitterSwitch::addSpecialOneItem(int week, QString devName, QString action, QDate date, QTime execTime)
+{
+
+}
+
+/* 重新排序布局 */
+void TransmitterSwitch::sortLayout(int weekDay)
+{
+    if(weekDay < 7 && weekDay >= 0)
+    {
+        sortNormalDayData(weekDay);
+    }else if(weekDay == 7)
+    {
+        sortSpecialDayData();
+    }
+    /* 重新布局 */
+    sortLayoutUI(weekDay);
+}
+
+/* 排序正常日 */
+void TransmitterSwitch::sortNormalDayData(int weekDay)
+{
+    /* 获取当前页容器 */
+    auto list = IData.getOneDay(weekDay);
+    // LH_WRITE_LOG_DEBUG(QString("获取到的容器大小:%1").arg(list->size()));
+    if(list == nullptr)
+    {
+        return;
+    }
+    /* 将当前页,按时间升序排序 */
+    std::sort(list->begin(), list->end(), [&](OneItem* t1, OneItem* t2) 
+    {
+        /* 按照日期排序,再按照名称排序 */
+        if(t1->getDate() < t2->getDate())
+        {
+            return true;
+        }
+        else if(t1->getDate() > t2->getDate())
+        {
+            return false;
+        }
+        else
+        {
+            if(t1->getExecTime() < t2->getExecTime())
+            {
+                return true;
+            }
+            else if(t1->getExecTime() > t2->getExecTime())
+            {
+                return false;
+            }else
+            {
+                return t1->getDevName() < t2->getDevName();
+            }
+        }
+    });
+    /* 设置序号 */
+    int num1 = 1;
+    for(auto& it : *list)
+    {
+        it->setNum(num1);
+        num1++;
+    }
+}
+
+/* 排序特殊日 */
+void TransmitterSwitch::sortSpecialDayData()
+{
+
+}
+
+/* 重新布局项 */
+void TransmitterSwitch::sortLayoutUI(int weekDay)
+{
+    /* 获取数据列表和layout */
+    auto listItem = IData.getOneDay(weekDay);
+    if(listItem == nullptr)
+    {
+        return;
+    }
+    auto layout = m_vecLayouts[weekDay];
+    /* 刷新UI,先清空layout中的所有控件,就是将item的父指针设置为0 */
+    int num1 = 0;
+    for(auto& it : *listItem)
+    {
+        it->setParent(nullptr);
+    }
+    /* 将item重新加入到layout中 */
+    for(auto& it : *listItem)
+    {
+        layout->addWidget(it);
+    }
+}
+
 /* 事件过滤器 */
 bool TransmitterSwitch::eventFilter(QObject *watched, QEvent *event)
 {

+ 21 - 2
TransmitterSwitch/transmitterswitch.h

@@ -32,14 +32,33 @@ private slots:
     /* 点击了添加计划按钮 */
     void do_pBtnAddExecPlan();
 
-    /* 添加一项正常日计划 */
-    void do_addNormalOneItem(QString devName, QString action, QTime execTime);
+    /* 删除一项正常日计划 */
+    void do_deleteOneItem(int week, int index);
+    /* 一个计划修改了设备 */
+    void do_changeDev();
+    /* 点击修改执行时间 */
+    void do_editExecTime(QTime t);
+
+
     /* 导入数据 */
     void do_importData();
 
 private:
     /* 创建一周8天的item页面 */
     void createWeekWidget();
+    /* 添加一个正常日的计划 */
+    void addNormalOneItem(int week, QString devName, QString action, QTime execTime);
+    /* 添加一项特殊日计划 */
+    void addSpecialOneItem(int week, QString devName, QString action, QDate date, QTime execTime);
+
+    /* 重新排序布局 */
+    void sortLayout(int weekDay);
+    /* 排序正常日 */
+    void sortNormalDayData(int weekDay);
+    /* 排序特殊日 */
+    void sortSpecialDayData();
+    /* 重新布局项 */
+    void sortLayoutUI(int weekDay);
 
 protected:
     /* 事件过滤器 */

+ 6 - 0
show1/CMakeLists.txt

@@ -22,6 +22,11 @@ file(GLOB LOCAL_SRC
     ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/ImageBlur/*.cpp
     ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/combobox/*.cpp
     ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/SelectTime/*.cpp
+    ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/date/*.cpp
+    ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/date/*.qrc
+    ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/DropShadow/*.cpp
+    ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/PaintHelper/*.cpp
+    ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/StyleManager/*.cpp
 
     # ${LHQLog_SOURCE_DIRS}/*.cpp
     ${LHHTTPAPI_SOURCE_DIRS}/*.cpp
@@ -54,6 +59,7 @@ target_include_directories(${execName1} PRIVATE
     ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/ImageBlur
     ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/combobox
     ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/SelectTime
+    ${CMAKE_SOURCE_DIR}/TransmitterSwitch/common/date
 
 
     # ${LHQLog_INCLUDE_DIRS}

+ 9 - 3
show1/main.cpp

@@ -2,17 +2,20 @@
 #include <QApplication>
 #include <QFontDatabase>
 #include <QDebug>
+#include <QDialog>
+
 
 #include "widget.h"
 #include "spdlog/spdlog.h"
-
+#include "TransmitterSwitchInfo.h"
 
 void addFont();
 
+
 int main(int argc, char *argv[])
 {
     
-    QApplication a(argc, argv);
+    QApplication app(argc, argv);
     addFont();
 
     /* 设置日志输出等级 */
@@ -21,7 +24,7 @@ int main(int argc, char *argv[])
     Widget w;
     w.show();
 
-    return a.exec();
+    return app.exec();
 }
 
 
@@ -48,3 +51,6 @@ void addFont()
     QApplication::setFont(font_main);
 }
 
+
+
+

+ 3 - 0
show1/widget.h

@@ -3,6 +3,8 @@
 
 #include <QWidget>
 #include <QVBoxLayout>
+#include <QMouseEvent>
+#include <QDebug>
 
 #include "transmitterswitch.h"
 
@@ -25,4 +27,5 @@ private:
     QVBoxLayout* m_layout;                  /* 布局 */
 };
 
+
 #endif // WIDGET_H