#include "VisitorRecordTableModel.h" #include "BoostLog.h" #include "Database/Session.h" #include "DateTime.h" VisitorRecordTableModel::VisitorRecordTableModel(Session &session) : m_session(session) { Wt::Dbo::Transaction transaction(session); Wt::Dbo::collection> records = session.find(); int index = 1; std::unordered_map users; for (auto &record : records) { if (record->url.size() <= 1) continue; if (!users.contains(record->visitorUuid)) { users.insert({record->visitorUuid, std::format("匿名用户{}", index++)}); } m_records.push_back({*record, false}); std::get<0>(m_records.back()).visitorUuid = users.at(record->visitorUuid); std::get<0>(m_records.back()).id = record.id(); } } int VisitorRecordTableModel::columnCount(const Wt::WModelIndex &parent) const { return 5; } int VisitorRecordTableModel::rowCount(const Wt::WModelIndex &parent) const { return m_records.size(); } Wt::WFlags VisitorRecordTableModel::headerFlags(int section, Wt::Orientation orientation) const { if (section == 0 && orientation == Wt::Orientation::Horizontal) { return Wt::HeaderFlag::UserCheckable; } else { return Wt::None; } } Wt::cpp17::any VisitorRecordTableModel::headerData(int section, Wt::Orientation orientation, Wt::ItemDataRole role) const { if (orientation == Wt::Orientation::Horizontal) { if (role == Wt::ItemDataRole::Level) return Wt::WAbstractTableModel::headerData(section, orientation, role); if ((role == Wt::ItemDataRole::Checked || role == Wt::ItemDataRole::Edit) && section == 0) { // Assuming first column for checkbox return m_selectAll; } else if ((section == 1) && (role == Wt::ItemDataRole::Display)) { return "文章"; } else if ((section == 2) && (role == Wt::ItemDataRole::Display)) { return "时间"; } else if ((section == 3) && (role == Wt::ItemDataRole::Display)) { return "浏览器"; } else if ((section == 4) && (role == Wt::ItemDataRole::Display)) { return "用户"; } else { return Wt::cpp17::any{}; } } else { return Wt::WAbstractTableModel::headerData(section, orientation, role); } } bool VisitorRecordTableModel::setHeaderData(int section, Wt::Orientation orientation, const Wt::cpp17::any &value, Wt::ItemDataRole role) { if ((section == 0) && (role == Wt::ItemDataRole::Checked)) { m_selectAll = Wt::cpp17::any_cast(value); for (int i = 0; i < m_records.size(); i++) { std::get<1>(m_records[i]) = m_selectAll; } dataChanged().emit(index(0, 0), index(m_records.size(), 0)); return true; } else { return Wt::WAbstractTableModel::setHeaderData(section, orientation, value, role); } } void VisitorRecordTableModel::sort(int column, Wt::SortOrder order) { if (column == 2) { layoutAboutToBeChanged().emit(); std::sort(m_records.begin(), m_records.end(), [order](const VisitorRecord &lfh, const VisitorRecord &rfh) { if (order == Wt::SortOrder::Ascending) { return lfh.time < rfh.time; } else { return lfh.time > rfh.time; } }); layoutChanged().emit(); } } Wt::WFlags VisitorRecordTableModel::flags(const Wt::WModelIndex &index) const { if (index.column() == 0) { return Wt::ItemFlag::UserCheckable | Wt::ItemFlag::Selectable; } else if (index.column() == 1) { return Wt::ItemFlag::XHTMLText | Wt::ItemFlag::Selectable; } else { return Wt::ItemFlag::Selectable; } } Wt::cpp17::any VisitorRecordTableModel::data(const Wt::WModelIndex &index, Wt::ItemDataRole role) const { // 选择框 int row = index.row(); auto &record = std::get<0>(m_records.at(row)); if ((role == Wt::ItemDataRole::Checked || role == Wt::ItemDataRole::Edit) && index.column() == 0) { // Assuming first column for checkbox return std::get<1>(m_records.at(row)); } else if ((index.column() == 1) && (role == Wt::ItemDataRole::Display)) { auto pos = record.url.rfind("/"); auto name = record.url; if (pos != std::string::npos && pos < (name.size() - 1)) { name = name.substr(pos + 1); } return std::format("{}", record.url, name); } else if ((index.column() == 2) && (role == Wt::ItemDataRole::Display)) { return DateTime::toString(record.time); } else if ((index.column() == 3) && (role == Wt::ItemDataRole::Display)) { return record.userAgent; } else if ((index.column() == 4) && (role == Wt::ItemDataRole::Display)) { return record.visitorUuid; } else { return Wt::cpp17::any{}; } } bool VisitorRecordTableModel::setData(const Wt::WModelIndex &index, const Wt::cpp17::any &value, Wt::ItemDataRole role) { int row = index.row(); if ((index.column() == 0) && (role == Wt::ItemDataRole::Checked)) { std::get<1>(m_records[row]) = Wt::cpp17::any_cast(value); auto iterator = std::find_if_not(m_records.begin(), m_records.end(), [](const Item &item) { return std::get<1>(item); }); if (iterator == m_records.end()) { if (!m_selectAll) { m_selectAll = true; headerDataChanged().emit(Wt::Orientation::Horizontal, 0, 0); } } else { if (m_selectAll) { m_selectAll = false; headerDataChanged().emit(Wt::Orientation::Horizontal, 0, 0); } } return true; } else { return Wt::WAbstractTableModel::setData(index, value, role); } } std::vector VisitorRecordTableModel::selected() const { std::vector ret; for (int i = 0; i < m_records.size(); i++) { if (std::get<1>(m_records.at(i))) { ret.push_back(std::get<0>(m_records.at(i))); } } return ret; } void VisitorRecordTableModel::removeSelected() { Wt::Dbo::Transaction transaction(m_session); for (auto iterator = m_records.cbegin(); iterator != m_records.cend();) { auto selected = std::get<1>(*iterator); auto &r = std::get<0>(*iterator); if (selected) { Wt::Dbo::ptr item = m_session.find().where("id = ?").bind(r.id); item.remove(); iterator = m_records.erase(iterator); } else { ++iterator; } } }