ali 3 år sedan
förälder
incheckning
765a4f84dc

+ 33 - 0
src/api/models/Invoice.js

@@ -7,6 +7,7 @@ export default class InvoiceAPI extends APIRepository {
     super('invoice', appApi)
     this.APIAdresses = {
       base: '/accounting/invoices',
+      instalments: '/accounting/instalments',
       byId: (id) => '/accounting/invoices/' + id,
       pay: (id) => '/accounting/invoices/' + id + '/pay'
     }
@@ -54,6 +55,38 @@ export default class InvoiceAPI extends APIRepository {
     })
   }
 
+  instalments(data) {
+    return this.sendRequest({
+      apiMethod: 'get',
+      api: this.api,
+      request: this.APIAdresses.base,
+      data: this.getNormalizedSendData({
+        type: null, // String -> overdue - ...
+        page: 1 // Number
+      }, data),
+      resolveCallback: (response) => {
+        const paginate = response.data
+        const results = response.data.results
+        delete paginate.results
+        return {
+          list: new InvoiceList(results),
+          paginate
+          // {
+          //   "count": 1,
+          //   "num_pages": 1,
+          //   "per_page": 10,
+          //   "current": 1,
+          //   "next": null,
+          //   "previous": null,
+          // }
+        }
+      },
+      rejectCallback: (error) => {
+        return error
+      }
+    })
+  }
+
   pay(invoiceId) {
     return this.sendRequest({
       apiMethod: 'put',

+ 21 - 0
src/components/Widgets/Invoice/OverdueInstalments/OptionPanel.vue

@@ -0,0 +1,21 @@
+<template>
+  <option-panel-tabs v-model:options="localOptions">
+    <template #main-tab>
+      ...
+    </template>
+  </option-panel-tabs>
+</template>
+
+<script>
+import { defineComponent } from 'vue'
+import { mixinOptionPanel } from 'quasar-ui-q-page-builder'
+import OptionPanelTabs from 'quasar-ui-q-page-builder/src/components/OptionPanelComponents/OptionPanelTabs.vue'
+
+export default defineComponent({
+  name: 'OptionPanel',
+  components: {
+    OptionPanelTabs
+  },
+  mixins: [mixinOptionPanel]
+})
+</script>

+ 195 - 0
src/components/Widgets/Invoice/OverdueInstalments/OverdueInstalments.vue

@@ -0,0 +1,195 @@
+<template>
+  <div class="InvoiceList"
+       :style="localOptions.style">
+
+    <q-banner inline-actions
+              class="text-white bg-red q-mb-md text-center">
+      لطفا اقساط معوقه خود را پرداخت کنید.
+    </q-banner>
+    <entity-index v-if="mounted"
+                  ref="entityIndex"
+                  v-model:value="inputs"
+                  title="لیست اقساط معوقه"
+                  :api="api"
+                  :table="table"
+                  :table-keys="tableKeys"
+                  :create-route-name="createRouteName"
+                  :table-grid-size="$q.screen.lt.sm"
+                  :show-search-button="false"
+                  :show-expand-button="false"
+                  :show-reload-button="false">
+      <template #entity-index-table-cell="{inputData}">
+        <template v-if="inputData.col.name === 'number'">
+          {{ inputData.rowNumber }}
+        </template>
+        <template v-else-if="inputData.col.name === 'action'">
+          <q-btn color="primary"
+                 :to="{name: 'UserPanel.Invoice.Show', params: {id: inputData.props.row.invoice}}">
+            مشاهده جزییات
+          </q-btn>
+        </template>
+        <template v-else>
+          {{ inputData.col.value }}
+        </template>
+      </template>
+      <template #entity-index-table-item-cell="{inputData}">
+        <entity-index-grid-item :input-data="inputData">
+          <template #col="{col, row}">
+            <template v-if="col.name === 'number'">
+              {{ inputData.rowNumber }}
+            </template>
+            <template v-else-if="col.name === 'action'">
+              <q-btn color="primary"
+                     :to="{name: 'UserPanel.Invoice.Show', params: {id: row.invoice}}">
+                مشاهده جزییات
+              </q-btn>
+            </template>
+          </template>
+        </entity-index-grid-item>
+      </template>
+    </entity-index>
+  </div>
+</template>
+
+<script>
+import Assist from 'assets/js/Assist.js'
+import { EntityIndex } from 'quasar-crud'
+import { Invoice } from 'src/models/Invoice.js'
+import { mixinWidget } from 'src/mixin/Mixins.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import { FormBuilderAssist } from 'quasar-form-builder'
+import EntityIndexGridItem from 'src/components/EntityIndexGridItem.vue'
+
+export default {
+  name: 'InvoiceList',
+  components: { EntityIndex, EntityIndexGridItem },
+  mixins: [mixinWidget],
+  data: () => {
+    return {
+      api: APIGateway.invoice.APIAdresses.instalments,
+      tableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      },
+      inputs: [
+        { type: 'hidden', name: 'type', value: 'overdue' }
+      ],
+      table: {
+        columns: [
+          {
+            name: 'number',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: () => ''
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'شناسه',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'title',
+            required: true,
+            label: 'عنوان',
+            align: 'left',
+            field: row => row.invoice_info.title
+          },
+          {
+            name: 'status',
+            required: true,
+            label: 'وضعیت',
+            align: 'left',
+            field: row => (new Invoice(row.invoice_info)).status_info.label
+          },
+          {
+            name: 'amount',
+            required: true,
+            label: 'مبلغ صورتحساب(ریال)',
+            align: 'left',
+            field: row => row.invoice_info.amount.toLocaleString('fa')
+          },
+          {
+            name: 'amount',
+            required: true,
+            label: 'مبلغ قسط(ریال)',
+            align: 'left',
+            field: row => row.amount.toLocaleString('fa')
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'زمان ثبت',
+            align: 'left',
+            field: row => Assist.miladiToShamsi(row.creation_time)
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'تاریخ سررسید',
+            align: 'left',
+            field: row => Assist.miladiToShamsi(row.due_date, 'jYYYY/jMM/jDD')
+          },
+          {
+            name: 'action',
+            required: true,
+            label: 'جزییات',
+            align: 'left',
+            field: row => ''
+          }
+        ]
+      },
+      mounted: false,
+      createRouteName: ''
+    }
+  },
+  mounted() {
+    this.setOwner()
+    this.setActionBtn()
+    this.mounted = true
+  },
+  methods: {
+    setOwner () {
+      const user = this.$store.getters['Auth/user']
+      FormBuilderAssist.setAttributeByName(this.inputs, 'owner', 'value', user.id)
+    },
+    setActionBtn () {
+      FormBuilderAssist.setAttributeByName(this.inputs, 'btn', 'atClick', this.search)
+    },
+    search () {
+      this.$refs.entityIndex.search()
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.InvoiceList {
+  .title {
+    font-style: normal;
+    font-weight: 700;
+    font-size: 24px;
+    line-height: 140%;
+    color: #424242;
+    margin-bottom: 27px;
+  }
+  :deep(.list) {
+    .quasar-crud-index-table {
+      padding: 0;
+      .q-table__container {
+        background-color: transparent;
+        box-shadow: none;
+        border: none;
+        .q-table__top {
+          display: none;
+        }
+      }
+    }
+  }
+}
+</style>

+ 13 - 9
src/mixin/Auth.js

@@ -1,17 +1,21 @@
-import { APIGateway } from 'src/api/APIGateway'
+import { User } from 'src/models/User.js'
+import { APIGateway } from 'src/api/APIGateway.js'
 
 const mixinAuth = {
-  computed: {
-    user: {
-      get () {
-        return this.$store.getters['Auth/user']
-      },
-      set (newInfo) {
-        this.$store.commit('Auth/updateUser', newInfo)
-      }
+  data () {
+    return {
+      user: new User(),
+      isUserLogin: false
     }
   },
+  mounted () {
+    this.loadAuthData()
+  },
   methods: {
+    loadAuthData () { // prevent Hydration node mismatch
+      this.user = this.$store.getters['Auth/user']
+      this.isUserLogin = this.$store.getters['Auth/isUserLogin']
+    },
     async getUserData () {
       APIGateway.user.showUser()
         .then((response) => {

+ 1 - 0
src/models/User.js

@@ -16,6 +16,7 @@ class User extends Model {
       { key: 'national_code' },
       { key: 'picture' },
       { key: 'has_seminary_education' },
+      { key: 'has_overdue_instalment' },
       { key: 'last_academic_degree' },
       { key: 'last_academic_degree_field' },
       { key: 'last_academy_name' },

+ 48 - 40
src/pages/User/Profile/classrooms.vue

@@ -1,46 +1,51 @@
 <template>
   <breadcrumbs style="margin-top: 29px; margin-bottom: 19px;" />
-  <entity-index v-if="mounted"
-                ref="entityIndex"
-                v-model:value="inputs"
-                title="لیست دوره ها"
-                :api="api"
-                :table="table"
-                :table-keys="tableKeys"
-                :table-grid-size="$q.screen.lt.sm"
-                :show-expand-button="false"
-                :show-reload-button="false"
-                :show-search-button="false">
-    <template #entity-index-table-cell="{inputData}">
-      <template v-if="inputData.col.name === 'number'">
-        {{ inputData.rowNumber }}
-      </template>
-      <template v-else-if="inputData.col.name === 'action'">
-        <q-btn size="md"
-               color="primary"
-               label="جزییات"
-               :to="{name: 'UserPanel.Profile.ClassroomInfo', params: {id: inputData.props.row.classroom_info.id}}" />
-      </template>
-      <template v-else>
-        {{ inputData.col.value }}
+  <template v-if="user.has_overdue_instalment">
+    <overdue-instalments />
+  </template>
+  <template v-else>
+    <entity-index v-if="mounted"
+                  ref="entityIndex"
+                  v-model:value="inputs"
+                  title="لیست دوره ها"
+                  :api="api"
+                  :table="table"
+                  :table-keys="tableKeys"
+                  :table-grid-size="$q.screen.lt.sm"
+                  :show-expand-button="false"
+                  :show-reload-button="false"
+                  :show-search-button="false">
+      <template #entity-index-table-cell="{inputData}">
+        <template v-if="inputData.col.name === 'number'">
+          {{ inputData.rowNumber }}
+        </template>
+        <template v-else-if="inputData.col.name === 'action'">
+          <q-btn size="md"
+                 color="primary"
+                 label="جزییات"
+                 :to="{name: 'UserPanel.Profile.ClassroomInfo', params: {id: inputData.props.row.classroom_info.id}}" />
+        </template>
+        <template v-else>
+          {{ inputData.col.value }}
+        </template>
       </template>
-    </template>
-    <template #entity-index-table-item-cell="{inputData}">
-      <entity-index-grid-item :input-data="inputData">
-        <template #col="{col, row}">
-          <template v-if="col.name === 'number'">
-            {{ inputData.rowNumber }}
-          </template>
-          <template v-else-if="col.name === 'action'">
-            <q-btn size="md"
-                   color="primary"
-                   label="جزییات"
-                   :to="{name: 'UserPanel.Profile.ClassroomInfo', params: {id: row.classroom_info.id}}" />
+      <template #entity-index-table-item-cell="{inputData}">
+        <entity-index-grid-item :input-data="inputData">
+          <template #col="{col, row}">
+            <template v-if="col.name === 'number'">
+              {{ inputData.rowNumber }}
+            </template>
+            <template v-else-if="col.name === 'action'">
+              <q-btn size="md"
+                     color="primary"
+                     label="جزییات"
+                     :to="{name: 'UserPanel.Profile.ClassroomInfo', params: {id: row.classroom_info.id}}" />
+            </template>
           </template>
-        </template>
-      </entity-index-grid-item>
-    </template>
-  </entity-index>
+        </entity-index-grid-item>
+      </template>
+    </entity-index>
+  </template>
 </template>
 
 <script>
@@ -48,6 +53,7 @@ import { shallowRef } from 'vue'
 import { EntityIndex } from 'quasar-crud'
 import Enums from 'src/assets/Enums/Enums.js'
 import { Invoice } from 'src/models/Invoice.js'
+import { mixinAuth } from 'src/mixin/Mixins.js'
 import ShamsiDate from 'src/assets/ShamsiDate.js'
 import { APIGateway } from 'src/api/APIGateway.js'
 import { FormBuilderAssist } from 'quasar-form-builder'
@@ -55,6 +61,7 @@ import BtnControl from 'src/components/Control/btn.vue'
 import { Registration } from 'src/models/Registration.js'
 import EntityIndexGridItem from 'src/components/EntityIndexGridItem.vue'
 import Breadcrumbs from 'src/components/Widgets/Breadcrumbs/Breadcrumbs.vue'
+import OverdueInstalments from 'src/components/Widgets/Invoice/OverdueInstalments/OverdueInstalments.vue'
 
 const BtnControlComp = shallowRef(BtnControl)
 
@@ -63,8 +70,10 @@ export default {
   components: {
     EntityIndex,
     Breadcrumbs,
+    OverdueInstalments,
     EntityIndexGridItem
   },
+  mixins: [mixinAuth],
   data () {
     return {
       mounted: false,
@@ -199,7 +208,6 @@ export default {
             label: 'وضعیت مالی',
             align: 'left',
             field: row => (new Invoice(row.invoice_info)).status_info.label ? (new Invoice(row.invoice_info)).status_info.label : '-'
-            // field: row => row.invoice_info ? this.getInvoiceStatusTitle(row.invoice_info) : 'نام مشخص'
           },
           {
             name: 'action',