12
This commit is contained in:
@@ -68,7 +68,6 @@
|
||||
{ id: 5, name: 'account__company_data', icon: 'mdi-account-group-outline', description: 'account__company_data_description', pathName: 'your_company' },
|
||||
{ id: 6, name: 'account__settings', icon: 'mdi-cog-outline', description: 'account__settings_description', iconColor: 'info', pathName: 'settings' },
|
||||
{ id: 7, name: 'account__support', icon: 'mdi-lifebuoy', description: 'account__support_description', iconColor: 'info', pathName: 'support' },
|
||||
{ id: 8, name: 'account__3rd_party_software', icon: 'mdi-scale-balance', description: 'account__3rd_party_software_description', iconColor: 'grey', pathName: '3software' },
|
||||
{ id: 9, name: 'account__terms_of_use', icon: 'mdi-book-open-variant-outline', description: '', iconColor: 'grey', pathName: 'terms' },
|
||||
{ id: 10, name: 'account__privacy', icon: 'mdi-lock-outline', description: '', iconColor: 'grey', pathName: 'privacy' }
|
||||
]))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<company-block
|
||||
v-model="newCompany"
|
||||
title="company_create__title_card"
|
||||
btnText="company_create__btn"
|
||||
title="company_add__title_card"
|
||||
btnText="company_add__btn"
|
||||
@update = "addCompany"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
v-model="searchProject"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
:placeholder="$t('project_chats__search')"
|
||||
:placeholder="$t('projects__search')"
|
||||
dense
|
||||
class="col-grow q-px-md q-py-md"
|
||||
>
|
||||
@@ -91,22 +91,22 @@
|
||||
class="flex column items-center w100"
|
||||
:class="showArchive ? 'bg-grey-12' : ''"
|
||||
>
|
||||
<q-btn-dropdown
|
||||
class="w100 fix-rotate-arrow"
|
||||
<q-btn
|
||||
class="w100 rotate-icon-btn"
|
||||
color="grey"
|
||||
flat no-caps
|
||||
flat
|
||||
no-caps
|
||||
@click="showArchive=!showArchive"
|
||||
dropdown-icon="arrow_drop_up"
|
||||
icon-right="arrow_drop_down"
|
||||
:class="{ 'rotate-icon': showArchive }"
|
||||
>
|
||||
<template #label>
|
||||
<span class="text-caption">
|
||||
{{ !showArchive
|
||||
? $t('projects__show_archive') + ' (' + archiveProjects.length +')'
|
||||
: $t('projects__hide_archive')
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
</q-btn-dropdown>
|
||||
<span class="text-caption">
|
||||
{{ !showArchive
|
||||
? $t('projects__show_archive') + ' (' + archiveProjects.length +')'
|
||||
: $t('projects__hide_archive')
|
||||
}}
|
||||
</span>
|
||||
</q-btn>
|
||||
|
||||
<div class="w100" style="overflow: hidden">
|
||||
<transition
|
||||
@@ -186,6 +186,7 @@
|
||||
color="negative"
|
||||
title="projects__dialog_archive_title"
|
||||
message1="projects__dialog_archive_message"
|
||||
message2="projects__dialog_archive_message2"
|
||||
mainBtnLabel="projects__dialog_archive_ok"
|
||||
@clickMainBtn="onConfirmArchiveProject()"
|
||||
@close="onCancel()"
|
||||
@@ -198,7 +199,8 @@
|
||||
color="green"
|
||||
title="projects__dialog_restore_title"
|
||||
message1="projects__dialog_restore_message"
|
||||
mainBtnLabel="projects__dialog_cancel_ok"
|
||||
message2="projects__dialog_restore_message2"
|
||||
mainBtnLabel="projects__dialog_restore_ok"
|
||||
@clickMainBtn="restoreFromArchive()"
|
||||
/>
|
||||
</template>
|
||||
@@ -319,7 +321,17 @@
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.fix-rotate-arrow :deep(.q-btn-dropdown--simple) {
|
||||
margin-left: 0;
|
||||
.rotate-icon-btn {
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.rotate-icon-btn.rotate-icon :deep(.q-icon) {
|
||||
transform: rotate(180deg);
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
|
||||
}
|
||||
|
||||
.rotate-icon-btn :deep(.q-icon) {
|
||||
transform: rotate(0deg);
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,234 +0,0 @@
|
||||
<template>
|
||||
<pn-page-card>
|
||||
<template #title>
|
||||
{{ $t('software__title') }}
|
||||
</template>
|
||||
|
||||
<pn-scroll-list>
|
||||
<template #card-body-header>
|
||||
<div class="q-pa-md">
|
||||
{{ $t('software__description') }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<q-list separator>
|
||||
<q-expansion-item
|
||||
v-for="item in software"
|
||||
group="somegroup"
|
||||
>
|
||||
<template #header>
|
||||
<q-item-section avatar>
|
||||
<q-avatar square size="sm" v-if="item.logo">
|
||||
<img :src="'3software/logo/' + item.logo">
|
||||
</q-avatar>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<div class="flex items-baseline">
|
||||
<span class="text-h6">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<span v-if = "item.ver" class="text-caption q-pl-xs">
|
||||
{{ 'v.' + item.ver }}
|
||||
</span>
|
||||
</div>
|
||||
</q-item-section>
|
||||
</template>
|
||||
<div class="w100 flex column q-px-md q-gutter-y-md q-py-sm">
|
||||
<div class="flex row no-wrap items-center">
|
||||
<q-icon name="mdi-scale-balance" size="sm" class="q-pr-lg" color="grey"/>
|
||||
<div
|
||||
@click="downloadFile('3software/license/' + item.license_file)"
|
||||
class="flex w100 column q-pl-sm cursor-pointer"
|
||||
>
|
||||
<span> {{ item.license }} </span>
|
||||
<span
|
||||
class="text-caption"
|
||||
style="white-space: pre-line;"
|
||||
>
|
||||
{{ item.license_copyright }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex row no-wrap items-center" v-if="item.web">
|
||||
<q-icon name="mdi-web" size="sm" class="q-pr-lg" color="grey"/>
|
||||
<span
|
||||
class="q-pl-sm cursor-pointer"
|
||||
@click="tg.openLink(item.web_url)"
|
||||
>
|
||||
{{ item.web }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex row no-wrap items-center" v-if="item.git">
|
||||
<q-icon name="mdi-github" size="sm" class="q-pr-lg" color="grey"/>
|
||||
<span
|
||||
class="q-pl-sm cursor-pointer"
|
||||
@click="tg.openLink(item.git_url)"
|
||||
>
|
||||
{{ item.git }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</q-expansion-item>
|
||||
</q-list>
|
||||
</pn-scroll-list>
|
||||
</pn-page-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { inject } from 'vue'
|
||||
import type { WebApp } from '@twa-dev/types'
|
||||
|
||||
const tg = inject('tg') as WebApp
|
||||
|
||||
const software = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Vue',
|
||||
ver: '3.4',
|
||||
logo: 'vue.webp',
|
||||
web: 'vuejs.org',
|
||||
web_url: 'https://vuejs.org/',
|
||||
git: 'vuejs/core',
|
||||
git_url: 'https://github.com/vuejs/core',
|
||||
license: 'MIT License',
|
||||
license_copyright: 'Copyright (c) 2018-present, Yuxi (Evan) You and Vue contributors',
|
||||
license_file: 'vue/LICENSE.txt'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Quasar',
|
||||
ver: '2.x',
|
||||
logo: 'quasar.png',
|
||||
web: 'quasar.dev',
|
||||
web_url: 'https://quasar.dev/',
|
||||
git: 'quasarframework/quasar',
|
||||
git_url: 'https://github.com/quasarframework/quasar',
|
||||
license: 'MIT License',
|
||||
license_copyright: 'Copyright (c) 2015-present Razvan Stoenescu',
|
||||
license_file: 'quasar/LICENSE.txt'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Pinia',
|
||||
ver: '2.x',
|
||||
logo: 'pinia.svg',
|
||||
web: 'pinia.vuejs.org',
|
||||
web_url: 'https://pinia.vuejs.org/',
|
||||
git: 'vuejs/pinia',
|
||||
git_url: 'https://github.com/vuejs/pinia',
|
||||
license: 'MIT License',
|
||||
license_copyright: 'Copyright (c) 2019-present Eduardo San Martin Morote',
|
||||
license_file: 'pinia/LICENSE.txt'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Vue Router',
|
||||
ver: '4.x',
|
||||
logo: 'vue.webp',
|
||||
web: 'router.vuejs.org',
|
||||
web_url: 'https://router.vuejs.org/',
|
||||
git: 'vuejs/router',
|
||||
git_url: 'https://github.com/vuejs/router',
|
||||
license: 'MIT License',
|
||||
license_copyright: 'Copyright (c) 2019-present Eduardo San Martin Morote',
|
||||
license_file: 'vue-router/LICENSE.txt'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Vue i18n',
|
||||
ver: '9.x',
|
||||
logo: 'vue-i18n.svg',
|
||||
web: 'vue-i18n.intlify.dev',
|
||||
web_url: 'https://vue-i18n.intlify.dev/',
|
||||
git: 'intlify/vue-i18n',
|
||||
git_url: 'https://github.com/intlify/vue-i18n',
|
||||
license: 'MIT License',
|
||||
license_copyright: 'Copyright (c) 2016-present kazuya kawaguchi and contributors',
|
||||
license_file: 'vue-i18n/LICENSE.txt'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Axios',
|
||||
ver: '1.x',
|
||||
logo: 'axios.svg',
|
||||
web: 'axios-http.com',
|
||||
web_url: 'https://axios-http.com/',
|
||||
git: 'axios/axios',
|
||||
git_url: 'https://github.com/axios/axios',
|
||||
license: 'MIT License',
|
||||
license_copyright: 'Copyright (c) 2014-present Matt Zabriskie & Collaborators',
|
||||
license_file: 'axios/LICENSE.txt'
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'better-sqlite3',
|
||||
ver: '11.x',
|
||||
logo: '',
|
||||
web: '',
|
||||
web_url: '',
|
||||
git: 'WiseLibs/better-sqlite3',
|
||||
git_url: 'https://github.com/WiseLibs/better-sqlite3',
|
||||
license: 'MIT License',
|
||||
license_copyright: 'Copyright (c) 2017 Joshua Wise',
|
||||
license_file: 'better-sqlite3/LICENSE.txt'
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Express',
|
||||
ver: '4.x',
|
||||
logo: 'express.svg',
|
||||
web: 'expressjs.com',
|
||||
web_url: 'https://expressjs.com/',
|
||||
git: 'expressjs/express',
|
||||
git_url: 'https://github.com/expressjs/express',
|
||||
license: 'MIT License',
|
||||
license_copyright: `Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
|
||||
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>`,
|
||||
license_file: 'express/LICENSE.txt'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
const downloadFile = async (url: string) => {
|
||||
try {
|
||||
const fullUrl = '/admin/' + url;
|
||||
const fileUrl = new URL(fullUrl, window.location.origin).href;
|
||||
|
||||
const response = await fetch(fileUrl)
|
||||
|
||||
if (!response.ok) throw new Error(`HTTP error: ${response.status}`)
|
||||
|
||||
const blob = await response.blob()
|
||||
const downloadUrl = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
|
||||
const extractFileName = (url: string): string => {
|
||||
return url.substring(url.lastIndexOf('/') + 1)
|
||||
}
|
||||
|
||||
link.href = downloadUrl
|
||||
link.download = extractFileName(url)
|
||||
link.style.display = 'none'
|
||||
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(link)
|
||||
URL.revokeObjectURL(downloadUrl)
|
||||
}, 100)
|
||||
|
||||
} catch (error) {
|
||||
console.error('Download error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scope>
|
||||
</style>
|
||||
@@ -6,75 +6,120 @@
|
||||
|
||||
<pn-scroll-list>
|
||||
<q-list separator>
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-avatar color="primary" rounded text-color="white" icon="mdi-translate" size="md" />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<span>{{ $t('settings__language') }}</span>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-select
|
||||
class="fix-input-right text-body1"
|
||||
v-model="locale"
|
||||
:options="localeOptions"
|
||||
dense
|
||||
borderless
|
||||
emit-value
|
||||
map-options
|
||||
hide-bottom-space
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-avatar color="primary" rounded text-color="white" icon="mdi-format-size" size="md" />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<span>{{ $t('settings__font_size') }}</span>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<div class="flex justify-end">
|
||||
<q-btn
|
||||
@click="settingsStore.decreaseFontSize()"
|
||||
color="negative" flat
|
||||
icon="mdi-format-font-size-decrease"
|
||||
class="q-pa-sm q-mx-xs"
|
||||
:disable="!settingsStore.canDecrease"
|
||||
/>
|
||||
<q-btn
|
||||
@click="settingsStore.increaseFontSize()"
|
||||
color="positive" flat
|
||||
icon="mdi-format-font-size-increase"
|
||||
class="q-pa-sm q-mx-xs"
|
||||
:disable="!settingsStore.canIncrease"
|
||||
/>
|
||||
</div>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item-label header>{{ $t('settings__software_title') }}</q-item-label>
|
||||
|
||||
<pn-item-btm-dialog
|
||||
title="settings__language"
|
||||
caption="settings__software_title"
|
||||
icon="mdi-translate"
|
||||
iconColor="primary"
|
||||
>
|
||||
<template #value>
|
||||
{{ localeOptions.find(el => el.value === locale)?.label }}
|
||||
</template>
|
||||
<pn-list-selector
|
||||
v-model="locale"
|
||||
:options="localeOptions"
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
|
||||
<pn-item-btm-dialog
|
||||
title="settings__font_size"
|
||||
caption="settings__software_title"
|
||||
icon="mdi-format-size"
|
||||
iconColor="primary"
|
||||
>
|
||||
<template #value>
|
||||
{{ $t(fontSizeLabel) }}
|
||||
</template>
|
||||
<pn-list-selector
|
||||
v-model="fontSize"
|
||||
:options="fontSizeOptions"
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
|
||||
<q-item-label class="q-mt-md" header>{{ $t('settings__bot_title') }}</q-item-label>
|
||||
|
||||
<pn-item-btm-dialog
|
||||
title="settings__language"
|
||||
caption="settings__bot_title"
|
||||
icon="mdi-translate"
|
||||
iconColor="primary"
|
||||
>
|
||||
<template #value>
|
||||
{{ localeOptions.find(el => el.value === localeBot)?.label }}
|
||||
</template>
|
||||
<pn-list-selector
|
||||
v-model="localeBot"
|
||||
:options="localeOptions"
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
<pn-item-btm-dialog
|
||||
title="settings__timezone"
|
||||
caption="settings__bot_title"
|
||||
icon="mdi-map-clock-outline"
|
||||
iconColor="primary"
|
||||
>
|
||||
<template #value>
|
||||
{{ timeZoneBot.tz }}
|
||||
{{ timeZoneBot.offsetString }}
|
||||
</template>
|
||||
|
||||
<pn-time-zone-selector
|
||||
v-model="timeZoneBot"
|
||||
:locale
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
</q-list>
|
||||
</pn-scroll-list>
|
||||
</pn-page-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { ref, watch, computed, onMounted } from 'vue'
|
||||
import { useSettingsStore } from 'stores/settings'
|
||||
import pnItemBtmDialog from 'components/pnItemBtmDialog.vue'
|
||||
import pnListSelector from 'components/pnListSelector.vue'
|
||||
import pnTimeZoneSelector from 'components/pnTimeZoneSelector.vue'
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
const locale = ref('')
|
||||
const localeBot = ref('')
|
||||
const localeOptions = settingsStore.supportLocale
|
||||
|
||||
const locale = computed({
|
||||
get: () => settingsStore.settings.locale,
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
set: (value: string) => settingsStore.updateLocale(value)
|
||||
watch(locale, async (newValue) => {
|
||||
await settingsStore.updateSettings({ locale: newValue })
|
||||
})
|
||||
|
||||
watch(localeBot, async (newValue) => {
|
||||
await settingsStore.updateSettings({ localeBot: newValue })
|
||||
})
|
||||
|
||||
const fontSize = ref(14)
|
||||
const fontSizeOptions = settingsStore.supportFontSizes
|
||||
const fontSizeLabel = computed(() =>
|
||||
fontSizeOptions.find(el => el.value === fontSize.value)?.label ?? ''
|
||||
)
|
||||
|
||||
watch(fontSize, async (newValue) => {
|
||||
await settingsStore.updateSettings({ fontSize: newValue })
|
||||
})
|
||||
|
||||
const timeZoneBot = ref<{ tz: string, offset: number }>({ tz: '', offset: 1 })
|
||||
|
||||
watch(timeZoneBot, async (newValue) => {
|
||||
if (newValue) await settingsStore.updateSettings({ timeZoneBot: newValue })
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
locale.value = settingsStore.settings.locale
|
||||
localeBot.value = settingsStore.settings.localeBot
|
||||
fontSize.value = settingsStore.settings.fontSize
|
||||
timeZoneBot.value = settingsStore.settings.timeZoneBot
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fix-input-right :deep(.q-field__native) {
|
||||
justify-content: end;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
v-model="search"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
:placeholder="$t('project_chats__search')"
|
||||
:placeholder="$t('chats__search')"
|
||||
dense
|
||||
class="col-grow"
|
||||
v-if="chats.length !== 0"
|
||||
@@ -71,8 +71,8 @@
|
||||
<pn-onboard-btn
|
||||
v-if="chats.length === 0 && chatsInit"
|
||||
icon="mdi-chat-plus-outline"
|
||||
:message1="$t('project_chat__onboard_msg1')"
|
||||
:message2="$t('project_chat__onboard_msg2')"
|
||||
:message1="$t('chats__onboard_msg1')"
|
||||
:message2="$t('chats__onboard_msg2')"
|
||||
@click="showOverlay=true; fabState=true"
|
||||
/>
|
||||
<div
|
||||
@@ -110,7 +110,7 @@
|
||||
anchor="center left" self="center end"
|
||||
style="width: calc(min(100vw, var(--body-width)) - 102px) !important;"
|
||||
>
|
||||
{{ $t('project_chats_disabled_FAB')}}
|
||||
{{ $t('chats_disabled_FAB')}}
|
||||
</q-tooltip>
|
||||
</template>
|
||||
<q-fab-action
|
||||
@@ -152,9 +152,10 @@
|
||||
v-model="showDialogDeleteChat"
|
||||
icon="mdi-link-off"
|
||||
color="negative"
|
||||
title="project_chat__delete_warning"
|
||||
message1="project_chat__delete_warning_message"
|
||||
mainBtnLabel="project_chat__dialog_cancel_ok"
|
||||
title="chats__dialog_unlink_title"
|
||||
message1="chats__dialog_unlink_message"
|
||||
message2="chats__dialog_unlink_message2"
|
||||
mainBtnLabel="chats__dialog_unlink_ok"
|
||||
@clickMainBtn="onConfirm()"
|
||||
@close="onCancel()"
|
||||
@before-hide="onDialogBeforeHide()"
|
||||
@@ -190,8 +191,8 @@
|
||||
const chatsInit = computed(() => chatsStore.isInit)
|
||||
|
||||
const fabMenu = [
|
||||
{id: 1, icon: 'mdi-chat-plus-outline', name: 'project_chats__attach_chat', description: 'project_chats__attach_chat_description', func: attachChat},
|
||||
{id: 2, icon: 'mdi-share-outline', name: 'project_chats__send_chat', description: 'project_chats__send_chat_description', func: sendChat},
|
||||
{id: 1, icon: 'mdi-chat-plus-outline', name: 'chats__attach_chat', description: 'chats__attach_chat_description', func: attachChat},
|
||||
{id: 2, icon: 'mdi-share-outline', name: 'chats__send_chat', description: 'chats__send_chat_description', func: sendChat},
|
||||
]
|
||||
|
||||
const displayChats = computed(() => {
|
||||
@@ -253,7 +254,7 @@
|
||||
const key = await chatsStore.getKey()
|
||||
const message = urlAdmin + key + urlAdminPermission
|
||||
const tgShareUrl = 'https://t.me/share/url?url=' +
|
||||
encodeURIComponent( t('project_chats__send_chat_title')) +
|
||||
encodeURIComponent( t('chats__send_chat_title')) +
|
||||
'&text=' + `${encodeURIComponent(message)}`
|
||||
tg.openTelegramLink(tgShareUrl)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:color="companies.length <= 2 ? 'grey-6' : 'primary'"
|
||||
flat
|
||||
no-caps
|
||||
@click="maskCompany()"
|
||||
@click="maskCompany"
|
||||
:disable="companies.length <= 2"
|
||||
class="q-pr-md"
|
||||
rounded
|
||||
@@ -16,9 +16,10 @@
|
||||
left
|
||||
size="sm"
|
||||
name="mdi-domino-mask"
|
||||
class="q-mr-xs"
|
||||
/>
|
||||
<div>
|
||||
{{ $t('company__mask')}}
|
||||
{{ $t('companies__mask')}}
|
||||
</div>
|
||||
</q-btn>
|
||||
</div>
|
||||
@@ -53,7 +54,7 @@
|
||||
<q-item-label lines="1" class="text-caption text-amber-10" v-if="item.id === myCompany?.id">
|
||||
<div class="flex items-center">
|
||||
<q-icon name="star" class="q-pr-xs"/>
|
||||
{{ $t('company__my_company') }}
|
||||
{{ $t('companies__my_company') }}
|
||||
</div>
|
||||
</q-item-label>
|
||||
<q-item-label lines="1" class="text-bold">{{ item.name }}</q-item-label>
|
||||
@@ -93,9 +94,9 @@
|
||||
<pn-onboard-btn
|
||||
v-if="companies.length <= 1 && companiesInit"
|
||||
icon="mdi-account-multiple-plus-outline"
|
||||
:message1="$t('company__onboard_msg1')"
|
||||
:message2="$t('company__onboard_msg2')"
|
||||
@btn-click="createCompany()"
|
||||
:message1="$t('companies__onboard_msg1')"
|
||||
:message2="$t('companies__onboard_msg2')"
|
||||
@btn-click="createCompany"
|
||||
/>
|
||||
<div
|
||||
class="flex column justify-center items-center w100"
|
||||
@@ -130,9 +131,10 @@
|
||||
v-model="showDialogDeleteCompany"
|
||||
icon="mdi-account-multiple-minus-outline"
|
||||
color="negative"
|
||||
title="company__dialog_delete_title"
|
||||
message1="company__dialog_delete_message"
|
||||
mainBtnLabel="company__dialog_delete_ok"
|
||||
title="companies__dialog_delete_title"
|
||||
message1="companies__dialog_delete_message"
|
||||
message2="companies__dialog_delete_message2"
|
||||
mainBtnLabel="companies__dialog_delete_ok"
|
||||
@clickMainBtn="onConfirm()"
|
||||
@close="onCancel()"
|
||||
@before-hide="onDialogBeforeHide()"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
v-model="search"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
:placeholder="$t('project_users__search')"
|
||||
:placeholder="$t('users__search')"
|
||||
dense
|
||||
class="col-grow"
|
||||
>
|
||||
@@ -60,27 +60,92 @@
|
||||
</q-slide-item>
|
||||
</q-list>
|
||||
|
||||
<!-- LEAVE USERS SECTION -->
|
||||
<div
|
||||
v-if="leaveUsers.length!==0"
|
||||
class="flex column items-center w100"
|
||||
:class="showLeaveUsers ? 'bg-grey-12' : ''"
|
||||
>
|
||||
<q-btn
|
||||
class="w100 rotate-icon-btn"
|
||||
color="grey"
|
||||
flat
|
||||
no-caps
|
||||
@click="showLeaveUsers=!showLeaveUsers"
|
||||
icon-right="arrow_drop_down"
|
||||
:class="{ 'rotate-icon': showLeaveUsers }"
|
||||
>
|
||||
<span class="text-caption">
|
||||
{{ !showLeaveUsers
|
||||
? $t('users__show_left_users') + ' (' + leaveUsers.length +')'
|
||||
: $t('users__hide_left_users')
|
||||
}}
|
||||
</span>
|
||||
</q-btn>
|
||||
|
||||
<div class="w100" style="overflow: hidden">
|
||||
<transition
|
||||
appear
|
||||
enter-active-class="animated slideInDown"
|
||||
leave-active-class="animated slideOutUp"
|
||||
>
|
||||
<q-list separator v-if="showLeaveUsers" class="w100">
|
||||
<q-item
|
||||
v-for = "item in leaveUsers"
|
||||
:key="item.id"
|
||||
class="w100 text-grey"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<pn-auto-avatar
|
||||
:img="item.photo"
|
||||
:name="item.section1"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label lines="1" class="text-bold" v-if="item.section1">
|
||||
{{item.section1}}
|
||||
</q-item-label>
|
||||
<q-item-label lines="1" caption v-if="item.section3">
|
||||
{{item.section3}}
|
||||
</q-item-label>
|
||||
<q-item-label caption lines="2">
|
||||
<div class="flex items-center">
|
||||
<q-icon name="telegram" v-if="item.section2_1 || item.section2_2" class="q-pr-xs" style="color: #27a7e7"/>
|
||||
<div v-if="item.section2_1" class="q-mr-sm text-bold">{{item.section2_1}}</div>
|
||||
<div class="text-blue" v-if="item.section2_2">{{'@' + item.section2_2}}</div>
|
||||
</div>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END LEAVE USERS SECTION -->
|
||||
|
||||
|
||||
<!-- BLOCKED USERS SECTION -->
|
||||
<div
|
||||
v-if="blockedUsers.length!==0"
|
||||
class="flex column items-center w100"
|
||||
:class="showBlockedUsers ? 'bg-grey-12' : ''"
|
||||
>
|
||||
<q-btn-dropdown
|
||||
class="w100 fix-rotate-arrow"
|
||||
<q-btn
|
||||
class="w100 rotate-icon-btn"
|
||||
color="grey"
|
||||
flat no-caps
|
||||
flat
|
||||
no-caps
|
||||
@click="showBlockedUsers=!showBlockedUsers"
|
||||
dropdown-icon="arrow_drop_up"
|
||||
icon-right="arrow_drop_down"
|
||||
:class="{ 'rotate-icon': showBlockedUsers }"
|
||||
>
|
||||
<template #label>
|
||||
<span class="text-caption">
|
||||
{{ !showBlockedUsers
|
||||
? $t('users__show_archive') + ' (' + blockedUsers.length +')'
|
||||
: $t('user__hide_archive')
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
</q-btn-dropdown>
|
||||
<span class="text-caption">
|
||||
{{ !showBlockedUsers
|
||||
? $t('users__show_blocked_users') + ' (' + blockedUsers.length +')'
|
||||
: $t('users__hide_blocked_users')
|
||||
}}
|
||||
</span>
|
||||
</q-btn>
|
||||
|
||||
<div class="w100" style="overflow: hidden">
|
||||
<transition
|
||||
@@ -123,12 +188,13 @@
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END BLOCKED USERS SECTION -->
|
||||
|
||||
<pn-onboard-btn
|
||||
v-if="users.length === 0 && usersInit"
|
||||
icon="mdi-account-outline"
|
||||
:message1="$t('project_users__onboard_msg1')"
|
||||
:message2="$t('project_users__onboard_msg2')"
|
||||
:message1="$t('users__onboard_msg1')"
|
||||
:message2="$t('users__onboard_msg2')"
|
||||
noBtn
|
||||
/>
|
||||
<div
|
||||
@@ -142,13 +208,14 @@
|
||||
</div>
|
||||
|
||||
<pn-small-dialog
|
||||
v-model="showDialogDeleteUser"
|
||||
v-model="showDialogBlockUser"
|
||||
icon="mdi-account-remove-outline"
|
||||
color="negative"
|
||||
title="user__dialog_delete_title"
|
||||
message1="user__dialog_delete_message"
|
||||
mainBtnLabel="user__dialog_delete_ok"
|
||||
@clickMainBtn="onConfirmDeleteUser()"
|
||||
title="users__dialog_block_title"
|
||||
message1="users__dialog_block_message"
|
||||
message2="users__dialog_block_message2"
|
||||
mainBtnLabel="users__dialog_block_ok"
|
||||
@clickMainBtn="onConfirmBlockUser()"
|
||||
@close="onCancel()"
|
||||
@before-hide="onDialogBeforeHide()"
|
||||
/>
|
||||
@@ -157,9 +224,10 @@
|
||||
v-model="showDialogRestoreUser"
|
||||
icon="mdi-account-reactivate-outline"
|
||||
color="green"
|
||||
title="user__dialog_restore_title"
|
||||
message1="user__dialog_restore_message"
|
||||
mainBtnLabel="user__dialog_restore_ok"
|
||||
title="users__dialog_restore_title"
|
||||
message1="users__dialog_restore_message"
|
||||
message2="users__dialog_restore_message2"
|
||||
mainBtnLabel="users__dialog_restore_ok"
|
||||
@clickMainBtn="onConfirmRestoreUser()"
|
||||
/>
|
||||
|
||||
@@ -183,12 +251,18 @@
|
||||
const users = usersStore.getUsers
|
||||
const usersInit = computed(() => usersStore.isInit)
|
||||
|
||||
const deleteUserId = ref<number | undefined>(undefined)
|
||||
const showDialogDeleteUser = ref<boolean>(false)
|
||||
const blockUserId = ref<number | undefined>(undefined)
|
||||
const showDialogBlockUser = ref<boolean>(false)
|
||||
const currentSlideEvent = ref<SlideEvent | null>(null)
|
||||
const closedByUserAction = ref(false)
|
||||
|
||||
const mapUsers = computed(() => users.map(el => ({...el, ...userSection(el)})))
|
||||
const mapUsers = computed(() => users.map(el => ({
|
||||
...el,
|
||||
...userSection(el),
|
||||
companyName: el.company_id && companiesStore.companyById(el.company_id)
|
||||
? companiesStore.companyById(el.company_id)?.name
|
||||
: null
|
||||
})))
|
||||
|
||||
interface SlideEvent {
|
||||
reset: () => void
|
||||
@@ -202,12 +276,13 @@
|
||||
el.section1.toLowerCase().includes(searchValue) ||
|
||||
el.section2_1.toLowerCase().includes(searchValue) ||
|
||||
el.section2_2.toLowerCase().includes(searchValue) ||
|
||||
el.section3.toLowerCase().includes(searchValue)
|
||||
el.section3.toLowerCase().includes(searchValue) ||
|
||||
el.companyName && el.companyName.toLowerCase().includes(searchValue)
|
||||
)
|
||||
return arrOut
|
||||
})
|
||||
|
||||
const displayUsers = computed(() => displayUsersAll.value.filter(el => !el.is_block))
|
||||
const displayUsers = computed(() => displayUsersAll.value.filter(el => !el.is_blocked))
|
||||
|
||||
function userSection (user: User) {
|
||||
const tname = () => {
|
||||
@@ -244,8 +319,8 @@
|
||||
|
||||
function handleSlide (event: SlideEvent, id: number) {
|
||||
currentSlideEvent.value = event
|
||||
showDialogDeleteUser.value = true
|
||||
deleteUserId.value = id
|
||||
showDialogBlockUser.value = true
|
||||
blockUserId.value = id
|
||||
}
|
||||
|
||||
function onDialogBeforeHide () {
|
||||
@@ -263,26 +338,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function onConfirmDeleteUser() {
|
||||
async function onConfirmBlockUser() {
|
||||
closedByUserAction.value = true
|
||||
if (deleteUserId.value) {
|
||||
await usersStore.blockUser(deleteUserId.value)
|
||||
if (blockUserId.value) {
|
||||
await usersStore.blockUser(blockUserId.value)
|
||||
}
|
||||
currentSlideEvent.value = null
|
||||
}
|
||||
|
||||
const showBlockedUsers = ref(false)
|
||||
const blockedUsers = computed(() => displayUsersAll.value.filter(el => el.is_block))
|
||||
const blockedUsers = computed(() => displayUsersAll.value.filter(el => el.is_blocked))
|
||||
const unblockUserId = ref<number | undefined> (undefined)
|
||||
const showDialogRestoreUser = ref(false)
|
||||
|
||||
const showLeaveUsers = ref(false)
|
||||
const leaveUsers = computed(() => displayUsersAll.value.filter(el => el.is_leave))
|
||||
|
||||
function handleUnblockUser (id: number) {
|
||||
showDialogRestoreUser.value = true
|
||||
unblockUserId.value = id
|
||||
}
|
||||
|
||||
async function onConfirmRestoreUser () {
|
||||
if (unblockUserId.value) await usersStore.restore(unblockUserId.value)
|
||||
if (unblockUserId.value) await usersStore.unblockUser(unblockUserId.value)
|
||||
}
|
||||
|
||||
watch(showDialogRestoreUser, (newD :boolean) => {
|
||||
@@ -293,5 +371,18 @@
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
.rotate-icon-btn {
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.rotate-icon-btn.rotate-icon :deep(.q-icon) {
|
||||
transform: rotate(180deg);
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
|
||||
}
|
||||
|
||||
.rotate-icon-btn :deep(.q-icon) {
|
||||
transform: rotate(0deg);
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user