onlineuserswidget.cpp 14 KB

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