#include "TaskPage.h" #include "Application.h" #include "BoostLog.h" #include "Database/Session.h" #include #include #include #include #include #include #include #include TaskPage::TaskPage() : Wt::WTemplate(tr("Wt.Task.Home")) { using namespace Wt; addStyleClass("bulma-is-flex-grow-1 bulma-is-flex bulma-is-flex-direction-column"); auto addButton = bindNew("add-new", "创建"); addButton->clicked().connect(this, [this]() { showAddTaskDialog(-1); }); update(); } std::unique_ptr TaskPage::createTask(const Wt::Dbo::ptr &task) { auto ret = std::make_unique(tr("Wt.Task.Item")); auto app = dynamic_cast(Wt::WApplication::instance()); if (app->inDocusaurus()) { ret->addStyleClass("li-none-style"); } ret->bindString("content", task->content); ret->bindString("remark", task->remark); ret->setHtmlTagName("li"); auto checkbox = ret->bindNew("finished-checkbox"); checkbox->setChecked(task->finished); checkbox->clicked().connect(ret.get(), [this, id = task.id(), checkbox]() { { auto session = Database::session(); Wt::Dbo::Transaction transaction(*session); Wt::Dbo::ptr task = session->find().where("id = ?").bind(id); if (task) { task.modify()->finished = checkbox->isChecked(); } } update(); }); auto addButton = ret->bindNew("add-child", tr("Wt.Icon.Add"), Wt::TextFormat::XHTML); addButton->clicked().connect(ret.get(), [id = task.id(), this]() { showAddTaskDialog(id); }); auto removeButton = ret->bindNew("remove-button", tr("Wt.Icon.Remove"), Wt::TextFormat::XHTML); removeButton->clicked().connect(ret.get(), [this, id = task.id()]() { Wt::StandardButton result = Wt::WMessageBox::show("删除任务", "是否删除任务?子任务也将一起删除", Wt::StandardButton::Ok | Wt::StandardButton::Cancel); if (result == Wt::StandardButton::Ok) { { auto session = Database::session(); Wt::Dbo::Transaction transaction(*session); Wt::Dbo::ptr task = session->find().where("id = ?").bind(id); if (task) { removeTask(task); } } update(); } }); auto collapseButton = ret->bindNew("collapse-button", tr("Wt.Icon.Expand"), Wt::TextFormat::XHTML); collapseButton->setCheckable(true); if (task->children.empty()) { ret->bindEmpty("children"); collapseButton->addStyleClass("bulma-is-invisible"); } else { auto list = ret->bindNew("children"); list->setList(true); for (auto child : task->children) { list->addWidget(createTask(child)); } collapseButton->clicked().connect(ret.get(), [collapseButton, list]() { collapseButton->setText(collapseButton->isChecked() ? tr("Wt.Icon.Fold") : tr("Wt.Icon.Expand")); if (collapseButton->isChecked()) { list->addStyleClass("bulma-is-hidden"); } else { list->removeStyleClass("bulma-is-hidden"); } }); } return ret; } class AddTaskModel : public Wt::WFormModel { public: static constexpr Field ContentField = "task-content"; static constexpr Field RemarkField = "task-remark"; AddTaskModel() : Wt::WFormModel() { addField(ContentField); addField(RemarkField); } Task task() { Task t; t.content = Wt::asString(value(ContentField)).toUTF8(); t.remark = Wt::asString(value(RemarkField)).toUTF8(); return t; } }; class AddTaskView : public Wt::WTemplateFormView { public: AddTaskView(const Wt::WString &text) : Wt::WTemplateFormView(text), m_model{std::make_shared()} { setFormWidget(AddTaskModel::ContentField, std::make_unique()); auto remark = std::make_unique(); remark->setColumns(40); remark->setRows(5); setFormWidget(AddTaskModel::RemarkField, std::move(remark)); auto button = bindWidget("submit-button", std::make_unique("确定")); button->clicked().connect(this, &AddTaskView::process); updateView(m_model.get()); } Wt::Signal &accepted() { return m_accepted; } std::unique_ptr task() const { return std::make_unique(m_model->task()); } protected: void process() { updateModel(m_model.get()); if (m_model->validate()) { m_accepted.emit(m_model->task()); // updateView(m_model.get()); } else { LOG(error) << "validate failed."; updateView(m_model.get()); } } private: Wt::Signal m_accepted; std::shared_ptr m_model; }; void TaskPage::showAddTaskDialog(int64_t parentId) { auto d = std::make_unique("添加任务"); d->setMovable(false); auto content = d->contents()->addNew(tr("Wt.Task.Add")); auto cancelButton = content->bindNew("cancel-button", "取消"); cancelButton->clicked().connect(content, [dialog = d.get()]() { dialog->reject(); }); content->accepted().connect(this, [dialog = d.get()](const Task &task) { dialog->accept(); }); auto code = d->exec(); if (code == Wt::DialogCode::Accepted) { auto task = content->task(); auto session = Database::session(); if (session) { Wt::Dbo::Transaction transaction(*session); Wt::Dbo::ptr parent; if (parentId >= 0) { parent = session->find(std::format("where id = {}", parentId)); } if (parent) { task->parent = parent; } session->add(std::move(task)); } update(); } } void TaskPage::update() { auto session = Database::session(); Wt::Dbo::Transaction transaction(*session); Tasks tasks = session->find("WHERE parent_id IS NULL"); if (tasks.empty()) { bindEmpty("tasks"); return; } else { auto list = bindNew("tasks"); list->setList(true); for (auto &task : tasks) { list->addWidget(createTask(task)); } } } void TaskPage::removeTask(Wt::Dbo::ptr task) { if (!task->children.empty()) { for (auto child : task->children) { removeTask(child); } } task.remove(); }