Modify Tx and Delete Tx
This commit is contained in:
parent
d373c36594
commit
38e2285ad3
@ -2,6 +2,16 @@
|
|||||||
<profile version="1.0">
|
<profile version="1.0">
|
||||||
<option name="myName" value="Project Default" />
|
<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="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" />
|
<inspection_tool class="HtmlUnknownTarget" enabled="true" level="WEAK WARNING" enabled_by_default="true" editorAttributes="INFO_ATTRIBUTES" />
|
||||||
</profile>
|
</profile>
|
||||||
</component>
|
</component>
|
||||||
@ -10,8 +10,12 @@
|
|||||||
<cargoProject FILE="$PROJECT_DIR$/bookkeeper/Cargo.toml" />
|
<cargoProject FILE="$PROJECT_DIR$/bookkeeper/Cargo.toml" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<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$/.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>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@ -44,30 +48,30 @@
|
|||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent"><![CDATA[{
|
<component name="PropertiesComponent">{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
"ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||||
"Cargo.Run bookkeeper.executor": "Run",
|
"Cargo.Run bookkeeper.executor": "Run",
|
||||||
"DefaultHtmlFileTemplate": "HTML File",
|
"DefaultHtmlFileTemplate": "HTML File",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"RunOnceActivity.git.unshallow": "true",
|
"RunOnceActivity.git.unshallow": "true",
|
||||||
"RunOnceActivity.rust.reset.selective.auto.import": "true",
|
"RunOnceActivity.rust.reset.selective.auto.import": "true",
|
||||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||||
"git-widget-placeholder": "main",
|
"git-widget-placeholder": "main",
|
||||||
"last_opened_file_path": "D:/code/finance-consumer/bookkeeper/templates",
|
"last_opened_file_path": "D:/code/finance-consumer/bookkeeper/templates",
|
||||||
"node.js.detected.package.eslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"nodejs_package_manager_path": "npm",
|
"nodejs_package_manager_path": "npm",
|
||||||
"org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
|
"org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
|
||||||
"org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon": "",
|
"org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon": "",
|
||||||
"org.rust.first.attach.projects": "true",
|
"org.rust.first.attach.projects": "true",
|
||||||
"run.code.analysis.last.selected.profile": "pProject Default",
|
"run.code.analysis.last.selected.profile": "pProject Default",
|
||||||
"settings.editor.selected.configurable": "preferences.pluginManager",
|
"settings.editor.selected.configurable": "preferences.pluginManager",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}]]></component>
|
}</component>
|
||||||
<component name="RecentsManager">
|
<component name="RecentsManager">
|
||||||
<key name="CopyFile.RECENT_KEYS">
|
<key name="CopyFile.RECENT_KEYS">
|
||||||
<recent name="D:\code\finance-consumer\bookkeeper\templates" />
|
<recent name="D:\code\finance-consumer\bookkeeper\templates" />
|
||||||
@ -146,7 +150,8 @@
|
|||||||
<workItem from="1735391132866" duration="1139000" />
|
<workItem from="1735391132866" duration="1139000" />
|
||||||
<workItem from="1735392290940" duration="620000" />
|
<workItem from="1735392290940" duration="620000" />
|
||||||
<workItem from="1735392928494" duration="12910000" />
|
<workItem from="1735392928494" duration="12910000" />
|
||||||
<workItem from="1735470376833" duration="15948000" />
|
<workItem from="1735470376833" duration="16014000" />
|
||||||
|
<workItem from="1735553493290" duration="4033000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="Add bookkeeper">
|
<task id="LOCAL-00001" summary="Add bookkeeper">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@ -196,7 +201,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1735486473481</updated>
|
<updated>1735486473481</updated>
|
||||||
</task>
|
</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 />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@ -220,7 +233,8 @@
|
|||||||
<MESSAGE value="Add index page" />
|
<MESSAGE value="Add index page" />
|
||||||
<MESSAGE value="Refine data structure and index page" />
|
<MESSAGE value="Refine data structure and index page" />
|
||||||
<MESSAGE value="Implement add transaction" />
|
<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>
|
||||||
<component name="XSLT-Support.FileAssociations.UIState">
|
<component name="XSLT-Support.FileAssociations.UIState">
|
||||||
<expand />
|
<expand />
|
||||||
|
|||||||
@ -19,6 +19,7 @@ use sea_orm::{ActiveModelTrait, ColumnTrait, ConnectOptions, DatabaseConnection,
|
|||||||
use sea_orm_rocket::{rocket::figment::Figment, Config, Connection, Database};
|
use sea_orm_rocket::{rocket::figment::Figment, Config, Connection, Database};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use rocket::http::Status;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(sea_orm_rocket::Database, Debug)]
|
#[derive(sea_orm_rocket::Database, Debug)]
|
||||||
@ -98,6 +99,49 @@ struct SplitPiece{
|
|||||||
volume: i32,
|
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")]
|
#[get("/add")]
|
||||||
async fn get_add() -> Template {
|
async fn get_add() -> Template {
|
||||||
Template::render("tx", context! {
|
Template::render("tx", context! {
|
||||||
@ -108,7 +152,6 @@ async fn get_add() -> Template {
|
|||||||
|
|
||||||
#[post("/add", data = "<trans>")]
|
#[post("/add", data = "<trans>")]
|
||||||
async fn add(trans: Form<TransModel<'_>>, conn: Connection<'_, Db>) -> Flash<Redirect> {
|
async fn add(trans: Form<TransModel<'_>>, conn: Connection<'_, Db>) -> Flash<Redirect> {
|
||||||
dbg!(&trans);
|
|
||||||
let record = translate(trans);
|
let record = translate(trans);
|
||||||
|
|
||||||
record.insert(conn.into_inner()).await.unwrap();
|
record.insert(conn.into_inner()).await.unwrap();
|
||||||
@ -174,5 +217,5 @@ async fn rocket() -> _ {
|
|||||||
.attach(Db::init())
|
.attach(Db::init())
|
||||||
.attach(AdHoc::try_on_ignite("Migrations", run_migrations))
|
.attach(AdHoc::try_on_ignite("Migrations", run_migrations))
|
||||||
.attach(Template::fairing())
|
.attach(Template::fairing())
|
||||||
.mount("/", routes![index, add, get_add])
|
.mount("/", routes![index, add, get_add, get_tx, post_tx, delete_tx])
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.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;" 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;">
|
<td rowspan="{{ loop.length }}" style="vertical-align: middle;">
|
||||||
<a href="#">修改</a>
|
<a row-id="{{ r.id }}" class="modify-row">改</a> <a row-id="{{ r.id }}" class="delete-row has-text-danger">删</a>
|
||||||
</td>
|
</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td>{{ p.date or "" }}</td>
|
<td>{{ p.date or "" }}</td>
|
||||||
@ -63,7 +63,8 @@
|
|||||||
<td></td>
|
<td></td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
<td>-</td>
|
<td>-</td>
|
||||||
<td><a href="#">修改</a></td>
|
<td><a row-id="{{ r.id }}" class="modify-row">改</a> <a row-id="{{ r.id }}" class="delete-row has-text-danger">删</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -109,6 +110,33 @@
|
|||||||
openModal($target);
|
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
|
// 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) => {
|
(document.querySelectorAll('.modal-background, .modal-close, .modal-card-head .delete, .modal-card-foot .button') || []).forEach(($close) => {
|
||||||
const $target = $close.closest('.modal');
|
const $target = $close.closest('.modal');
|
||||||
@ -148,6 +176,8 @@
|
|||||||
this_row.parentElement.removeChild(this_row);
|
this_row.parentElement.removeChild(this_row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock container %}
|
{% endblock container %}
|
||||||
|
|||||||
@ -34,30 +34,32 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<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><label class="label">实际买入</label></th>
|
<th><label class="label">实际卖出入</label></th>
|
||||||
<th style="min-width: 4rem; vertical-align: middle;">操作</th>
|
<th style="min-width: 4rem; vertical-align: middle;">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
{% if r.split_pieces %}
|
||||||
|
{% for split in r.split_pieces %}
|
||||||
<tr>
|
<tr>
|
||||||
{% if r.split_pieces %}
|
<td><input name="split_pieces[{{ loop.index0 }}].date" class="input" type="date" placeholder="YYYY-MM-DD" value="{{ split.date or '' }}"></td>
|
||||||
{% for split in r.split_pieces %}
|
<td><input name="split_pieces[{{ loop.index0 }}].sell" class="input" type="number" placeholder="Sell" value="{{ split.sell or '' }}"></td>
|
||||||
<td><input name="split_pieces[].date" class="input" type="date" placeholder="YYYY-MM-DD" value="{{ split.date 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[].sell" class="input" type="number" placeholder="Sell" value="{{ split.sell 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><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><a onclick="deleteRow(this)">删除</a></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>
|
</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">
|
<tr class="is-light" id="add-row-line">
|
||||||
<td colspan="5" style="text-align: center"><a onclick="addRow()">添加</a></td>
|
<td colspan="5" style="text-align: center"><a onclick="addRow()">添加</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -67,9 +69,6 @@
|
|||||||
<div class="control">
|
<div class="control">
|
||||||
<button class="button is-link">Submit</button>
|
<button class="button is-link">Submit</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
|
||||||
<button class="button is-link is-light">Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user