Modify Tx and Delete Tx

This commit is contained in:
wjsjwr 2024-12-30 20:42:24 +08:00
parent d373c36594
commit 38e2285ad3
5 changed files with 146 additions and 50 deletions

View File

@ -2,6 +2,16 @@
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="HtmlFormInputWithoutLabel" enabled="true" level="WEAK WARNING" enabled_by_default="true" editorAttributes="INFO_ATTRIBUTES" />
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="row-id" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
<inspection_tool class="HtmlUnknownTarget" enabled="true" level="WEAK WARNING" enabled_by_default="true" editorAttributes="INFO_ATTRIBUTES" />
</profile>
</component>

View File

@ -10,8 +10,12 @@
<cargoProject FILE="$PROJECT_DIR$/bookkeeper/Cargo.toml" />
</component>
<component name="ChangeListManager">
<list default="true" id="76b3b902-7a5c-4bcd-9c1b-8241d748fb44" name="更改" comment="Implement add transaction">
<list default="true" id="76b3b902-7a5c-4bcd-9c1b-8241d748fb44" name="更改" comment="Update some settings">
<change beforePath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/bookkeeper/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/bookkeeper/src/main.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/bookkeeper/templates/index.html.j2" beforeDir="false" afterPath="$PROJECT_DIR$/bookkeeper/templates/index.html.j2" afterDir="false" />
<change beforePath="$PROJECT_DIR$/bookkeeper/templates/tx.html.j2" beforeDir="false" afterPath="$PROJECT_DIR$/bookkeeper/templates/tx.html.j2" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -44,30 +48,30 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
"Cargo.Run bookkeeper.executor": "Run",
"DefaultHtmlFileTemplate": "HTML File",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"RunOnceActivity.rust.reset.selective.auto.import": "true",
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
"git-widget-placeholder": "main",
"last_opened_file_path": "D:/code/finance-consumer/bookkeeper/templates",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
"org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon": "",
"org.rust.first.attach.projects": "true",
"run.code.analysis.last.selected.profile": "pProject Default",
"settings.editor.selected.configurable": "preferences.pluginManager",
"vue.rearranger.settings.migration": "true"
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;ASKED_SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
&quot;Cargo.Run bookkeeper.executor&quot;: &quot;Run&quot;,
&quot;DefaultHtmlFileTemplate&quot;: &quot;HTML File&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;RunOnceActivity.rust.reset.selective.auto.import&quot;: &quot;true&quot;,
&quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;main&quot;,
&quot;last_opened_file_path&quot;: &quot;D:/code/finance-consumer/bookkeeper/templates&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;org.rust.cargo.project.model.PROJECT_DISCOVERY&quot;: &quot;true&quot;,
&quot;org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon&quot;: &quot;&quot;,
&quot;org.rust.first.attach.projects&quot;: &quot;true&quot;,
&quot;run.code.analysis.last.selected.profile&quot;: &quot;pProject Default&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}]]></component>
}</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="D:\code\finance-consumer\bookkeeper\templates" />
@ -146,7 +150,8 @@
<workItem from="1735391132866" duration="1139000" />
<workItem from="1735392290940" duration="620000" />
<workItem from="1735392928494" duration="12910000" />
<workItem from="1735470376833" duration="15948000" />
<workItem from="1735470376833" duration="16014000" />
<workItem from="1735553493290" duration="4033000" />
</task>
<task id="LOCAL-00001" summary="Add bookkeeper">
<option name="closed" value="true" />
@ -196,7 +201,15 @@
<option name="project" value="LOCAL" />
<updated>1735486473481</updated>
</task>
<option name="localTasksCounter" value="7" />
<task id="LOCAL-00007" summary="Update some settings">
<option name="closed" value="true" />
<created>1735486582714</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1735486582714</updated>
</task>
<option name="localTasksCounter" value="8" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -220,7 +233,8 @@
<MESSAGE value="Add index page" />
<MESSAGE value="Refine data structure and index page" />
<MESSAGE value="Implement add transaction" />
<option name="LAST_COMMIT_MESSAGE" value="Implement add transaction" />
<MESSAGE value="Update some settings" />
<option name="LAST_COMMIT_MESSAGE" value="Update some settings" />
</component>
<component name="XSLT-Support.FileAssociations.UIState">
<expand />

