Prechádzať zdrojové kódy

بهبود پنل کاربر

hgh 1 rok pred
rodič
commit
76d0702e3e

+ 7 - 3
src/assets/Enums/invoiceStatus.js

@@ -1,8 +1,12 @@
 const invoiceStatus = [
+  { label: 'در حال تأیید', value: 'VERIFYING' },
   { label: 'لغو شده', value: 'CANCELED' },
-  { label: 'در حال پرداخت', value: 'IN_PROGRESS' },
-  { label: 'پرداخت نقدی', value: 'PAID' },
-  { label: 'پرداخت قسطی', value: 'PAY_IN_INSTALMENT' }
+  { label: 'تأیید نشده', value: 'NOT_VERIFIED' },
+  { label: 'در حال پرداخت', value: 'PAYING' },
+  { label: 'درحال تایید پرداخت', value: 'TRANSACTION_VERIFYING' },
+  { label: 'پرداخت شده', value: 'PAID_FULL' },
+  { label: 'درحال پرداخت اقساط', value: 'PAYING_IN_INSTALMENT' },
+  { label: 'اقساط پرداخت شده', value: 'PAID_IN_INSTALMENT' }
 ]
 
 export default invoiceStatus

+ 3 - 20
src/components/Widgets/Classroom/ClassroomList/ClassroomList.vue

@@ -41,24 +41,7 @@
       </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-if="col.name === 'status'">
-            <div :class="this.getRegistrationStatusTitleClass(row)">
-              {{ this.getRegistrationStatusTitle(row) }}
-            </div>
-          </template>
-          <template v-else-if="col.name === 'action'">
-            <q-btn size="md"
-                   color="primary"
-                   label="جزییات"
-                   :to="{name: showPageRouteName, params: {id: row.classroom_info.id}}" />
-          </template>
-        </template>
-      </entity-index-grid-item>
+      <user-classroom-card :registration="inputData.props.row" />
     </template>
   </entity-index>
 </template>
@@ -74,7 +57,7 @@ import { FormBuilderAssist } from 'quasar-form-builder'
 import BtnControl from 'src/components/Control/btn.vue'
 import { Registration } from 'src/models/Registration.js'
 import { mixinAuth, mixinWidget } from 'src/mixin/Mixins.js'
-import EntityIndexGridItem from 'src/components/EntityIndexGridItem.vue'
+import UserClassroomCard from 'src/components/Widgets/Classroom/UserClassroomCard/UserClassroomCard.vue'
 import Breadcrumbs from 'src/components/Widgets/Breadcrumbs/Breadcrumbs.vue'
 import { TranscriptSheet } from 'src/models/TranscriptSheet'
 import FormBuilderBarCode from 'src/components/FormBuilderCustumComponents/FormBuilderBarCode.vue'
@@ -87,7 +70,7 @@ export default {
     FormBuilderBarCode,
     EntityIndex,
     Breadcrumbs,
-    EntityIndexGridItem
+    UserClassroomCard
   },
   mixins: [mixinAuth, mixinWidget],
   data () {

+ 28 - 0
src/components/Widgets/Classroom/UserClassroomCard/OptionPanel.vue

@@ -0,0 +1,28 @@
+<template>
+  <option-panel-tabs v-model:options="localOptions">
+    <template #main-tab>
+      <q-option-group v-model="localOptions.classroomType"
+                      :options="classroomTypeOptions" />
+    </template>
+  </option-panel-tabs>
+</template>
+
+<script>
+import { defineComponent } from 'vue'
+import { UnitCategory } from 'src/models/UnitCategory.js'
+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],
+  data () {
+    return {
+      classroomTypeOptions: (new UnitCategory()).typeEnums
+    }
+  }
+})
+</script>

+ 308 - 0
src/components/Widgets/Classroom/UserClassroomCard/UserClassroomCard.vue

