feat: log staff sign-in and sign-out and force logout at a set time

This commit is contained in:
2026-10-19 13:34:55 +03:30
parent 3863c5e7d1
commit 8590579605
25 changed files with 588 additions and 15 deletions
+47
View File
@@ -492,6 +492,23 @@ async function toggleStatus(user: OrgUserDto) {
}
}
async function changeLogoutTime(user: OrgUserDto, raw: string) {
if (!canInvite.value || user.role === 'owner') return;
const next = raw.trim();
if (next === (user.logoutTime ?? '')) return;
error.value = '';
ok.value = '';
try {
await api.patch(`/users/${user.id}/logout-time`, { logoutTime: next || null });
ok.value = next
? `ساعت خروج «${user.fullName}» روی ${toFaDigits(next)} تنظیم شد.`
: `محدودیت خروج «${user.fullName}» برداشته شد.`;
await load();
} catch (e) {
error.value = apiError(e, 'ذخیره ساعت خروج ناموفق بود');
}
}
async function changeCommission(user: OrgUserDto, raw: string) {
if (!canInvite.value) return;
const next = Number(raw);
@@ -980,6 +997,7 @@ onUnmounted(() => {
<span :class="{ flip: !sortLoginDesc }">▴</span>
</button>
</th>
<th>ساعت خروج</th>
<th class="ops" />
</tr>
</thead>
@@ -1019,6 +1037,19 @@ onUnmounted(() => {
</span>
</td>
<td class="muted">{{ formatLastLogin(user.lastLoginAt) }}</td>
<td @click.stop>
<span v-if="user.role === 'owner'" class="muted">—</span>
<input
v-else
class="logout-time"
type="time"
dir="ltr"
:value="user.logoutTime || ''"
:disabled="!canInvite"
:aria-label="`ساعت خروج ${user.fullName}`"
@change="changeLogoutTime(user, ($event.target as HTMLInputElement).value)"
/>
</td>
<td class="ops" @click.stop>
<UiDropdownMenu
:open="menuUserId === user.id"
@@ -1825,6 +1856,22 @@ tbody tr + tr td {
color: #94a3b8;
}
.logout-time {
width: 7.2rem;
min-height: 2rem;
border: 1px solid #e2e8f0;
border-radius: 10px;
padding: 0 0.45rem;
font: inherit;
background: #fff;
box-sizing: border-box;
}
.logout-time:disabled {
background: #f8fafc;
color: #94a3b8;
}
.roles-grid,
.roles-tree {
display: grid;