Преглед изворни кода

feat(class_package): adiciona grupos

ebagabee пре 3 недеља
родитељ
комит
f36ac05583
1 измењених фајлова са 122 додато и 53 уклоњено
  1. 122 53
      src/pages/packages/components/AddEditPackageDialog.vue

+ 122 - 53
src/pages/packages/components/AddEditPackageDialog.vue

@@ -212,9 +212,17 @@
                     <template v-for="unit in filteredUnits" :key="unit.id">
                     <template v-for="unit in filteredUnits" :key="unit.id">
                       <q-separator />
                       <q-separator />
                       <div class="row items-center q-px-sm q-py-sm">
                       <div class="row items-center q-px-sm q-py-sm">
-                        <span class="col text-body2">{{
-                          unit.fantasy_name
-                        }}</span>
+                        <span class="col text-body2 row items-center q-gutter-x-xs">
+                          {{ unit.fantasy_name }}
+                          <q-icon
+                            v-if="lockedUnitIds.has(unit.id)"
+                            name="mdi-lock"
+                            color="amber-7"
+                            size="xs"
+                          >
+                            <q-tooltip>Visibilidade definida por grupo</q-tooltip>
+                          </q-icon>
+                        </span>
                         <div class="col-auto row q-gutter-x-xs">
                         <div class="col-auto row q-gutter-x-xs">
                           <q-btn
                           <q-btn
                             round
                             round
@@ -228,10 +236,11 @@
                             round
                             round
                             :outline="unit.visible"
                             :outline="unit.visible"
                             :unelevated="!unit.visible"
                             :unelevated="!unit.visible"
-                            :color="unit.visible ? 'negative' : 'negative'"
+                            color="negative"
                             icon="mdi-close"
                             icon="mdi-close"
                             size="xs"
                             size="xs"
-                            @click="unit.visible = false"
+                            :disable="lockedUnitIds.has(unit.id)"
+                            @click="!lockedUnitIds.has(unit.id) && (unit.visible = false)"
                           />
                           />
                         </div>
                         </div>
                       </div>
                       </div>
@@ -302,49 +311,59 @@
                     overflow-y: auto;
                     overflow-y: auto;
                   "
                   "
                 >
                 >
-                  <div class="row items-center q-mb-xs q-px-sm">
-                    <q-icon
-                      name="mdi-account-group"
-                      color="secondary"
-                      size="sm"
-                      class="q-mr-xs"
-                    />
-                    <span class="text-body2">
-                      Grupos Ativos ({{ filteredGroups.length }})
-                    </span>
+                  <div v-if="loadingGroups" class="flex flex-center q-py-md">
+                    <q-spinner color="secondary" size="sm" />
                   </div>
                   </div>
 
 
-                  <q-separator class="q-mb-xs" />
+                  <template v-else>
+                    <div class="row items-center q-mb-xs q-px-sm">
+                      <q-icon
+                        name="mdi-account-group"
+                        color="secondary"
+                        size="sm"
+                        class="q-mr-xs"
+                      />
+                      <span class="text-body2">
+                        Grupos ({{ filteredGroups.length }})
+                      </span>
+                    </div>
 
 
-                  <div class="row q-px-sm q-py-xs">
-                    <span class="col text-caption text-grey-6">Grupo</span>
-                    <span class="col-auto text-caption text-grey-6">Status</span>
-                  </div>
+                    <q-separator class="q-mb-xs" />
 
 
-                  <template v-for="group in filteredGroups" :key="group.id">
-                    <q-separator />
-                    <div class="row items-center q-px-sm q-py-sm">
-                      <span class="col text-body2">{{ group.name }}</span>
-                      <div class="col-auto row q-gutter-x-xs">
-                        <q-btn
-                          round
-                          unelevated
-                          :color="group.visible ? 'positive' : 'grey-4'"
-                          icon="mdi-check"
-                          size="xs"
-                          @click="group.visible = true"
-                        />
-                        <q-btn
-                          round
-                          :outline="group.visible"
-                          :unelevated="!group.visible"
-                          color="negative"
-                          icon="mdi-close"
-                          size="xs"
-                          @click="group.visible = false"
-                        />
-                      </div>
+                    <div class="row q-px-sm q-py-xs">
+                      <span class="col text-caption text-grey-6">Grupo</span>
+                      <span class="col-6 text-caption text-grey-6">Unidades</span>
+                      <span class="col-auto text-caption text-grey-6">Status</span>
                     </div>
                     </div>