@@ -0,0 +1,308 @@
+<template>
+  <div class="classroom-card row">
+    <div class="right-side col-6">
+      <img class="thumbnail"
+           :src="registration.classroom_info.thumbnail">
+      <q-btn color="primary"
+             :to="{name: showPageRouteName, params: {id: registration.classroom_info.id}}">
+        مشاهده
+      </q-btn>
+    </div>
+    <div class="left-side col-6">
+      <div class="title-box">
+        <q-banner class="banner">{{ registration.classroom_info.title }}</q-banner>
+        {{ getHoldingType(registration.classroom_info.holding_type) }}
+        |
+        {{ registration.classroom_info.sessions_count }} جلسه
+      </div>
+      <div class="status-box">
+        <div class="registration-status-box">
+          <q-icon name="event_note"
+                  class="material-icons-outlined" />
+          {{ this.getRegistrationStatusTitle(registration) }}
+        </div>
+        <div class="financial-status-box">
+          <q-icon name="credit_card"
+                  class="material-icons-outlined" />
+          {{ this.getInvoiceStatusTitle(registration.invoice_info.status) }}
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import Enums from 'assets/Enums/Enums.js'
+import ShamsiDate from 'assets/ShamsiDate.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import { Classroom } from 'src/models/Classroom.js'
+import { Registration } from 'src/models/Registration.js'
+import { UnitCategory } from 'src/models/UnitCategory'
+import { mixinWidget } from 'src/mixin/Mixins.js'
+import { TranscriptSheet } from 'src/models/TranscriptSheet'
+
+export default {
+  name: 'UserClassroomCard',
+  mixins: [mixinWidget],
+  props: {
+    registration: {
+      type: Registration,
+      default: new Registration()
+    },
+    classroom: {
+      type: Classroom,
+      default: new Classroom()
+    },
+    classroomId: {
+      type: Number,
+      default: null
+    },
+    ownerId: {
+      type: Number,
+      default: null
+    },
+    classroomType: {
+      type: String,
+      default: 'TRAINING'
+    }
+  },
+  emits: [],
+  data: () => ({
+    defaultOptions: {
+      profileMode: false,
+      classroomType: 'TRAINING'
+    },
+    acceptClassType: 'register', // accept - enrollment - rules
+    fetchCodesLoading: false,
+    dropLoading: false,
+    rulesAccept: false,
+    rulesDialog: false,
+    loading: true
+  }),
+  computed: {
+    listTitle () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'لیست دوره های آموزشی'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'لیست رویدادها'
+      }
+      return 'لیست دوره های آموزشی'
+    },
+    showPageRouteName () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'UserPanel.Profile.ClassroomInfo'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'UserPanel.Profile.EventInfo'
+      }
+      return 'UserPanel.Profile.ClassroomInfo'
+    },
+    classroomTypeTitle () {
+      const unitCategory = new UnitCategory({ type: this.localOptions.classroomType })
+      return unitCategory.type_info.label
+    }
+  },
+  methods: {
+    getTitledDateTime (dateTime) {
+      return ShamsiDate.getTitledDateTime(dateTime)
+    },
+    acceptAndContinue () {
+      this.$store.commit('Shop/updateOnRegisterClassroom', this.classroom)
+      this.$router.push({ name: 'UserPanel.ShopCompleteInfo', query: { type: this.acceptClassType, source: this.classroomType === 'EVENT' ? 'event' : 'classroom' } })
+    },
+    onEnrolment () {
+      this.acceptClassType = 'enrollment'
+      this.rulesDialog = true
+    },
+    onDropping () {
+      this.$q.dialog({
+        title: 'توجه',
+        message: 'آیا از حذف این دوره اطمینان دارید؟',
+        cancel: true,
+        persistent: true
+      }).onOk(() => {
+        this.dropLoading = true
+        APIGateway.classroom.dropByUser(this.classroom.id)
+          .then(() => {
+            this.dropLoading = false
+            this.$emit('onDrop')
+          })
+          .catch(() => {
+            this.dropLoading = false
+          })
+      })
+    },
+    openRulesDialog () {
+      this.acceptClassType = 'rules'
+      this.rulesDialog = true
+    },
+    openCodeLink () {
+      if (!this.classroom.codes) {
+        return
+      }
+
+      const fileName = (this.classroom.codes.match(/(?<=\/)[^/?#]+(?=[^/]*$)/gm) || [this.classroom.title])[0]
+      this.fetchCodesLoading = true
+      fetch(this.classroom.codes)
+        .then(response => response.blob())
+        .then(blob => {
+          const link = document.createElement('a')
+          link.href = URL.createObjectURL(blob)
+          link.download = fileName
+          link.click()
+          this.fetchCodesLoading = false
+        })
+        .catch(() => {
+          this.fetchCodesLoading = false
+        })
+    },
+    openRegisterDialog () {
+      this.acceptClassType = 'register'
+      this.rulesDialog = true
+    },
+    getHoldingType (type) {
+      const target = Enums.classroomHoldingTypes.find(item => item.value === type)
+      if (target) {
+        return target.label
+      }
+      return '-'
+    },
+    getClassroomHoldingTypeTitle (type) {
+      const target = Enums.classroomHoldingTypes.find(item => item.value === type)
+      if (!target) {
+        return '-'
+      }
+
+      return target.label
+    },
+    getRegistrationStatusTitle (registration) {
+      if (registration.status === 'REGISTERED' && registration.transcript_sheet_info) {
+        return (new TranscriptSheet(registration.transcript_sheet_info)).status_info.label
+      } else {
+        return (new Registration(registration)).status_info.label
+      }
+    },
+    getRegistrationStatusTitleClass (registration) {
+      if (registration.status === 'REGISTERED' && registration.transcript_sheet_info) {
+        return (new TranscriptSheet(registration.transcript_sheet_info)).status_info.value
+      }
+      return null
+    },
+    getClassroomStatusTitle (type) {
+      const target = Enums.classroomStatuses.find(item => item.value === type)
+      if (!target) {
+        return '-'
+      }
+
+      return target.label
+    },
+    getInvoiceStatusTitle (type) {
+      const target = Enums.invoiceStatus.find(item => item.value === type)
+      if (!target) {
+        return '-'
+      }
+
+      return target.label
+    },
+    getAudienceGenderType (type) {
+      const target = Enums.classroomGenders.find(item => item.value === type)
+      if (target) {
+        return target.label
+      }
+      return '-'
+    },
+    getTime (time) {
+      return ShamsiDate.getDateTime(time)
+    },
+    getTerm (classroom) {
+      if (!classroom.beginning_registration_period) {
+        return '-'
+      }
+      return ShamsiDate.getTerm(classroom.beginning_registration_period)
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.classroom-card {
+  display: flex;
+  margin-bottom: 8px;
+  justify-content: space-between;
+  align-items: flex-start;
+  align-self: stretch;
+  border-radius: 8px;
+  background: #FFF;
+  box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
+  .right-side {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    padding: 0 4px;
+
+    .thumbnail {
+      max-width: 100%;
+      height: auto;
+      display: block;
+    }
+
+    .q-btn {
+      display: flex;
+      height: 48px;
+      padding: 8px 24px;
+      justify-content: center;
+      align-items: center;
+      align-self: stretch;
+      border-radius: 0 0 0 8px;
+    }
+  }
+  .left-side {
+    display: flex;
+
+    flex-direction: column;
+    justify-content: center;
+    align-items: flex-end;
+    gap: 12px;
+    align-self: stretch;
+
+    .title-box {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: flex-start;
+      align-self: stretch;
+
+      :deep(.q-banner) {
+        padding: 8px 4px;
+        .q-banner__content {
+          font-size: 16px;
+        }
+      }
+    }
+
+    .status-box {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: flex-start;
+      align-self: stretch;
+
+      .registration-status-box {
+        display: flex;
+        height: 30px;
+        align-items: center;
+        gap: 4px;
+        align-self: stretch;
+      }
+
+      .financial-status-box {
+        display: flex;
+        align-items: center;
+        gap: 4px;
+        align-self: stretch;
+      }
+    }
+  }
+}
+</style>