onlineuserswidget.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. #include "onlineuserswidget.h"
  2. #include <QApplication>
  3. #include <QDateTime>
  4. #include <QDebug>
  5. #include <QJsonDocument>
  6. OnlineUsersWidget::OnlineUsersWidget(QWidget *parent)
  7. : QWidget(parent)
  8. , m_mainLayout(nullptr)
  9. , m_headerLayout(nullptr)
  10. , m_titleLabel(nullptr)
  11. , m_countLabel(nullptr)
  12. , m_refreshButton(nullptr)
  13. , m_searchEdit(nullptr)
  14. , m_usersTable(nullptr)
  15. , m_contextMenu(nullptr)
  16. , m_privateMessageAction(nullptr)
  17. , m_viewProfileAction(nullptr)
  18. , m_kickUserAction(nullptr)
  19. {
  20. setupUI();
  21. setupTable();
  22. setupContextMenu();
  23. applyStyles();
  24. // 添加一些示例数据
  25. addUser(OnlineUser("1", "管理员", "在线"));
  26. addUser(OnlineUser("2", "用户A", "在线"));
  27. addUser(OnlineUser("3", "用户B", "离开"));
  28. addUser(OnlineUser("4", "用户C", "忙碌"));
  29. }
  30. OnlineUsersWidget::~OnlineUsersWidget()
  31. {
  32. }
  33. void OnlineUsersWidget::setupUI()
  34. {
  35. m_mainLayout = new QVBoxLayout(this);
  36. m_mainLayout->setContentsMargins(8, 8, 8, 8);
  37. m_mainLayout->setSpacing(6);
  38. // 头部布局
  39. m_headerLayout = new QHBoxLayout();
  40. m_titleLabel = new QLabel("在线用户", this);
  41. m_titleLabel->setObjectName("titleLabel");
  42. m_countLabel = new QLabel("(0)", this);
  43. m_countLabel->setObjectName("countLabel");
  44. m_refreshButton = new QPushButton("刷新", this);
  45. m_refreshButton->setObjectName("refreshButton");
  46. m_refreshButton->setMaximumWidth(60);
  47. m_headerLayout->addWidget(m_titleLabel);
  48. m_headerLayout->addWidget(m_countLabel);
  49. m_headerLayout->addStretch();
  50. m_headerLayout->addWidget(m_refreshButton);
  51. // 搜索框
  52. m_searchEdit = new QLineEdit(this);
  53. m_searchEdit->setPlaceholderText("搜索用户...");
  54. m_searchEdit->setObjectName("searchEdit");
  55. // 用户表格
  56. m_usersTable = new QTableWidget(this);
  57. m_usersTable->setObjectName("usersTable");
  58. // 添加到主布局
  59. m_mainLayout->addLayout(m_headerLayout);
  60. m_mainLayout->addWidget(m_searchEdit);
  61. m_mainLayout->addWidget(m_usersTable);
  62. // 连接信号
  63. connect(m_refreshButton, &QPushButton::clicked, this, &OnlineUsersWidget::onRefreshClicked);
  64. connect(m_searchEdit, &QLineEdit::textChanged, this, &OnlineUsersWidget::onSearchTextChanged);
  65. }
  66. void OnlineUsersWidget::setupTable()
  67. {
  68. // 设置表格列
  69. m_usersTable->setColumnCount(3);
  70. QStringList headers;
  71. headers << "状态" << "用户名" << "最后活动";
  72. m_usersTable->setHorizontalHeaderLabels(headers);
  73. // 设置表格属性
  74. m_usersTable->setSelectionBehavior(QAbstractItemView::SelectRows);
  75. m_usersTable->setSelectionMode(QAbstractItemView::SingleSelection);
  76. m_usersTable->setAlternatingRowColors(true);
  77. m_usersTable->setShowGrid(false);
  78. m_usersTable->verticalHeader()->setVisible(false);
  79. // 设置列宽
  80. QHeaderView *header = m_usersTable->horizontalHeader();
  81. header->setStretchLastSection(true);
  82. header->resizeSection(0, 60); // 状态列
  83. header->resizeSection(1, 120); // 用户名列
  84. // 连接信号
  85. connect(m_usersTable, &QTableWidget::itemDoubleClicked,
  86. [this](QTableWidgetItem *item) {
  87. if (item) {
  88. onTableDoubleClicked(item->row(), item->column());
  89. }
  90. });
  91. m_usersTable->setContextMenuPolicy(Qt::CustomContextMenu);
  92. connect(m_usersTable, &QTableWidget::customContextMenuRequested,
  93. this, &OnlineUsersWidget::onTableContextMenu);
  94. }
  95. void OnlineUsersWidget::setupContextMenu()
  96. {
  97. m_contextMenu = new QMenu(this);
  98. m_privateMessageAction = new QAction("发送私信", this);
  99. m_viewProfileAction = new QAction("查看资料", this);
  100. m_kickUserAction = new QAction("踢出用户", this);
  101. m_contextMenu->addAction(m_privateMessageAction);
  102. m_contextMenu->addAction(m_viewProfileAction);
  103. m_contextMenu->addSeparator();
  104. m_contextMenu->addAction(m_kickUserAction);
  105. // 连接信号
  106. connect(m_privateMessageAction, &QAction::triggered, [this]() {
  107. if (!m_selectedUserId.isEmpty()) {
  108. emit privateMessageRequested(m_selectedUserId, m_selectedUsername);
  109. }
  110. });
  111. connect(m_viewProfileAction, &QAction::triggered, [this]() {
  112. if (!m_selectedUserId.isEmpty()) {
  113. emit userProfileRequested(m_selectedUserId, m_selectedUsername);
  114. }
  115. });
  116. connect(m_kickUserAction, &QAction::triggered, [this]() {
  117. // TODO: 实现踢出用户功能
  118. qDebug() << "踢出用户:" << m_selectedUsername;
  119. });
  120. }
  121. void OnlineUsersWidget::applyStyles()
  122. {
  123. setStyleSheet(
  124. "#titleLabel {"
  125. " font-size: 14px;"
  126. " font-weight: bold;"
  127. " color: #2c3e50;"
  128. "}"
  129. "#countLabel {"
  130. " font-size: 12px;"
  131. " color: #7f8c8d;"
  132. " margin-left: 5px;"
  133. "}"
  134. "#refreshButton {"
  135. " padding: 4px 8px;"
  136. " border: 1px solid #bdc3c7;"
  137. " border-radius: 3px;"
  138. " background-color: #ecf0f1;"
  139. "}"
  140. "#refreshButton:hover {"
  141. " background-color: #d5dbdb;"
  142. "}"
  143. "#refreshButton:pressed {"
  144. " background-color: #bdc3c7;"
  145. "}"
  146. "#searchEdit {"
  147. " padding: 6px;"
  148. " border: 1px solid #bdc3c7;"
  149. " border-radius: 3px;"
  150. " font-size: 12px;"
  151. "}"
  152. "#usersTable {"
  153. " border: 1px solid #bdc3c7;"
  154. " border-radius: 3px;"
  155. " background-color: white;"
  156. " gridline-color: #ecf0f1;"
  157. "}"
  158. "#usersTable::item {"
  159. " padding: 8px;"
  160. " border-bottom: 1px solid #ecf0f1;"
  161. "}"
  162. "#usersTable::item:selected {"
  163. " background-color: #3498db;"
  164. " color: white;"
  165. "}"
  166. "#usersTable::item:hover {"
  167. " background-color: #ecf0f1;"
  168. "}"
  169. );
  170. }
  171. void OnlineUsersWidget::addUser(const OnlineUser &user)
  172. {
  173. // 检查用户是否已存在
  174. int existingRow = findUserRow(user.userId);
  175. if (existingRow >= 0) {
  176. // 更新现有用户
  177. m_users[existingRow] = user;
  178. updateTableRow(existingRow, user);
  179. return;
  180. }
  181. // 添加新用户
  182. m_users.append(user);
  183. // 如果当前有过滤条件,检查是否匹配
  184. if (!m_currentFilter.isEmpty()) {
  185. if (!user.username.contains(m_currentFilter, Qt::CaseInsensitive)) {
  186. updateUserCountLabel();
  187. return;
  188. }
  189. }
  190. // 添加到表格
  191. int row = m_usersTable->rowCount();
  192. m_usersTable->insertRow(row);
  193. updateTableRow(row, user);
  194. updateUserCountLabel();
  195. }
  196. void OnlineUsersWidget::removeUser(const QString &userId)
  197. {
  198. int row = findUserRow(userId);
  199. if (row >= 0) {
  200. m_users.removeAt(row);
  201. m_usersTable->removeRow(row);
  202. updateUserCountLabel();
  203. }
  204. }
  205. void OnlineUsersWidget::updateUserStatus(const QString &userId, const QString &status)
  206. {
  207. int userIndex = -1;
  208. for (int i = 0; i < m_users.size(); ++i) {
  209. if (m_users[i].userId == userId) {
  210. userIndex = i;
  211. break;
  212. }
  213. }
  214. if (userIndex >= 0) {
  215. m_users[userIndex].status = status;
  216. m_users[userIndex].lastSeen = QDateTime::currentDateTime();
  217. // 更新表格中对应的行
  218. int row = findUserRow(userId);
  219. if (row >= 0) {
  220. updateTableRow(row, m_users[userIndex]);
  221. }
  222. }
  223. }
  224. void OnlineUsersWidget::updateUserList(const QJsonArray &users)
  225. {
  226. clearUsers();
  227. for (const auto &value : users) {
  228. if (value.isObject()) {
  229. QJsonObject userObj = value.toObject();
  230. OnlineUser user;
  231. user.userId = userObj["id"].toString();
  232. user.username = userObj["username"].toString();
  233. user.status = userObj["status"].toString("在线");
  234. user.isAdmin = userObj["isAdmin"].toBool(false);
  235. if (userObj.contains("lastSeen")) {
  236. user.lastSeen = QDateTime::fromString(userObj["lastSeen"].toString(), Qt::ISODate);
  237. } else {
  238. user.lastSeen = QDateTime::currentDateTime();
  239. }
  240. addUser(user);
  241. }
  242. }
  243. }
  244. void OnlineUsersWidget::clearUsers()
  245. {
  246. m_users.clear();
  247. m_usersTable->setRowCount(0);
  248. updateUserCountLabel();
  249. }
  250. QList<OnlineUser> OnlineUsersWidget::getAllUsers() const
  251. {
  252. return m_users;
  253. }
  254. OnlineUser OnlineUsersWidget::getUser(const QString &userId) const
  255. {
  256. for (const auto &user : m_users) {
  257. if (user.userId == userId) {
  258. return user;
  259. }
  260. }
  261. return OnlineUser();
  262. }
  263. int OnlineUsersWidget::getUserCount() const
  264. {
  265. return m_users.size();
  266. }
  267. void OnlineUsersWidget::setSearchVisible(bool visible)
  268. {
  269. m_searchEdit->setVisible(visible);
  270. }
  271. void OnlineUsersWidget::filterUsers(const QString &keyword)
  272. {
  273. m_currentFilter = keyword;
  274. // 清空表格
  275. m_usersTable->setRowCount(0);
  276. // 重新添加匹配的用户
  277. for (const auto &user : m_users) {
  278. if (keyword.isEmpty() || user.username.contains(keyword, Qt::CaseInsensitive)) {
  279. int row = m_usersTable->rowCount();
  280. m_usersTable->insertRow(row);
  281. updateTableRow(row, user);
  282. }
  283. }
  284. updateUserCountLabel();
  285. }
  286. void OnlineUsersWidget::onTableDoubleClicked(int row, int column)
  287. {
  288. Q_UNUSED(column);
  289. if (row >= 0 && row < m_usersTable->rowCount()) {
  290. QTableWidgetItem *userItem = m_usersTable->item(row, 1); // 用户名列
  291. if (userItem) {
  292. QString username = userItem->text();
  293. // 从用户列表中找到对应的userId
  294. for (const auto &user : m_users) {
  295. if (user.username == username) {
  296. emit userDoubleClicked(user.userId, username);
  297. break;
  298. }
  299. }
  300. }
  301. }
  302. }
  303. void OnlineUsersWidget::onTableContextMenu(const QPoint &position)
  304. {
  305. QTableWidgetItem *item = m_usersTable->itemAt(position);
  306. if (!item) return;
  307. int row = item->row();
  308. QTableWidgetItem *userItem = m_usersTable->item(row, 1);
  309. if (!userItem) return;
  310. QString username = userItem->text();
  311. // 从用户列表中找到对应的userId
  312. for (const auto &user : m_users) {
  313. if (user.username == username) {
  314. m_selectedUserId = user.userId;
  315. m_selectedUsername = username;
  316. // 根据用户权限显示/隐藏菜单项
  317. m_kickUserAction->setVisible(user.isAdmin); // 示例:只有管理员能踢人
  318. QPoint globalPos = m_usersTable->mapToGlobal(position);
  319. emit userRightClicked(user.userId, username, globalPos);
  320. m_contextMenu->exec(globalPos);
  321. break;
  322. }
  323. }
  324. }
  325. void OnlineUsersWidget::onSearchTextChanged(const QString &text)
  326. {
  327. filterUsers(text);
  328. }
  329. void OnlineUsersWidget::onRefreshClicked()
  330. {
  331. // TODO: 发送刷新用户列表的请求
  332. qDebug() << "刷新用户列表";
  333. }
  334. void OnlineUsersWidget::updateUserCountLabel()
  335. {
  336. int totalUsers = m_users.size();
  337. int displayedUsers = m_usersTable->rowCount();
  338. if (m_currentFilter.isEmpty()) {
  339. m_countLabel->setText(QString("(%1)").arg(totalUsers));
  340. } else {
  341. m_countLabel->setText(QString("(%1/%2)").arg(displayedUsers).arg(totalUsers));
  342. }
  343. }
  344. void OnlineUsersWidget::updateTableRow(int row, const OnlineUser &user)
  345. {
  346. // 状态列
  347. QTableWidgetItem *statusItem = new QTableWidgetItem(getStatusIcon(user.status) + " " + user.status);
  348. statusItem->setFlags(statusItem->flags() & ~Qt::ItemIsEditable);
  349. m_usersTable->setItem(row, 0, statusItem);
  350. // 用户名列
  351. QTableWidgetItem *nameItem = new QTableWidgetItem(user.username);
  352. nameItem->setFlags(nameItem->flags() & ~Qt::ItemIsEditable);
  353. if (user.isAdmin) {
  354. nameItem->setText(user.username + " (管理员)");
  355. nameItem->setForeground(QColor("#e74c3c"));
  356. }
  357. m_usersTable->setItem(row, 1, nameItem);
  358. // 最后活动时间列
  359. QString timeText = user.lastSeen.toString("hh:mm");
  360. QTableWidgetItem *timeItem = new QTableWidgetItem(timeText);
  361. timeItem->setFlags(timeItem->flags() & ~Qt::ItemIsEditable);
  362. m_usersTable->setItem(row, 2, timeItem);
  363. }
  364. int OnlineUsersWidget::findUserRow(const QString &userId) const
  365. {
  366. for (int i = 0; i < m_users.size(); ++i) {
  367. if (m_users[i].userId == userId) {
  368. // 在表格中查找对应行
  369. for (int row = 0; row < m_usersTable->rowCount(); ++row) {
  370. QTableWidgetItem *nameItem = m_usersTable->item(row, 1);
  371. if (nameItem && nameItem->text().contains(m_users[i].username)) {
  372. return row;
  373. }
  374. }
  375. break;
  376. }
  377. }
  378. return -1;
  379. }
  380. QString OnlineUsersWidget::getStatusIcon(const QString &status) const
  381. {
  382. if (status == "在线") {
  383. return "🟢";
  384. } else if (status == "离开") {
  385. return "🟡";
  386. } else if (status == "忙碌") {
  387. return "🔴";
  388. } else {
  389. return "⚪";
  390. }
  391. }