#include "VisitorRecordTableModel.h" #include "BoostLog.h" #include "Database/Session.h" #include "DateTime.h" VisitorRecordTableModel::VisitorRecordTableModel(Session &session) : m_session(session) { filter(""); } 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 Item &lfh, const Item &rfh) { if (order == Wt::SortOrder::Ascending) { return std::get<0>(lfh).time < std::get<0>(rfh).time; } else { return std::get<0>(lfh).time > std::get<0>(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); } } Wt::WModelIndexSet VisitorRecordTableModel::selectedIndexes() const { Wt::WModelIndexSet ret; for (int i = 0; i < m_records.size(); i++) { if (std::get<1>(m_records.at(i))) { ret.insert(index(i, 0)); } } return ret; } void VisitorRecordTableModel::filter(const std::string &search) { layoutAboutToBeChanged().emit(); m_records.clear(); Wt::Dbo::Transaction transaction(m_session); VisitorRecords records = m_session.find().where(std::format("url LIKE '%{}%'", search)); 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(); } layoutChanged().emit(); } bool VisitorRecordTableModel::removeSelectedRows(const Wt::WModelIndexSet &indexes) { Wt::Dbo::Transaction transaction(m_session); layoutAboutToBeChanged().emit(); std::vector ids; for (auto &index : indexes) { auto &r = std::get<0>(m_records.at(index.row())); ids.push_back(r.id); Wt::Dbo::ptr item = m_session.find().where("id = ?").bind(r.id); item.remove(); } for (auto id : ids) { std::erase_if(m_records, [id](const Item &item) { return std::get<0>(item).id == id; }); } layoutChanged().emit(); return true; } bool VisitorRecordTableModel::removeRows(int row, int count, const Wt::WModelIndex &parent) { if ((row + count) > m_records.size()) { return false; } Wt::Dbo::Transaction transaction(m_session); beginRemoveRows(parent, row, row + count - 1); for (int i = row; i < (row + count); ++i) { auto &r = std::get<0>(m_records.at(i)); Wt::Dbo::ptr item = m_session.find().where("id = ?").bind(r.id); item.remove(); } m_records.erase(m_records.cbegin() + row, m_records.cbegin() + row + count); endRemoveRows(); return true; }