This commit is contained in:
2025-04-14 10:27:58 +03:00
parent f977d6b3d4
commit 7e798a7a83
55 changed files with 5625 additions and 353 deletions

337
backend/public/index.html Normal file
View File

@@ -0,0 +1,337 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="format-detection" content="telephone=no" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="MobileOptimized" content="176" />
<meta name="HandheldFriendly" content="True" />
<meta name="robots" content="noindex,nofollow" />
<script src="https://telegram.org/js/telegram-web-app.js?56"></script>
<title></title>
<style>
*[hidden] {display: none;}
.block {border: 1px black solid; padding:10px; margin-bottom: 10px;}
#settings input {width: 45%;}
#delete {color:red; cursor: pointer; margin-left: 10px;}
</style>
</head>
<body>
<div id = "adminapp" hidden>
<b>Админка</b>
<div id = "settings" class = "block">
<b>Настройки</b><br>
<input id = "name" type = "text" placeholder = "Name">
<div>
<button id = "upload-group" href = "">Не задано</button>
<button id = "upload-group-selector" href = "" admin>Задать</button>
</div>
<b>Company</b>
<div id = "company">
<input id = "company-name" type = "text" placeholder = "Name">
<input id = "company-phone" type = "text" placeholder = "Phone">
<input id = "company-site" type = "text" placeholder = "Site">
<input id = "company-description" type = "text" placeholder = "Description">
</div>
<button id = "update-profile">Update</button>
</div>
<div id = "projects" class = "block">
<b>Список проектов</b><button id = "add-project">Добавить/Обновить</button>
<br>
<input id = "project-id" placeholder = "Id">
<input id = "project-name" placeholder = "Name">
<input id = "project-description" placeholder = "Description">
<br>
<div id = "project-list">Loading...</div>
</div>
<div id = "groups" class = "block">
<b>Список групп</b><button id = "add-group" href="" admin>Добавить</button>
<br>
<div id = "group-list">Проект не выбран</div>
<button id = "share" href = "">Отправить ключ подключения</button>
</div>
<div id = "users" class = "block">
<b>Список пользователей</b>
<br>
<div id = "user-list">Проект не выбран</div>
</div>
<div id = "companies" class = "block">
<b>Список компаний</b><button id = "add-company">Добавить/Обновить</button>
<br>
<input id = "company-id" placeholder = "Id">
<input id = "company-name" placeholder = "Name">
<input id = "company-description" placeholder = "Description">
<br>
<div id = "company-list">Проект не выбран</div>
</div>
</div>
<div id = "miniapp" style = "min-height: 20px; border: 1px black solid; padding:10px; word-break: break-all;" hidden>
Пользов
</div>
<script type="text/javascript">
const $miniapp = document.getElementById('miniapp')
const $adminapp = document.getElementById('adminapp')
$adminapp.querySelector('#settings #update-profile').addEventListener('click', async function (event) {
const $e = this.parentNode
const data = {
name: $e.querySelector('#name').value,
company: {
name: $e.querySelector('#company-name').value,
phone: $e.querySelector('#company-phone').value,
site: $e.querySelector('#company-site').value,
description: $e.querySelector('#company-description').value
}
}
const res = await fetch('/api/admin/customer/profile', {
method: 'PUT',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json())
console.log(res)
})
$adminapp.querySelector('#projects #project-list').addEventListener('click', async function (event) {
const $e = event.target
if ($e.id != 'delete')
return
const id = $e.parentNode.id
const res = await fetch('/api/admin/project/' + id, {
method: 'DELETE'
}).then(res => res.json())
.then(res => $e.parentNode.remove())
.catch(alert)
})
$adminapp.querySelector('#projects #project-list').addEventListener('click', async function (event) {
const $e = event.target
if ($e.parentNode.id != 'project-list')
return
$adminapp.querySelector('#projects #project-id').value = $e.id
$adminapp.querySelector('#projects #project-name').value = $e.getAttribute('name')
$adminapp.querySelector('#projects #project-description').value = $e.getAttribute('title')
$adminapp.querySelector('#groups #add-group').setAttribute('href', 'https://t.me/ready_or_not_2025_bot?startgroup=' + $e.id)
reloadGroups($e.id)
reloadUsers($e.id)
reloadCompanies($e.id)
const reqKey = await fetch('/api/admin/project/' + $e.id + '/token').then(res => res.json())
const url = 'https://t.me/share/url?url=' + reqKey.data
$adminapp.querySelector('#groups #share').setAttribute('href', url)
})
$adminapp.querySelector('#companies #company-list').addEventListener('click', async function (event) {
const $e = event.target
if ($e.id != 'delete')
return
const id = $e.parentNode.id
const project_id = $adminapp.querySelector('#groups #group-list').getAttribute('project-id')
const res = await fetch(`/api/admin/project/${project_id}/company/${id}`, {
method: 'DELETE'
}).then(res => res.json())
.then(res => $e.parentNode.remove())
.catch(alert)
})
$adminapp.querySelector('#companies #company-list').addEventListener('click', async function (event) {
const $e = event.target
if ($e.parentNode.id != 'company-list')
return
$adminapp.querySelector('#companies #company-id').value = $e.id
$adminapp.querySelector('#companies #company-name').value = $e.getAttribute('name')
$adminapp.querySelector('#companies #company-description').value = $e.getAttribute('title')
})
$adminapp.querySelector('#groups #group-list').addEventListener('click', async function (event) {
const $e = event.target
if ($e.id != 'delete')
return
const id = $e.parentNode.id
const project_id = $adminapp.querySelector('#groups #group-list').getAttribute('project-id')
const res = await fetch(`/api/admin/project/${project_id}/group/${id}`, {
method: 'DELETE'
}).then(res => res.json())
.then(res => $e.parentNode.remove())
.catch(alert)
})
$adminapp.querySelectorAll('button[href]')
.forEach($e => {
$e.addEventListener('click', async function (event) {
// &admin=change_info+delete_messages+restrict_members+invite_users+pin_messages+promote_members
let url = this.getAttribute('href')
if ($e.hasAttribute('admin'))
url += '&admin=change_info+pin_messages'
window.Telegram.WebApp.openTelegramLink(url)
})
})
async function reloadProjects() {
const reqProjects = await fetch('/api/admin/project').then(res => res.json())
const projects = reqProjects.data
const $projectList = $adminapp.querySelector('#projects #project-list')
$projectList.innerHTML = projects.map(e => `<div id = "${e.id}" title = "${e.description}" name = "${e.name}">${e.name}<span id = "delete">x</div></div>`).join('') || 'Пусто'
}
async function reloadGroups(projectId) {
const req = await fetch('/api/admin/project/' + projectId + '/group').then(res => res.json())
const groups = req.data
const $groupList = $adminapp.querySelector('#groups #group-list')
$groupList.setAttribute('project-id', projectId)
$groupList.innerHTML = groups.map(e => `<div id = "${e.id}" name = "${e.name}">${e.name}<span id = "delete">x</div></div>`).join('') || 'Пусто'
}
async function reloadCompanies(projectId) {
const req = await fetch('/api/admin/project/' + projectId + '/company').then(res => res.json())
const companies = req.data
const $companyList = $adminapp.querySelector('#companies #company-list')
$companyList.setAttribute('project-id', projectId)
$companyList.innerHTML = companies.map(e => `<div id = "${e.id}" name = "${e.name}" title = "${e.description}">${e.name}<span id = "delete">x</div></div>`).join('') || 'Пусто'
}
async function reloadUsers(projectId) {
const req = await fetch('/api/admin/project/' + projectId + '/user').then(res => res.json())
const users = req.data
const $userList = $adminapp.querySelector('#users #user-list')
$userList.setAttribute('user-id', projectId)
$userList.innerHTML = users.map(e => `<div id = "${e.id}">${e.firstname} ${e.lastname}</div>`).join('') || 'Пусто'
}
$adminapp.querySelector('#projects #add-project').addEventListener('click', async function (event) {
const $e = this.parentNode
const id = +$e.querySelector('#project-id').value
const data = {
name: $e.querySelector('#project-name').value,
description: $e.querySelector('#project-description').value
}
const url = id ? '/api/admin/project/' + id : '/api/admin/project'
const method = id ? 'PUT' : 'POST'
await fetch(url, {
method,
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json()).then(() => {
reloadProjects()
$e.querySelector('#project-id').value = ''
$e.querySelector('#project-name').value = ''
$e.querySelector('#project-description').value = ''
}).catch(alert)
})
$adminapp.querySelector('#companies #add-company').addEventListener('click', async function (event) {
const $e = this.parentNode
const project_id = +$adminapp.querySelector('#groups #group-list').getAttribute('project-id')
const id = +$e.querySelector('#company-id').value
const data = {
name: $e.querySelector('#company-name').value,
description: $e.querySelector('#company-description').value
}
const url = '/api/admin/project/' + project_id + '/company' + (id ? '/' + id : '')
const method = id ? 'PUT' : 'POST'
await fetch(url, {
method,
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json()).then(() => {
reloadCompanies(project_id)
$e.querySelector('#company-id').value = ''
$e.querySelector('#company-name').value = ''
$e.querySelector('#company-description').value = ''
}).catch(alert)
})
try {
(async () => {
const startParams = (Telegram.WebApp.initDataUnsafe.start_param || '').split('_')
const isAdmin = startParams[0] == 'admin'
const $app = isAdmin ? $adminapp : $miniapp
$app.hidden = false
const login_url = isAdmin ? '/api/admin/customer/login?' : '/api/miniapp/user/login?'
const login = await fetch(login_url + Telegram.WebApp.initData, {method: 'POST'}).then(res => res.json())
console.log(login)
if (isAdmin) {
const reqProfile = await fetch('/api/admin/customer/profile').then(res => res.json())
const profile = reqProfile.data
$adminapp.querySelector('#settings #name').value = profile.name || ''
$adminapp.querySelector('#settings #company-name').value = profile.company?.name || ''
$adminapp.querySelector('#settings #company-phone').value = profile.company?.phone || ''
$adminapp.querySelector('#settings #company-site').value = profile.company?.site || ''
$adminapp.querySelector('#settings #company-description').value = profile.company?.description || ''
$adminapp.querySelector('#settings #upload-group-selector').setAttribute('href', 'https://t.me/ready_or_not_2025_bot?startgroup=-' + profile.id)
const $uploadGroup = $adminapp.querySelector('#settings #upload-group')
if (profile.upload_group) {
$uploadGroup.innerHTML = profile.upload_group.name || 'Ошибка'
$uploadGroup.setAttribute('href', 'https://t.me/c/' + profile.upload_group.telegram_id)
} else {
$uploadGroup.innerHTML = 'Не задано'
$uploadGroup.setAttribute('href', '')
}
await reloadProjects()
} else {
// Пользовательский
if (startParams[1])
alert('Группа на проекте ' + startParams[1])
}
})()
} catch (err) {
alert(err)
}
</script>
</body>
</html>