Files
tgCrewAdmin/src/pages/CompanyMaskPage.vue
2025-11-02 10:08:57 +03:00

288 lines
8.4 KiB
Vue

<template>
<pn-page-card>
<template #title>
{{$t('mask__title')}}
</template>
<template #footer>
<q-btn
rounded color="primary"
class="w100 q-mt-md q-mb-xs fix-disabled-btn"
@click="updateCompanies()"
>
{{ $t('mask__btn_ok') }}
</q-btn>
</template>
<pn-scroll-list>
<template #card-body-header>
<div class="q-ma-sm q-pa-sm bg-grey-11 flex no-wrap items-center" style="border-radius: var(--top-radius);">
<q-icon name="mdi-information q-pr-xs" size="sm" color="primary"/>
<span class="text-caption">
{{ $t('mask__info_block')}}
</span>
</div>
</template>
<q-table
flat
:rows="displayCompanies"
:columns="tableColumns"
hide-pagination
:pagination="{ rowsPerPage: 0 }"
dense
row-key="id"
style="max-width: 100% !important"
>
<template #header>
<q-tr>
<q-th style="width: 10%">
<q-icon name="mdi-domino-mask" size="sm"/>
</q-th>
<q-th style="width: 45%">
<span class="text-bold">
{{ $t('mask__table_header_company') }}
</span>
</q-th>
<q-th style="width: 45%">
<span class="text-bold">
{{ $t('mask__table_header_visible') }}
<q-btn
flat
@click="showDialogHelp=true"
color="primary"
dense round
size="sm"
icon="mdi-help-circle-outline"
/>
</span>
</q-th>
</q-tr>
</template>
<template #body="props">
<q-tr :props="props">
<q-td key="checkbox" :props="props">
<q-toggle
v-model="props.row.masked"
size="sm"
:color="props.row.masked ? 'red' : 'brand'"
/>
</q-td>
<q-td key="name" :props="props">
{{ props.row.name }}
</q-td>
<q-td key="visible" :props="props">
<q-select
v-if="props.row.masked"
v-model="props.row.company_list"
multiple
:options="companiesSelect(props.row.id)"
option-value="id"
emit-value
dense
borderless
dropdown-icon="mdi-plus"
class="fix-select"
:label-slot="!props.row.hasFocus && !props.row.isMenuOpen && (props.row.company_list.length === 0)"
@popup-show="props.row.isMenuOpen = true"
@popup-hide="props.row.isMenuOpen = false"
@focus="props.row.hasFocus = true"
@blur="props.row.hasFocus = false"
>
<template #label>
<span
v-if="(!props.row.hasFocus || !props.row.isMenuOpen) && (props.row.company_list.length === 0)"
class="q-field__label"
>
{{ $t('mask__table_visible_none') }}
</span>
</template>
<template #selected>
<div
v-for="id in props.row.company_list"
:key=id
class="q-pa-xs"
>
<pn-auto-avatar
:img="getCompanyById(id)?.logo"
:name="getCompanyById(id)?.name"
size="md"
type="rounded"
/>
</div>
</template>
<template #option="scope">
<q-item v-bind="scope.itemProps">
<q-item-section avatar>
<pn-auto-avatar
:img="scope.opt.logo"
:name="scope.opt.name"
size="md"
type="rounded"
/>
</q-item-section>
<q-item-section>
<q-item-label>{{ scope.opt.name }}</q-item-label>
</q-item-section>
</q-item>
</template>
</q-select>
<span
v-else
>
{{ $t('mask__table_visible_all') }}
</span>
</q-td>
</q-tr>
</template>
</q-table>
<div class="q-py-none flex column w100" style="min-height: 18px"/>
</pn-scroll-list>
<q-dialog v-model="showDialogHelp">
<q-card class="q-ma-sm w100">
<q-card-section class="row items-center q-pb-none">
<span class="text-h6">
<q-icon name="mdi-domino-mask"/>
{{ $t('mask__help_title')}}
</span>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card-section class="q-pt-sm">
<p>{{ $t('mask__help_message1')}}</p>
<p>{{ $t('mask__help_message2')}}</p>
</q-card-section>
</q-card>
</q-dialog>
</pn-page-card>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useCompaniesStore } from 'stores/companies'
import { useRouter } from 'vue-router'
const showDialogHelp = ref<boolean>(false)
const companiesStore = useCompaniesStore()
const router = useRouter()
const companies = computed(() => companiesStore.companies)
const companiesMask = computed(() => companiesStore.companiesMask)
const tableColumns = [
{ name: 'checkbox', field: 'checkbox', label: 'checkbox', sortable: false, style: "width: 10%" },
{ name: 'name', field: 'name', align: 'left' as const, label: 'name', sortable: false, style: "width: 45% !important; text-wrap: auto" },
{ name: 'visible', field: 'visible', align: 'center' as const, label: 'visible', sortable: false, style: "width: 45% !important" }
]
interface DisplayCompany {
id: number
name: string
logo?: string
masked: boolean
company_list: number[],
isMenuOpen: boolean
hasFocus: boolean
}
const displayCompanies = ref<DisplayCompany[]>([])
watch(
() => [companies.value, companiesMask.value],
() => {
updateDisplayCompanies()
},
{ immediate: true, deep: true }
)
function updateDisplayCompanies() {
if (companies.value.length === 0 || companiesMask.value.length === 0) return
displayCompanies.value = companies.value
.filter(el => !el.is_own)
.map(el => ({
id: el.id,
name: el.name,
logo: el.logo ?? '',
masked: companiesStore.checkCompanyMasked(el.id),
company_list: getList(el.id),
isMenuOpen: false,
hasFocus: false
}))
}
function getList (companyId: number) {
const company = companiesMask.value.find(el => Number(el.company_id) === companyId)
return company?.company_list ?? []
}
const mask = computed(() => displayCompanies.value
.filter(el => el.masked)
.map(el => ({
company_id: el.id,
company_list: el.company_list.sort(compareNumbers)
}))
.sort((a, b) => compareNumbers(a.company_id, b.company_id))
)
function getCompanyById (id: number) {
return companies.value.find(c => c.id === id)
}
function companiesSelect (id :number) {
return displayCompanies.value
.map(el => ({
id: el.id,
name: el.name,
logo: el.logo
}))
.filter(el => el.id !== id)
}
async function updateCompanies () {
await companiesStore.updateMask(mask.value)
router.back()
}
function compareNumbers (a: number, b: number): number {
if (Number.isNaN(a)) return Number.isNaN(b) ? 0 : 1
if (Number.isNaN(b)) return -1
if (a === b) return 0
return a < b ? -1 : 1
}
</script>
<style scoped lang="scss">
.fix-select :deep(.q-field__control) {
align-items: center;
}
.fix-select :deep(.q-field__native) {
justify-content: flex-end;
}
.fix-select :deep(.q-field__label.no-pointer-events) {
left: 50% !important;
transform: translateX(-50%) !important;
}
:deep(.fix-select .q-icon) {
color: $green-14 !important;
}
:deep(.masked .q-icon) {
color: red;
}
:deep(.unmasked .q-icon) {
color: 'brand';
}
</style>