generated from VLADIMIR/template_frontend
350 lines
19 KiB
Vue
350 lines
19 KiB
Vue
<script setup lang="ts">
|
|
import { NAlert, NButton, NCard, NInput, NModal, useMessage } from 'naive-ui'
|
|
import { ref } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
import { getAuthClient } from '@/api/auth_client'
|
|
import HeaderMenu from '@/components/HeaderMenu.vue'
|
|
import { useAuthStore } from '@/stores/auth'
|
|
|
|
const authStore = useAuthStore()
|
|
const router = useRouter()
|
|
const message = useMessage()
|
|
const client = getAuthClient()
|
|
|
|
const permissions = ref<string[]>([])
|
|
|
|
async function getPermissions() {
|
|
permissions.value = []
|
|
try {
|
|
const res = await client.GetPermissions({})
|
|
permissions.value = res.permissions || []
|
|
} catch (err) {
|
|
message.error('Не удалось загрузить права доступа')
|
|
console.error('Failed to load permissions:', err)
|
|
}
|
|
}
|
|
|
|
getPermissions()
|
|
|
|
type Tip = {
|
|
header: string
|
|
text: string
|
|
}
|
|
|
|
/**
|
|
* Функция возвращает случайный детективный совет
|
|
* с шутками, зависящими от даты
|
|
*/
|
|
function getDetectiveTip(): Tip {
|
|
// ----- 1. Получаем текущую дату и определяем "настроение" -----
|
|
const now = new Date()
|
|
const dayOfWeek = now.getDay() // 0 - Воскресенье, 1 - Понедельник, ...
|
|
const dayOfMonth = now.getDate()
|
|
const month = now.getMonth() + 1 // Январь = 1, Декабрь = 12
|
|
|
|
const isMonday = dayOfWeek === 1
|
|
const isFriday13 = dayOfWeek === 5 && dayOfMonth === 13
|
|
const isNewYear = (month === 1 && dayOfMonth === 1) || (month === 12 && dayOfMonth === 31)
|
|
const isSummer = month >= 6 && month <= 8
|
|
const isWinter = month === 12 || month <= 2
|
|
const isFullMoonJoke = dayOfMonth % 5 === 0 // Просто для разнообразия
|
|
|
|
// ----- 2. База из 100 советов -----
|
|
const tips: string[] = [
|
|
// 1-10
|
|
'Всегда носи с собой запасную ручку — признания любят записывать в самый неподходящий момент.',
|
|
'Если подозреваемый слишком вежлив, он либо дипломат, либо прячет труп в гараже.',
|
|
'Кофе в участке — это не напиток, это яд для улик. Пей только свой.',
|
|
'Следы на месте преступления всегда ведут к тому, кто забыл закрыть дверь.',
|
|
'Лучший способ разговорить молчуна — предложить ему чай с тремя ложками сахара.',
|
|
'Если всё указывает на дворецкого, ищи того, кто нанимал дворецкого.',
|
|
'Записывай каждую мелочь. Особенно цвет носков убитого.',
|
|
"Не верь алиби, которое начинается со слов 'Я бы никогда...'",
|
|
'Преступник всегда возвращается на место преступления. Или за забытым телефоном.',
|
|
'Ищи того, кому есть что терять, кроме своего времени.',
|
|
|
|
// 11-20
|
|
'Если женщина плачет в кабинете — дай ей платок. Если мужчина — дай ему стакан воды.',
|
|
'Самое опасное оружие — не пистолет, а бухгалтерская книга.',
|
|
'Собака всегда знает убийцу. Но она не говорит, потому что у неё контракт.',
|
|
'Проверяй чеки, билеты и смс. Ложь не терпит документации.',
|
|
'Если у тела нет врагов — ты плохо искал врагов.',
|
|
'Лупа нужна не для увеличения улик, а для того, чтобы выглядеть умнее.',
|
|
'Интуиция — это когда ты уже знаешь ответ, но хочешь убедиться, что не ошибся.',
|
|
'Подозревай всех, даже самого себя. Иногда преступник — это ты в прошлом.',
|
|
'Хороший детектив видит улики. Великий — видит их отсутствие.',
|
|
'Никогда не допрашивай свидетеля на голодный желудок. И себя тоже.',
|
|
|
|
// 21-30
|
|
'Если дело зашло в тупик, переверни бумаги вверх ногами.',
|
|
'Самый ценный свидетель — это камера наблюдения, у которой сломана защита.',
|
|
'Не ищи мотив. Ищи возможность.',
|
|
'Преступник не оставляет следов. Он оставляет выбор.',
|
|
'Если дверь была закрыта изнутри — ищи люк, который открывается снаружи.',
|
|
'Лучший детектив — тот, кого не замечают в толпе.',
|
|
'Учись читать по губам. Пригодится на допросах с адвокатом.',
|
|
'Запах духов на месте преступления важнее запаха пороха.',
|
|
'Если ты нашел отпечаток пальца — проверь, не твой ли он.',
|
|
'Раскрыть дело — это искусство. Не раскрыть — тоже искусство, но другое.',
|
|
|
|
// 31-40
|
|
'Никогда не спорь с баллистикой. Она всегда права, даже если ты не согласен.',
|
|
'В каждом деле есть одна странная деталь. Найди её — и пазл сложится.',
|
|
'Если преступник умный — он оставит ложный след. Если глупый — он оставит следы в соцсетях.',
|
|
'Лучший друг детектива — тишина. Второй друг — кофе.',
|
|
'Если свидетель говорит слишком много, он врет. Если молчит — он тоже врет.',
|
|
'Преступление редко бывает идеальным. Идеальным бывает только алиби жены.',
|
|
'Всегда смотри на часы на трупе. Возможно, они показывают время, когда он перестал верить в людей.',
|
|
'Воры любят темноту. Детективы — свет. А маньяки — полную луну.',
|
|
'Если ты поймал преступника, не радуйся раньше времени — может, он просто лжец.',
|
|
'В каждом городе есть одно место, где собираются все сплетники. Начни оттуда.',
|
|
|
|
// 41-50
|
|
'Не верь в совпадения. Но верь в удачу.',
|
|
'Если у тебя нет улик — придумай их. Но только мысленно, чтобы знать, где искать.',
|
|
'Жертва всегда знала убийцу. Даже если она не знала, что знает.',
|
|
'Проверяй алиби на разрыв. Если оно выдерживает — ты ошибся.',
|
|
'Самый страшный враг детектива — не маньяк, а его собственная лень.',
|
|
'Если преступник оставил записку — прочитай её. И сожги, чтобы никто не узнал твой почерк.',
|
|
'Всегда носи с собой фонарик. Даже днём. Для эффекта.',
|
|
'В деле важно всё: от укуса комара до размера обуви.',
|
|
'Если ты думаешь, что дело простое — значит, ты не додумал.',
|
|
'Убийца всегда ищет внимания. Или наоборот, избегает его.',
|
|
|
|
// 51-60
|
|
'Стук в дверь в полночь — это либо полиция, либо заказчик.',
|
|
'Никогда не давай обещаний родственникам жертвы. Только факты.',
|
|
'Если у тебя есть три версии — выбирай четвёртую.',
|
|
'Лучшее оружие — это бумага. На ней можно написать что угодно.',
|
|
'Когда ты смотришь на улику, смотри на неё глазами преступника.',
|
|
'Все любят детективы, пока не становятся подозреваемыми.',
|
|
'Следы крови важны. Но важнее — следы лжи.',
|
|
'Если ты не спишь третьи сутки, значит, ты либо гений, либо дурак.',
|
|
"Проверяй каждого, кто говорит 'Я ничего не видел'.",
|
|
'В каждом деле есть один человек, который знает всё. И он не говорит.',
|
|
|
|
// 61-70
|
|
'Не суди преступника по одежде. Суди по тому, как он её снимал.',
|
|
'Дыра в алиби — это как дыра в лодке. Рано или поздно она утонет.',
|
|
'Если преступник использует перчатки — он профессионал. Если нет — он любитель.',
|
|
'Запомни: первая версия — всегда неверная.',
|
|
'Если у тебя кончились идеи, иди в бар. Там всегда есть кто-то, кто расскажет тебе дело.',
|
|
'Свидетель с фотороботом — это как слепой с компасом.',
|
|
'Никогда не смейся над уликами. Они могут обидеться и исчезнуть.',
|
|
'Если ты нашёл оружие — не трогай его. Иначе твои отпечатки будут на нём.',
|
|
'Преступник умён, но ты умнее. Потому что ты пьёшь правильный кофе.',
|
|
'Всегда пересматривай видеозаписи. Особенно в два раза медленнее.',
|
|
|
|
// 71-80
|
|
'Если на месте преступления есть кот — он видел всё. Но он не скажет.',
|
|
'Лучший способ поймать преступника — пригласить его на обед.',
|
|
'Если подозреваемый улыбается, он либо невиновен, либо психопат.',
|
|
'Проверяй мусор. В нём всегда есть что-то полезное.',
|
|
'Никогда не доверяй красивым историям. Только уродливым фактам.',
|
|
'Если ты нашёл улику слишком легко — это ловушка.',
|
|
'Убийца всегда оставляет послание. Даже если это просто тишина.',
|
|
'Если ты запнулся на допросе — делай вид, что так и задумано.',
|
|
'Помни: все врут. Даже я тебе советую.',
|
|
'Если ты боишься темноты — стань детективом. Страх пройдёт.',
|
|
|
|
// 81-90
|
|
'Самые лучшие признания случаются под утро, когда все устали.',
|
|
'Если преступник использовал компьютер, значит, он либо хакер, либо дурак.',
|
|
'Следы шин — это как подпись на дороге.',
|
|
'Никогда не забывай про запах. Он помнит дольше, чем люди.',
|
|
'Если ты не знаешь, что делать — съешь шоколадку.',
|
|
'В каждом деле есть одна минута слабости. Найди её.',
|
|
'Преступник всегда нервничает. Даже если он не нервничает.',
|
|
'Если у тебя есть подозреваемый и нет улик — подожди. Улики появятся.',
|
|
'Не верь в чудеса. Верь в логику.',
|
|
'Если ты устал — возьми отпуск. Преступление никуда не денется.',
|
|
|
|
// 91-100
|
|
'Запомни: самый опасный преступник — тот, кто читал детективы.',
|
|
'Если ты думаешь, что всё кончено — значит, ты пропустил поворот.',
|
|
'Следы на полу важнее следов в душе.',
|
|
'Если преступник оставил окурок — он курил. Или хотел, чтобы ты так думал.',
|
|
'Хороший детектив всегда голоден. Это помогает мыслить.',
|
|
'Не суди по первому впечатлению. Суди по второму, когда увидишь его в наручниках.',
|
|
'Если у тебя есть тайный агент — не доверяй ему.',
|
|
'В деле всегда есть тот, кто знает больше, чем говорит.',
|
|
'Если ты не можешь найти убийцу — стань им (в мыслях).',
|
|
'И последнее: всегда проверяй, закрыл ли ты дверь участка.',
|
|
]
|
|
|
|
// ----- 3. Шутки, зависящие от даты -----
|
|
const dateJokes: string[] = []
|
|
|
|
if (isMonday) {
|
|
dateJokes.push(
|
|
'☕ Понедельник: Сегодня даже преступники не хотят работать. Проверь тех, кто был слишком бодр.',
|
|
)
|
|
}
|
|
if (isFriday13) {
|
|
dateJokes.push('🔮 Пятница 13-е: Если улики ведут к чёрной кошке, ищи чёрного кота с алиби.')
|
|
}
|
|
if (isNewYear) {
|
|
dateJokes.push(
|
|
'🎄 Новый год: Свидетель в костюме Деда Мороза врёт. Настоящий Дед Мороз всегда в отпуске.',
|
|
)
|
|
}
|
|
if (isSummer) {
|
|
dateJokes.push(
|
|
'☀️ Лето: В жару преступники забывают улики в карманах, потому что снимают пиджаки.',
|
|
)
|
|
}
|
|
if (isWinter) {
|
|
dateJokes.push('❄️ Зима: Следы на снегу ведут к тому, у кого самые холодные руки.')
|
|
}
|
|
if (isFullMoonJoke) {
|
|
dateJokes.push(
|
|
'🌕 Полнолуние: Если подозреваемый воет на луну, он либо оборотень, либо фанат рока.',
|
|
)
|
|
}
|
|
|
|
// ----- 4. Объединяем все советы и выбираем случайный -----
|
|
const allTips = tips.concat(dateJokes)
|
|
const randomTip = allTips[Math.floor(Math.random() * allTips.length)]
|
|
|
|
// ----- 5. Красивый заголовок -----
|
|
const headers = [
|
|
'🔍 Заметки сыщика:',
|
|
'📓 Из дневника инспектора:',
|
|
'🕵️ Мудрость Шерлока:',
|
|
'🧠 Гениально и просто:',
|
|
'📌 Правило большого пальца:',
|
|
'☕ Кофейная истина:',
|
|
]
|
|
|
|
const header = headers[Math.floor(Math.random() * headers.length)]
|
|
|
|
return { header: header, text: randomTip }
|
|
}
|
|
|
|
const tip = getDetectiveTip()
|
|
|
|
// ===== Удаление аккаунта =====
|
|
const showDeleteDialog = ref(false)
|
|
const deletePassword = ref('')
|
|
const deleteError = ref('')
|
|
|
|
async function confirmDeleteAccount() {
|
|
deleteError.value = ''
|
|
const res = await authStore.deleteAccount(deletePassword.value)
|
|
if (!res) {
|
|
deleteError.value = authStore.error || 'Не удалось удалить аккаунт'
|
|
return
|
|
}
|
|
message.success('Аккаунт и персональные данные удалены')
|
|
showDeleteDialog.value = false
|
|
router.push('/login')
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="center-block-custom">
|
|
<div class="width700">
|
|
<n-alert :title="tip.header" :show-icon="false" type="info" style="margin-bottom: 20px">
|
|
{{ tip.text }}
|
|
</n-alert>
|
|
|
|
<p>Доброго времени суток, {{ authStore.username }}.</p>
|
|
|
|
<div class="danger-zone">
|
|
<div class="danger-zone-text">
|
|
<div class="danger-zone-title">Удаление аккаунта</div>
|
|
<div class="danger-zone-hint">
|
|
Удаление необратимо: аккаунт и все персональные данные будут стёрты (ст. 21 152-ФЗ).
|
|
</div>
|
|
</div>
|
|
<n-button type="error" ghost @click="showDeleteDialog = true">Удалить аккаунт</n-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<n-modal
|
|
v-model:show="showDeleteDialog"
|
|
class="delete-modal"
|
|
>
|
|
<n-card
|
|
title="Удаление аккаунта"
|
|
:bordered="false"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
closable
|
|
@close="showDeleteDialog = false"
|
|
>
|
|
<p class="delete-modal-text">
|
|
Это действие необратимо. Для подтверждения удаления введите пароль от учётной записи — он
|
|
понадобится, чтобы убедиться, что аккаунт удаляет его владелец.
|
|
</p>
|
|
<n-input
|
|
v-model:value="deletePassword"
|
|
type="password"
|
|
placeholder="Пароль для подтверждения"
|
|
@keyup.enter="confirmDeleteAccount"
|
|
/>
|
|
<p v-if="deleteError" class="delete-modal-error">{{ deleteError }}</p>
|
|
<div class="delete-modal-buttons">
|
|
<n-button @click="showDeleteDialog = false">Отмена</n-button>
|
|
<n-button
|
|
type="error"
|
|
:disabled="deletePassword.length == 0"
|
|
:loading="authStore.isLoading"
|
|
@click="confirmDeleteAccount"
|
|
>
|
|
Удалить навсегда
|
|
</n-button>
|
|
</div>
|
|
</n-card>
|
|
</n-modal>
|
|
|
|
<HeaderMenu active="office" />
|
|
</template>
|
|
|
|
<style scoped>
|
|
.danger-zone {
|
|
align-items: center;
|
|
background-color: #222;
|
|
border: 1px solid rgb(224 108 117 / 40%);
|
|
border-radius: 10px;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 16px;
|
|
justify-content: space-between;
|
|
margin-top: 40px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.danger-zone-title {
|
|
color: #e06c75;
|
|
font-size: 17px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.danger-zone-hint {
|
|
color: #999;
|
|
font-size: 14px;
|
|
margin-top: 6px;
|
|
}
|
|
|
|
.delete-modal-text {
|
|
color: #bbb;
|
|
line-height: 1.5;
|
|
margin: 0 0 16px;
|
|
}
|
|
|
|
.delete-modal-error {
|
|
color: #e06c75;
|
|
margin: 12px 0 0;
|
|
}
|
|
|
|
.delete-modal-buttons {
|
|
display: flex;
|
|
gap: 12px;
|
|
justify-content: flex-end;
|
|
margin-top: 20px;
|
|
}
|
|
</style>
|