Sfoglia il codice sorgente

feat: :sparkles: crud tipos servicos

crud tipos servicos
Gustavo Zanatta 1 mese fa
parent
commit
d3b4dc06fb

+ 26 - 0
src/api/serviceType.js

@@ -0,0 +1,26 @@
+import api from "src/api";
+
+export const getServiceType = async (id) => {
+  const { data } = await api.get("/service-type/" + id);
+  return data.payload;
+};
+
+export const getServiceTypes = async () => {
+  const { data } = await api.get("/service-types");
+  return data.payload;
+};
+
+export const createServiceType = async (serviceType) => {
+  const { data } = await api.post("/service-type", serviceType);
+  return data.payload;
+};
+
+export const updateServiceType = async (serviceType, id) => {
+  const { data } = await api.put(`/service-type/${id}`, serviceType);
+  return data.payload;
+};
+
+export const deleteServiceType = async (id) => {
+  const { data } = await api.delete(`/service-type/${id}`);
+  return data.payload;
+};

+ 114 - 0
src/components/serviceType/ServiceTypeSelect.vue

@@ -0,0 +1,114 @@
+<template>
+  <q-select
+    v-model="selectedServiceType"
+    v-bind="$attrs"
+    use-input
+    hide-selected
+    fill-input
+    clearable
+    :options="serviceTypeOptions"
+    :label
+    :rules
+    :loading
+    :placeholder="$t('common.actions.search') + ' ' + $t('ui.navigation.service_type')"
+    :error
+    :error-message
+    @filter="filterFn"
+  >
+    <template #no-option>
+      <q-item>
+        <q-item-section class="text-grey">
+          {{ $t("http.errors.no_records_found") }}
+        </q-item-section>
+      </q-item>
+    </template>
+  </q-select>
+</template>
+
+<script setup>
+import { getServiceTypes } from "src/api/serviceType";
+import { ref, onMounted } from "vue";
+import { normalizeString } from "src/helpers/utils";
+import { useI18n } from "vue-i18n";
+
+const { label, rules, initialId } = defineProps({
+  label: {
+    type: String,
+    default: () => useI18n().t("ui.navigation.service_type"),
+  },
+  rules: {
+    type: Array,
+    default: () => [],
+  },
+  initialId: {
+    type: Number,
+    required: false,
+    default: null,
+  },
+  error: {
+    type: Boolean,
+    default: false,
+  },
+  errorMessage: {
+    type: String,
+    default: "",
+  },
+});
+
+const selectedServiceType = defineModel({ type: Object });
+
+const loading = ref(false);
+const baseOptions = ref([]);
+const serviceTypeOptions = ref([]);
+
+const filterFn = async (val, update) => {
+  const needle = normalizeString(val);
+  serviceTypeOptions.value = baseOptions.value.filter((v) => {
+    return (
+      normalizeString(v.label).includes(needle) ||
+      normalizeString(v.document).includes(needle)
+    );
+  });
+  update();
+};
+
+const selectServiceTypeByName = (name) => {
+  if (selectedServiceType.value?.label === name) {
+    return;
+  }
+  selectedServiceType.value = baseOptions.value.find((serviceType) => serviceType.label === name);
+};
+
+const selectServiceTypeById = (id) => {
+  if (selectedServiceType.value?.value === id) {
+    return;
+  }
+  selectedServiceType.value = baseOptions.value.find((serviceType) => serviceType.value === id);
+};
+
+onMounted(async () => {
+  try {
+    loading.value = true;
+    const baseServiceTypes = await getServiceTypes();
+    baseOptions.value = baseServiceTypes.map((serviceType) => ({
+      label: serviceType.user?.name || serviceType.document,
+      value: serviceType.id,
+      document: serviceType.document,
+      user_id: serviceType.user_id,
+    }));
+    serviceTypeOptions.value = baseOptions.value;
+    if (initialId) {
+      selectServiceTypeById(initialId);
+    }
+  } catch (e) {
+    console.log(e);
+  } finally {
+    loading.value = false;
+  }
+});
+
+defineExpose({
+  selectServiceTypeByName,
+  selectServiceTypeById,
+});
+</script>