+
+                    <template v-for="group in filteredGroups" :key="group.id">
+                      <q-separator />
+                      <div class="row items-center q-px-sm q-py-sm">
+                        <span class="col text-body2">{{ group.name }}</span>
+                        <span class="col-6 text-caption text-grey-6">
+                          {{ group.unit_ids?.length ?? 0 }} unidade(s)
+                        </span>
+                        <div class="col-auto row q-gutter-x-xs">
+                          <q-btn
+                            round
+                            unelevated
+                            :color="group.visible ? 'positive' : 'grey-4'"
+                            icon="mdi-check"
+                            size="xs"
+                            @click="group.visible = true"
+                          />
+                          <q-btn
+                            round
+                            :outline="group.visible"
+                            :unelevated="!group.visible"
+                            color="negative"
+                            icon="mdi-close"
+                            size="xs"
+                            @click="group.visible = false"
+                          />
+                        </div>
+                      </div>
+                    </template>
                   </template>
                   </template>
                 </div>
                 </div>
               </div>
               </div>
@@ -372,7 +391,7 @@
 </template>
 </template>
 
 
 <script setup>
 <script setup>
-import { ref, computed, onMounted } from "vue";
+import { ref, computed, onMounted, watch } from "vue";
 import { useDialogPluginComponent } from "quasar";
 import { useDialogPluginComponent } from "quasar";
 
 
 import CustomTabComponent from "src/components/shared/CustomTabComponent.vue";
 import CustomTabComponent from "src/components/shared/CustomTabComponent.vue";
@@ -384,6 +403,7 @@ import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.v
 import { getUnitsForSelect } from "src/api/unit";
 import { getUnitsForSelect } from "src/api/unit";
 import { getPackage, createPackage, updatePackage } from "src/api/package";
 import { getPackage, createPackage, updatePackage } from "src/api/package";
 import { getProductsForSelect } from "src/api/product";
 import { getProductsForSelect } from "src/api/product";
+import { getGroups } from "src/api/group";
 
 
 defineEmits([...useDialogPluginComponent.emits]);
 defineEmits([...useDialogPluginComponent.emits]);
 
 
@@ -400,6 +420,7 @@ const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
 const formRef = ref(null);
 const formRef = ref(null);
 const loading = ref(false);
 const loading = ref(false);
 const loadingUnits = ref(false);
 const loadingUnits = ref(false);
