交易记录和期权新增编辑功能

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 13:56:40 +08:00
parent b22123bdfc
commit 8b5fa347cb
4 changed files with 234 additions and 2 deletions
+36
View File
@@ -103,6 +103,42 @@ def close_trade(
return RedirectResponse("/options/", status_code=303)
@router.post("/{trade_id}/edit")
def edit_trade(
request: Request,
trade_id: int,
contract_code: str = Form(...),
option_type: str = Form(...),
direction: str = Form(...),
strike_price: float = Form(...),
open_date: str = Form(...),
open_price: float = Form(...),
open_fee: float = Form(0.0),
close_date: str = Form(""),
close_price: float = Form(None),
close_fee: float = Form(None),
db: Session = Depends(get_db),
):
t = db.query(OptionTrade).filter(OptionTrade.id == trade_id).first()
if t:
code = contract_code.upper()
contract = db.query(Contract).filter(Contract.code == code).first()
t.product_code = contract.product.code if contract else code[:2]
t.contract_code = code
t.option_type = option_type
t.direction = direction
t.strike_price = strike_price
t.open_date = date.fromisoformat(open_date)
t.open_price = open_price
t.open_fee = open_fee
if close_date and close_price is not None:
t.close_date = date.fromisoformat(close_date)
t.close_price = close_price
t.close_fee = close_fee or 0
db.commit()
return RedirectResponse("/options/", status_code=303)
@router.post("/{trade_id}/delete")
def delete_trade(trade_id: int, db: Session = Depends(get_db)):
t = db.query(OptionTrade).filter(OptionTrade.id == trade_id).first()
+32
View File
@@ -108,6 +108,38 @@ def close_trade(
return RedirectResponse("/trades/", status_code=303)
@router.post("/{trade_id}/edit")
def edit_trade(
request: Request,
trade_id: int,
contract_code: str = Form(...),
direction: str = Form(...),
open_date: str = Form(...),
open_price: float = Form(...),
open_fee: float = Form(0.0),
close_date: str = Form(""),
close_price: float = Form(None),
close_fee: float = Form(None),
db: Session = Depends(get_db),
):
t = db.query(Trade).filter(Trade.id == trade_id).first()
if t:
code = contract_code.upper()
contract = db.query(Contract).filter(Contract.code == code).first()
t.product_code = contract.product.code if contract else code[:2]
t.contract_code = code
t.direction = direction
t.open_date = date.fromisoformat(open_date)
t.open_price = open_price
t.open_fee = open_fee
if close_date and close_price is not None:
t.close_date = date.fromisoformat(close_date)
t.close_price = close_price
t.close_fee = close_fee or 0
db.commit()
return RedirectResponse("/trades/", status_code=303)
@router.post("/{trade_id}/delete")
def delete_trade(trade_id: int, db: Session = Depends(get_db)):
t = db.query(Trade).filter(Trade.id == trade_id).first()
+90 -1
View File
@@ -118,7 +118,9 @@
<td>
<button style="background:var(--accent);color:#fff;border:none;padding:3px 10px;border-radius:4px;cursor:pointer;font-size:0.78rem;"
onclick="showCloseForm({{ t.id }})">平仓</button>
<form method="post" action="/options/{{ t.id }}/delete" style="display:inline;margin-left:8px;">
<button style="background:none;border:none;color:var(--sub);cursor:pointer;font-size:0.78rem;"
onclick="showEditForm('option', {{ t.id }}, '{{ t.product_code }}', '{{ t.contract_code }}', '{{ t.option_type }}', '{{ t.direction }}', {{ t.strike_price }}, {{ t.open_price }}, {{ t.open_fee or 0 }}, '{{ t.open_date }}', null, null, null, '{{ t.status }}')">编辑</button>
<form method="post" action="/options/{{ t.id }}/delete" style="display:inline;margin-left:8px;">
<button style="background:var(--danger-bg);color:var(--danger-fg);border:1px solid var(--danger);padding:3px 10px;border-radius:4px;cursor:pointer;font-size:0.78rem;" onclick="return confirm('删除此记录?')">删除</button>
</form>
</td>
@@ -200,6 +202,8 @@
{% endif %}
</td>
<td>
<button style="background:none;border:none;color:var(--sub);cursor:pointer;font-size:0.78rem;margin-right:6px;"
onclick="showEditForm('option', {{ t.id }}, '{{ t.product_code }}', '{{ t.contract_code }}', '{{ t.option_type }}', '{{ t.direction }}', {{ t.strike_price }}, {{ t.open_price }}, {{ t.open_fee or 0 }}, '{{ t.open_date }}', {{ t.close_price }}, {{ t.close_fee or 0 }}, '{{ t.close_date }}', '{{ t.status }}')">编辑</button>
<form method="post" action="/options/{{ t.id }}/delete" style="display:inline;margin-left:8px;">
<button style="background:var(--danger-bg);color:var(--danger-fg);border:1px solid var(--danger);padding:3px 10px;border-radius:4px;cursor:pointer;font-size:0.78rem;" onclick="return confirm('删除此记录?')">删除</button>
</form>
@@ -258,6 +262,67 @@ function hideCloseForm() {
</script>
{% endif %}
<div id="editFormOverlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.35);z-index:98;" onclick="hideEditForm()"></div>
<div id="editFormBox" style="display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:24px;z-index:99;width:400px;max-width:90vw;max-height:90vh;overflow-y:auto;">
<h3 style="margin-bottom:16px;">编辑记录</h3>
<form method="post" id="editForm">
<div class="form-group">
<label>合约</label>
<input type="text" name="contract_code" id="editContract" required style="font-size:0.9rem;">
</div>
<div class="form-group">
<label>类型</label>
<select name="option_type" id="editOptionType" required>
{% for v, label in option_types %}
<option value="{{ v }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>买卖</label>
<select name="direction" id="editDirection" required>
{% for v, label in option_directions %}
<option value="{{ v }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>行权价</label>
<input type="number" step="any" name="strike_price" id="editStrike" required style="font-size:0.9rem;">
</div>
<div class="form-group">
<label>开仓日期</label>
<input type="date" name="open_date" id="editOpenDate" required style="font-size:0.85rem;">
</div>
<div class="form-group">
<label>权利金</label>
<input type="number" step="any" name="open_price" id="editOpenPrice" required style="font-size:0.9rem;">
</div>
<div class="form-group">
<label>手续费</label>
<input type="number" step="any" name="open_fee" id="editOpenFee" value="0" style="font-size:0.9rem;">
</div>
<div id="editCloseFields" style="display:none;">
<div class="form-group">
<label>平仓日期</label>
<input type="date" name="close_date" id="editCloseDate" style="font-size:0.85rem;">
</div>
<div class="form-group">
<label>平仓价格</label>
<input type="number" step="any" name="close_price" id="editClosePrice" style="font-size:0.9rem;">
</div>
<div class="form-group">
<label>手续费</label>
<input type="number" step="any" name="close_fee" id="editCloseFee" value="0" style="font-size:0.9rem;">
</div>
</div>
<div style="display:flex;gap:10px;justify-content:flex-end;">
<button type="button" class="btn" style="background:var(--th-bg);color:var(--fg);" onclick="hideEditForm()">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
<div id="pnlOverlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.35);z-index:99;" onclick="hidePnlDrawer()"></div>
<div id="pnlBox" style="display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:24px;z-index:100;width:380px;max-width:90vw;">
<h3 style="margin-bottom:4px;" id="pnlTitle"></h3>
@@ -285,6 +350,30 @@ function showPnlDrawer(title, direction, openPrice, closePrice, openFee, closeFe
document.getElementById('pnlOverlay').style.display = 'block';
document.getElementById('pnlBox').style.display = 'block';
}
function showEditForm(type, id, productCode, contractCode, optionType, direction, strike, openPrice, openFee, openDate, closePrice, closeFee, closeDate, status) {
document.getElementById('editForm').action = '/' + type + 's/' + id + '/edit';
document.getElementById('editContract').value = contractCode;
document.getElementById('editOptionType').value = optionType;
document.getElementById('editDirection').value = direction;
document.getElementById('editStrike').value = strike;
document.getElementById('editOpenDate').value = openDate;
document.getElementById('editOpenPrice').value = openPrice;
document.getElementById('editOpenFee').value = openFee || 0;
if (status === 'closed' && closeDate) {
document.getElementById('editCloseFields').style.display = 'block';
document.getElementById('editCloseDate').value = closeDate;
document.getElementById('editClosePrice').value = closePrice;
document.getElementById('editCloseFee').value = closeFee || 0;
} else {
document.getElementById('editCloseFields').style.display = 'none';
}
document.getElementById('editFormOverlay').style.display = 'block';
document.getElementById('editFormBox').style.display = 'block';
}
function hideEditForm() {
document.getElementById('editFormOverlay').style.display = 'none';
document.getElementById('editFormBox').style.display = 'none';
}
function hidePnlDrawer() {
document.getElementById('pnlOverlay').style.display = 'none';
document.getElementById('pnlBox').style.display = 'none';
+76 -1
View File
@@ -98,7 +98,9 @@
<td>
<button style="background:var(--accent);color:#fff;border:none;padding:3px 10px;border-radius:4px;cursor:pointer;font-size:0.78rem;"
onclick="showCloseForm({{ t.id }})">平仓</button>
<form method="post" action="/trades/{{ t.id }}/delete" style="display:inline;margin-left:8px;">
<button style="background:none;border:none;color:var(--sub);cursor:pointer;font-size:0.78rem;"
onclick="showEditForm('trade', {{ t.id }}, '{{ t.product_code }}', '{{ t.contract_code }}', '{{ t.direction }}', {{ t.open_price }}, {{ t.open_fee or 0 }}, '{{ t.open_date }}', null, null, null, '{{ t.status }}')">编辑</button>
<form method="post" action="/trades/{{ t.id }}/delete" style="display:inline;margin-left:8px;">
<button style="background:var(--danger-bg);color:var(--danger-fg);border:1px solid var(--danger);padding:3px 10px;border-radius:4px;cursor:pointer;font-size:0.78rem;" onclick="return confirm('删除此记录?')">删除</button>
</form>
</td>
@@ -172,6 +174,8 @@
{% endif %}
</td>
<td>
<button style="background:none;border:none;color:var(--sub);cursor:pointer;font-size:0.78rem;margin-right:6px;"
onclick="showEditForm('trade', {{ t.id }}, '{{ t.product_code }}', '{{ t.contract_code }}', '{{ t.direction }}', {{ t.open_price }}, {{ t.open_fee or 0 }}, '{{ t.open_date }}', {{ t.close_price }}, {{ t.close_fee or 0 }}, '{{ t.close_date }}', '{{ t.status }}')">编辑</button>
<form method="post" action="/trades/{{ t.id }}/delete" style="display:inline;margin-left:8px;">
<button style="background:var(--danger-bg);color:var(--danger-fg);border:1px solid var(--danger);padding:3px 10px;border-radius:4px;cursor:pointer;font-size:0.78rem;" onclick="return confirm('删除此记录?')">删除</button>
</form>
@@ -230,6 +234,55 @@ function hideCloseForm() {
</script>
{% endif %}
<div id="editFormOverlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.35);z-index:98;" onclick="hideEditForm()"></div>
<div id="editFormBox" style="display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:24px;z-index:99;width:400px;max-width:90vw;max-height:90vh;overflow-y:auto;">
<h3 style="margin-bottom:16px;">编辑记录</h3>
<form method="post" id="editForm">
<div class="form-group">
<label>合约</label>
<input type="text" name="contract_code" id="editContract" required style="font-size:0.9rem;">
</div>
<div class="form-group">
<label>方向</label>
<select name="direction" id="editDirection" required>
{% for v, label in directions %}
<option value="{{ v }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>开仓日期</label>
<input type="date" name="open_date" id="editOpenDate" required style="font-size:0.85rem;">
</div>
<div class="form-group">
<label>开仓价</label>
<input type="number" step="any" name="open_price" id="editOpenPrice" required style="font-size:0.9rem;">
</div>
<div class="form-group">
<label>开仓手续费</label>
<input type="number" step="any" name="open_fee" id="editOpenFee" value="0" style="font-size:0.9rem;">
</div>
<div id="editCloseFields" style="display:none;">
<div class="form-group">
<label>平仓日期</label>
<input type="date" name="close_date" id="editCloseDate" style="font-size:0.85rem;">
</div>
<div class="form-group">
<label>平仓价格</label>
<input type="number" step="any" name="close_price" id="editClosePrice" style="font-size:0.9rem;">
</div>
<div class="form-group">
<label>平仓手续费</label>
<input type="number" step="any" name="close_fee" id="editCloseFee" value="0" style="font-size:0.9rem;">
</div>
</div>
<div style="display:flex;gap:10px;justify-content:flex-end;">
<button type="button" class="btn" style="background:var(--th-bg);color:var(--fg);" onclick="hideEditForm()">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
<div id="pnlOverlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.35);z-index:99;" onclick="hidePnlDrawer()"></div>
<div id="pnlBox" style="display:none;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:24px;z-index:100;width:380px;max-width:90vw;">
<h3 style="margin-bottom:4px;" id="pnlTitle"></h3>
@@ -261,5 +314,27 @@ function hidePnlDrawer() {
document.getElementById('pnlOverlay').style.display = 'none';
document.getElementById('pnlBox').style.display = 'none';
}
function showEditForm(type, id, productCode, contractCode, direction, openPrice, openFee, openDate, closePrice, closeFee, closeDate, status) {
document.getElementById('editForm').action = '/' + type + 's/' + id + '/edit';
document.getElementById('editContract').value = contractCode;
document.getElementById('editDirection').value = direction;
document.getElementById('editOpenDate').value = openDate;
document.getElementById('editOpenPrice').value = openPrice;
document.getElementById('editOpenFee').value = openFee || 0;
if (status === 'closed' && closeDate) {
document.getElementById('editCloseFields').style.display = 'block';
document.getElementById('editCloseDate').value = closeDate;
document.getElementById('editClosePrice').value = closePrice;
document.getElementById('editCloseFee').value = closeFee || 0;
} else {
document.getElementById('editCloseFields').style.display = 'none';
}
document.getElementById('editFormOverlay').style.display = 'block';
document.getElementById('editFormBox').style.display = 'block';
}
function hideEditForm() {
document.getElementById('editFormOverlay').style.display = 'none';
document.getElementById('editFormBox').style.display = 'none';
}
</script>
{% endblock %}