+ 2 - 1
src/i18n/locales/en.json

@@ -353,7 +353,8 @@
       "provider": "Provider",
       "exit": "Exit",
       "admin": "Admin",
-      "user": "User"
+      "user": "User",
+      "service_type": "Service Type"
     }
   },
   "charts": {

+ 2 - 1
src/i18n/locales/es.json

@@ -353,7 +353,8 @@
       "provider": "Proveedor",
       "exit": "Salir",
       "admin": "Admin",
-      "user": "Usuario"
+      "user": "Usuario",
+      "service_type": "Tipo de Servicio"
     }
   },
   "charts": {

+ 2 - 1
src/i18n/locales/pt.json

@@ -353,7 +353,8 @@
       "provider": "Prestador",
       "exit": "Sair",
       "admin": "Admin",
-      "user": "Usuário"
+      "user": "Usuário",
+      "service_type": "Tipo de Serviço"
     }
   },
   "charts": {

+ 105 - 0
src/pages/serviceType/ServiceTypesPage.vue

@@ -0,0 +1,105 @@
+<template>
+  <div>
+    <DefaultHeaderPage />
+    <div>
+      <DefaultTable
+        ref="tableRef"
+        :columns="columns"
+        :api-call="getServiceTypes"
+        :delete-function="deleteServiceType"
+        :mostrar-selecao-de-colunas="false"
+        :mostrar-botao-fullscreen="false"
+        :mostrar-toggle-inativos="false"
+        open-item
+        add-item
+        @on-row-click="onRowClick"
+        @on-add-item="onAddItem"
+      />
+    </div>
+  </div>
+</template>
+<script setup>
+import { defineAsyncComponent, useTemplateRef } from "vue";
+import { useQuasar } from "quasar";
+import { useI18n } from "vue-i18n";
+import { permissionStore } from "src/stores/permission";
+import { getServiceTypes, deleteServiceType } from "src/api/serviceType";
+
+import DefaultTable from "src/components/defaults/DefaultTable.vue";
+import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
+
+const AddEditServiceTypeDialog = defineAsyncComponent(() =>
+  import("src/pages/serviceType/components/AddEditServiceTypeDialog.vue")
+);
+
+const permission_store = permissionStore();
+const $q = useQuasar();
+const tableRef = useTemplateRef("tableRef");
+const { t } = useI18n();
+
+const columns = [
+  {
+    name: "description",
+    label: t("common.terms.description"),
+    field: "description",
+    align: "left",
+    sortable: true,
+  },
+  {
+    name: "is_active",
+    label: t("common.status.active"),
+    field: (row) => (row.is_active ? t("common.status.yes") : t("common.status.no")),
+    align: "left",
+    sortable: true,
+  },
+  {
+    name: "actions",
+    required: true,
+  },
+];
+
+const onRowClick = ({ row }) => {
+  if (permission_store.getAccess("config.service_type", "edit") === false) {
+    $q.loading.hide();
+    $q.notify({
+      type: "negative",
+      message: t("validation.permissions.edit"),
+    });
+    return;
+  }
+  $q.dialog({
+    component: AddEditServiceTypeDialog,
+    componentProps: {
+      serviceType: row,
+      title: () =>
+        useI18n().t("common.actions.edit") + " " + useI18n().t("ui.navigation.service_type"),
+    },
+  }).onOk(async (success) => {
+    if (success) {
+      tableRef.value.refresh();
+    }
+  });
+};
+
+const onAddItem = () => {
+  if (permission_store.getAccess("config.service_type", "add") === false) {
+    $q.loading.hide();
+    $q.notify({
+      type: "negative",
+      message: t("validation.permissions.add"),
+    });
+    return;
+  }
+  $q.dialog({
+    component: AddEditServiceTypeDialog,
+    componentProps: {
+      title: () =>
+        useI18n().t("common.actions.add") + " " + useI18n().t("ui.navigation.service_type"),
+    },
+  }).onOk(async (success) => {
+    if (success) {
+      tableRef.value.refresh();
+    }
+  });
+};
+</script>

+ 91 - 0
src/pages/serviceType/components/AddEditServiceTypeDialog.vue

@@ -0,0 +1,91 @@
+<template>
+  <q-dialog ref="dialogRef" @hide="onDialogHide">
+    <q-card class="q-dialog-plugin overflow-hidden" style="width: 1000px; max-width: 90vw">
+      <DefaultDialogHeader :title="title" @close="onDialogCancel" />
+        <q-form ref="formRef" @submit="onOKClick">
+          <q-card-section class="row q-col-gutter-sm">
+            <q-input
+              v-model="form.description"
+              fill-mask
+              unmasked-value
+              :label="$t('common.terms.description')"
+              :rules="[inputRules.required]"
+              :error="!!serverErrors?.description"
+              :error-message="serverErrors?.description"
+              class="col-12"
+            />
+
+            <div class="col-12">
+              <q-checkbox
+                v-model="form.is_active"
+                :label="$t('common.status.active')"
+              />
+            </div>
+
+          </q-card-section>
+          <q-card-actions align="center">
+            <q-btn color="primary" label="Cancel" @click="onDialogCancel" />
+            <q-space />
+            <q-btn color="primary" label="OK" :type="'submit'" :loading="loading" :disable="!hasUpdatedFields" />
+          </q-card-actions>
+        </q-form>
+    </q-card>
+  </q-dialog>
+</template>
+<script setup>
+import { useTemplateRef } from "vue";
+import { useInputRules } from "src/composables/useInputRules";
+import { useDialogPluginComponent } from "quasar";
+import { useI18n } from "vue-i18n";
+import { createServiceType, updateServiceType } from "src/api/serviceType";
+import { useFormUpdateTracker } from "src/composables/useFormUpdateTracker";
+import { useSubmitHandler } from "src/composables/useSubmitHandler";
+import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
+
+defineEmits([
+  ...useDialogPluginComponent.emits,
+]);
+
+const { serviceType, title } = defineProps({
+  serviceType: {
+    type: Object,
+    default: null,
+  },
+  title: {
+    type: Function,
+    default: () => useI18n().t("common.terms.title"),
+  },
+});
+
+const { inputRules } = useInputRules();
+
+const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
+  useDialogPluginComponent();
+
+const formRef = useTemplateRef("formRef");
+const { form, getUpdatedFields, hasUpdatedFields } = useFormUpdateTracker({
+  description: serviceType ? serviceType?.description : "",
+  is_active: serviceType ? serviceType?.is_active : false,
+});
+
+// const birthDate = ref(null);
+
+const {
+  loading,
+  serverErrors,
+  execute: submitForm,
+} = useSubmitHandler({
+  onSuccess: () => onDialogOK(true),
+  formRef: formRef,
+});
+
+
+const onOKClick = async () => {
+  if (serviceType) {
+    await submitForm(() => updateServiceType(getUpdatedFields.value, serviceType.id));
+  } else {
+    await submitForm(() => createServiceType({ ...form }));
+  }
+};
+
+</script>

+ 22 - 0
src/router/routes/serviceType.route.js

@@ -0,0 +1,22 @@
+export default [
+  {
+    path: "/service-type",
+    name: "ServiceTypesPage",
+    component: () => import("pages/serviceType/ServiceTypesPage.vue"),
+    meta: {
+      title: "ui.navigation.service_type",
+      requireAuth: true,
+      requiredPermission: "config.service_type",
+      breadcrumbs: [
+        {
+          name: "DashboardPage",
+          title: "ui.navigation.dashboard",
+        },
+        {
+          name: "ServiceTypePage",
+          title: "ui.navigation.service_type",
+        },
+      ],
+    },
+  },
+];

+ 9 - 0
src/stores/navigation.js

@@ -66,6 +66,15 @@ export const navigationStore = defineStore("navigation", () => {
           permission: false,
           permissionScope: "config.provider",
         },
+        {
+          type: "single",
+          title: "ui.navigation.service_type",
+          name: "ServiceTypesPage",
+          icon: "mdi-briefcase-check-outline",
+          disable: false,
+          permission: false,
+          permissionScope: "config.service_type",
+        },
         {
           type: "single",
           title: "ui.navigation.users",