Compare commits

..
5 Commits
4 changed files with 44 additions and 36 deletions

No files matched your search

+10 -8
View File
@@ -616,12 +616,14 @@ def dashboard(request: Request, user: User = Depends(get_current_user_web), db:
sent_country_counts: dict[str, int] = {} sent_country_counts: dict[str, int] = {}
received_country_counts: dict[str, int] = {} received_country_counts: dict[str, int] = {}
for c in all_cards: for c in all_cards:
if c.status in ("pending", "sent", "delivered"):
if not c.country_to: if not c.country_to:
continue continue
if c.status in ("pending", "sent", "delivered"):
sent_country_counts[c.country_to] = sent_country_counts.get(c.country_to, 0) + 1 sent_country_counts[c.country_to] = sent_country_counts.get(c.country_to, 0) + 1
elif c.status == "received": elif c.status == "received":
received_country_counts[c.country_to] = received_country_counts.get(c.country_to, 0) + 1 if not c.country_from:
continue
received_country_counts[c.country_from] = received_country_counts.get(c.country_from, 0) + 1
sent_country_stats = sorted(sent_country_counts.items(), key=lambda x: -x[1]) sent_country_stats = sorted(sent_country_counts.items(), key=lambda x: -x[1])
received_country_stats = sorted(received_country_counts.items(), key=lambda x: -x[1]) received_country_stats = sorted(received_country_counts.items(), key=lambda x: -x[1])
@@ -898,7 +900,7 @@ def postcard_delete(postcard_id: int, user: User = Depends(get_current_user_web)
@router.post("/postcards/{postcard_id}/mark-delivered") @router.post("/postcards/{postcard_id}/mark-delivered")
def mark_delivered( async def mark_delivered(
postcard_id: int, postcard_id: int,
user: User = Depends(get_current_user_web), user: User = Depends(get_current_user_web),
db: Session = Depends(get_db), db: Session = Depends(get_db),
@@ -910,16 +912,16 @@ def mark_delivered(
.first() .first()
) )
if not pc: if not pc:
return _redirect("/profiles") return JSONResponse({"ok": False}, status_code=404)
pc.status = "delivered" pc.status = "delivered"
if not pc.arrival_time: if not pc.arrival_time:
pc.arrival_time = datetime.now() pc.arrival_time = datetime.now()
db.commit() db.commit()
return _redirect(f"/postcards/{postcard_id}") return JSONResponse({"ok": True})
@router.post("/postcards/{postcard_id}/mark-sent") @router.post("/postcards/{postcard_id}/mark-sent")
def mark_sent( async def mark_sent(
postcard_id: int, postcard_id: int,
user: User = Depends(get_current_user_web), user: User = Depends(get_current_user_web),
db: Session = Depends(get_db), db: Session = Depends(get_db),
@@ -932,12 +934,12 @@ def mark_sent(
.first() .first()
) )
if not pc: if not pc:
return _redirect("/profiles") return JSONResponse({"ok": False}, status_code=404)
pc.status = "sent" pc.status = "sent"
if not pc.send_time: if not pc.send_time:
pc.send_time = datetime.now() pc.send_time = datetime.now()
db.commit() db.commit()
return _redirect(f"/postcards/{postcard_id}") return JSONResponse({"ok": True})
# ---------- Image Upload ---------- # ---------- Image Upload ----------
+2 -6
View File
@@ -10,13 +10,9 @@
<div class="detail-actions"> <div class="detail-actions">
<a href="/postcards/{{ postcard.id }}/edit" class="btn">{{ 'pc_detail.edit'|t(user.language) }}</a> <a href="/postcards/{{ postcard.id }}/edit" class="btn">{{ 'pc_detail.edit'|t(user.language) }}</a>
{% if postcard.status == 'pending' %} {% if postcard.status == 'pending' %}
<form method="post" action="/postcards/{{ postcard.id }}/mark-sent" class="inline"> <button type="button" class="btn btn-primary" onclick="if(confirm('{{ 'pc_detail.confirm_sent'|t(user.language) }}'))fetch('/postcards/{{ postcard.id }}/mark-sent',{method:'POST'}).then(function(){location.reload();})">{{ 'pc_detail.mark_sent'|t(user.language) }}</button>
<button type="submit" class="btn btn-primary" onclick="return confirm('{{ 'pc_detail.confirm_sent'|t(user.language) }}')">{{ 'pc_detail.mark_sent'|t(user.language) }}</button>
</form>
{% elif postcard.status == 'sent' %} {% elif postcard.status == 'sent' %}
<form method="post" action="/postcards/{{ postcard.id }}/mark-delivered" class="inline"> <button type="button" class="btn btn-primary" onclick="if(confirm('{{ 'pc_detail.confirm_delivered'|t(user.language) }}'))fetch('/postcards/{{ postcard.id }}/mark-delivered',{method:'POST'}).then(function(){location.reload();})">{{ 'pc_detail.mark_delivered'|t(user.language) }}</button>
<button type="submit" class="btn btn-primary" onclick="return confirm('{{ 'pc_detail.confirm_delivered'|t(user.language) }}')">{{ 'pc_detail.mark_delivered'|t(user.language) }}</button>
</form>
{% endif %} {% endif %}
<form method="post" action="/postcards/{{ postcard.id }}/delete" class="inline"> <form method="post" action="/postcards/{{ postcard.id }}/delete" class="inline">
<button type="submit" class="btn btn-danger" onclick="return confirm('{{ 'pc_detail.confirm_delete'|t(user.language) }}')">{{ 'pc_detail.delete'|t(user.language) }}</button> <button type="submit" class="btn btn-danger" onclick="return confirm('{{ 'pc_detail.confirm_delete'|t(user.language) }}')">{{ 'pc_detail.delete'|t(user.language) }}</button>
+29 -15
View File
@@ -23,6 +23,9 @@
<label>{{ 'pc_form.sender'|t(user.language) }} *</label> <label>{{ 'pc_form.sender'|t(user.language) }} *</label>
<input type="text" name="sender_name" value="{{ postcard.sender_name if is_edit else '' }}"> <input type="text" name="sender_name" value="{{ postcard.sender_name if is_edit else '' }}">
<label>{{ 'pc_form.send_time'|t(user.language) }}</label>
<input type="date" name="send_time" value="{{ postcard.send_time.strftime('%Y-%m-%d') if is_edit and postcard.send_time else '' }}">
<label>{{ 'pc_form.receive_time'|t(user.language) }} *</label> <label>{{ 'pc_form.receive_time'|t(user.language) }} *</label>
<input type="date" name="receive_time" value="{{ postcard.receive_time.strftime('%Y-%m-%d') if is_edit and postcard.receive_time else today }}"> <input type="date" name="receive_time" value="{{ postcard.receive_time.strftime('%Y-%m-%d') if is_edit and postcard.receive_time else today }}">
@@ -55,7 +58,7 @@
<div id="fields-sent-delivered"> <div id="fields-sent-delivered">
<label>{{ 'pc_form.recipient'|t(user.language) }} *</label> <label>{{ 'pc_form.recipient'|t(user.language) }} *</label>
<input type="text" name="recipient_name" value="{{ postcard.recipient_name if is_edit else '' }}"> <input type="text" name="recipient_name" value="{{ postcard.recipient_name if is_edit else '' }}">
<label>{{ 'pc_form.send_time'|t(user.language) }} *</label> <label id="label-send-time">{{ 'pc_form.send_time'|t(user.language) }} *</label>
<input type="date" name="send_time" id="input-send-time" value="{{ postcard.send_time.strftime('%Y-%m-%d') if is_edit and postcard.send_time else (today if is_new else '') }}"> <input type="date" name="send_time" id="input-send-time" value="{{ postcard.send_time.strftime('%Y-%m-%d') if is_edit and postcard.send_time else (today if is_new else '') }}">
<label id="label-arrival">{{ 'pc_form.arrival_time'|t(user.language) }}</label> <label id="label-arrival">{{ 'pc_form.arrival_time'|t(user.language) }}</label>
<input type="date" name="arrival_time" id="input-arrival" value="{{ postcard.arrival_time.strftime('%Y-%m-%d') if is_edit and postcard.arrival_time else '' }}" {% if is_new or (is_edit and edit_status=='sent') %}disabled{% endif %}> <input type="date" name="arrival_time" id="input-arrival" value="{{ postcard.arrival_time.strftime('%Y-%m-%d') if is_edit and postcard.arrival_time else '' }}" {% if is_new or (is_edit and edit_status=='sent') %}disabled{% endif %}>
@@ -79,21 +82,25 @@
</form> </form>
<script> <script>
{% if is_new and not is_received_form %} {% if is_new and not is_received_form %}
// ── 新建寄出:根据日期自动判定状态,可手动覆盖 ── // ── 新建寄出:待寄出时禁用寄出时间,寄出时自动填入 ──
(function() { (function() {
var sendTime = document.getElementById('input-send-time'); var sendTime = document.getElementById('input-send-time');
var select = document.getElementById('status-select'); var select = document.getElementById('status-select');
var arrival = document.getElementById('input-arrival'); var arrival = document.getElementById('input-arrival');
var labelArrival = document.getElementById('label-arrival'); var labelArrival = document.getElementById('label-arrival');
var labelSend = document.getElementById('label-send-time');
var today = new Date().toISOString().slice(0, 10); var today = new Date().toISOString().slice(0, 10);
function updateSendTime(s) {
if (s === 'pending') {
sendTime.disabled = true;
sendTime.value = '';
if (labelSend) labelSend.textContent = '{{ "pc_form.send_time"|t(user.language) }}';
} else {
sendTime.disabled = false;
if (!sendTime.value) sendTime.value = today; if (!sendTime.value) sendTime.value = today;
if (labelSend) labelSend.textContent = '{{ "pc_form.send_time"|t(user.language) }} *';
var userOverrode = false; }
function autoFromSendTime() {
var v = sendTime.value;
if (!v) return 'sent';
return v > today ? 'pending' : 'sent';
} }
function updateArrival(s) { function updateArrival(s) {
@@ -109,22 +116,29 @@
} }
function sync() { function sync() {
var auto = autoFromSendTime();
if (!userOverrode) select.value = auto;
updateArrival(select.value); updateArrival(select.value);
updateSendTime(select.value);
} }
select.addEventListener('change', function() { userOverrode = true; updateArrival(select.value); }); select.addEventListener('change', sync);
sendTime.addEventListener('change', function() { if (!userOverrode) sync(); });
sendTime.addEventListener('input', function() { if (!userOverrode) sync(); });
sync(); sync();
})(); })();
{% elif is_edit and not is_received_form %} {% elif is_edit and not is_received_form %}
// ── 编辑寄出:根据状态切换 arrival 可用性 ── // ── 编辑寄出:根据状态切换 send_time / arrival 可用性 ──
function toggleFields() { function toggleFields() {
var s = document.getElementById('status-select').value; var s = document.getElementById('status-select').value;
var sendTime = document.getElementById('input-send-time');
var labelSend = document.getElementById('label-send-time');
var arrival = document.getElementById('input-arrival'); var arrival = document.getElementById('input-arrival');
var labelArrival = document.getElementById('label-arrival'); var labelArrival = document.getElementById('label-arrival');
var today = new Date().toISOString().slice(0, 10);
if (s === 'pending') {
sendTime.disabled = true;
if (labelSend) labelSend.textContent = '{{ "pc_form.send_time"|t(user.language) }}';
} else {
sendTime.disabled = false;
if (labelSend) labelSend.textContent = '{{ "pc_form.send_time"|t(user.language) }} *';
}
if (s === 'delivered') { if (s === 'delivered') {
arrival.disabled = false; arrival.disabled = false;
labelArrival.textContent = '{{ "pc_form.arrival_time"|t(user.language) }} *'; labelArrival.textContent = '{{ "pc_form.arrival_time"|t(user.language) }} *';
+2 -6
View File
@@ -56,13 +56,9 @@
{% if pc.notes %}<span class="postcard-row-notes">{{ pc.notes[:50] }}{% if pc.notes|length > 50 %}…{% endif %}</span>{% endif %} {% if pc.notes %}<span class="postcard-row-notes">{{ pc.notes[:50] }}{% if pc.notes|length > 50 %}…{% endif %}</span>{% endif %}
<div class="postcard-row-action"> <div class="postcard-row-action">
{% if pc.status == 'pending' %} {% if pc.status == 'pending' %}
<form method="post" action="/postcards/{{ pc.id }}/mark-sent" onclick="event.preventDefault();event.stopPropagation();if(confirm('{{ 'pc_list.confirm_sent'|t(user.language) }}'))this.submit();"> <button type="button" class="btn btn-sm btn-primary" onclick="event.preventDefault();event.stopPropagation();if(confirm('{{ 'pc_list.confirm_sent'|t(user.language) }}'))fetch('/postcards/{{ pc.id }}/mark-sent',{method:'POST'}).then(function(){location.reload();})">{{ 'pc_list.mark_sent'|t(user.language) }}</button>
<button type="submit" class="btn btn-sm btn-primary">{{ 'pc_list.mark_sent'|t(user.language) }}</button>
</form>
{% elif pc.status == 'sent' %} {% elif pc.status == 'sent' %}
<form method="post" action="/postcards/{{ pc.id }}/mark-delivered" onclick="event.preventDefault();event.stopPropagation();if(confirm('{{ 'pc_list.confirm_delivered'|t(user.language) }}'))this.submit();"> <button type="button" class="btn btn-sm btn-primary" onclick="event.preventDefault();event.stopPropagation();if(confirm('{{ 'pc_list.confirm_delivered'|t(user.language) }}'))fetch('/postcards/{{ pc.id }}/mark-delivered',{method:'POST'}).then(function(){location.reload();})">{{ 'pc_list.mark_delivered'|t(user.language) }}</button>
<button type="submit" class="btn btn-sm btn-primary">{{ 'pc_list.mark_delivered'|t(user.language) }}</button>
</form>
{% endif %} {% endif %}
</div> </div>
</a> </a>