Vendored
+1
@@ -28,6 +28,7 @@ declare module 'vue' {
|
|||||||
InputText: typeof import('primevue/inputtext')['default']
|
InputText: typeof import('primevue/inputtext')['default']
|
||||||
ManagePlacementInstructions: typeof import('./src/components/manage/ManagePlacementInstructions.vue')['default']
|
ManagePlacementInstructions: typeof import('./src/components/manage/ManagePlacementInstructions.vue')['default']
|
||||||
ProgressSpinner: typeof import('primevue/progressspinner')['default']
|
ProgressSpinner: typeof import('primevue/progressspinner')['default']
|
||||||
|
QRCodeCard: typeof import('./src/components/manage/QRCodeCard.vue')['default']
|
||||||
QueryRender: typeof import('./src/components/QueryRender.vue')['default']
|
QueryRender: typeof import('./src/components/QueryRender.vue')['default']
|
||||||
RadioButton: typeof import('primevue/radiobutton')['default']
|
RadioButton: typeof import('primevue/radiobutton')['default']
|
||||||
ReadContactInfo: typeof import('./src/components/read/ReadContactInfo.vue')['default']
|
ReadContactInfo: typeof import('./src/components/read/ReadContactInfo.vue')['default']
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
"name": "НаСвязи",
|
"name": "НаСвязи",
|
||||||
"short_name": "НаСвязи",
|
"short_name": "НаСвязи",
|
||||||
"categories": ["communication", "utilities", "social", "productivity"],
|
"categories": ["communication", "utilities", "social", "productivity"],
|
||||||
"start_url": "/",
|
"id": "https://hereconnect.condev.ru",
|
||||||
|
"start_url": "https://hereconnect.condev.ru/manage/dashboard",
|
||||||
|
"scope": "https://hereconnect.condev.ru/",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/android-chrome-192x192.png",
|
"src": "/android-chrome-192x192.png",
|
||||||
|
|||||||
@@ -5,16 +5,26 @@ type Props = {
|
|||||||
query: UseQueryReturnType<R, E>
|
query: UseQueryReturnType<R, E>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const slots = defineSlots<{
|
||||||
|
default?: (slotBindings: { data: R }) => void
|
||||||
|
error?: (slotBindings: { error: E; reload: typeof refetch }) => void
|
||||||
|
loading?: () => void
|
||||||
|
}>()
|
||||||
|
|
||||||
const { query } = defineProps<Props>()
|
const { query } = defineProps<Props>()
|
||||||
|
|
||||||
const { data, error, refetch, isSuccess, isError, isLoading } = query
|
const { data, error, refetch, isSuccess, isError, isLoading } = query
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<slot v-if="isSuccess" name="default" :data="data! as R" />
|
<slot v-if="isSuccess" name="default" :data="data!" />
|
||||||
<slot v-else-if="isLoading" name="loading"><p class="text-gray-500">Загрузка данных...</p></slot>
|
<slot v-else-if="isLoading" name="loading">
|
||||||
<slot v-else-if="isError" name="error" :error="error as E" :reload="refetch">
|
<p class="text-gray-500" v-if="!slots.loading">Загрузка данных...</p>
|
||||||
Ошибка загрузки данных:
|
</slot>
|
||||||
{{ error && typeof error === 'object' && 'message' in error ? error.message : error }}
|
<slot v-else-if="isError" name="error" :error="error!" :reload="refetch">
|
||||||
|
<template v-if="!slots.error">
|
||||||
|
Ошибка загрузки данных:
|
||||||
|
{{ error && typeof error === 'object' && 'message' in error ? error.message : error }}
|
||||||
|
</template>
|
||||||
</slot>
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<template>
|
||||||
|
<RouterLink :to="`/manage/qr/${qrCode.uri}`" class="p-4 rounded-lg bg-white shadow-md">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<i :class="['pi', iconClass, 'text-gray-500', 'mr-2']" />
|
||||||
|
<h2 class="text-lg font-semibold">{{ qrCode.name }}</h2>
|
||||||
|
</div>
|
||||||
|
<!-- <Button-->
|
||||||
|
<!-- label="Настроить"-->
|
||||||
|
<!-- :to="`/manage/${qrCode.uri}/settings`"-->
|
||||||
|
<!-- as="router-link"-->
|
||||||
|
<!-- class="p-button-outlined p-button-sm"-->
|
||||||
|
<!-- />-->
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-500">Создано: {{ formatedCreatedAt }}</div>
|
||||||
|
</RouterLink>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, defineProps } from 'vue'
|
||||||
|
import type { QRCodeDocument } from '@hereconnect/types'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
qrCode: QRCodeDocument
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const iconClass = computed(() => {
|
||||||
|
const icons: Record<string, string> = {
|
||||||
|
car: 'pi-car',
|
||||||
|
pet: 'pi-paw',
|
||||||
|
door: 'pi-door-closed',
|
||||||
|
store: 'pi-shop',
|
||||||
|
restaurant_table: 'pi-utensils',
|
||||||
|
other: 'pi-question-circle',
|
||||||
|
}
|
||||||
|
return icons[props.qrCode.placement] || 'pi-question-circle'
|
||||||
|
})
|
||||||
|
|
||||||
|
const formatDate = (date: string) => {
|
||||||
|
// Форматирование даты
|
||||||
|
const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' }
|
||||||
|
return new Date(date).toLocaleDateString(['ru-RU'], options)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatedCreatedAt = computed(() => formatDate(props.qrCode.created_at))
|
||||||
|
</script>
|
||||||
@@ -3,6 +3,7 @@ export const ROUTE_NAMES = {
|
|||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
MANAGE_QR_CODE_READY: 'manage-qr-code-ready',
|
MANAGE_QR_CODE_READY: 'manage-qr-code-ready',
|
||||||
MANAGE_QR_CODE_CHAT: 'manage-qr-code-chat',
|
MANAGE_QR_CODE_CHAT: 'manage-qr-code-chat',
|
||||||
|
MANAGE_DASHBOARD: 'manage-dashboard',
|
||||||
READ_QR_CODE: 'read-qr-code',
|
READ_QR_CODE: 'read-qr-code',
|
||||||
DONATE: 'donate',
|
DONATE: 'donate',
|
||||||
PUBLIC_CHAT: 'public-chat',
|
PUBLIC_CHAT: 'public-chat',
|
||||||
|
|||||||
@@ -14,13 +14,19 @@ const routes = [
|
|||||||
component: () => import('@/views/CreateView.vue'),
|
component: () => import('@/views/CreateView.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/manage/:qr_code_uri/ready',
|
path: '/manage/dashboard',
|
||||||
|
name: ROUTE_NAMES.MANAGE_DASHBOARD,
|
||||||
|
component: () => import('@/views/ManageDashboardView.vue'),
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/manage/qr/:qr_code_uri/ready',
|
||||||
name: ROUTE_NAMES.MANAGE_QR_CODE_READY,
|
name: ROUTE_NAMES.MANAGE_QR_CODE_READY,
|
||||||
component: () => import('@/views/ManageQRCodeReadyView.vue'),
|
component: () => import('@/views/ManageQRCodeReadyView.vue'),
|
||||||
props: true,
|
props: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/manage/:qr_code_uri/chat/:chat',
|
path: '/manage/qr/:qr_code_uri/chat/:chat',
|
||||||
name: ROUTE_NAMES.MANAGE_QR_CODE_CHAT,
|
name: ROUTE_NAMES.MANAGE_QR_CODE_CHAT,
|
||||||
component: () => import('@/views/ManageQRCodeChatView.vue'),
|
component: () => import('@/views/ManageQRCodeChatView.vue'),
|
||||||
props: true,
|
props: true,
|
||||||
@@ -37,7 +43,7 @@ const routes = [
|
|||||||
component: () => import('@/views/DonateView.vue'),
|
component: () => import('@/views/DonateView.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/chat/:qr_code_uri/:chat',
|
path: '/read/:qr_code_uri/chat/:chat',
|
||||||
name: ROUTE_NAMES.PUBLIC_CHAT,
|
name: ROUTE_NAMES.PUBLIC_CHAT,
|
||||||
component: () => import('@/views/PublicChatView.vue'),
|
component: () => import('@/views/PublicChatView.vue'),
|
||||||
props: true,
|
props: true,
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<h1 class="text-2xl font-bold mb-4 text-center">Управление QR-кодами</h1>
|
||||||
|
<QueryRender :query="query">
|
||||||
|
<template #default="{ data }">
|
||||||
|
<div v-if="data.rows.length > 0" class="flex flex-col gap-5">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
<QRCodeCard v-for="{ doc: qrCode } in data.rows" :key="qrCode!.uri" :qrCode="qrCode!" />
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<Button
|
||||||
|
icon="pi pi-qrcode"
|
||||||
|
label="Создать QR‑код"
|
||||||
|
to="/create"
|
||||||
|
as="router-link"
|
||||||
|
class="p-button-sm"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="text-center text-gray-500">
|
||||||
|
<p>Нет созданных QR-кодов. Вы можете создать их прямо сейчас!</p>
|
||||||
|
<Button
|
||||||
|
icon="pi pi-qrcode"
|
||||||
|
label="Создать QR‑код"
|
||||||
|
to="/create"
|
||||||
|
as="router-link"
|
||||||
|
class="p-button-lg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #error="{ reload }">
|
||||||
|
<div class="text-center text-red-500">
|
||||||
|
<p>Произошла ошибка при загрузке данных. Пожалуйста, попробуйте позже.</p>
|
||||||
|
<Button label="Повторить попытку" class="p-button mt-4" @click="reload()" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #loading>
|
||||||
|
<div class="text-center text-gray-500">
|
||||||
|
<p>Загрузка QR-кодов...</p>
|
||||||
|
<ProgressSpinner styleClass="mt-4" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</QueryRender>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useQuery } from '@tanstack/vue-query'
|
||||||
|
import { qrCodeDbLocal } from '@/api/dbs'
|
||||||
|
|
||||||
|
const query = useQuery({
|
||||||
|
queryKey: ['qrCodes'],
|
||||||
|
queryFn: async () => {
|
||||||
|
return qrCodeDbLocal.allDocs({
|
||||||
|
include_docs: true,
|
||||||
|
startkey: 'qr_code:',
|
||||||
|
endkey: 'qr_code:\uffff',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -121,7 +121,7 @@ const start = async () => {
|
|||||||
requireInteraction: true,
|
requireInteraction: true,
|
||||||
timestamp,
|
timestamp,
|
||||||
data: {
|
data: {
|
||||||
url: `/manage/${msgDoc.qr_code_uri}/chat/${msgDoc.chat}#message-${msgDoc.created_at}`,
|
url: `/manage/qr/${msgDoc.qr_code_uri}/chat/${msgDoc.chat}#message-${msgDoc.created_at}`,
|
||||||
payload: { tag },
|
payload: { tag },
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
@@ -200,7 +200,7 @@ const start = async () => {
|
|||||||
requireInteraction: true,
|
requireInteraction: true,
|
||||||
timestamp,
|
timestamp,
|
||||||
data: {
|
data: {
|
||||||
url: `/chat/${msgDoc.qr_code_uri}/${msgDoc.chat}#message-${msgDoc.created_at}`,
|
url: `/read/qr/${msgDoc.qr_code_uri}/chat/${msgDoc.chat}#msg-${msgDoc.created_at}`,
|
||||||
payload: { tag },
|
payload: { tag },
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
Reference in New Issue
Block a user