繰り返し課題のAPI管理UIを追加、課題一覧のUX向上
This commit is contained in:
@@ -98,6 +98,11 @@
|
||||
<li><code>PUT /api/v1/assignments/:id</code> - 課題更新</li>
|
||||
<li><code>DELETE /api/v1/assignments/:id</code> - 課題削除</li>
|
||||
<li><code>PATCH /api/v1/assignments/:id/toggle</code> - 完了状態切替</li>
|
||||
<li><code>GET /api/v1/statistics</code> - 統計情報取得</li>
|
||||
<li><code>GET /api/v1/recurring</code> - 繰り返し設定一覧取得</li>
|
||||
<li><code>GET /api/v1/recurring/:id</code> - 繰り返し設定詳細取得</li>
|
||||
<li><code>PUT /api/v1/recurring/:id</code> - 繰り返し設定更新</li>
|
||||
<li><code>DELETE /api/v1/recurring/:id</code> - 繰り返し設定削除</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -76,6 +76,39 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{if .recurring}}
|
||||
<!-- 繰り返し設定 -->
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-body py-2">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h6 class="mb-0"><i class="bi bi-arrow-repeat me-1"></i>繰り返し設定</h6>
|
||||
<a href="/recurring/{{.recurring.ID}}/edit" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-pencil me-1"></i>編集
|
||||
</a>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<small class="text-muted">タイプ</small>
|
||||
<div class="fw-bold">
|
||||
{{if eq .recurring.RecurrenceType "daily"}}毎日{{end}}
|
||||
{{if eq .recurring.RecurrenceType "weekly"}}毎週{{end}}
|
||||
{{if eq .recurring.RecurrenceType "monthly"}}毎月{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<small class="text-muted">状態</small>
|
||||
<div>
|
||||
{{if .recurring.IsActive}}
|
||||
<span class="badge bg-success">有効</span>
|
||||
{{else}}
|
||||
<span class="badge bg-secondary">停止中</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="d-flex gap-2">
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg me-1"></i>更新</button>
|
||||
<a href="/assignments" class="btn btn-outline-secondary">キャンセル</a>
|
||||
|
||||
@@ -56,6 +56,13 @@
|
||||
期限切れ
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link py-2 rounded-0 border-0 text-muted"
|
||||
href="/recurring">
|
||||
繰り返し
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<hr class="mt-0 mb-3 text-muted" style="opacity: 0.1;">
|
||||
|
||||
@@ -92,9 +99,9 @@
|
||||
<thead class="bg-secondary-subtle">
|
||||
<tr>
|
||||
<th style="width: 50px;" class="ps-3 text-center text-dark fw-bold">状態</th>
|
||||
<th class="text-dark fw-bold">タイトル</th>
|
||||
<th style="width: 120px;" class="text-dark fw-bold">科目</th>
|
||||
<th style="width: 80px;" class="text-dark fw-bold">重要度</th>
|
||||
<th class="text-dark fw-bold">タイトル</th>
|
||||
<th style="width: 140px;" class="text-dark fw-bold">期限</th>
|
||||
<th style="width: 120px;" class="countdown-col text-dark fw-bold">残り</th>
|
||||
<th style="width: 80px;" class="text-end pe-3 text-dark fw-bold">操作</th>
|
||||
@@ -125,9 +132,6 @@
|
||||
</form>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold text-dark text-truncate" style="max-width: 300px;">{{.Title}}</div>
|
||||
</td>
|
||||
<td><span class="badge bg-secondary text-white border-0 fw-bold">{{.Subject}}</span></td>
|
||||
<td>
|
||||
{{if eq .Priority "high"}}
|
||||
@@ -138,6 +142,22 @@
|
||||
<span class="badge bg-dark text-white border-0 fw-bold small">低</span>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="fw-bold text-dark text-truncate" style="max-width: 280px;">{{.Title}}</div>
|
||||
{{if .RecurringAssignmentID}}
|
||||
<button type="button" class="btn btn-link p-0 ms-2 text-info" data-bs-toggle="modal"
|
||||
data-bs-target="#recurringModal" data-recurring-id="{{.RecurringAssignmentID}}"
|
||||
data-assignment-id="{{.ID}}"
|
||||
data-recurring-title="{{.Title}}"
|
||||
data-recurring-type="{{if .RecurringAssignment}}{{.RecurringAssignment.RecurrenceType}}{{else}}unknown{{end}}"
|
||||
data-recurring-active="{{if .RecurringAssignment}}{{.RecurringAssignment.IsActive}}{{else}}true{{end}}"
|
||||
title="繰り返し課題">
|
||||
<i class="fa-solid fa-repeat"></i>
|
||||
</button>
|
||||
{{end}}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small fw-bold text-dark user-select-all">{{.DueDate.Format "2006/01/02 15:04"}}
|
||||
</div>
|
||||
@@ -154,6 +174,12 @@
|
||||
<a href="/assignments/{{.ID}}/edit" class="text-primary me-3 text-decoration-none">
|
||||
<i class="bi bi-pencil-fill"></i>
|
||||
</a>
|
||||
{{if .RecurringAssignmentID}}
|
||||
<button type="button" class="btn btn-link p-0 text-danger text-decoration-none border-0 bg-transparent"
|
||||
onclick="showDeleteRecurringModal({{.ID}}, {{.RecurringAssignmentID}})">
|
||||
<i class="bi bi-trash-fill"></i>
|
||||
</button>
|
||||
{{else}}
|
||||
<form action="/assignments/{{.ID}}/delete" method="POST" class="d-inline"
|
||||
onsubmit="return confirm('削除しますか?');">
|
||||
<input type="hidden" name="_csrf" value="{{$.csrfToken}}">
|
||||
@@ -162,6 +188,7 @@
|
||||
<i class="bi bi-trash-fill"></i>
|
||||
</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -290,5 +317,126 @@
|
||||
const btnText = document.getElementById('countdownBtnText');
|
||||
if (btnText) btnText.textContent = 'カウントダウン非表示中';
|
||||
}
|
||||
|
||||
// Recurring modal handler - wait for DOM to be ready
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const recurringModal = document.getElementById('recurringModal');
|
||||
if (recurringModal) {
|
||||
recurringModal.addEventListener('show.bs.modal', function (event) {
|
||||
const button = event.relatedTarget;
|
||||
const id = button.getAttribute('data-recurring-id');
|
||||
const assignmentId = button.getAttribute('data-assignment-id');
|
||||
const title = button.getAttribute('data-recurring-title');
|
||||
const type = button.getAttribute('data-recurring-type');
|
||||
const isActive = button.getAttribute('data-recurring-active') === 'true';
|
||||
|
||||
document.getElementById('recurringModalTitle').textContent = title;
|
||||
document.getElementById('recurringStopForm').action = '/recurring/' + id + '/stop';
|
||||
document.getElementById('recurringEditBtn').href = '/recurring/' + id + '/edit';
|
||||
|
||||
const typeLabels = {
|
||||
'daily': '毎日',
|
||||
'weekly': '毎週',
|
||||
'monthly': '毎月',
|
||||
'unknown': '(読み込み中...)'
|
||||
};
|
||||
document.getElementById('recurringTypeLabel').textContent = typeLabels[type] || type || '不明';
|
||||
|
||||
|
||||
const statusEl = document.getElementById('recurringStatus');
|
||||
if (isActive) {
|
||||
statusEl.innerHTML = '<span class="badge bg-success">有効</span>';
|
||||
document.getElementById('recurringStopBtn').style.display = 'inline-block';
|
||||
} else {
|
||||
statusEl.innerHTML = '<span class="badge bg-secondary">停止中</span>';
|
||||
document.getElementById('recurringStopBtn').style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Recurring Modal -->
|
||||
<div class="modal fade" id="recurringModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="fa-solid fa-repeat me-2"></i>繰り返し課題</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h6 id="recurringModalTitle" class="mb-3 fw-bold"></h6>
|
||||
<table class="table table-sm table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="text-muted" style="width: 100px;">繰り返し</th>
|
||||
<td id="recurringTypeLabel">読み込み中...</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-muted">状態</th>
|
||||
<td id="recurringStatus">読み込み中...</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="alert alert-info small mb-0">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
繰り返しを停止すると、今後新しい課題は自動作成されなくなります。既存の課題はそのまま残ります。
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">閉じる</button>
|
||||
<a id="recurringEditBtn" href="#" class="btn btn-primary">
|
||||
<i class="bi bi-pencil me-1"></i>編集
|
||||
</a>
|
||||
<form id="recurringStopForm" method="POST" class="d-inline">
|
||||
<input type="hidden" name="_csrf" value="{{.csrfToken}}">
|
||||
<button type="submit" id="recurringStopBtn" class="btn btn-danger"
|
||||
onclick="return confirm('繰り返しを停止しますか?');">
|
||||
<i class="bi bi-stop-fill me-1"></i>停止
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Recurring Confirmation Modal -->
|
||||
<div class="modal fade" id="deleteRecurringModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-trash me-2"></i>繰り返し課題の削除</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>この課題は繰り返し設定に関連付けられています。</p>
|
||||
<p>繰り返し設定も停止しますか?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">キャンセル</button>
|
||||
<form id="deleteOnlyForm" method="POST" class="d-inline">
|
||||
<input type="hidden" name="_csrf" value="{{.csrfToken}}">
|
||||
<button type="submit" class="btn btn-outline-danger">
|
||||
課題のみ削除
|
||||
</button>
|
||||
</form>
|
||||
<form id="deleteAndStopForm" method="POST" class="d-inline">
|
||||
<input type="hidden" name="_csrf" value="{{.csrfToken}}">
|
||||
<button type="submit" class="btn btn-danger">
|
||||
削除して繰り返しも削除
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function showDeleteRecurringModal(assignmentId, recurringId) {
|
||||
var modal = new bootstrap.Modal(document.getElementById('deleteRecurringModal'));
|
||||
document.getElementById('deleteOnlyForm').action = '/assignments/' + assignmentId + '/delete';
|
||||
document.getElementById('deleteAndStopForm').action = '/assignments/' + assignmentId + '/delete?stop_recurring=' + recurringId;
|
||||
modal.show();
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
@@ -101,25 +101,25 @@
|
||||
<label class="form-label small">曜日</label>
|
||||
<div class="btn-group btn-group-sm w-100" role="group">
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd0"
|
||||
value="0">
|
||||
value="0" {{if eq .currentWeekday 0}}checked{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd0">日</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd1"
|
||||
value="1" checked>
|
||||
value="1" {{if eq .currentWeekday 1}}checked{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd1">月</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd2"
|
||||
value="2">
|
||||
value="2" {{if eq .currentWeekday 2}}checked{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd2">火</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd3"
|
||||
value="3">
|
||||
value="3" {{if eq .currentWeekday 3}}checked{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd3">水</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd4"
|
||||
value="4">
|
||||
value="4" {{if eq .currentWeekday 4}}checked{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd4">木</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd5"
|
||||
value="5">
|
||||
value="5" {{if eq .currentWeekday 5}}checked{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd5">金</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd6"
|
||||
value="6">
|
||||
value="6" {{if eq .currentWeekday 6}}checked{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd6">土</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,37 +127,9 @@
|
||||
<label for="recurrence_day" class="form-label small">日</label>
|
||||
<select class="form-select form-select-sm" id="recurrence_day"
|
||||
name="recurrence_day">
|
||||
<option value="1">1日</option>
|
||||
<option value="2">2日</option>
|
||||
<option value="3">3日</option>
|
||||
<option value="4">4日</option>
|
||||
<option value="5">5日</option>
|
||||
<option value="6">6日</option>
|
||||
<option value="7">7日</option>
|
||||
<option value="8">8日</option>
|
||||
<option value="9">9日</option>
|
||||
<option value="10">10日</option>
|
||||
<option value="11">11日</option>
|
||||
<option value="12">12日</option>
|
||||
<option value="13">13日</option>
|
||||
<option value="14">14日</option>
|
||||
<option value="15">15日</option>
|
||||
<option value="16">16日</option>
|
||||
<option value="17">17日</option>
|
||||
<option value="18">18日</option>
|
||||
<option value="19">19日</option>
|
||||
<option value="20">20日</option>
|
||||
<option value="21">21日</option>
|
||||
<option value="22">22日</option>
|
||||
<option value="23">23日</option>
|
||||
<option value="24">24日</option>
|
||||
<option value="25">25日</option>
|
||||
<option value="26">26日</option>
|
||||
<option value="27">27日</option>
|
||||
<option value="28">28日</option>
|
||||
<option value="29">29日</option>
|
||||
<option value="30">30日</option>
|
||||
<option value="31">31日</option>
|
||||
{{range $i := seq 1 31}}
|
||||
<option value="{{$i}}" {{if eq $.currentDay $i}}selected{{end}}>{{$i}}日</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
<div id="end_group" style="display: none;">
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<title>{{.title}} - Super Homework Manager</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.1/css/all.min.css" rel="stylesheet">
|
||||
<link href="/static/css/style.css" rel="stylesheet">
|
||||
<style>
|
||||
.navbar-dark .navbar-nav .nav-link,
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
<i class="bi bi-exclamation-octagon-fill me-2"></i>
|
||||
<span id="urgentMessage"></span>
|
||||
<div class="urgent-countdown mt-1">
|
||||
<i class="bi bi-stopwatch"></i> あと <span id="urgentCountdown"></span>
|
||||
<i class="bi bi-stopwatch"></i> <span id="urgentCountdown"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -164,9 +164,9 @@
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center"
|
||||
data-priority="{{.Priority}}" data-due="{{.DueDate.UnixMilli}}">
|
||||
<div>
|
||||
{{if .Subject}}<span class="badge bg-secondary me-1">{{.Subject}}</span>{{end}}
|
||||
{{if eq .Priority "high"}}<span class="badge bg-danger me-1">重要</span>{{end}}
|
||||
<strong>{{.Title}}</strong>
|
||||
{{if eq .Priority "high"}}<span class="badge bg-danger ms-1">重要</span>{{end}}
|
||||
{{if .Subject}}<span class="badge bg-secondary ms-2">{{.Subject}}</span>{{end}}
|
||||
<br><small class="text-danger">{{formatDateTime .DueDate}}</small>
|
||||
</div>
|
||||
<form action="/assignments/{{.ID}}/toggle" method="POST"><input type="hidden" name="_csrf"
|
||||
@@ -187,9 +187,9 @@
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center"
|
||||
data-priority="{{.Priority}}" data-due="{{.DueDate.UnixMilli}}">
|
||||
<div>
|
||||
{{if .Subject}}<span class="badge bg-secondary me-1">{{.Subject}}</span>{{end}}
|
||||
{{if eq .Priority "high"}}<span class="badge bg-danger me-1">重要</span>{{end}}
|
||||
<strong>{{.Title}}</strong>
|
||||
{{if eq .Priority "high"}}<span class="badge bg-danger ms-1">重要</span>{{end}}
|
||||
{{if .Subject}}<span class="badge bg-secondary ms-2">{{.Subject}}</span>{{end}}
|
||||
<br><small class="text-muted">{{formatDateTime .DueDate}}</small>
|
||||
</div>
|
||||
<form action="/assignments/{{.ID}}/toggle" method="POST"><input type="hidden" name="_csrf"
|
||||
@@ -210,9 +210,9 @@
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center"
|
||||
data-priority="{{.Priority}}" data-due="{{.DueDate.UnixMilli}}">
|
||||
<div>
|
||||
{{if .Subject}}<span class="badge bg-secondary me-1">{{.Subject}}</span>{{end}}
|
||||
{{if eq .Priority "high"}}<span class="badge bg-danger me-1">重要</span>{{end}}
|
||||
<strong>{{.Title}}</strong>
|
||||
{{if eq .Priority "high"}}<span class="badge bg-danger ms-1">重要</span>{{end}}
|
||||
{{if .Subject}}<span class="badge bg-secondary ms-2">{{.Subject}}</span>{{end}}
|
||||
<br><small class="text-muted">{{formatDateTime .DueDate}}</small>
|
||||
</div>
|
||||
<form action="/assignments/{{.ID}}/toggle" method="POST"><input type="hidden" name="_csrf"
|
||||
@@ -306,10 +306,10 @@
|
||||
var mins = Math.floor((diff % 3600000) / 60000);
|
||||
var secs = Math.floor((diff % 60000) / 1000);
|
||||
|
||||
var text = '';
|
||||
if (days > 0) text = days + '日 ' + hours + '時間 ' + mins + '分 ' + secs + '秒';
|
||||
else if (hours > 0) text = hours + '時間 ' + mins + '分 ' + secs + '秒';
|
||||
else text = mins + '分 ' + secs + '秒';
|
||||
var text = 'あと ';
|
||||
if (days > 0) text += days + '日 ' + hours + '時間 ' + mins + '分 ' + secs + '秒';
|
||||
else if (hours > 0) text += hours + '時間 ' + mins + '分 ' + secs + '秒';
|
||||
else text += mins + '分 ' + secs + '秒';
|
||||
|
||||
countdown.textContent = text;
|
||||
}
|
||||
|
||||
148
web/templates/recurring/edit.html
Normal file
148
web/templates/recurring/edit.html
Normal file
@@ -0,0 +1,148 @@
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-6">
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0"><i class="bi bi-arrow-repeat me-2"></i>繰り返し課題の編集</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{if .error}}<div class="alert alert-danger">{{.error}}</div>{{end}}
|
||||
<form method="POST" action="/recurring/{{.recurring.ID}}">
|
||||
{{.csrfField}}
|
||||
<div class="mb-3">
|
||||
<label for="title" class="form-label">タイトル <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="title" name="title" value="{{.recurring.Title}}" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="subject" class="form-label">科目</label>
|
||||
<input type="text" class="form-control" id="subject" name="subject" value="{{.recurring.Subject}}">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="priority" class="form-label">重要度</label>
|
||||
<select class="form-select" id="priority" name="priority">
|
||||
<option value="low" {{if eq .recurring.Priority "low"}}selected{{end}}>小</option>
|
||||
<option value="medium" {{if eq .recurring.Priority "medium"}}selected{{end}}>中</option>
|
||||
<option value="high" {{if eq .recurring.Priority "high"}}selected{{end}}>大</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">説明</label>
|
||||
<textarea class="form-control" id="description" name="description" rows="3">{{.recurring.Description}}</textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="due_time" class="form-label">時刻</label>
|
||||
<input type="time" class="form-control" id="due_time" name="due_time" value="{{.recurring.DueTime}}">
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mb-3">
|
||||
<div class="card-body py-3">
|
||||
<h6 class="mb-3"><i class="bi bi-arrow-repeat me-1"></i>繰り返し設定</h6>
|
||||
<div class="row mb-3">
|
||||
<div class="col-6">
|
||||
<label for="recurrence_type" class="form-label small">繰り返しタイプ</label>
|
||||
<select class="form-select form-select-sm" id="recurrence_type" name="recurrence_type" onchange="updateRecurrenceOptions()">
|
||||
<option value="daily" {{if eq .recurring.RecurrenceType "daily"}}selected{{end}}>毎日</option>
|
||||
<option value="weekly" {{if eq .recurring.RecurrenceType "weekly"}}selected{{end}}>毎週</option>
|
||||
<option value="monthly" {{if eq .recurring.RecurrenceType "monthly"}}selected{{end}}>毎月</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="recurrence_interval" class="form-label small">間隔</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="number" class="form-control" id="recurrence_interval" name="recurrence_interval" value="{{.recurring.RecurrenceInterval}}" min="1" max="12">
|
||||
<span class="input-group-text" id="interval_label">{{if eq .recurring.RecurrenceType "daily"}}日{{else if eq .recurring.RecurrenceType "weekly"}}週{{else}}月{{end}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="weekday_group" class="mb-3">
|
||||
<label class="form-label small">曜日</label>
|
||||
<div class="btn-group btn-group-sm w-100" role="group">
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd0" value="0" {{if .recurring.RecurrenceWeekday}}{{if eq (derefInt .recurring.RecurrenceWeekday) 0}}checked{{end}}{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd0">日</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd1" value="1" {{if .recurring.RecurrenceWeekday}}{{if eq (derefInt .recurring.RecurrenceWeekday) 1}}checked{{end}}{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd1">月</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd2" value="2" {{if .recurring.RecurrenceWeekday}}{{if eq (derefInt .recurring.RecurrenceWeekday) 2}}checked{{end}}{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd2">火</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd3" value="3" {{if .recurring.RecurrenceWeekday}}{{if eq (derefInt .recurring.RecurrenceWeekday) 3}}checked{{end}}{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd3">水</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd4" value="4" {{if .recurring.RecurrenceWeekday}}{{if eq (derefInt .recurring.RecurrenceWeekday) 4}}checked{{end}}{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd4">木</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd5" value="5" {{if .recurring.RecurrenceWeekday}}{{if eq (derefInt .recurring.RecurrenceWeekday) 5}}checked{{end}}{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd5">金</label>
|
||||
<input type="radio" class="btn-check" name="recurrence_weekday" id="wd6" value="6" {{if .recurring.RecurrenceWeekday}}{{if eq (derefInt .recurring.RecurrenceWeekday) 6}}checked{{end}}{{end}}>
|
||||
<label class="btn btn-outline-primary" for="wd6">土</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="day_group" class="mb-3">
|
||||
<label for="recurrence_day" class="form-label small">日</label>
|
||||
<select class="form-select form-select-sm" id="recurrence_day" name="recurrence_day">
|
||||
{{range $i := seq 1 31}}
|
||||
<option value="{{$i}}" {{if $.recurring.RecurrenceDay}}{{if eq (derefInt $.recurring.RecurrenceDay) $i}}selected{{end}}{{end}}>{{$i}}日</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="small text-muted">状態:</span>
|
||||
{{if .recurring.IsActive}}
|
||||
<span class="badge bg-success">有効</span>
|
||||
{{else}}
|
||||
<span class="badge bg-secondary">停止中</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg me-1"></i>更新</button>
|
||||
<a href="/assignments" class="btn btn-outline-secondary">キャンセル</a>
|
||||
{{if .recurring.IsActive}}
|
||||
<button type="button" class="btn btn-outline-danger" onclick="if(confirm('繰り返しを停止しますか?今後新しい課題は自動作成されなくなります。')) document.getElementById('stopForm').submit();">
|
||||
<i class="bi bi-stop-fill me-1"></i>停止
|
||||
</button>
|
||||
{{else}}
|
||||
<button type="button" class="btn btn-outline-success" onclick="document.getElementById('resumeForm').submit();">
|
||||
<i class="bi bi-play-fill me-1"></i>再開
|
||||
</button>
|
||||
{{end}}
|
||||
<button type="button" class="btn btn-outline-danger ms-auto" onclick="if(confirm('この繰り返し設定を削除しますか?この操作は取り消せません。')) document.getElementById('deleteForm').submit();">
|
||||
<i class="bi bi-trash me-1"></i>削除
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{if .recurring.IsActive}}
|
||||
<form id="stopForm" action="/recurring/{{.recurring.ID}}/stop" method="POST" class="d-none">
|
||||
{{.csrfField}}
|
||||
</form>
|
||||
{{else}}
|
||||
<form id="resumeForm" action="/recurring/{{.recurring.ID}}/resume" method="POST" class="d-none">
|
||||
{{.csrfField}}
|
||||
</form>
|
||||
{{end}}
|
||||
<form id="deleteForm" action="/recurring/{{.recurring.ID}}/delete" method="POST" class="d-none">
|
||||
{{.csrfField}}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function updateRecurrenceOptions() {
|
||||
var type = document.getElementById('recurrence_type').value;
|
||||
document.getElementById('weekday_group').style.display = type === 'weekly' ? 'block' : 'none';
|
||||
document.getElementById('day_group').style.display = type === 'monthly' ? 'block' : 'none';
|
||||
var label = document.getElementById('interval_label');
|
||||
if (type === 'daily') label.textContent = '日';
|
||||
else if (type === 'weekly') label.textContent = '週';
|
||||
else if (type === 'monthly') label.textContent = '月';
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateRecurrenceOptions();
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
68
web/templates/recurring/index.html
Normal file
68
web/templates/recurring/index.html
Normal file
@@ -0,0 +1,68 @@
|
||||
{{template "base" .}}
|
||||
|
||||
{{define "content"}}
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<h4 class="mb-0 fw-bold"><i class="bi bi-arrow-repeat me-2"></i>繰り返し設定一覧</h4>
|
||||
</div>
|
||||
<a href="/assignments" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>課題一覧に戻る
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="ps-3">タイトル</th>
|
||||
<th>科目</th>
|
||||
<th>繰り返し</th>
|
||||
<th>状態</th>
|
||||
<th class="text-end pe-3">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .recurrings}}
|
||||
<tr>
|
||||
<td class="ps-3">
|
||||
<div class="fw-bold">{{.Title}}</div>
|
||||
{{if .Description}}
|
||||
<div class="text-muted small text-truncate" style="max-width: 200px;">{{.Description}}</div>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
{{if .Subject}}
|
||||
<span class="badge bg-secondary">{{.Subject}}</span>
|
||||
{{else}}
|
||||
<span class="text-muted">-</span>
|
||||
{{end}}
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-dark">{{recurringSummary .}}</span>
|
||||
</td>
|
||||
<td>
|
||||
{{if .IsActive}}
|
||||
<span class="badge bg-success">有効</span>
|
||||
{{else}}
|
||||
<span class="badge bg-secondary">停止中</span>
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="text-end pe-3">
|
||||
<a href="/recurring/{{.ID}}/edit" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{else}}
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-4 text-muted">
|
||||
繰り返し設定がありません
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user