FinancialCard.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. <template>
  2. <q-card
  3. class="financial-card"
  4. :class="{
  5. 'financial-card--selected': selected,
  6. 'financial-card--clickable': clickable,
  7. }"
  8. @click="clickable && emit('click')"
  9. >
  10. <div class="row justify-between items-start no-wrap">
  11. <span class="text-subtitle1 text-dark card-title">{{ title }}</span>
  12. <div class="row items-center no-wrap" style="gap: 4px">
  13. <q-btn
  14. v-if="editable"
  15. flat
  16. dense
  17. round
  18. size="sm"
  19. icon="mdi-pencil-outline"
  20. color="dark"
  21. @click.stop="emit('edit')"
  22. />
  23. <q-icon :name="icon" size="22px" color="dark" />
  24. </div>
  25. </div>
  26. <div class="bottom-area">
  27. <div class="text-h5 text-primary value-text">{{ formattedValue }}</div>
  28. <template v-if="hasFooter">
  29. <q-separator class="q-mt-sm q-mb-xs" />
  30. <div class="row items-center justify-between no-wrap">
  31. <div class="column" style="gap: 2px">
  32. <span v-if="percentage !== null" class="text-caption text-foreground">
  33. {{ hideValues ? "••" : percentage }}% vs o mês anterior
  34. </span>
  35. <span v-if="integer !== null" class="text-caption text-foreground">
  36. {{ hideValues ? "•" : integer }} {{ integerLabel }}
  37. </span>
  38. </div>
  39. <span v-if="description" class="text-caption text-foreground">
  40. {{ description }}
  41. </span>
  42. </div>
  43. </template>
  44. </div>
  45. </q-card>
  46. </template>
  47. <script setup>
  48. import { computed } from "vue";
  49. const props = defineProps({
  50. title: { type: String, required: true },
  51. icon: { type: String, default: "mdi-cash-multiple" },
  52. financialValue: { type: Number, default: 0 },
  53. legend: { type: String, default: "" },
  54. percentage: { type: Number, default: null },
  55. integer: { type: Number, default: null },
  56. integerLabel: { type: String, default: "pagamentos restantes" },
  57. description: { type: String, default: "" },
  58. hideValues: { type: Boolean, default: false },
  59. clickable: { type: Boolean, default: false },
  60. selected: { type: Boolean, default: false },
  61. editable: { type: Boolean, default: false },
  62. });
  63. const emit = defineEmits(["click", "edit"]);
  64. const formattedValue = computed(() =>
  65. props.hideValues
  66. ? "R$ ••••"
  67. : new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(
  68. props.financialValue,
  69. ),
  70. );
  71. const hasFooter = computed(
  72. () => props.percentage !== null || props.integer !== null || !!props.description,
  73. );
  74. </script>
  75. <style scoped lang="scss">
  76. @import "src/css/quasar.variables.scss";
  77. .financial-card--clickable {
  78. cursor: pointer;
  79. &:hover {
  80. box-shadow: 0 0 0 1.5px $primary !important;
  81. }
  82. }
  83. .financial-card--selected {
  84. box-shadow: 0 0 0 2px $primary !important;
  85. }
  86. .financial-card {
  87. flex: 1 1 0;
  88. min-width: 220px;
  89. border-radius: 12px;
  90. box-shadow: 0 0 0 1px #c0c0c0c0 !important;
  91. padding: 16px 20px;
  92. display: flex;
  93. flex-direction: column;
  94. justify-content: space-between;
  95. gap: 12px;
  96. }
  97. .card-title {
  98. line-height: 1.3;
  99. }
  100. .bottom-area {
  101. display: flex;
  102. flex-direction: column;
  103. }
  104. .value-text {
  105. font-weight: 600;
  106. line-height: 1.2;
  107. }
  108. </style>