View File

@ -19,6 +19,7 @@ use sea_orm::{ActiveModelTrait, ColumnTrait, ConnectOptions, DatabaseConnection,
use sea_orm_rocket::{rocket::figment::Figment, Config, Connection, Database};
use std::str::FromStr;
use std::time::Duration;
use rocket::http::Status;
use serde::{Deserialize, Serialize};
#[derive(sea_orm_rocket::Database, Debug)]
@ -98,6 +99,49 @@ struct SplitPiece{
volume: i32,
}
#[get("/tx/<id>")]
async fn get_tx(conn: Connection<'_, Db>, id: i32) -> Result<Template, Status> {
let row = TE::find_by_id(id)
.one(conn.into_inner())
.await
.unwrap();
match row {
None => { Err(Status::NotFound) },
Some(row) => {
Ok(Template::render("tx", context! {
r: row,
target: "/tx/".to_owned() + id.to_string().as_str(),
}))
}
}
}
#[post("/tx/<id>", data = "<data>")]
async fn post_tx(data: Form<TransModel<'_>>, conn: Connection<'_, Db>, id: i32) -> Result<Redirect, Status> {
dbg!(&data);
let mut record = translate(data);
record.id = Set(id);
dbg!(&record);
match record.update(conn.into_inner()).await {
Err(_) => { Err(Status::NotFound) },
Ok(_) => { Ok(Redirect::to("/")) },
}
}
#[delete("/tx/<id>")]
async fn delete_tx(conn: Connection<'_, Db>, id: i32) -> Result<Redirect, Status> {
match TE::delete_by_id(id).exec(conn.into_inner()).await {
Err(_) => { Err(Status::InternalServerError) },
Ok(res) => {
if res.rows_affected == 1 {
Ok(Redirect::to("/"))
} else {
Err(Status::NotFound)
}
}
}
}
#[get("/add")]
async fn get_add() -> Template {
Template::render("tx", context! {
@ -108,7 +152,6 @@ async fn get_add() -> Template {
#[post("/add", data = "<trans>")]
async fn add(trans: Form<TransModel<'_>>, conn: Connection<'_, Db>) -> Flash<Redirect> {
dbg!(&trans);
let record = translate(trans);
record.insert(conn.into_inner()).await.unwrap();
@ -174,5 +217,5 @@ async fn rocket() -> _ {
.attach(Db::init())
.attach(AdHoc::try_on_ignite("Migrations", run_migrations))
.attach(Template::fairing())
.mount("/", routes![index, add, get_add])
.mount("/", routes![index, add, get_add, get_tx, post_tx, delete_tx])
}

View File

@ -39,7 +39,7 @@
<td rowspan="{{ loop.length }}" style="vertical-align: middle;" class="{% if r.gain|float > 0 %}is-success{% else %}is-danger{% endif %}">{{ (r.gain or 0)|float|round(4) }}%</td>
<td rowspan="{{ loop.length }}" style="vertical-align: middle;" class="{% if r.net_gain|float > 0 %}is-success{% else %}is-danger{% endif %}">{{ (r.net_gain or 0)|float|round(4) }}%</td>
<td rowspan="{{ loop.length }}" style="vertical-align: middle;">
<a href="#">修改</a>
<a row-id="{{ r.id }}" class="modify-row">改</a>&nbsp;<a row-id="{{ r.id }}" class="delete-row has-text-danger">删</a>
</td>
{% else %}
<td>{{ p.date or "" }}</td>
@ -63,7 +63,8 @@
<td></td>
<td>-</td>
<td>-</td>
<td><a href="#">修改</a></td>
<td><a row-id="{{ r.id }}" class="modify-row">改</a>&nbsp;<a row-id="{{ r.id }}" class="delete-row has-text-danger">删</a>
</td>
</tr>
{% endif %}
{% endfor %}
@ -109,6 +110,33 @@
openModal($target);
});
(document.querySelectorAll('.modify-row') || []).forEach(($cl) => {
$cl.addEventListener('click', async () => {
const rowId = $cl.attributes.getNamedItem("row-id").value;
const $target = document.getElementById("modal");
const response = await fetch(`/tx/${rowId}`);
if (!response.ok) {
return;
}
document.getElementById('modal-content').innerHTML = await response.text();
openModal($target);
});
});
(document.querySelectorAll('.delete-row') || []).forEach(($cl) => {
$cl.addEventListener('click', async () => {
const rowId = $cl.attributes.getNamedItem("row-id").value;
if (confirm(`删除${$cl.parentElement.parentElement.innerText}吗?`) !== true) {
return;
}
const response = await fetch(`/tx/${rowId}`, {method: 'DELETE'});
alert(`${response.ok ? "OK" : "Fail"}: ${response.status}`);
if (response.ok) {
$cl.parentElement.parentElement.remove();
}
});
});
// Add a click event on various child elements to close the parent modal
(document.querySelectorAll('.modal-background, .modal-close, .modal-card-head .delete, .modal-card-foot .button') || []).forEach(($close) => {
const $target = $close.closest('.modal');
@ -148,6 +176,8 @@
this_row.parentElement.removeChild(this_row);
}
}
</script>
{% endblock container %}

View File

@ -34,30 +34,32 @@
<thead>
<tr>
<th><label class="label">卖出日期</label></th>
<th><label class="label">买入价</label></th>
<th><label class="label">卖出价</label></th>
<th><label class="label">成交量</label></th>
<th><label class="label">实际入</label></th>
<th><label class="label">实际卖出入</label></th>
<th style="min-width: 4rem; vertical-align: middle;">操作</th>
</tr>
</thead>
<tbody>
{% if r.split_pieces %}
{% for split in r.split_pieces %}
<tr>
{% if r.split_pieces %}
{% for split in r.split_pieces %}
<td><input name="split_pieces[].date" class="input" type="date" placeholder="YYYY-MM-DD" value="{{ split.date or '' }}"></td>
<td><input name="split_pieces[].sell" class="input" type="number" placeholder="Sell" value="{{ split.sell or '' }}"></td>
<td><input name="split_pieces[].volume" class="input" type="number" placeholder="Volume" value="{{ split.volume or '' }}"></td>
<td><input name="split_pieces[].net_sell" class="input" type="number" placeholder="Net Sell" value="{{ split.net_sell or '' }}"></td>
<td><input name="split_pieces[{{ loop.index0 }}].date" class="input" type="date" placeholder="YYYY-MM-DD" value="{{ split.date or '' }}"></td>
<td><input name="split_pieces[{{ loop.index0 }}].sell" class="input" type="number" placeholder="Sell" value="{{ split.sell or '' }}"></td>
<td><input name="split_pieces[{{ loop.index0 }}].volume" class="input" type="number" placeholder="Volume" value="{{ split.volume or '' }}"></td>
<td><input name="split_pieces[{{ loop.index0 }}].net_sell" class="input" type="number" placeholder="Net Sell" value="{{ split.net_sell or '' }}"></td>
<td><a onclick="deleteRow(this)">删除</a></td>
{% endfor %}
{% else %}
<td><input name="split_pieces[0].date" class="input" type="date" placeholder="YYYY-MM-DD"></td>
<td><input name="split_pieces[0].sell" class="input" type="number" placeholder="Sell"></td>
<td><input name="split_pieces[0].volume" class="input" type="number" placeholder="Volume"></td>
<td><input name="split_pieces[0].net_sell" class="input" type="number" placeholder="Net Sell"></td>
<td style="vertical-align: middle;"><a onclick="deleteRow(this)">删除</a></td>
{% endif %}
</tr>
{% endfor %}
{% else %}
<tr>
<td><input name="split_pieces[0].date" class="input" type="date" placeholder="YYYY-MM-DD"></td>
<td><input name="split_pieces[0].sell" class="input" type="number" placeholder="Sell"></td>
<td><input name="split_pieces[0].volume" class="input" type="number" placeholder="Volume"></td>
<td><input name="split_pieces[0].net_sell" class="input" type="number" placeholder="Net Sell"></td>
<td style="vertical-align: middle;"><a onclick="deleteRow(this)">删除</a></td>
</tr>
{% endif %}
<tr class="is-light" id="add-row-line">
<td colspan="5" style="text-align: center"><a onclick="addRow()">添加</a></td>
</tr>
@ -67,9 +69,6 @@
<div class="control">
<button class="button is-link">Submit</button>
</div>
<div class="control">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>