before delete 3software

This commit is contained in:
2025-06-29 18:55:59 +03:00
parent ebd77a3e66
commit b51a472738
147 changed files with 257326 additions and 3151 deletions

View File

@@ -1,102 +1,150 @@
<template>
<pn-page-card>
<template #title>
<div class="col-grow">
{{$t('company__mask')}}
</div>
{{$t('company__mask')}}
<q-btn
v-if="!checkIsDirty(mask, originalMask)"
@click = "updateCompanies()"
flat round
icon="mdi-check"
/>
</template>
<pn-scroll-list>
<template #card-body-header>
<div style="min-height: var(--top-raduis);"/>
</template>
<q-list
separator
<q-table
flat
:rows="displayCompanies"
:columns="tableColumns"
hide-pagination
:pagination="{ rowsPerPage: 0 }"
dense
row-key="id"
style="max-width: 100% !important"
>
<q-item>
<q-item-section>
<div>
<q-btn flat round color="primary" icon="mdi-help-circle-outline" @click="showDialogHelp = true" />
</div>
</q-item-section>
<q-item-section></q-item-section>
<q-item-section align="end" class="col-grow">
{{ $t('mask__title_table') }}
</q-item-section>
</q-item>
<q-item
v-for = "company in companies"
:key="company.id"
class="w100"
>
<q-item-section>
<q-checkbox
v-model="company.masked"
:label="company.name"
unchecked-icon="mdi-drama-masks"
checked-icon="mdi-drama-masks"
:class="company.masked ? 'masked' : 'unmasked'"
/>
</q-item-section>
<q-item-section>
<q-select
v-if="company.masked"
v-model="company.unmasked"
multiple
:options="companiesSelect(company.id)"
dense
borderless
dropdown-icon="mdi-plus"
class="fix-select"
>
<template #selected>
<div
v-for="(comp, idx) in company.unmasked"
:key=idx
class="q-pa-xs"
>
<q-avatar rounded size="md">
<img v-if="comp['logo']" :src="comp['logo']"/>
<pn-auto-avatar v-else :name="comp['name']"/>
</q-avatar>
</div>
<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 #option="scope">
<q-item v-bind="scope.itemProps">
<q-item-section avatar>
<q-avatar rounded size="md">
<img v-if="scope.opt.logo" :src="scope.opt.logo"/>
<pn-auto-avatar v-else :name="scope.opt.name"/>
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label>{{ scope.opt.name }}</q-item-label>
</q-item-section>
</q-item>
</template>
</q-select>
</q-item-section>
</q-item>
<q-item
class="q-pa-none q-ma-none"
style="min-height: 18px"
>
<div class="q-py-none flex column w100"/>
</q-item>
</q-list>
<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-drama-masks"/>
<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">
{{ $t('mask__help_message')}}
<p>{{ $t('mask__help_message1')}}</p>
<p>{{ $t('mask__help_message2')}}</p>
<p>{{ $t('mask__help_message3')}}</p>
</q-card-section>
</q-card>
</q-dialog>
@@ -104,26 +152,53 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
// import { useCompaniesStore } from 'src/stores/companies'
import { ref, computed, onMounted } from 'vue'
import { useCompaniesStore } from 'stores/companies'
import type { CompanyMask } from 'types/Company'
import { useRouter } from 'vue-router'
const showDialogHelp = ref<boolean>(false)
// const companiesStore = useCompaniesStore()
const companiesStore = useCompaniesStore()
const router = useRouter()
// const companies = computed(() => companiesStore.companies)
const companies = computed(() => companiesStore.companies)
const companiesMask = computed(() => companiesStore.companiesMask)
const companies = ref([
{id: "com11", name: 'Рога и копытца1', logo: '', description: 'Монтажники вывески', qtyPersons: 3, masked: false, unmasked: [] },
{id: "com21", name: 'ООО "Василек1"', logo: 'https://cdn.quasar.dev/img/avatar5.jpg', qtyPersons: 2, masked: true, unmasked: [] },
{id: "ch13", name: 'Откат и деньги1', logo: 'https://cdn.quasar.dev/img/avatar4.jpg', description: 'Договариваются с администрацией', qtyPersons: 5, masked: false, unmasked: [] },
{id: "ch14", name: 'Откат и деньги2', logo: '', description: 'Договариваются о чем-то', qtyPersons: 5, masked: false, unmasked: [] },
{id: "com111", name: 'Рога и копытца2', logo: '', description: 'Монтажники вывески', qtyPersons: 3, masked: false, unmasked: []},
{id: "com211", name: 'ООО "Василек2"', logo: '', qtyPersons: 2, masked: true, unmasked: [] },
{id: "ch131", name: 'Откат и деньги3', logo: '', description: 'Договариваются с администрацией', qtyPersons: 5, masked: false, unmasked: [] },
])
interface DisplayCompany {
id: number
name: string
logo?: string
masked: boolean
company_list: number[],
isMenuOpen: boolean
hasFocus: boolean
}
function companiesSelect (id :string) {
return companies.value
//
const displayCompanies = ref<DisplayCompany[]>([])
const originalMask = ref<CompanyMask[]>([])
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" }
]
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,
@@ -132,26 +207,103 @@
.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
}
function checkIsDirty (arr1: CompanyMask[], arr2: CompanyMask[]): boolean {
// Проверка длины массивов
if (arr1.length !== arr2.length) return false
// Функция для нормализации объекта в строковый ключ
const getKey = (obj: { company_id: number; company_list: number[] }): string => {
const sortedList = [...obj.company_list].sort(compareNumbers)
return `${obj.company_id}|${sortedList.join(',')}`
}
// Создаем Map для подсчета объектов в первом массиве
const countMap = new Map<string, number>()
for (const item of arr1) {
const key = getKey(item)
countMap.set(key, (countMap.get(key) || 0) + 1)
}
// Проверяем объекты второго массива
for (const item of arr2) {
const key = getKey(item)
const count = countMap.get(key) || 0
if (count === 0) return false
countMap.set(key, count - 1)
}
return true
}
onMounted(() => {
function getList (companyId: number) {
const company = companiesMask.value.find(el => el.company_id === companyId)
return company?.company_list ?? []
}
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
}))
console.log(companies.value)
console.log(displayCompanies.value)
originalMask.value = [ ...(companiesMask.value.sort((a, b) => compareNumbers(a.company_id, b.company_id))) ]
})
</script>
<style scoped lang="scss">
:deep(.fix-select .q-field__control) {
.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;
opacity: 1;
}
:deep(.unmasked .q-icon) {
color: grey;
opacity: 0.5;
color: 'brand';
}
</style>