Files
Card-data-sorting/templates/expenses/expense_list.html

151 lines
4.7 KiB
HTML

{% extends 'base.html' %}
{% block title %}明細編集{% endblock %}
{% block content %}
<section>
<h2>明細編集</h2>
{% if imported %}
<p>取込件数: {{ imported }} / 重複件数: {{ duplicated }} / 文字コード: {{ encoding }}</p>
{% endif %}
<form>
{% csrf_token %}
</form>
<table>
<thead>
<tr>
<th>利用日</th>
<th>利用先</th>
<th>金額</th>
<th>店舗区分</th>
<th>経費区分</th>
<th>会社/家計</th>
<th>備考</th>
</tr>
</thead>
<tbody>
{% for expense in expenses %}
<tr data-expense-id="{{ expense.id }}">
<td>{{ expense.use_date }}</td>
<td>{{ expense.description }}</td>
<td>{{ expense.amount }}</td>
<td>
<select class="js-expense-field" data-field="store_id">
<option value="">未設定</option>
{% for store in stores %}
<option value="{{ store.id }}" {% if expense.store_id == store.id %}selected{% endif %}>
{{ store.name }}
</option>
{% endfor %}
</select>
</td>
<td>
<select class="js-expense-field" data-field="expense_category_id">
<option value="">未設定</option>
{% for category in categories %}
<option value="{{ category.id }}" {% if expense.expense_category_id == category.id %}selected{% endif %}>
{{ category.name }}
</option>
{% endfor %}
</select>
</td>
<td>
<label>
<input
class="js-expense-field"
data-field="is_business"
type="radio"
name="is_business_{{ expense.id }}"
value="true"
{% if expense.is_business is True %}checked{% endif %}
>
会社
</label>
<label>
<input
class="js-expense-field"
data-field="is_business"
type="radio"
name="is_business_{{ expense.id }}"
value="false"
{% if expense.is_business is False %}checked{% endif %}
>
家計
</label>
<label>
<input
class="js-expense-field"
data-field="is_business"
type="radio"
name="is_business_{{ expense.id }}"
value=""
{% if expense.is_business is None %}checked{% endif %}
>
未設定
</label>
</td>
<td>
<input
class="js-expense-field"
data-field="note"
type="text"
value="{{ expense.note }}"
>
</td>
</tr>
{% empty %}
<tr>
<td colspan="7">データがありません。</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]')?.value;
async function saveExpense(expenseId, payload) {
const response = await fetch(`/expenses/${expenseId}/update/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken,
},
body: JSON.stringify(payload),
});
if (!response.ok) {
throw new Error('保存に失敗しました');
}
return response.json();
}
function coerceValue(field, value) {
if (field === 'is_business') {
if (value === '') {
return null;
}
return value === 'true';
}
return value;
}
document.querySelectorAll('.js-expense-field').forEach((element) => {
const eventName = element.tagName === 'INPUT' ? 'change' : 'change';
element.addEventListener(eventName, async (event) => {
const row = event.target.closest('tr');
if (!row) {
return;
}
const expenseId = row.dataset.expenseId;
const field = event.target.dataset.field;
const value = coerceValue(field, event.target.value);
try {
await saveExpense(expenseId, { [field]: value });
} catch (error) {
alert(error.message);
}
});
});
</script>
</section>
{% endblock %}