+const loadingGroups = ref(false);
 const currentTab = ref("informacoes");
 const currentTab = ref("informacoes");
 
 
 const tabs = [
 const tabs = [
@@ -456,11 +477,31 @@ const units = ref([]);
 
 
 // Grupos tab
 // Grupos tab
 const groupSearch = ref("");
 const groupSearch = ref("");
-const groups = ref([
-  { id: 1, name: "Grupo 1", visible: true },
-  { id: 2, name: "Grupo 2", visible: true },
-  { id: 3, name: "Grupo 3", visible: true },
-]);
+const groups = ref([]);
+
+// Set of unit IDs that are locked because they belong to a selected group
+const lockedUnitIds = computed(() => {
+  const ids = new Set();
+  groups.value.forEach((g) => {
+    if (g.visible && g.unit_ids) {
+      g.unit_ids.forEach((id) => ids.add(id));
+    }
+  });
+  return ids;
+});
+
+// When group visibility changes, force locked units to visible
+watch(
+  lockedUnitIds,
+  (newLockedIds) => {
+    units.value.forEach((u) => {
+      if (newLockedIds.has(u.id)) {
+        u.visible = true;
+      }
+    });
+  },
+  { deep: true },
+);
 
 
 const filteredUnits = computed(() => {
 const filteredUnits = computed(() => {
   const q = unitSearch.value.toLowerCase();
   const q = unitSearch.value.toLowerCase();
@@ -469,13 +510,19 @@ const filteredUnits = computed(() => {
 });
 });
 
 
 const setAllVisible = (visible) => {
 const setAllVisible = (visible) => {
-  units.value.forEach((u) => (u.visible = visible));
+  units.value.forEach((u) => {
+    // Cannot hide a unit that is locked by a group
+    if (!visible && lockedUnitIds.value.has(u.id)) return;
+    u.visible = visible;
+  });
 };
 };
 
 
 const filteredGroups = computed(() => {
 const filteredGroups = computed(() => {
   const q = groupSearch.value.toLowerCase();
   const q = groupSearch.value.toLowerCase();
   if (!q) return groups.value;
   if (!q) return groups.value;
-  return groups.value.filter((g) => g.name.toLowerCase().includes(q));
+  return groups.value.filter((g) =>
+    g.name.toLowerCase().includes(q),
+  );
 });
 });
 
 
 const setAllGroupsVisible = (visible) => {
 const setAllGroupsVisible = (visible) => {
@@ -484,16 +531,19 @@ const setAllGroupsVisible = (visible) => {
 
 
 onMounted(async () => {
 onMounted(async () => {
   loadingUnits.value = true;
   loadingUnits.value = true;
+  loadingGroups.value = true;
   try {
   try {
-    const [allUnits, allProducts] = await Promise.all([
+    const [allUnits, allProducts, allGroups] = await Promise.all([
       getUnitsForSelect(),
       getUnitsForSelect(),
       getProductsForSelect(),
       getProductsForSelect(),
+      getGroups(),
     ]);
     ]);
 
 
     products.value = allProducts;
     products.value = allProducts;
 
 
     let visibilityMap = {};
     let visibilityMap = {};
     let savedMaterials = null;
     let savedMaterials = null;
+    let savedGroupIds = [];
 
 
     if (props.package?.id) {
     if (props.package?.id) {
       const pkg = await getPackage(props.package.id);
       const pkg = await getPackage(props.package.id);
@@ -507,12 +557,27 @@ onMounted(async () => {
           price: m.price,
           price: m.price,
         }));
         }));
       }
       }
+      savedGroupIds = pkg.group_ids ?? [];
     }
     }
 
 
+    // Build groups with visibility flag and their unit_ids
+    groups.value = allGroups.map((g) => ({
+      id: g.id,
+      name: g.name,
+      unit_ids: g.unit_ids ?? [],
+      visible: savedGroupIds.includes(g.id),
+    }));
+
+    // Units locked by groups start visible = true
+    const groupLockedIds = new Set();
+    groups.value.forEach((g) => {
+      if (g.visible) g.unit_ids.forEach((id) => groupLockedIds.add(id));
+    });
+
     units.value = allUnits.map((u) => ({
     units.value = allUnits.map((u) => ({
       id: u.id,
       id: u.id,
       fantasy_name: u.fantasy_name,
       fantasy_name: u.fantasy_name,
-      visible: visibilityMap[u.id] ?? true,
+      visible: groupLockedIds.has(u.id) ? true : (visibilityMap[u.id] ?? true),
     }));
     }));
 
 
     if (savedMaterials) {
     if (savedMaterials) {
@@ -520,6 +585,7 @@ onMounted(async () => {
     }
     }
   } finally {
   } finally {
     loadingUnits.value = false;
     loadingUnits.value = false;
+    loadingGroups.value = false;
   }
   }
 });
 });
 
 
@@ -534,6 +600,9 @@ const onOKClick = async () => {
       contract_value: form.value.contract_value,
       contract_value: form.value.contract_value,
       contract_register_value: form.value.contract_register_value,
       contract_register_value: form.value.contract_register_value,
       contrat_discount_value: form.value.contrat_discount_value,
       contrat_discount_value: form.value.contrat_discount_value,
+      group_ids: groups.value
+        .filter((g) => g.visible)
+        .map((g) => g.id),
       unit_visibilities: units.value.map((u) => ({
       unit_visibilities: units.value.map((u) => ({
         unit_id: u.id,
         unit_id: u.id,
         visible: u.visible,
         visible: u.visible,