ali před 3 roky
rodič
revize
7e5858982d
21 změnil soubory, kde provedl 909 přidání a 1134 odebrání
  1. 247 122
      src/components/Widgets/Classroom/AdminClassroomCreate/AdminClassroomCreate.vue
  2. 9 2
      src/components/Widgets/Classroom/AdminClassroomCreate/OptionPanel.vue
  3. 188 96
      src/components/Widgets/Classroom/AdminClassroomList/AdminClassroomList.vue
  4. 9 2
      src/components/Widgets/Classroom/AdminClassroomList/OptionPanel.vue
  5. 95 18
      src/components/Widgets/Classroom/AdminClassroomShow/AdminClassroomShow.vue
  6. 2 10
      src/components/Widgets/Classroom/AdminClassroomShow/OptionPanel.vue
  7. 33 5
      src/components/Widgets/Classroom/AdminClassroomShow/components/ClassroomInfo.vue
  8. 44 5
      src/components/Widgets/Classroom/AdminClassroomShow/components/SessionList.vue
  9. 10 3
      src/components/Widgets/SessionAttendanceSheet/AdminSessionAttendanceSheetList/AdminSessionAttendanceSheetList.vue
  10. 9 2
      src/components/Widgets/SessionAttendanceSheet/AdminSessionAttendanceSheetList/OptionPanel.vue
  11. 21 1
      src/models/UnitCategory.js
  12. 1 1
      src/pages/Admin/Classroom/SessionActivitySheets/sessionActivitySheets.vue
  13. 10 238
      src/pages/Admin/Classroom/create.vue
  14. 11 249
      src/pages/Admin/Classroom/index.vue
  15. 1 1
      src/pages/Admin/Classroom/show.vue
  16. 2 2
      src/pages/Admin/Event/SessionActivitySheets/sessionActivitySheets.vue
  17. 10 159
      src/pages/Admin/Event/create.vue
  18. 172 0
      src/pages/Admin/Event/ema-create.vue
  19. 23 0
      src/pages/Admin/Event/ema-index.vue
  20. 11 217
      src/pages/Admin/Event/index.vue
  21. 1 1
      src/pages/Admin/Event/show.vue

+ 247 - 122
src/components/Widgets/Classroom/AdminClassroomCreate/AdminClassroomCreate.vue

@@ -1,169 +1,294 @@
 <template>
-  <div class="AdminPostCreate"
-       :style="localOptions.style">
-    <div class="flex justify-end">
-      <q-btn flat
-             color="grey"
-             @click="$router.go(-1)">
-        بازگشت
-        >
-      </q-btn>
-    </div>
+  <div class="flex justify-end">
+    <q-btn flat
+           color="grey"
+           @click="$router.go(-1)">
+      بازگشت
+      >
+    </q-btn>
+  </div>
+  <div class="AdminClassroomCreate">
+    <q-linear-progress v-if="unitsLoading"
+                       indeterminate />
     <entity-create v-if="mounted"
-                   ref="entityCreate"
+                   ref="classroomEntityCreate"
+                   :key="classroomEntityCreateKey"
                    v-model:value="inputs"
-                   title="ایجاد پست"
+                   :title="'مشخصات ' + classroomTypeTitle"
                    :api="api"
                    :entity-id-key="entityIdKey"
                    :entity-param-key="entityParamKey"
-                   :show-route-name="showRouteName"
+                   :show-route-name="showPageRouteName"
                    :show-close-button="false"
                    :show-edit-button="false"
                    :show-expand-button="false"
                    :show-save-button="false"
-                   :show-reload-button="false" />
+                   :show-reload-button="false">
+      <template #after-form-builder>
+        <div class="flex justify-end q-mt-md">
+          <q-btn color="primary"
+                 :label="'ایجاد ' + classroomTypeTitle + 'جدید'"
+                 @click="createClassroom" />
+        </div>
+      </template>
+    </entity-create>
   </div>
 </template>
 
 <script>
 import { shallowRef } from 'vue'
 import { EntityCreate } from 'quasar-crud'
+import Enums from 'src/assets/Enums/Enums.js'
 import { mixinWidget } from 'src/mixin/Mixins.js'
 import { APIGateway } from 'src/api/APIGateway.js'
-import BtnControl from 'src/components/Control/btn.vue'
-import PostMixin from 'src/components/Widgets/Post/PostMixin.js'
-import PostCategorySelector from 'src/components/FormBuilderCustumComponents/PostCategorySelector.vue'
-import FormBuilderTiptapEditor from 'src/components/FormBuilderCustumComponents/FormBuilderTiptapEditor.vue'
-// import { FormBuilderAssist } from 'quasar-form-builder'
+import { FormBuilderAssist } from 'quasar-form-builder'
+import { UnitCategory } from 'src/models/UnitCategory.js'
+import FormBuilderInputEditor from 'src/components/FormBuilderCustumComponents/FormBuilderInputEditor.vue'
 
-const BtnControlComp = shallowRef(BtnControl)
-const PostCategorySelectorComp = shallowRef(PostCategorySelector)
-const FormBuilderTiptapEditorComp = shallowRef(FormBuilderTiptapEditor)
+const FormBuilderInputEditorComp = shallowRef(FormBuilderInputEditor)
 
 export default {
-  name: 'AdminPostCreate',
-  components: { EntityCreate },
-  mixins: [mixinWidget, PostMixin],
+  name: 'Admin.Classroom.Create',
+  components: {
+    EntityCreate
+  },
+  mixins: [mixinWidget],
   data () {
-    const authorization = 'Bearer ' + this.$store.getters['Auth/accessToken']
-    const uploadVideo = this.uploadVideo
-    const uploadAudio = this.uploadAudio
     return {
       mounted: false,
-      entityLoading: false,
-      api: APIGateway.post.APIAdresses.base,
+      unitsLoading: false,
+      classroomEntityCreateKey: Date.now(),
+      newUnitLoading: false,
+      newUnitName: null,
+      newUnitSessionCount: null,
+      api: APIGateway.classroom.APIAdresses.base,
       entityIdKey: 'id',
       entityParamKey: 'id',
-      showRouteName: 'Admin.Post.Show',
       inputs: [
-        { type: 'input', name: 'title', responseKey: 'title', label: 'عنوان', placeholder: ' ', col: 'col-12' },
-        { type: 'input', name: 'order', responseKey: 'order', label: 'ترتیب', placeholder: ' ', col: 'col-md-6 col-12' },
-        { type: 'file', name: 'thumbnail', responseKey: 'thumbnail', label: 'عکس', placeholder: ' ', col: 'col-md-6 col-12' },
-        { type: PostCategorySelectorComp, name: 'category', responseKey: 'category', col: 'col-12' },
+        { type: 'separator', name: 'space1', label: 'مشخصات', className: 'custom-separator', col: 'col-12' },
+        { type: 'file', name: 'thumbnail', responseKey: 'thumbnail', label: 'آپلود عکس', col: 'col-md-3 col-12' },
+        { type: 'file', name: 'codes', responseKey: 'codes', label: 'آیین نامه', col: 'col-md-3 col-12' },
+        { type: 'separator', name: 'space', size: '0', col: 'col-md-12' },
+        { type: 'select', name: 'category', responseKey: 'category', options: [], value: null, placeholder: ' ', label: 'دسته بندی', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'unit', responseKey: 'unit', options: [], value: null, placeholder: ' ', label: 'درس', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'holding_type', responseKey: 'holding_type', options: Enums.classroomHoldingTypes, value: null, placeholder: ' ', label: 'نوع برگزاری', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'price', responseKey: 'price', placeholder: ' ', label: 'هزینه برگزاری', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'live_streaming_url', responseKey: 'live_streaming_url', placeholder: ' ', label: 'لینک مکان مجازی', col: 'col-12' },
+        { type: FormBuilderInputEditorComp, name: 'classroom_address', responseKey: 'classroom_address', placeholder: ' ', label: 'آدرس مکان فیزیکی', col: 'col-12' },
         {
-          // type: 'tiptap-editor',
-          type: FormBuilderTiptapEditorComp,
-          name: 'summary',
-          responseKey: 'summary',
-          label: 'خلاصه',
-          options: {
-            bubbleMenu: false,
-            floatingMenu: false,
-            poem: false,
-            reading: false,
-            loadBareHtml: true,
-            persianKeyboard: true,
-            mathliveOptions: { smartFence: false },
-            uploadServer: {
-              url: '/api' + APIGateway.media.APIAdresses.base,
-              instantUpload: true,
-              responseKey: 'file',
-              headers: { Authorization: authorization }
-            },
-            uploadVideo,
-            uploadAudio
-          },
-          col: 'col-md-12 col-12'
+          type: 'select',
+          name: 'holding_year',
+          responseKey: 'holding_year',
+          options: [1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410],
+          value: null,
+          label: 'انتخاب سال',
+          placeholder: ' ',
+          col: 'col-md-3'
         },
         {
-          // type: 'tiptap-editor',
-          type: FormBuilderTiptapEditorComp,
-          name: 'text',
-          responseKey: 'text',
-          label: 'متن',
-          options: {
-            bubbleMenu: false,
-            floatingMenu: false,
-            poem: false,
-            reading: false,
-            loadBareHtml: true,
-            persianKeyboard: true,
-            mathliveOptions: { smartFence: false },
-            uploadServer: {
-              url: '/api' + APIGateway.media.APIAdresses.base,
-              instantUpload: true,
-              responseKey: 'file',
-              headers: { Authorization: authorization }
-            },
-            uploadVideo,
-            uploadAudio
-          },
-          col: 'col-md-12 col-12'
+          type: 'select',
+          name: 'holding_month',
+          responseKey: 'holding_month',
+          options: [
+            'فروردین',
+            'اردیبهشت',
+            'خرداد',
+            'تیر',
+            'مرداد',
+            'شهریور',
+            'مهر',
+            'آبان',
+            'آذر',
+            'دی',
+            'بهمن',
+            'اسفند'
+          ],
+          value: null,
+          label: 'انتخاب ماه',
+          placeholder: ' ',
+          col: 'col-md-3'
         },
-        { type: BtnControlComp, name: 'btn', responseKey: 'btn', label: 'ایجاد محتوا', placeholder: ' ', atClick: () => {}, col: 'col-md-6' }
+        { type: 'input', name: 'sessions_frequency', responseKey: 'sessions_frequency', placeholder: ' ', label: 'دوره تناوب', col: 'col-12' },
+        { type: 'select', name: 'professor', responseKey: 'professor', options: [], value: null, placeholder: ' ', label: 'استاد', col: 'col-md-3 col-12' },
+
+        { type: 'separator', name: 'space', label: 'مشخصات اندیشه جو', className: 'custom-separator', col: 'col-12' },
+        { type: 'select', name: 'audience_status_wwwww', responseKey: 'audience_status_wwwww', options: [], placeholder: ' ', label: 'وضعیت(؟)', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'category1', responseKey: 'category1', options: [], placeholder: ' ', label: 'مجموعه(؟)', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'audience_gender_type', responseKey: 'audience_gender_type', options: Enums.genders, placeholder: ' ', label: 'جنسیت', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'audience_bashgah_wwwww', responseKey: 'audience_bashgah_wwwww', options: [], placeholder: ' ', label: 'باشگاه(؟)', col: 'col-md-3 col-12' },
+
+        { type: 'separator', name: 'space', label: 'تنظیمات', className: 'custom-separator', col: 'col-12' },
+        { type: 'input', name: 'capacity', responseKey: 'capacity', placeholder: ' ', label: 'ظرفیت گروه درسی', col: 'col-md-3 col-12' },
+
+        { type: 'input', name: 'allowed_absence_count', responseKey: 'allowed_absence_count', placeholder: ' ', label: 'تعداد مجاز غیبت', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'effective_absence_coefficient', responseKey: 'effective_absence_coefficient', placeholder: ' ', label: 'ضریب نمره حضور و غیاب', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'mandatory_assignment_count', responseKey: 'mandatory_assignment_count', placeholder: ' ', label: 'تعداد تکالیف اجباری', col: 'col-md-3 col-12' },
+
+        { type: 'input', name: 'special_passing_mark', responseKey: 'special_passing_mark', placeholder: ' ', label: 'نمره قبولی مشروطی ها', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'minimum_conditional_passing_mark', responseKey: 'minimum_conditional_passing_mark', placeholder: ' ', label: 'نمره قبولی مشروط', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'minimum_clean_passing_mark', responseKey: 'minimum_clean_passing_mark', placeholder: ' ', label: 'نمره قبولی', col: 'col-md-3 col-12' },
+
+        { type: 'separator', name: 'space', label: 'ثبت نام و حذف و اضافه', className: 'custom-separator', col: 'col-12' },
+        { type: 'dateTime', name: 'beginning_enrollment_period', responseKey: 'beginning_enrollment_period', placeholder: ' ', label: 'تاریخ شروع پیش ثبت نام', col: 'col-md-6 col-12' },
+        { type: 'dateTime', name: 'ending_enrollment_period', responseKey: 'ending_enrollment_period', placeholder: ' ', label: 'تاریخ پایان پیش ثبت نام', col: 'col-md-6 col-12' },
+        { type: 'dateTime', name: 'beginning_registration_period', responseKey: 'beginning_registration_period', placeholder: ' ', label: 'تاریخ شروع ثبت نام', col: 'col-md-6 col-12' },
+        { type: 'dateTime', name: 'ending_registration_period', responseKey: 'ending_registration_period', placeholder: ' ', label: 'تاریخ پایان ثبت نام', col: 'col-md-6 col-12' },
+
+        { type: 'input', name: 'registration_period_refund_percent', responseKey: 'registration_period_refund_percent', placeholder: ' ', label: 'درصد برگشت هزینه انصراف در بازه ثبت نام', col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_enrollment_period', responseKey: 'allow_dropping_on_enrollment_period', label: 'امکان حذف در بازه پیش ثبت نام', value: false, col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_adding_on_registration_period', responseKey: 'allow_adding_on_registration_period', label: 'امکان اضافه کردن در بازه ثبت نام', value: false, col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_registration_period', responseKey: 'allow_dropping_on_registration_period', label: 'امکان حذف ثبت نام در بازه ثبت نام', value: false, col: 'col-md-3 col-12' },
+
+        { type: 'dateTime', name: 'beginning_drop_add_period', responseKey: 'beginning_drop_add_period', placeholder: ' ', label: 'تاریخ شروع حذف و اضافه', col: 'col-md-6 col-12' },
+        { type: 'dateTime', name: 'ending_drop_add_period', responseKey: 'ending_drop_add_period', placeholder: ' ', label: 'تاریخ پایان حذف و اضافه', col: 'col-md-6 col-12' },
+
+        { type: 'input', name: 'drop_add_period_refund_percent', responseKey: 'drop_add_period_refund_percent', placeholder: ' ', label: 'درصد برگشت هزینه انصراف در بازه حذف و اضافه', col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_adding_on_drop_add_period', responseKey: 'allow_adding_on_drop_add_period', label: 'امکان اضافه شدن در بازه حذف و اضافه', value: false, col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان حذف در بازه حذف و اضافه', value: false, col: 'col-md-3 col-12' },
+
+        { type: 'dateTime', name: 'publish_time', responseKey: 'publish_time', placeholder: ' ', label: 'تاریخ انتشار', col: 'col-md-6 col-12' },
+
+        { type: 'separator', name: 'space', label: 'قوانین', className: 'custom-separator', col: 'col-12' },
+        { type: FormBuilderInputEditorComp, name: 'rules', responseKey: 'rules', label: 'قوانین', col: 'col-12' },
+
+        { type: FormBuilderInputEditorComp, name: 'description', responseKey: 'description', label: 'توضیحات', col: 'col-12' },
+        { type: FormBuilderInputEditorComp, name: 'specification', responseKey: 'specification', label: 'مشخصات', col: 'col-12' },
+        { type: FormBuilderInputEditorComp, name: 'bulletin', responseKey: 'bulletin', label: 'تابلو اعلانات', col: 'col-12' },
+
+        // -----------------------------------------------------------------------------------------------------------
+
+        { type: 'separator', name: 'space', label: 'موارد زیر در طرح نبودند', className: 'custom-separator', col: 'col-12' },
+        { type: 'select', name: 'audience_role', responseKey: 'audience_role', options: Enums.groups, placeholder: ' ', label: 'نقش', col: 'col-md-4 col-12' },
+
+        { type: 'hidden', name: 'id', responseKey: 'id', label: 'id', col: 'col-md-3 col-12' }
       ]
     }
   },
+  computed: {
+    classroomTypeTitle () {
+      const unitCategory = new UnitCategory({ type: this.localOptions.classroomType })
+      return unitCategory.type_info.label
+    },
+    createPageRouteName () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'Admin.Classroom.Create'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'Admin.Event.Create'
+      }
+      return 'Admin.Classroom.Create'
+    },
+    showPageRouteName () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'Admin.Classroom.Show'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'Admin.Event.Show'
+      }
+      return 'Admin.Classroom.Show'
+    },
+    selectedCategoryId () {
+      return FormBuilderAssist.getInputsByName(this.inputs, 'category')?.value
+    }
+  },
+  watch: {
+    selectedCategoryId () {
+      FormBuilderAssist.setAttributeByName(this.inputs, 'space1', 'value', null)
+      FormBuilderAssist.setAttributeByName(this.inputs, 'unit', 'options', [])
+      this.getUnits(this.selectedCategoryId)
+    }
+  },
   mounted () {
-    this.setActionBtn()
-    // const options = FormBuilderAssist.getInputsByName(this.inputs, 'text').options
-    // options.uploadVideo = this.uploadVideo
-    // FormBuilderAssist.setAttributeByName(this.inputs, 'text', 'options', options)
-    this.mounted = true
+    this.setClassroomTypeOfInputs()
+    this.preLoadData()
+      .then(() => {
+        this.mounted = true
+      })
+      .catch(() => {
+      })
   },
   methods: {
-    setActionBtn () {
-      this.inputs.forEach((item, index) => {
-        if (item.name === 'btn') {
-          this.inputs[index].atClick = this.onSubmit
-        }
+    setClassroomTypeOfInputs () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        FormBuilderAssist.setAttributeByName(this.inputs, 'professor', 'label', 'استاد')
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        FormBuilderAssist.setAttributeByName(this.inputs, 'professor', 'label', 'برگزار کننده')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'unit', 'label', 'دسته')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'category', 'type', 'hidden') // unit -> category__type filter
+        FormBuilderAssist.setAttributeByName(this.inputs, 'allowed_absence_count', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'effective_absence_coefficient', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'mandatory_assignment_count', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'special_passing_mark', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'minimum_conditional_passing_mark', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'minimum_clean_passing_mark', 'type', 'hidden')
+      }
+    },
+    setInputAttr (name, attr, value) {
+      this.$refs.classroomEntityCreate.setInputAttributeByName(name, attr, value)
+    },
+    preLoadData () {
+      return new Promise((resolve, reject) => {
+        const promise1 = this.getProfessors()
+        const promise2 = this.getCategories()
+        const promise3 = (this.localOptions.classroomType === 'EVENT') ? this.getUnits(null, this.localOptions.classroomType) : (Promise.resolve())
+        this.$nextTick(() => {
+          Promise.all([promise1, promise2, promise3])
+            .then(() => {
+              resolve()
+            })
+            .catch(() => {
+              reject()
+            })
+        })
       })
     },
-    onSubmit () {
-      this.create()
+    getProfessors () {
+      return APIGateway.user.index({ per_page: 9999, role: 'professor' })
+        .then((users) => {
+          FormBuilderAssist.setAttributeByName(this.inputs, 'professor', 'options', users.list.list.map(item => {
+            return {
+              value: item.id,
+              label: this.getUserFullname(item)
+            }
+          }))
+        })
+        .catch(() => {})
     },
-    create() {
-      this.entityLoading = true
-      this.$refs.entityCreate.createEntity()
-        .then(() => {
-          this.entityLoading = false
+    getCategories () {
+      return APIGateway.unitCategory.index({ per_page: 9999, type: 'TRAINING' })
+        .then((categories) => {
+          FormBuilderAssist.setAttributeByName(this.inputs, 'category', 'options', categories.list.list.map(item => {
+            return {
+              value: item.id,
+              label: item.title
+            }
+          }))
+        })
+        .catch(() => {})
+    },
+    getUnits (selectedcategoryId = null, categoryType = null) {
+      this.unitsLoading = true
+      APIGateway.unit.index({ per_page: 9999, category: selectedcategoryId, category__typ: categoryType })
+        .then((units) => {
+          FormBuilderAssist.setAttributeByName(this.inputs, 'unit', 'options', units.list.list.map(item => {
+            return {
+              value: item.id,
+              label: item.title
+            }
+          }))
+          this.unitsLoading = false
         })
         .catch(() => {
-          this.entityLoading = false
+          this.unitsLoading = false
         })
+    },
+    getUserFullname (user) {
+      return user.firstname + ' ' + user.lastname
+    },
+    createClassroom () {
+      this.$refs.classroomEntityCreate.createEntity()
     }
   }
 }
 </script>
-
-<style scoped lang="scss">
-.AdminPostCreate {
-  .title {
-    font-style: normal;
-    font-weight: 700;
-    font-size: 24px;
-    line-height: 140%;
-    color: #424242;
-    margin-bottom: 27px;
-    position: relative;
-    .back-action {
-      position: absolute;
-      right: 0;
-      top: 0;
-    }
-  }
-  :deep(.form) {
-    padding: 24px;
-  }
-}
-</style>

+ 9 - 2
src/components/Widgets/Classroom/AdminClassroomCreate/OptionPanel.vue

@@ -1,13 +1,15 @@
 <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'
 
@@ -16,6 +18,11 @@ export default defineComponent({
   components: {
     OptionPanelTabs
   },
-  mixins: [mixinOptionPanel]
+  mixins: [mixinOptionPanel],
+  data () {
+    return {
+      classroomTypeOptions: (new UnitCategory()).typeEnums
+    }
+  }
 })
 </script>

+ 188 - 96
src/components/Widgets/Classroom/AdminClassroomList/AdminClassroomList.vue

@@ -1,26 +1,47 @@
 <template>
-  <div class="AdminInvoiceList"
-       :style="localOptions.style">
+  <div class="AdminClassroomIndex">
+    <div class="add-new-action-row">
+      <q-btn color="primary"
+             :to="{name: createPageRouteName}">
+        <svg data-name="Close Square"
+             xmlns="http://www.w3.org/2000/svg"
+             width="20"
+             height="20"
+             viewBox="0 0 20 20"
+             class="q-mr-md">
+          <path id="Combined_Shape"
+                data-name="Combined Shape"
+                d="M5.665,20C2.276,20,0,17.623,0,14.084V5.916C0,2.377,2.276,0,5.665,0h8.67C17.723,0,20,2.377,20,5.916v8.168C20,17.623,17.723,20,14.333,20ZM1.5,5.916v8.168c0,2.683,1.634,4.416,4.164,4.416h8.669c2.532,0,4.167-1.733,4.167-4.416V5.916c0-2.682-1.635-4.415-4.166-4.415H5.665C3.135,1.5,1.5,3.234,1.5,5.916Zm7.968,8a.747.747,0,0,1-.22-.53V10.741H6.611a.75.75,0,0,1-.75-.75.749.749,0,0,1,.75-.75H9.249V6.6a.75.75,0,1,1,1.5,0V9.241h2.639a.75.75,0,0,1,0,1.5H10.748v2.642a.75.75,0,0,1-1.28.53Z"
+                fill="#fff" />
+        </svg>
+        ایجاد
+        {{ classroomTypeTitle }}
+        جدید
+      </q-btn>
+    </div>
     <entity-index v-if="mounted"
                   ref="entityIndex"
                   v-model:value="inputs"
-                  title="لیست صورتحساب ها"
+                  :title="'لیست ' + classroomTypeTitle"
                   :api="api"
                   :table="table"
                   :table-keys="tableKeys"
-                  :create-route-name="createRouteName"
-                  :show-search-button="false"
                   :show-expand-button="false"
-                  :show-reload-button="false">
-      <template #entity-index-table-cell="{inputData}">
+                  :show-reload-button="false"
+                  :show-search-button="false">
+      <template v-slot:entity-index-table-cell="{inputData, showConfirmRemoveDialog}">
         <template v-if="inputData.col.name === 'number'">
           {{ inputData.rowNumber }}
         </template>
         <template v-else-if="inputData.col.name === 'action'">
-          <q-btn color="primary"
-                 :to="{name: 'Admin.Invoice.Show', params: {id: inputData.props.row.id}}">
-            جزییات جزییات
-          </q-btn>
+          <div class="action-column-entity-index">
+            <q-btn size="md"
+                   color="primary"
+                   label="جزییات"
+                   :to="{name: showPageRouteName, params: {id: inputData.props.row.id}}"
+                   class="q-mr-md" />
+            <delete-btn @click="showConfirmRemoveDialog(inputData.props.row, 'id', getRemoveMessage(inputData.props.row))" />
+          </div>
         </template>
         <template v-else>
           {{ inputData.col.value }}
@@ -32,52 +53,54 @@
 
 <script>
 import { shallowRef } from 'vue'
-import Assist from 'assets/js/Assist.js'
 import { EntityIndex } from 'quasar-crud'
-import { Invoice } from 'src/models/Invoice.js'
+import Enums from 'src/assets/Enums/Enums.js'
+import ShamsiDate from 'src/assets/ShamsiDate.js'
 import { mixinWidget } from 'src/mixin/Mixins.js'
 import { APIGateway } from 'src/api/APIGateway.js'
-import { FormBuilderAssist } from 'quasar-form-builder'
 import BtnControl from 'src/components/Control/btn.vue'
+import { FormBuilderAssist } from 'quasar-form-builder'
+import { UnitCategory } from 'src/models/UnitCategory.js'
+import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
 
 const BtnControlComp = shallowRef(BtnControl)
 
 export default {
-  name: 'AdminInvoiceList',
-  components: { EntityIndex },
+  name: 'Admin.Classroom.Index',
+  components: {
+    EntityIndex,
+    DeleteBtn
+  },
   mixins: [mixinWidget],
   data () {
     return {
-      api: APIGateway.invoice.APIAdresses.base,
-      tableKeys: {
-        data: 'results',
-        total: 'count',
-        currentPage: 'current',
-        perPage: 'per_page',
-        pageKey: 'page'
-      },
+      mounted: false,
       inputs: [
         {
-          type: 'dateTime',
-          name: 'creation_time__gte',
-          label: 'از تاریخ',
+          type: 'select',
+          name: 'status',
+          options: Enums.classroomStatuses,
+          value: null,
+          label: 'وضعیت ',
           placeholder: ' ',
-          col: 'col-md-3 col-12'
+          col: 'col-md-2 col-12'
         },
         {
-          type: 'dateTime',
-          name: 'creation_time__lt',
-          label: 'تا تاریخ',
+          type: 'select',
+          name: 'unit',
+          options: [],
+          value: null,
+          label: 'درس',
           placeholder: ' ',
-          col: 'col-md-3 col-12'
+          col: 'col-md-2 col-12'
         },
-        { type: 'select', name: 'status', options: (new Invoice()).statusEnums, label: 'وضعیت', placeholder: ' ', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'type', options: (new Invoice()).typeEnums, label: 'نوع', placeholder: ' ', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'owner__firstname', label: 'نام سفارش دهنده', placeholder: ' ', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'owner__lastname', label: 'نام خانوادگی سفارش دهنده', placeholder: ' ', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'owner__national_code', label: 'کدملی سفارش دهنده', placeholder: ' ', col: 'col-md-3 col-12' },
-        { type: BtnControlComp, name: 'btn', responseKey: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-3 col-12' }
+        { type: 'hidden', name: 'unit__category__type', value: null },
+        { type: BtnControlComp, name: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-2 col-12' }
       ],
+      defaultOptions: {
+        classroomType: 'TRAINING'
+      },
+      api: APIGateway.classroom.APIAdresses.base,
       table: {
         columns: [
           {
@@ -95,118 +118,187 @@ export default {
             field: row => row.id
           },
           {
-            name: 'id',
+            name: 'title',
             required: true,
-            label: 'سفارش دهنده',
+            label: 'عنوان',
             align: 'left',
-            field: row => row.owner_info.firstname + ' ' + row.owner_info.lastname
+            field: row => row.title
           },
           {
-            name: 'id',
+            name: 'audience_gender_type',
             required: true,
-            label: 'کدملی سفارش دهنده',
+            label: 'جنسیت',
             align: 'left',
-            field: row => row.owner_info.national_code
+            field: row => (row.audience_gender_type === 'FEMALE') ? 'خواهران' : (row.audience_gender_type === 'MALE') ? 'برادران' : 'خواهران و برادران'
           },
           {
-            name: 'id',
+            name: 'status',
             required: true,
-            label: 'عنوان',
+            label: 'وضعیت',
             align: 'left',
-            field: row => this.getInvoiceTitle(row)
+            field: row => this.getClassroomStatusesTitle(row.status)
           },
           {
-            name: 'id',
+            name: 'title',
             required: true,
-            label: 'نوع صورتحساب',
+            label: 'نوع برگزاری',
             align: 'left',
-            field: row => (new Invoice(row)).type_info.label
+            field: row => this.getClassroomHoldingTypeTitle(row.holding_type)
           },
           {
-            name: 'amount',
+            name: 'title',
             required: true,
-            label: 'مبلغ تراکنش(ریال)',
+            label: 'هزینه(ریال)',
             align: 'left',
-            field: row => row.amount.toLocaleString('fa')
+            field: row => row.price
           },
           {
-            name: 'id',
+            name: 'title',
             required: true,
-            label: 'وضعیت تراکنش',
+            label: 'استاد مربوطه',
             align: 'left',
-            field: row => (new Invoice(row)).status_info.label
+            field: row => row.professor_info?.firstname + ' ' + row.professor_info?.lastname
           },
           {
-            name: 'creation_time',
+            name: 'title',
             required: true,
-            label: 'زمان ثبت',
+            label: 'تاریخ و زمان ثبت نام',
             align: 'left',
-            field: row => Assist.miladiToShamsi(row.creation_time)
+            field: row => row.beginning_registration_period ? ShamsiDate.getDateTime(row.beginning_registration_period) : '-'
           },
           {
-            name: 'last_modification_time',
+            name: 'title',
             required: true,
-            label: 'زمان آخرین بروز رسانی',
+            label: 'ترم برگزاری',
             align: 'left',
-            field: row => Assist.miladiToShamsi(row.last_modification_time)
+            field: row => (row.beginning_registration_period) ? ShamsiDate.getTerm(row.beginning_registration_period) : '-'
           },
           {
             name: 'action',
             required: true,
-            label: 'جزییات',
+            label: 'عملیات',
             align: 'left',
-            field: row => ''
+            field: ''
           }
-        ]
+        ],
+        data: []
       },
-      mounted: false,
-      createRouteName: ''
+      tableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
     }
   },
-  mounted() {
+  computed: {
+    classroomTypeTitle () {
+      const unitCategory = new UnitCategory({ type: this.localOptions.classroomType })
+      return unitCategory.type_info.label
+    },
+    createPageRouteName () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'Admin.Classroom.Create'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'Admin.Event.Create'
+      }
+      return 'Admin.Classroom.Create'
+    },
+    showPageRouteName () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'Admin.Classroom.Show'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'Admin.Event.Show'
+      }
+      return 'Admin.Classroom.Show'
+    }
+  },
+  mounted () {
     this.setActionBtn()
+    this.getUnits()
+    this.setClassroomTypeOfInputs()
     this.mounted = true
   },
   methods: {
-    getInvoiceTitle (invoice) {
-      if (invoice.item_info.item_type === 'CLASSROOM') {
-        return invoice.item_info.title
-      } else {
-        return invoice.item_info.title || '-'
-      }
+    setClassroomTypeOfInputs () {
+      FormBuilderAssist.setAttributeByName(this.inputs, 'status', 'label', 'وضعیت ' + this.classroomTypeTitle)
+      FormBuilderAssist.setAttributeByName(this.inputs, 'unit__category__type', 'value', this.localOptions.classroomType)
+      this.table.columns.forEach(col => {
+        if (col.name === 'title') {
+          col.label = 'نام ' + this.classroomTypeTitle
+        }
+      })
     },
     setActionBtn () {
-      FormBuilderAssist.setAttributeByName(this.inputs, 'btn', 'atClick', this.search)
+      this.inputs.forEach((item, index) => {
+        if (item.name === 'btn') {
+          this.inputs[index].atClick = this.search
+        }
+      })
     },
     search () {
       this.$refs.entityIndex.search()
+    },
+    getUnits () {
+      APIGateway.unit.index({ per_page: 9999, category__type: this.localOptions.classroomType })
+        .then((units) => {
+          this.loadSelectOptions('unit', this.getSelectOptions(units.list.list, 'id', 'title'))
+        })
+        .catch(() => {
+
+        })
+    },
+    loadSelectOptions (name, value) {
+      const inputIndex = this.inputs.findIndex(input => input.name === name)
+      this.inputs[inputIndex].options = value
+    },
+    getSelectOptions (result, value, label) {
+      return result.map(item => {
+        return {
+          value: item[value],
+          label: item[label]
+        }
+      })
+    },
+    getRemoveMessage (row) {
+      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
+    },
+    getClassroomHoldingTypeTitle (type) {
+      const target = Enums.classroomHoldingTypes.find(item => item.value === type)
+      if (!target) {
+        return '-'
+      }
+
+      return target.label
+    },
+    getClassroomStatusesTitle (type) {
+      const target = Enums.classroomStatuses.find(item => item.value === type)
+      if (!target) {
+        return '-'
+      }
+
+      return target.label
     }
   }
 }
 </script>
 
-<style scoped lang="scss">
-.AdminInvoiceList {
-  .title {
-    font-style: normal;
-    font-weight: 700;
-    font-size: 24px;
-    line-height: 140%;
-    color: #424242;
-    margin-bottom: 27px;
+<style lang="scss" scoped>
+.AdminClassroomIndex {
+  .add-new-action-row {
+    display: flex;
+    flex-flow: row;
+    align-items: center;
+    justify-content: flex-end;
+    margin-bottom: 22px;
   }
-  :deep(.list) {
-    .quasar-crud-index-table {
-      padding: 0;
-      .q-table__container {
-        background-color: transparent;
-        box-shadow: none;
-        border: none;
-        .q-table__top {
-          display: none;
-        }
-      }
-    }
+  .action-column-entity-index {
+    display: flex;
+    align-items: center;
+    justify-content: flex-start;
   }
 }
 </style>

+ 9 - 2
src/components/Widgets/Classroom/AdminClassroomList/OptionPanel.vue

@@ -1,13 +1,15 @@
 <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'
 
@@ -16,6 +18,11 @@ export default defineComponent({
   components: {
     OptionPanelTabs
   },
-  mixins: [mixinOptionPanel]
+  mixins: [mixinOptionPanel],
+  data () {
+    return {
+      classroomTypeOptions: (new UnitCategory()).typeEnums
+    }
+  }
 })
 </script>

+ 95 - 18
src/components/Widgets/Classroom/AdminClassroomShow/AdminClassroomShow.vue

@@ -12,7 +12,8 @@
       >
     </q-btn>
   </div>
-  <q-card class="AdminClassroomShow">
+  <q-card v-if="mounted"
+          class="AdminClassroomShow">
     <q-tabs v-model="tab"
             dense
             class="text-grey"
@@ -20,25 +21,35 @@
             indicator-color="primary"
             align="justify"
             narrow-indicator>
-      <q-tab name="classroomInfo"
+      <q-tab v-if="canShowTabPage('classroomInfo')"
+             name="classroomInfo"
              label="مشخصات" />
-      <q-tab name="sessions"
-             label="لیست جلسات" />
-      <q-tab name="projects"
+      <q-tab v-if="canShowTabPage('sessions')"
+             name="sessions"
+             :label="sessionsTabTitle" />
+      <q-tab v-if="canShowTabPage('projects')"
+             name="projects"
              label="پروژه‌ها" />
-      <q-tab name="movies2"
+      <q-tab v-if="canShowTabPage('exams')"
+             name="exams"
              label="آزمون" />
-      <q-tab name="members"
+      <q-tab v-if="canShowTabPage('members')"
+             name="members"
              label="اندیشه جویان" />
-      <q-tab name="teams"
+      <q-tab v-if="canShowTabPage('teams')"
+             name="teams"
              label="گروه" />
-      <q-tab name="graders"
+      <q-tab v-if="canShowTabPage('graders')"
+             name="graders"
              label="مصححین" />
-      <q-tab name="leaders"
+      <q-tab v-if="canShowTabPage('leaders')"
+             name="leaders"
              label="سرگروه ها" />
-      <q-tab name="activity_sheet"
+      <q-tab v-if="canShowTabPage('activity_sheet')"
+             name="activity_sheet"
              label="فعالیت کلاسی" />
-      <q-tab name="live_streaming_url"
+      <q-tab v-if="canShowTabPage('live_streaming_url')"
+             name="live_streaming_url"
              label="بخش آنلاین" />
     </q-tabs>
 
@@ -49,18 +60,20 @@
       <q-tab-panel name="classroomInfo"
                    class="q-pa-none">
         <classroom-info v-model:classroom="classroom"
+                        :classroom-type="localOptions.classroomType"
                         :classroom-id="$route.params.id" />
       </q-tab-panel>
       <q-tab-panel name="sessions"
                    class="q-pa-none">
-        <session-list :classroom-id="$route.params.id" />
+        <session-list :classroom-id="$route.params.id"
+                      :classroom-type="localOptions.classroomType" />
       </q-tab-panel>
 
       <q-tab-panel name="projects"
                    class="q-pa-none">
         <project-list :classroom-id="$route.params.id" />
       </q-tab-panel>
-      <q-tab-panel name="movies2">
+      <q-tab-panel name="exams">
         آزمون
       </q-tab-panel>
       <q-tab-panel name="members"
@@ -91,13 +104,15 @@
 </template>
 
 <script>
-import { Classroom } from 'src/models/Classroom.js'
 import TeamList from './components/TeamList.vue'
+import { mixinWidget } from 'src/mixin/Mixins.js'
+import { Classroom } from 'src/models/Classroom.js'
 import LeaderList from './components/LeaderList.vue'
 import GraderList from './components/GraderList.vue'
 import SessionList from './components/SessionList.vue'
 import ProjectList from './components/ProjectList.vue'
 import MembersList from './components/MembersList.vue'
+import { UnitCategory } from 'src/models/UnitCategory.js'
 import ClassroomInfo from './components/ClassroomInfo.vue'
 import LiveStreaming from './components/LiveStreaming.vue'
 import ActivitySheetList from './components/ActivitySheetList.vue'
@@ -117,8 +132,10 @@ export default {
     LiveStreaming,
     ActivitySheetList
   },
+  mixins: [mixinWidget],
   data () {
     return {
+      mounted: false,
       tab: 'classroomInfo',
       classroom: new Classroom()
     }
@@ -126,6 +143,63 @@ export default {
   computed: {
     classroomId () {
       return this.classroom.id
+    },
+    classroomTypeTitle () {
+      const unitCategory = new UnitCategory({ type: this.localOptions.classroomType })
+      return unitCategory.type_info.label
+    },
+    sessionsTabTitle () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'لیست جلسات'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'لیست برنامه ها'
+      }
+      return 'Admin.Classroom.Create'
+    },
+    indexPageRouteName () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'Admin.Classroom.Index'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'Admin.Event.Index'
+      }
+      return 'Admin.Classroom.Index'
+    },
+    showPageRouteName () {
+      if (this.localOptions.classroomType === 'TRAINING') {
+        return 'Admin.Classroom.Show'
+      }
+      if (this.localOptions.classroomType === 'EVENT') {
+        return 'Admin.Event.Show'
+      }
+      return 'Admin.Classroom.Show'
+    },
+    canShowTabPage () {
+      return (tabName) => {
+        const tabs = {
+          TRAINING: [
+            'classroomInfo',
+            'sessions',
+            'projects',
+            'exams',
+            'members',
+            'teams',
+            'graders',
+            'leaders',
+            'activity_sheet',
+            'live_streaming_url'
+          ],
+          EVENT: [
+            'classroomInfo',
+            'sessions',
+            'members',
+            'live_streaming_url'
+          ]
+        }
+
+        return tabs[this.localOptions.classroomType].includes(tabName)
+      }
     }
   },
   watch: {
@@ -137,6 +211,9 @@ export default {
       this.updateBreadcrumbs()
     }
   },
+  mounted () {
+    this.mounted = true
+  },
   methods: {
     updateBreadcrumbs () {
       this.$store.commit('AppLayout/updateBreadcrumbs', {
@@ -144,12 +221,12 @@ export default {
         loading: false,
         path: [
           {
-            label: 'دوره های آموزشی',
-            to: { name: 'Admin.Classroom.Index' }
+            label: 'لیست ' + this.classroomTypeTitle,
+            to: { name: this.indexPageRouteName }
           },
           {
             label: this.classroom.title,
-            to: { name: 'Admin.Classroom.Show', params: { id: this.$route.params.id } }
+            to: { name: this.showPageRouteName, params: { id: this.$route.params.id } }
           }
         ]
       })

+ 2 - 10
src/components/Widgets/Classroom/AdminClassroomShow/OptionPanel.vue

@@ -9,6 +9,7 @@
 
 <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'
 
@@ -20,16 +21,7 @@ export default defineComponent({
   mixins: [mixinOptionPanel],
   data () {
     return {
-      classroomTypeOptions: [
-        {
-          label: 'دوره آموزشی',
-          value: 'Classroom'
-        },
-        {
-          label: 'حلقه مباحثاتی',
-          value: 'DiscussionCircles'
-        }
-      ]
+      classroomTypeOptions: (new UnitCategory()).typeEnums
     }
   }
 })

+ 33 - 5
src/components/Widgets/Classroom/AdminClassroomShow/components/ClassroomInfo.vue

@@ -3,7 +3,7 @@
                ref="classroomEntityEdit"
                :key="classroomEntityEditKey"
                v-model:value="inputs"
-               title="مشخصات دوره آموزشی"
+               :title="'مشخصات ' + classroomTypeTitle"
                :api="api"
                :show-close-button="false"
                :show-edit-button="false"
@@ -31,6 +31,7 @@ import Enums from 'src/assets/Enums/Enums.js'
 import { APIGateway } from 'src/api/APIGateway.js'
 import { Classroom } from 'src/models/Classroom.js'
 import { FormBuilderAssist } from 'quasar-form-builder'
+import { UnitCategory } from 'src/models/UnitCategory.js'
 import FormBuilderInputEditor from 'src/components/FormBuilderCustumComponents/FormBuilderInputEditor.vue'
 
 const FormBuilderInputEditorComp = shallowRef(FormBuilderInputEditor)
@@ -45,6 +46,10 @@ export default {
       type: Number,
       default: null
     },
+    classroomType: {
+      type: String,
+      default: 'TRAINING'
+    },
     classroom: {
       type: Classroom,
       default: new Classroom()
@@ -159,6 +164,10 @@ export default {
     selectedCategoryId () {
       return FormBuilderAssist.getInputsByName(this.inputs, 'category').value
     },
+    classroomTypeTitle () {
+      const unitCategory = new UnitCategory({ type: this.classroomType })
+      return unitCategory.type_info.label
+    },
     localClassroom: {
       get () {
         return this.classroom
@@ -178,6 +187,7 @@ export default {
     }
   },
   mounted () {
+    this.setClassroomTypeOfInputs()
     this.localClassroom.loading = true
     this.preLoadData()
       .then(() => {
@@ -188,6 +198,22 @@ export default {
       })
   },
   methods: {
+    setClassroomTypeOfInputs () {
+      if (this.classroomType === 'TRAINING') {
+        FormBuilderAssist.setAttributeByName(this.inputs, 'professor', 'label', 'استاد')
+      }
+      if (this.classroomType === 'EVENT') {
+        FormBuilderAssist.setAttributeByName(this.inputs, 'professor', 'label', 'برگزار کننده')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'unit', 'label', 'دسته')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'category', 'type', 'hidden') // unit -> category__type filter
+        FormBuilderAssist.setAttributeByName(this.inputs, 'allowed_absence_count', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'effective_absence_coefficient', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'mandatory_assignment_count', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'special_passing_mark', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'minimum_conditional_passing_mark', 'type', 'hidden')
+        FormBuilderAssist.setAttributeByName(this.inputs, 'minimum_clean_passing_mark', 'type', 'hidden')
+      }
+    },
     afterLoadInputData (data) {
       this.localClassroom = new Classroom(data)
       this.localClassroom.loading = false
@@ -201,7 +227,9 @@ export default {
       return new Promise((resolve, reject) => {
         APIGateway.classroom.get(this.classroomId)
           .then((classroom) => {
-            this.setInputAttr('category', 'value', classroom.unit_info.category_info.id)
+            if (this.classroomType === 'TRAINING') {
+              this.setInputAttr('category', 'value', classroom.unit_info.category_info.id)
+            }
             this.setInputAttr('unit', 'value', classroom.unit)
             this.beforeLoadInputData(classroom)
               .then((classroom) => {
@@ -220,7 +248,7 @@ export default {
       return new Promise((resolve, reject) => {
         const promise1 = this.getProfessors()
         const promise2 = this.getCategories()
-        const promise3 = this.getUnits(responseData.unit_info.category)
+        const promise3 = (this.classroomType === 'EVENT') ? this.getUnits(null, this.classroomType) : this.getUnits(responseData.unit_info.category)
         this.$nextTick(() => {
           Promise.all([promise1, promise2, promise3])
             .then(() => {
@@ -259,8 +287,8 @@ export default {
         })
         .catch(() => {})
     },
-    getUnits (selectedcategoryId) {
-      return APIGateway.unit.index({ per_page: 9999, category: selectedcategoryId })
+    getUnits (selectedcategoryId = null, categoryType = null) {
+      return APIGateway.unit.index({ per_page: 9999, category: selectedcategoryId, category__typ: categoryType })
         .then((units) => {
           this.setInputAttr('unit', 'options', units.list.list.map(item => {
             return {

+ 44 - 5
src/components/Widgets/Classroom/AdminClassroomShow/components/SessionList.vue

@@ -2,7 +2,7 @@
   <entity-index v-if="mounted"
                 ref="sessionList"
                 v-model:value="sessionListInputs"
-                title="لیست جلسات"
+                :title="listTitle"
                 :api="sessionListApi"
                 :table="sessionListTable"
                 :table-keys="sessionListTableKeys"
@@ -14,7 +14,7 @@
              outline
              :loading="addNewSessionLoading"
              @click="addNewSession">
-        افزودن جلسه
+        {{ addBtnTitle }}
       </q-btn>
     </template>
     <template v-slot:entity-index-table-cell="{inputData, showConfirmRemoveDialog}">
@@ -27,7 +27,7 @@
                  outline
                  color="primary"
                  label="بررسی"
-                 :to="{name: 'Admin.Classroom.Session.AttendanceSheetList', params: {classroom_id: classroomId, session_id: inputData.props.row.id}}"
+                 :to="{name: sessionAttendanceSheetList, params: {classroom_id: classroomId, session_id: inputData.props.row.id}}"
                  class="q-mr-md" />
           <q-btn size="md"
                  color="primary"
@@ -63,12 +63,18 @@ export default {
     classroomId: {
       type: Number,
       default: null
+    },
+    classroomType: {
+      type: String,
+      default: 'TRAINING'
     }
   },
   data () {
     const classroomId = this.classroomId
     return {
       mounted: false,
+      listTitle: 'لیست جلسات',
+      addBtnTitle: 'افزودن جلسه',
       addNewSessionLoading: false,
 
       sessionListInputs: [
@@ -99,14 +105,14 @@ export default {
             field: row => row.title
           },
           {
-            name: 'creation_time',
+            name: 'beginning_time',
             required: true,
             label: 'زمان شروع جلسه',
             align: 'left',
             field: row => row.beginning_time ? ShamsiDate.getDateTime(row.beginning_time) : '-'
           },
           {
-            name: 'last_modification_time',
+            name: 'ending_time',
             required: true,
             label: 'زمان پایان جلسه',
             align: 'left',
@@ -130,10 +136,43 @@ export default {
       }
     }
   },
+  computed: {
+    sessionAttendanceSheetList () {
+      if (this.classroomType === 'TRAINING') {
+        return 'Admin.Classroom.Session.AttendanceSheetList'
+      }
+      if (this.classroomType === 'EVENT') {
+        return 'Admin.Event.Session.AttendanceSheetList'
+      }
+      return 'Admin.Classroom.Session.AttendanceSheetList'
+    }
+  },
   mounted () {
+    this.setClassroomTypeOfInputs()
     this.mounted = true
   },
   methods: {
+    setClassroomTypeOfInputs () {
+      if (this.classroomType === 'TRAINING') {
+        this.listTitle = 'لیست جلسات'
+        this.addBtnTitle = 'افزودن جلسه'
+      }
+      if (this.classroomType === 'EVENT') {
+        this.listTitle = 'لیست برنامه ها'
+        this.addBtnTitle = 'افزودن برنامه'
+        this.sessionListTable.columns.forEach(col => {
+          if (col.name === 'title') {
+            col.label = 'عنوان برنامه'
+          }
+          if (col.name === 'beginning_time') {
+            col.label = 'زمان شروع برنامه'
+          }
+          if (col.name === 'ending_time') {
+            col.label = 'زمان پایان برنامه'
+          }
+        })
+      }
+    },
     addNewSession () {
       this.addNewSessionLoading = true
       APIGateway.session.create({

+ 10 - 3
src/components/Widgets/SessionAttendanceSheet/AdminSessionAttendanceSheetList/AdminSessionAttendanceSheetList.vue

@@ -73,16 +73,17 @@
 
 <script>
 import { shallowRef } from 'vue'
-import { EntityIndex, EntityEdit } from 'quasar-crud'
+import Assist from 'assets/js/Assist.js'
 import { mixinWidget } from 'src/mixin/Mixins.js'
 import { APIGateway } from 'src/api/APIGateway.js'
 import { Classroom } from 'src/models/Classroom.js'
+import { EntityIndex, EntityEdit } from 'quasar-crud'
 import { FormBuilderAssist } from 'quasar-form-builder'
 import BtnControl from 'src/components/Control/btn.vue'
 import { Registration } from 'src/models/Registration.js'
+import { UnitCategory } from 'src/models/UnitCategory.js'
 import Breadcrumbs from 'src/components/Widgets/Breadcrumbs/Breadcrumbs.vue'
 import { SessionAttendanceSheets } from 'src/models/SessionAttendanceSheets.js'
-import Assist from 'assets/js/Assist'
 
 const BtnControlComp = shallowRef(BtnControl)
 
@@ -175,6 +176,12 @@ export default {
       createRouteName: ''
     }
   },
+  computed: {
+    classroomTypeTitle () {
+      const unitCategory = new UnitCategory({ type: this.localOptions.classroomType })
+      return unitCategory.type_info.label
+    }
+  },
   mounted() {
     this.mounted = true
     this.setActionBtn()
@@ -191,7 +198,7 @@ export default {
         loading: false,
         path: [
           {
-            label: 'دوره های آموزشی',
+            label: 'لیست ' + this.classroomTypeTitle,
             to: { name: 'Admin.Classroom.Index' }
           },
           {

+ 9 - 2
src/components/Widgets/SessionAttendanceSheet/AdminSessionAttendanceSheetList/OptionPanel.vue

@@ -1,13 +1,15 @@
 <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'
 
@@ -16,6 +18,11 @@ export default defineComponent({
   components: {
     OptionPanelTabs
   },
-  mixins: [mixinOptionPanel]
+  mixins: [mixinOptionPanel],
+  data () {
+    return {
+      classroomTypeOptions: (new UnitCategory()).typeEnums
+    }
+  }
 })
 </script>

+ 21 - 1
src/models/UnitCategory.js

@@ -16,11 +16,31 @@ class UnitCategory extends Model {
         key: 'units_info',
         relatedModel: UnitList
       },
+      { key: 'type' },
       { key: 'creation_time' },
       { key: 'last_modification_time' },
       { key: 'is_active' },
       { key: 'is_deleted' }
-    ])
+    ], {
+      type: {
+        infoKey: 'type_info',
+        enumListKey: 'typeEnums',
+        enums: [
+          {
+            label: 'دوره آموزشی',
+            value: 'TRAINING'
+          },
+          {
+            label: 'حلقه مباحثاتی',
+            value: 'DiscussionCircles'
+          },
+          {
+            label: 'رویداد',
+            value: 'EVENT'
+          }
+        ]
+      }
+    })
   }
 }
 

+ 1 - 1
src/pages/Admin/Classroom/SessionActivitySheets/sessionActivitySheets.vue

@@ -13,7 +13,7 @@ export default {
   mixins: [mixinPageOptions],
   data: () => {
     return {
-      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminSessionAttendanceSheetList' }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminSessionAttendanceSheetList', options: { style: {}, classroomType: 'TRAINING' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
     }
   },
   created() {

+ 10 - 238
src/pages/Admin/Classroom/create.vue

@@ -1,251 +1,23 @@
 <template>
-  <div class="flex justify-end">
-    <q-btn flat
-           color="grey"
-           @click="$router.go(-1)">
-      بازگشت
-      >
-    </q-btn>
-  </div>
-  <div class="AdminClassroomCreate">
-    <q-linear-progress v-if="unitsLoading"
-                       indeterminate />
-    <entity-create v-if="mounted"
-                   ref="classroomEntityCreate"
-                   :key="classroomEntityCreateKey"
-                   v-model:value="inputs"
-                   title="مشخصات دوره آموزشی"
-                   :api="api"
-                   :entity-id-key="entityIdKey"
-                   :entity-param-key="entityParamKey"
-                   :show-route-name="showRouteName"
-                   :show-close-button="false"
-                   :show-edit-button="false"
-                   :show-expand-button="false"
-                   :show-save-button="false"
-                   :show-reload-button="false">
-      <template #after-form-builder>
-        <div class="flex justify-end q-mt-md">
-          <q-btn color="primary"
-                 label="ایجاد دوره آموزشی جدید"
-                 @click="createClassroom" />
-        </div>
-      </template>
-    </entity-create>
-  </div>
+  <q-page-builder v-model:sections="currenSections"
+                  v-model:options="pageConfig"
+                  :editable="pageBuilderEditable"
+                  :loading="pageBuilderLoading" />
 </template>
 
 <script>
-import { shallowRef } from 'vue'
-import { EntityCreate } from 'quasar-crud'
-import Enums from 'src/assets/Enums/Enums.js'
-import { APIGateway } from 'src/api/APIGateway.js'
-import { FormBuilderAssist } from 'quasar-form-builder'
-import FormBuilderInputEditor from 'src/components/FormBuilderCustumComponents/FormBuilderInputEditor.vue'
-
-const FormBuilderInputEditorComp = shallowRef(FormBuilderInputEditor)
+import { mixinPageOptions } from 'src/mixin/Mixins.js'
 
 export default {
   name: 'Admin.Classroom.Create',
-  components: {
-    EntityCreate
-  },
-  data () {
+  mixins: [mixinPageOptions],
+  data: () => {
     return {
-      mounted: false,
-      unitsLoading: false,
-      classroomEntityCreateKey: Date.now(),
-      newUnitLoading: false,
-      newUnitName: null,
-      newUnitSessionCount: null,
-      api: APIGateway.classroom.APIAdresses.base,
-      entityIdKey: 'id',
-      entityParamKey: 'id',
-      showRouteName: 'Admin.Classroom.Show',
-      inputs: [
-        { type: 'separator', name: 'space', label: 'مشخصات دوره', className: 'custom-separator', col: 'col-12' },
-        { type: 'file', name: 'thumbnail', responseKey: 'thumbnail', label: 'آپلود عکس دوره', col: 'col-md-3 col-12' },
-        { type: 'file', name: 'codes', responseKey: 'codes', label: 'آیین نامه دوره', col: 'col-md-3 col-12' },
-        { type: 'separator', name: 'space', size: '0', col: 'col-md-12' },
-        { type: 'select', name: 'category', responseKey: 'unit_info.category', options: [], value: null, placeholder: ' ', label: 'دسته بندی', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'unit', responseKey: 'unit', options: [], value: null, placeholder: ' ', label: 'درس', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'holding_type', responseKey: 'holding_type', options: Enums.classroomHoldingTypes, value: null, placeholder: ' ', label: 'نوع برگزاری', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'price', responseKey: 'price', placeholder: ' ', label: 'هزینه برگزاری', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'live_streaming_url', responseKey: 'live_streaming_url', placeholder: ' ', label: 'لینک مکان مجازی دوره', col: 'col-12' },
-        { type: FormBuilderInputEditorComp, name: 'classroom_address', responseKey: 'classroom_address', placeholder: ' ', label: 'آدرس مکان فیزیکی دوره', col: 'col-12' },
-        {
-          type: 'select',
-          name: 'holding_year',
-          responseKey: 'holding_year',
-          options: [1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410],
-          value: null,
-          label: 'انتخاب سال دوره',
-          placeholder: ' ',
-          col: 'col-md-3'
-        },
-        {
-          type: 'select',
-          name: 'holding_month',
-          responseKey: 'holding_month',
-          options: [
-            'فروردین',
-            'اردیبهشت',
-            'خرداد',
-            'تیر',
-            'مرداد',
-            'شهریور',
-            'مهر',
-            'آبان',
-            'آذر',
-            'دی',
-            'بهمن',
-            'اسفند'
-          ],
-          value: null,
-          label: 'انتخاب ماه دوره',
-          placeholder: ' ',
-          col: 'col-md-3'
-        },
-        { type: 'input', name: 'sessions_frequency', responseKey: 'sessions_frequency', placeholder: ' ', label: 'دوره تناوب', col: 'col-12' },
-        { type: 'select', name: 'professor', responseKey: 'professor', options: [], value: null, placeholder: ' ', label: 'استاد دوره', col: 'col-md-3 col-12' },
-
-        { type: 'separator', name: 'space', label: 'مشخصات اندیشه جو', className: 'custom-separator', col: 'col-12' },
-        { type: 'select', name: 'audience_status_wwwww', responseKey: 'audience_status_wwwww', options: [], placeholder: ' ', label: 'وضعیت(؟)', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'category', responseKey: 'category', options: [], placeholder: ' ', label: 'مجموعه(؟)', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'audience_gender_type', responseKey: 'audience_gender_type', options: Enums.genders, placeholder: ' ', label: 'جنسیت', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'audience_bashgah_wwwww', responseKey: 'audience_bashgah_wwwww', options: [], placeholder: ' ', label: 'باشگاه(؟)', col: 'col-md-3 col-12' },
-
-        { type: 'separator', name: 'space', label: 'تنظیمات دوره', className: 'custom-separator', col: 'col-12' },
-        { type: 'input', name: 'capacity', responseKey: 'capacity', placeholder: ' ', label: 'ظرفیت گروه درسی', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'allowed_absence_count', responseKey: 'allowed_absence_count', placeholder: ' ', label: 'تعداد مجاز غیبت', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'effective_absence_coefficient', responseKey: 'effective_absence_coefficient', placeholder: ' ', label: 'ضریب نمره حضور و غیاب', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'mandatory_assignment_count', responseKey: 'mandatory_assignment_count', placeholder: ' ', label: 'تعداد تکالیف اجباری', col: 'col-md-3 col-12' },
-
-        { type: 'input', name: 'special_passing_mark', responseKey: 'special_passing_mark', placeholder: ' ', label: 'نمره قبولی مشروطی ها', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'minimum_conditional_passing_mark', responseKey: 'minimum_conditional_passing_mark', placeholder: ' ', label: 'نمره قبولی مشروط', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'minimum_clean_passing_mark', responseKey: 'minimum_clean_passing_mark', placeholder: ' ', label: 'نمره قبولی', col: 'col-md-3 col-12' },
-
-        { type: 'separator', name: 'space', label: 'ثبت نام و حذف و اضافه', className: 'custom-separator', col: 'col-12' },
-        { type: 'dateTime', name: 'beginning_enrollment_period', responseKey: 'beginning_enrollment_period', placeholder: ' ', label: 'تاریخ شروع پیش ثبت نام', col: 'col-md-6 col-12' },
-        { type: 'dateTime', name: 'ending_enrollment_period', responseKey: 'ending_enrollment_period', placeholder: ' ', label: 'تاریخ پایان پیش ثبت نام', col: 'col-md-6 col-12' },
-        { type: 'dateTime', name: 'beginning_registration_period', responseKey: 'beginning_registration_period', placeholder: ' ', label: 'تاریخ شروع ثبت نام', col: 'col-md-6 col-12' },
-        { type: 'dateTime', name: 'ending_registration_period', responseKey: 'ending_registration_period', placeholder: ' ', label: 'تاریخ پایان ثبت نام', col: 'col-md-6 col-12' },
-
-        { type: 'input', name: 'registration_period_refund_percent', responseKey: 'registration_period_refund_percent', placeholder: ' ', label: 'درصد برگشت هزینه انصراف در بازه ثبت نام', col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_dropping_on_enrollment_period', responseKey: 'allow_dropping_on_enrollment_period', label: 'امکان حذف در بازه پیش ثبت نام', value: false, col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_adding_on_registration_period', responseKey: 'allow_adding_on_registration_period', label: 'امکان اضافه کردن در بازه ثبت نام', value: false, col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_dropping_on_registration_period', responseKey: 'allow_dropping_on_registration_period', label: 'امکان حذف ثبت نام در بازه ثبت نام', value: false, col: 'col-md-3 col-12' },
-
-        { type: 'dateTime', name: 'beginning_drop_add_period', responseKey: 'beginning_drop_add_period', placeholder: ' ', label: 'تاریخ شروع حذف و اضافه', col: 'col-md-6 col-12' },
-        { type: 'dateTime', name: 'ending_drop_add_period', responseKey: 'ending_drop_add_period', placeholder: ' ', label: 'تاریخ پایان حذف و اضافه', col: 'col-md-6 col-12' },
-
-        { type: 'input', name: 'drop_add_period_refund_percent', responseKey: 'drop_add_period_refund_percent', placeholder: ' ', label: 'درصد برگشت هزینه انصراف در بازه حذف و اضافه', col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_adding_on_drop_add_period', responseKey: 'allow_adding_on_drop_add_period', label: 'امکان اضافه شدن در بازه حذف و اضافه', value: false, col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_dropping_on_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان حذف در بازه حذف و اضافه', value: false, col: 'col-md-3 col-12' },
-
-        { type: 'dateTime', name: 'publish_time', responseKey: 'publish_time', placeholder: ' ', label: 'تاریخ انتشار', col: 'col-md-6 col-12' },
-
-        { type: 'separator', name: 'space', label: 'قوانین', className: 'custom-separator', col: 'col-12' },
-        { type: FormBuilderInputEditorComp, name: 'rules', responseKey: 'rules', label: 'قوانین دوره آموزشی', col: 'col-12' },
-
-        { type: FormBuilderInputEditorComp, name: 'description', responseKey: 'description', label: 'توضیحات', col: 'col-12' },
-        { type: FormBuilderInputEditorComp, name: 'specification', responseKey: 'specification', label: 'مشخصات', col: 'col-12' },
-        { type: FormBuilderInputEditorComp, name: 'bulletin', responseKey: 'bulletin', label: 'تابلو اعلانات', col: 'col-12' },
-
-        // -----------------------------------------------------------------------------------------------------------
-
-        { type: 'separator', name: 'space', label: 'موارد زیر در طرح نبودند', className: 'custom-separator', col: 'col-12' },
-        { type: 'select', name: 'audience_role', responseKey: 'audience_role', options: Enums.groups, placeholder: ' ', label: 'نقش', col: 'col-md-4 col-12' },
-
-        { type: 'hidden', name: 'id', responseKey: 'id', label: 'id', col: 'col-md-3 col-12' }
-      ]
-    }
-  },
-  computed: {
-    selectedCategoryId () {
-      return FormBuilderAssist.getInputsByName(this.inputs, 'category')?.value
-    }
-  },
-  watch: {
-    selectedCategoryId () {
-      FormBuilderAssist.setAttributeByName(this.inputs, 'unit', 'value', null)
-      FormBuilderAssist.setAttributeByName(this.inputs, 'unit', 'options', [])
-      this.getUnits(this.selectedCategoryId)
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminClassroomCreate', options: { style: {}, classroomType: 'TRAINING' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
     }
   },
-  mounted () {
-    this.preLoadData()
-      .then(() => {
-        this.mounted = true
-      })
-      .catch(() => {
-      })
-  },
-  methods: {
-    setInputAttr (name, attr, value) {
-      this.$refs.classroomEntityCreate.setInputAttributeByName(name, attr, value)
-    },
-    preLoadData () {
-      return new Promise((resolve, reject) => {
-        const promise1 = this.getProfessors()
-        const promise2 = this.getCategories()
-        this.$nextTick(() => {
-          Promise.all([promise1, promise2])
-            .then(() => {
-              resolve()
-            })
-            .catch(() => {
-              reject()
-            })
-        })
-      })
-    },
-    getProfessors () {
-      return APIGateway.user.index({ per_page: 9999, role: 'professor' })
-        .then((users) => {
-          FormBuilderAssist.setAttributeByName(this.inputs, 'professor', 'options', users.list.list.map(item => {
-            return {
-              value: item.id,
-              label: this.getUserFullname(item)
-            }
-          }))
-        })
-        .catch(() => {})
-    },
-    getCategories () {
-      return APIGateway.unitCategory.index({ per_page: 9999, type: 'TRAINING' })
-        .then((categories) => {
-          FormBuilderAssist.setAttributeByName(this.inputs, 'category', 'options', categories.list.list.map(item => {
-            return {
-              value: item.id,
-              label: item.title
-            }
-          }))
-        })
-        .catch(() => {})
-    },
-    getUnits (selectedcategoryId = null) {
-      this.unitsLoading = true
-      APIGateway.unit.index({ per_page: 9999, category: selectedcategoryId })
-        .then((units) => {
-          FormBuilderAssist.setAttributeByName(this.inputs, 'unit', 'options', units.list.list.map(item => {
-            return {
-              value: item.id,
-              label: item.title
-            }
-          }))
-          this.unitsLoading = false
-        })
-        .catch(() => {
-          this.unitsLoading = false
-        })
-    },
-    getUserFullname (user) {
-      return user.firstname + ' ' + user.lastname
-    },
-    createClassroom () {
-      this.$refs.classroomEntityCreate.createEntity()
-    }
+  created() {
+    this.currenSections = this.sections
   }
 }
 </script>

+ 11 - 249
src/pages/Admin/Classroom/index.vue

@@ -1,261 +1,23 @@
 <template>
-  <div class="AdminClassroomIndex">
-    <div class="add-new-action-row">
-      <q-btn color="primary"
-             :to="{name: 'Admin.Classroom.Create'}">
-        <svg data-name="Close Square"
-             xmlns="http://www.w3.org/2000/svg"
-             width="20"
-             height="20"
-             viewBox="0 0 20 20"
-             class="q-mr-md">
-          <path id="Combined_Shape"
-                data-name="Combined Shape"
-                d="M5.665,20C2.276,20,0,17.623,0,14.084V5.916C0,2.377,2.276,0,5.665,0h8.67C17.723,0,20,2.377,20,5.916v8.168C20,17.623,17.723,20,14.333,20ZM1.5,5.916v8.168c0,2.683,1.634,4.416,4.164,4.416h8.669c2.532,0,4.167-1.733,4.167-4.416V5.916c0-2.682-1.635-4.415-4.166-4.415H5.665C3.135,1.5,1.5,3.234,1.5,5.916Zm7.968,8a.747.747,0,0,1-.22-.53V10.741H6.611a.75.75,0,0,1-.75-.75.749.749,0,0,1,.75-.75H9.249V6.6a.75.75,0,1,1,1.5,0V9.241h2.639a.75.75,0,0,1,0,1.5H10.748v2.642a.75.75,0,0,1-1.28.53Z"
-                fill="#fff" />
-        </svg>
-        ایجاد دوره آموزشی جدید
-      </q-btn>
-    </div>
-    <entity-index v-if="mounted"
-                  ref="entityIndex"
-                  v-model:value="inputs"
-                  title="لیست دسته بندی ها"
-                  :api="api"
-                  :table="table"
-                  :table-keys="tableKeys"
-                  :show-expand-button="false"
-                  :show-reload-button="false"
-                  :show-search-button="false">
-      <template v-slot:entity-index-table-cell="{inputData, showConfirmRemoveDialog}">
-        <template v-if="inputData.col.name === 'number'">
-          {{ inputData.rowNumber }}
-        </template>
-        <template v-else-if="inputData.col.name === 'action'">
-          <div class="action-column-entity-index">
-            <q-btn size="md"
-                   color="primary"
-                   label="جزییات"
-                   :to="{name: 'Admin.Classroom.Show', params: {id: inputData.props.row.id}}"
-                   class="q-mr-md" />
-            <delete-btn @click="showConfirmRemoveDialog(inputData.props.row, 'id', getRemoveMessage(inputData.props.row))" />
-          </div>
-        </template>
-        <template v-else>
-          {{ inputData.col.value }}
-        </template>
-      </template>
-    </entity-index>
-  </div>
+  <q-page-builder v-model:sections="currenSections"
+                  v-model:options="pageConfig"
+                  :editable="pageBuilderEditable"
+                  :loading="pageBuilderLoading" />
 </template>
 
 <script>
-import { shallowRef } from 'vue'
-import { EntityIndex } from 'quasar-crud'
-import Enums from 'src/assets/Enums/Enums.js'
-import ShamsiDate from 'src/assets/ShamsiDate.js'
-import { APIGateway } from 'src/api/APIGateway.js'
-import BtnControl from 'src/components/Control/btn.vue'
-import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
-
-const BtnControlComp = shallowRef(BtnControl)
+import { mixinPageOptions } from 'src/mixin/Mixins.js'
 
 export default {
-  name: 'Admin.Classroom.Index',
-  components: {
-    EntityIndex,
-    DeleteBtn
-  },
-  data () {
+  name: 'Admin.Classroom.Show',
+  mixins: [mixinPageOptions],
+  data: () => {
     return {
-      mounted: false,
-      inputs: [
-        {
-          type: 'select',
-          name: 'status',
-          options: Enums.classroomStatuses,
-          value: null,
-          label: 'وضعیت دوره',
-          placeholder: ' ',
-          col: 'col-md-2 col-12'
-        },
-        {
-          type: 'select',
-          name: 'unit',
-          options: [],
-          value: null,
-          label: 'درس',
-          placeholder: ' ',
-          col: 'col-md-2 col-12'
-        },
-        { type: 'hidden', name: 'unit__category__type', value: 'TRAINING' },
-        { type: BtnControlComp, name: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-2 col-12' }
-      ],
-      api: APIGateway.classroom.APIAdresses.base,
-      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.title
-          },
-          {
-            name: 'audience_gender_type',
-            required: true,
-            label: 'جنسیت',
-            align: 'left',
-            field: row => (row.audience_gender_type === 'FEMALE') ? 'خواهران' : (row.audience_gender_type === 'MALE') ? 'برادران' : 'خواهران و برادران'
-          },
-          {
-            name: 'status',
-            required: true,
-            label: 'وضعیت',
-            align: 'left',
-            field: row => this.getClassroomStatusesTitle(row.status)
-          },
-          {
-            name: 'title',
-            required: true,
-            label: 'نوع برگزاری',
-            align: 'left',
-            field: row => this.getClassroomHoldingTypeTitle(row.holding_type)
-          },
-          {
-            name: 'title',
-            required: true,
-            label: 'هزینه(ریال)',
-            align: 'left',
-            field: row => row.price
-          },
-          {
-            name: 'title',
-            required: true,
-            label: 'استاد مربوطه',
-            align: 'left',
-            field: row => row.professor_info?.firstname + ' ' + row.professor_info?.lastname
-          },
-          {
-            name: 'title',
-            required: true,
-            label: 'تاریخ و زمان ثبت نام',
-            align: 'left',
-            field: row => row.beginning_registration_period ? ShamsiDate.getDateTime(row.beginning_registration_period) : '-'
-          },
-          {
-            name: 'title',
-            required: true,
-            label: 'ترم برگزاری',
-            align: 'left',
-            field: row => (row.beginning_registration_period) ? ShamsiDate.getTerm(row.beginning_registration_period) : '-'
-          },
-          {
-            name: 'action',
-            required: true,
-            label: 'عملیات',
-            align: 'left',
-            field: ''
-          }
-        ],
-        data: []
-      },
-      tableKeys: {
-        data: 'results',
-        total: 'count',
-        currentPage: 'current',
-        perPage: 'per_page',
-        pageKey: 'page'
-      }
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminClassroomList', options: { style: {}, classroomType: 'TRAINING' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
     }
   },
-  mounted () {
-    this.setActionBtn()
-    this.mounted = true
-    this.getUnits()
-  },
-  methods: {
-    setActionBtn () {
-      this.inputs.forEach((item, index) => {
-        if (item.name === 'btn') {
-          this.inputs[index].atClick = this.search
-        }
-      })
-    },
-    search () {
-      this.$refs.entityIndex.search()
-    },
-    getUnits () {
-      APIGateway.unit.index({ per_page: 9999 })
-        .then((units) => {
-          this.loadSelectOptions('unit', this.getSelectOptions(units.list.list, 'id', 'title'))
-        })
-        .catch(() => {
-
-        })
-    },
-    loadSelectOptions (name, value) {
-      const inputIndex = this.inputs.findIndex(input => input.name === name)
-      this.inputs[inputIndex].options = value
-    },
-    getSelectOptions (result, value, label) {
-      return result.map(item => {
-        return {
-          value: item[value],
-          label: item[label]
-        }
-      })
-    },
-    getRemoveMessage (row) {
-      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
-    },
-    getClassroomHoldingTypeTitle (type) {
-      const target = Enums.classroomHoldingTypes.find(item => item.value === type)
-      if (!target) {
-        return '-'
-      }
-
-      return target.label
-    },
-    getClassroomStatusesTitle (type) {
-      const target = Enums.classroomStatuses.find(item => item.value === type)
-      if (!target) {
-        return '-'
-      }
-
-      return target.label
-    }
+  created() {
+    this.currenSections = this.sections
   }
 }
 </script>
-
-<style lang="scss" scoped>
-.AdminClassroomIndex {
-  .add-new-action-row {
-    display: flex;
-    flex-flow: row;
-    align-items: center;
-    justify-content: flex-end;
-    margin-bottom: 22px;
-  }
-  .action-column-entity-index {
-    display: flex;
-    align-items: center;
-    justify-content: flex-start;
-  }
-}
-</style>

+ 1 - 1
src/pages/Admin/Classroom/show.vue

@@ -13,7 +13,7 @@ export default {
   mixins: [mixinPageOptions],
   data: () => {
     return {
-      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminClassroomShow', options: { style: {}, classroomType: 'Classroom' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminClassroomShow', options: { style: {}, classroomType: 'TRAINING' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
     }
   },
   created() {

+ 2 - 2
src/pages/Admin/Event/SessionActivitySheets/sessionActivitySheets.vue

@@ -9,11 +9,11 @@
 import { mixinPageOptions } from 'src/mixin/Mixins.js'
 
 export default {
-  name: 'Admin.Content.Show',
+  name: 'Admin.Event.Session.AttendanceSheetList',
   mixins: [mixinPageOptions],
   data: () => {
     return {
-      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminSessionAttendanceSheetList' }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminSessionAttendanceSheetList', options: { style: {}, classroomType: 'EVENT' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
     }
   },
   created() {

+ 10 - 159
src/pages/Admin/Event/create.vue

@@ -1,172 +1,23 @@
 <template>
-  <div class="flex justify-end">
-    <q-btn flat
-           color="grey"
-           @click="$router.go(-1)">
-      بازگشت
-      >
-    </q-btn>
-  </div>
-  <div class="AdminEventCreate">
-    <q-linear-progress v-if="unitsLoading"
-                       indeterminate />
-    <entity-create v-if="mounted"
-                   ref="eventEntityCreate"
-                   :key="eventEntityCreateKey"
-                   v-model:value="inputs"
-                   title="مشخصات رویداد"
-                   :api="api"
-                   :entity-id-key="entityIdKey"
-                   :entity-param-key="entityParamKey"
-                   :show-route-name="showRouteName"
-                   :show-close-button="false"
-                   :show-edit-button="false"
-                   :show-expand-button="false"
-                   :show-save-button="false"
-                   :show-reload-button="false">
-      <template #after-form-builder>
-        <div class="flex justify-end q-mt-md">
-          <q-btn color="primary"
-                 label="ایجاد رویداد جدید"
-                 @click="createEvent" />
-        </div>
-      </template>
-    </entity-create>
-  </div>
+  <q-page-builder v-model:sections="currenSections"
+                  v-model:options="pageConfig"
+                  :editable="pageBuilderEditable"
+                  :loading="pageBuilderLoading" />
 </template>
 
 <script>
-import { shallowRef } from 'vue'
-import { EntityCreate } from 'quasar-crud'
-import { Event } from 'src/models/Event.js'
-import { APIGateway } from 'src/api/APIGateway.js'
-import { FormBuilderAssist } from 'quasar-form-builder'
-import ContentMedias from 'src/components/FormBuilderCustumComponents/ContentMedias/ContentMedias.vue'
-import FormBuilderInputEditor from 'src/components/FormBuilderCustumComponents/FormBuilderInputEditor.vue'
-
-const ContentMediasComp = shallowRef(ContentMedias)
-const FormBuilderInputEditorComp = shallowRef(FormBuilderInputEditor)
+import { mixinPageOptions } from 'src/mixin/Mixins.js'
 
 export default {
   name: 'Admin.Event.Create',
-  components: {
-    EntityCreate
-  },
-  data () {
+  mixins: [mixinPageOptions],
+  data: () => {
     return {
-      mounted: false,
-      unitsLoading: false,
-      eventEntityCreateKey: Date.now(),
-      newUnitLoading: false,
-      newUnitName: null,
-      newUnitSessionCount: null,
-      api: APIGateway.event.APIAdresses.base,
-      entityIdKey: 'id',
-      entityParamKey: 'id',
-      showRouteName: 'Admin.Event.Show',
-      inputs: [
-        { type: 'separator', name: 'space', label: 'مشخصات رویداد', className: 'custom-separator', col: 'col-12' },
-        { type: 'input', name: 'title', responseKey: 'title', label: 'عنوان رویداد', placeholder: ' ', col: 'col-12' },
-        { type: 'file', name: 'thumbnail', responseKey: 'thumbnail', label: 'آپلود عکس رویداد', col: 'col-md-3 col-12' },
-        { type: 'file', name: 'codes', responseKey: 'codes', label: 'آیین نامه رویداد', col: 'col-md-3 col-12' },
-        { type: 'separator', name: 'space', size: '0', col: 'col-md-12' },
-        { type: 'select', name: 'category', responseKey: 'category', options: (new Event()).categoryEnums, value: null, placeholder: ' ', label: 'دسته بندی', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'holding_type', responseKey: 'holding_type', options: (new Event()).holding_typeEnums, value: null, placeholder: ' ', label: 'نوع برگزاری', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'price', responseKey: 'price', placeholder: ' ', label: 'هزینه برگزاری', col: 'col-md-3 col-12' },
-        { type: 'input', name: 'live_streaming_url', responseKey: 'live_streaming_url', placeholder: ' ', label: 'لینک مکان مجازی رویداد', col: 'col-12' },
-        { type: FormBuilderInputEditorComp, name: 'event_address', responseKey: 'event_address', placeholder: ' ', label: 'آدرس مکان فیزیکی رویداد', col: 'col-12' },
-
-        { type: 'separator', name: 'space', label: 'مشخصات اندیشه جو', className: 'custom-separator', col: 'col-12' },
-        { type: 'select', name: 'audience_status_wwwww', responseKey: 'audience_status_wwwww', options: [], placeholder: ' ', label: 'وضعیت(؟)', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'category1', responseKey: 'category1', options: [], placeholder: ' ', label: 'مجموعه(؟)', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'audience_gender_type', responseKey: 'audience_gender_type', options: (new Event()).audience_gender_typeEnums, placeholder: ' ', label: 'جنسیت', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'audience_bashgah_wwwww', responseKey: 'audience_bashgah_wwwww', options: [], placeholder: ' ', label: 'باشگاه(؟)', col: 'col-md-3 col-12' },
-
-        { type: ContentMediasComp, name: 'medias', responseKey: 'medias_info', sourceType: 'EVENT', col: 'col-md-12 col-12' },
-
-        { type: 'separator', name: 'space', label: 'تنظیمات رویداد', className: 'custom-separator', col: 'col-12' },
-        { type: 'input', name: 'capacity', responseKey: 'capacity', placeholder: ' ', label: 'ظرفیت گروه درسی', col: 'col-md-3 col-12' },
-
-        { type: 'separator', name: 'space', label: 'ثبت نام و حذف و اضافه', className: 'custom-separator', col: 'col-12' },
-        { type: 'dateTime', name: 'beginning_enrollment_period', responseKey: 'beginning_enrollment_period', placeholder: ' ', label: 'تاریخ شروع پیش ثبت نام', col: 'col-md-6 col-12' },
-        { type: 'dateTime', name: 'ending_enrollment_period', responseKey: 'ending_enrollment_period', placeholder: ' ', label: 'تاریخ پایان پیش ثبت نام', col: 'col-md-6 col-12' },
-        { type: 'dateTime', name: 'beginning_registration_period', responseKey: 'beginning_registration_period', placeholder: ' ', label: 'تاریخ شروع ثبت نام', col: 'col-md-6 col-12' },
-        { type: 'dateTime', name: 'ending_registration_period', responseKey: 'ending_registration_period', placeholder: ' ', label: 'تاریخ پایان ثبت نام', col: 'col-md-6 col-12' },
-
-        { type: 'input', name: 'registration_period_refund_percent', responseKey: 'registration_period_refund_percent', placeholder: ' ', label: 'درصد برگشت هزینه انصراف در بازه ثبت نام', col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_dropping_on_enrollment_period', responseKey: 'allow_dropping_on_enrollment_period', label: 'امکان حذف در بازه پیش ثبت نام', value: false, col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_adding_on_registration_period', responseKey: 'allow_adding_on_registration_period', label: 'امکان اضافه کردن در بازه ثبت نام', value: false, col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_dropping_on_registration_period', responseKey: 'allow_dropping_on_registration_period', label: 'امکان حذف ثبت نام در بازه ثبت نام', value: false, col: 'col-md-3 col-12' },
-
-        { type: 'dateTime', name: 'beginning_drop_add_period', responseKey: 'beginning_drop_add_period', placeholder: ' ', label: 'تاریخ شروع حذف و اضافه', col: 'col-md-6 col-12' },
-        { type: 'dateTime', name: 'ending_drop_add_period', responseKey: 'ending_drop_add_period', placeholder: ' ', label: 'تاریخ پایان حذف و اضافه', col: 'col-md-6 col-12' },
-
-        { type: 'input', name: 'drop_add_period_refund_percent', responseKey: 'drop_add_period_refund_percent', placeholder: ' ', label: 'درصد برگشت هزینه انصراف در بازه حذف و اضافه', col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_adding_on_drop_add_period', responseKey: 'allow_adding_on_drop_add_period', label: 'امکان اضافه شدن در بازه حذف و اضافه', value: false, col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_dropping_on_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان حذف در بازه حذف و اضافه', value: false, col: 'col-md-3 col-12' },
-
-        { type: 'dateTime', name: 'publish_time', responseKey: 'publish_time', placeholder: ' ', label: 'تاریخ انتشار', col: 'col-md-6 col-12' },
-
-        { type: 'separator', name: 'space', label: 'قوانین', className: 'custom-separator', col: 'col-12' },
-        { type: FormBuilderInputEditorComp, name: 'rules', responseKey: 'rules', label: 'قوانین رویداد', col: 'col-12' },
-
-        { type: FormBuilderInputEditorComp, name: 'description', responseKey: 'description', label: 'توضیحات', col: 'col-12' },
-        { type: FormBuilderInputEditorComp, name: 'specification', responseKey: 'specification', label: 'مشخصات', col: 'col-12' },
-        { type: FormBuilderInputEditorComp, name: 'bulletin', responseKey: 'bulletin', label: 'تابلو اعلانات', col: 'col-12' },
-
-        // -----------------------------------------------------------------------------------------------------------
-
-        // { type: 'separator', name: 'space', label: 'موارد زیر در طرح نبودند', className: 'custom-separator', col: 'col-12' },
-        // { type: 'select', name: 'audience_role', responseKey: 'audience_role', options: Enums.groups, placeholder: ' ', label: 'نقش', col: 'col-md-4 col-12' },
-
-        { type: 'hidden', name: 'id', responseKey: 'id', label: 'id', col: 'col-md-3 col-12' }
-      ]
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminClassroomCreate', options: { style: {}, classroomType: 'EVENT' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
     }
   },
-  mounted () {
-    this.preLoadData()
-      .then(() => {
-        this.mounted = true
-      })
-      .catch(() => {
-      })
-  },
-  methods: {
-    setInputAttr (name, attr, value) {
-      this.$refs.eventEntityCreate.setInputAttributeByName(name, attr, value)
-    },
-    preLoadData () {
-      return new Promise((resolve, reject) => {
-        const promise1 = this.getProfessors()
-        this.$nextTick(() => {
-          Promise.all([promise1])
-            .then(() => {
-              resolve()
-            })
-            .catch(() => {
-              reject()
-            })
-        })
-      })
-    },
-    getProfessors () {
-      return APIGateway.user.index({ per_page: 9999, role: 'professor' })
-        .then((users) => {
-          FormBuilderAssist.setAttributeByName(this.inputs, 'professor', 'options', users.list.list.map(item => {
-            return {
-              value: item.id,
-              label: this.getUserFullname(item)
-            }
-          }))
-        })
-        .catch(() => {})
-    },
-    getUserFullname (user) {
-      return user.firstname + ' ' + user.lastname
-    },
-    createEvent () {
-      this.$refs.eventEntityCreate.createEntity()
-    }
+  created() {
+    this.currenSections = this.sections
   }
 }
 </script>

+ 172 - 0
src/pages/Admin/Event/ema-create.vue

@@ -0,0 +1,172 @@
+<template>
+  <div class="flex justify-end">
+    <q-btn flat
+           color="grey"
+           @click="$router.go(-1)">
+      بازگشت
+      >
+    </q-btn>
+  </div>
+  <div class="AdminEventCreate">
+    <q-linear-progress v-if="unitsLoading"
+                       indeterminate />
+    <entity-create v-if="mounted"
+                   ref="eventEntityCreate"
+                   :key="eventEntityCreateKey"
+                   v-model:value="inputs"
+                   title="مشخصات رویداد"
+                   :api="api"
+                   :entity-id-key="entityIdKey"
+                   :entity-param-key="entityParamKey"
+                   :show-route-name="showRouteName"
+                   :show-close-button="false"
+                   :show-edit-button="false"
+                   :show-expand-button="false"
+                   :show-save-button="false"
+                   :show-reload-button="false">
+      <template #after-form-builder>
+        <div class="flex justify-end q-mt-md">
+          <q-btn color="primary"
+                 label="ایجاد رویداد جدید"
+                 @click="createEvent" />
+        </div>
+      </template>
+    </entity-create>
+  </div>
+</template>
+
+<script>
+import { shallowRef } from 'vue'
+import { EntityCreate } from 'quasar-crud'
+import { Event } from 'src/models/Event.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import { FormBuilderAssist } from 'quasar-form-builder'
+import ContentMedias from 'src/components/FormBuilderCustumComponents/ContentMedias/ContentMedias.vue'
+import FormBuilderInputEditor from 'src/components/FormBuilderCustumComponents/FormBuilderInputEditor.vue'
+
+const ContentMediasComp = shallowRef(ContentMedias)
+const FormBuilderInputEditorComp = shallowRef(FormBuilderInputEditor)
+
+export default {
+  name: 'Admin.Event.Create',
+  components: {
+    EntityCreate
+  },
+  data () {
+    return {
+      mounted: false,
+      unitsLoading: false,
+      eventEntityCreateKey: Date.now(),
+      newUnitLoading: false,
+      newUnitName: null,
+      newUnitSessionCount: null,
+      api: APIGateway.event.APIAdresses.base,
+      entityIdKey: 'id',
+      entityParamKey: 'id',
+      showRouteName: 'Admin.Event.Show',
+      inputs: [
+        { type: 'separator', name: 'space', label: 'مشخصات رویداد', className: 'custom-separator', col: 'col-12' },
+        { type: 'input', name: 'title', responseKey: 'title', label: 'عنوان رویداد', placeholder: ' ', col: 'col-12' },
+        { type: 'file', name: 'thumbnail', responseKey: 'thumbnail', label: 'آپلود عکس رویداد', col: 'col-md-3 col-12' },
+        { type: 'file', name: 'codes', responseKey: 'codes', label: 'آیین نامه رویداد', col: 'col-md-3 col-12' },
+        { type: 'separator', name: 'space', size: '0', col: 'col-md-12' },
+        { type: 'select', name: 'category', responseKey: 'category', options: (new Event()).categoryEnums, value: null, placeholder: ' ', label: 'دسته بندی', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'holding_type', responseKey: 'holding_type', options: (new Event()).holding_typeEnums, value: null, placeholder: ' ', label: 'نوع برگزاری', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'price', responseKey: 'price', placeholder: ' ', label: 'هزینه برگزاری', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'live_streaming_url', responseKey: 'live_streaming_url', placeholder: ' ', label: 'لینک مکان مجازی رویداد', col: 'col-12' },
+        { type: FormBuilderInputEditorComp, name: 'event_address', responseKey: 'event_address', placeholder: ' ', label: 'آدرس مکان فیزیکی رویداد', col: 'col-12' },
+
+        { type: 'separator', name: 'space', label: 'مشخصات اندیشه جو', className: 'custom-separator', col: 'col-12' },
+        { type: 'select', name: 'audience_status_wwwww', responseKey: 'audience_status_wwwww', options: [], placeholder: ' ', label: 'وضعیت(؟)', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'category1', responseKey: 'category1', options: [], placeholder: ' ', label: 'مجموعه(؟)', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'audience_gender_type', responseKey: 'audience_gender_type', options: (new Event()).audience_gender_typeEnums, placeholder: ' ', label: 'جنسیت', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'audience_bashgah_wwwww', responseKey: 'audience_bashgah_wwwww', options: [], placeholder: ' ', label: 'باشگاه(؟)', col: 'col-md-3 col-12' },
+
+        { type: ContentMediasComp, name: 'medias', responseKey: 'medias_info', sourceType: 'EVENT', col: 'col-md-12 col-12' },
+
+        { type: 'separator', name: 'space', label: 'تنظیمات رویداد', className: 'custom-separator', col: 'col-12' },
+        { type: 'input', name: 'capacity', responseKey: 'capacity', placeholder: ' ', label: 'ظرفیت گروه درسی', col: 'col-md-3 col-12' },
+
+        { type: 'separator', name: 'space', label: 'ثبت نام و حذف و اضافه', className: 'custom-separator', col: 'col-12' },
+        { type: 'dateTime', name: 'beginning_enrollment_period', responseKey: 'beginning_enrollment_period', placeholder: ' ', label: 'تاریخ شروع پیش ثبت نام', col: 'col-md-6 col-12' },
+        { type: 'dateTime', name: 'ending_enrollment_period', responseKey: 'ending_enrollment_period', placeholder: ' ', label: 'تاریخ پایان پیش ثبت نام', col: 'col-md-6 col-12' },
+        { type: 'dateTime', name: 'beginning_registration_period', responseKey: 'beginning_registration_period', placeholder: ' ', label: 'تاریخ شروع ثبت نام', col: 'col-md-6 col-12' },
+        { type: 'dateTime', name: 'ending_registration_period', responseKey: 'ending_registration_period', placeholder: ' ', label: 'تاریخ پایان ثبت نام', col: 'col-md-6 col-12' },
+
+        { type: 'input', name: 'registration_period_refund_percent', responseKey: 'registration_period_refund_percent', placeholder: ' ', label: 'درصد برگشت هزینه انصراف در بازه ثبت نام', col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_enrollment_period', responseKey: 'allow_dropping_on_enrollment_period', label: 'امکان حذف در بازه پیش ثبت نام', value: false, col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_adding_on_registration_period', responseKey: 'allow_adding_on_registration_period', label: 'امکان اضافه کردن در بازه ثبت نام', value: false, col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_registration_period', responseKey: 'allow_dropping_on_registration_period', label: 'امکان حذف ثبت نام در بازه ثبت نام', value: false, col: 'col-md-3 col-12' },
+
+        { type: 'dateTime', name: 'beginning_drop_add_period', responseKey: 'beginning_drop_add_period', placeholder: ' ', label: 'تاریخ شروع حذف و اضافه', col: 'col-md-6 col-12' },
+        { type: 'dateTime', name: 'ending_drop_add_period', responseKey: 'ending_drop_add_period', placeholder: ' ', label: 'تاریخ پایان حذف و اضافه', col: 'col-md-6 col-12' },
+
+        { type: 'input', name: 'drop_add_period_refund_percent', responseKey: 'drop_add_period_refund_percent', placeholder: ' ', label: 'درصد برگشت هزینه انصراف در بازه حذف و اضافه', col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_adding_on_drop_add_period', responseKey: 'allow_adding_on_drop_add_period', label: 'امکان اضافه شدن در بازه حذف و اضافه', value: false, col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان حذف در بازه حذف و اضافه', value: false, col: 'col-md-3 col-12' },
+
+        { type: 'dateTime', name: 'publish_time', responseKey: 'publish_time', placeholder: ' ', label: 'تاریخ انتشار', col: 'col-md-6 col-12' },
+
+        { type: 'separator', name: 'space', label: 'قوانین', className: 'custom-separator', col: 'col-12' },
+        { type: FormBuilderInputEditorComp, name: 'rules', responseKey: 'rules', label: 'قوانین رویداد', col: 'col-12' },
+
+        { type: FormBuilderInputEditorComp, name: 'description', responseKey: 'description', label: 'توضیحات', col: 'col-12' },
+        { type: FormBuilderInputEditorComp, name: 'specification', responseKey: 'specification', label: 'مشخصات', col: 'col-12' },
+        { type: FormBuilderInputEditorComp, name: 'bulletin', responseKey: 'bulletin', label: 'تابلو اعلانات', col: 'col-12' },
+
+        // -----------------------------------------------------------------------------------------------------------
+
+        // { type: 'separator', name: 'space', label: 'موارد زیر در طرح نبودند', className: 'custom-separator', col: 'col-12' },
+        // { type: 'select', name: 'audience_role', responseKey: 'audience_role', options: Enums.groups, placeholder: ' ', label: 'نقش', col: 'col-md-4 col-12' },
+
+        { type: 'hidden', name: 'id', responseKey: 'id', label: 'id', col: 'col-md-3 col-12' }
+      ]
+    }
+  },
+  mounted () {
+    this.preLoadData()
+      .then(() => {
+        this.mounted = true
+      })
+      .catch(() => {
+      })
+  },
+  methods: {
+    setInputAttr (name, attr, value) {
+      this.$refs.eventEntityCreate.setInputAttributeByName(name, attr, value)
+    },
+    preLoadData () {
+      return new Promise((resolve, reject) => {
+        const promise1 = this.getProfessors()
+        this.$nextTick(() => {
+          Promise.all([promise1])
+            .then(() => {
+              resolve()
+            })
+            .catch(() => {
+              reject()
+            })
+        })
+      })
+    },
+    getProfessors () {
+      return APIGateway.user.index({ per_page: 9999, role: 'professor' })
+        .then((users) => {
+          FormBuilderAssist.setAttributeByName(this.inputs, 'professor', 'options', users.list.list.map(item => {
+            return {
+              value: item.id,
+              label: this.getUserFullname(item)
+            }
+          }))
+        })
+        .catch(() => {})
+    },
+    getUserFullname (user) {
+      return user.firstname + ' ' + user.lastname
+    },
+    createEvent () {
+      this.$refs.eventEntityCreate.createEntity()
+    }
+  }
+}
+</script>

+ 23 - 0
src/pages/Admin/Event/ema-index.vue

@@ -0,0 +1,23 @@
+<template>
+  <q-page-builder v-model:sections="currenSections"
+                  v-model:options="pageConfig"
+                  :editable="pageBuilderEditable"
+                  :loading="pageBuilderLoading" />
+</template>
+
+<script>
+import { mixinPageOptions } from 'src/mixin/Mixins.js'
+
+export default {
+  name: 'Admin.Event.Show',
+  mixins: [mixinPageOptions],
+  data: () => {
+    return {
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminClassroomList', options: { style: {}, classroomType: 'EVENT' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
+    }
+  },
+  created() {
+    this.currenSections = this.sections
+  }
+}
+</script>

+ 11 - 217
src/pages/Admin/Event/index.vue

@@ -1,229 +1,23 @@
 <template>
-  <div class="AdminEventIndex">
-    <div class="add-new-action-row">
-      <q-btn color="primary"
-             :to="{name: 'Admin.Event.Create'}">
-        <svg data-name="Close Square"
-             xmlns="http://www.w3.org/2000/svg"
-             width="20"
-             height="20"
-             viewBox="0 0 20 20"
-             class="q-mr-md">
-          <path id="Combined_Shape"
-                data-name="Combined Shape"
-                d="M5.665,20C2.276,20,0,17.623,0,14.084V5.916C0,2.377,2.276,0,5.665,0h8.67C17.723,0,20,2.377,20,5.916v8.168C20,17.623,17.723,20,14.333,20ZM1.5,5.916v8.168c0,2.683,1.634,4.416,4.164,4.416h8.669c2.532,0,4.167-1.733,4.167-4.416V5.916c0-2.682-1.635-4.415-4.166-4.415H5.665C3.135,1.5,1.5,3.234,1.5,5.916Zm7.968,8a.747.747,0,0,1-.22-.53V10.741H6.611a.75.75,0,0,1-.75-.75.749.749,0,0,1,.75-.75H9.249V6.6a.75.75,0,1,1,1.5,0V9.241h2.639a.75.75,0,0,1,0,1.5H10.748v2.642a.75.75,0,0,1-1.28.53Z"
-                fill="#fff" />
-        </svg>
-        ایجاد رویداد جدید
-      </q-btn>
-    </div>
-    <entity-index v-if="mounted"
-                  ref="entityIndex"
-                  v-model:value="inputs"
-                  title="لیست رویداد ها"
-                  :api="api"
-                  :table="table"
-                  :table-keys="tableKeys"
-                  :show-expand-button="false"
-                  :show-reload-button="false"
-                  :show-search-button="false">
-      <template v-slot:entity-index-table-cell="{inputData, showConfirmRemoveDialog}">
-        <template v-if="inputData.col.name === 'number'">
-          {{ inputData.rowNumber }}
-        </template>
-        <template v-else-if="inputData.col.name === 'action'">
-          <div class="action-column-entity-index">
-            <q-btn size="md"
-                   color="primary"
-                   label="جزییات"
-                   :to="{name: 'Admin.Event.Show', params: {id: inputData.props.row.id}}"
-                   class="q-mr-md" />
-            <delete-btn @click="showConfirmRemoveDialog(inputData.props.row, 'id', getRemoveMessage(inputData.props.row))" />
-          </div>
-        </template>
-        <template v-else>
-          {{ inputData.col.value }}
-        </template>
-      </template>
-    </entity-index>
-  </div>
+  <q-page-builder v-model:sections="currenSections"
+                  v-model:options="pageConfig"
+                  :editable="pageBuilderEditable"
+                  :loading="pageBuilderLoading" />
 </template>
 
 <script>
-import { shallowRef } from 'vue'
-import { EntityIndex } from 'quasar-crud'
-import { Event } from 'src/models/Event.js'
-import Enums from 'src/assets/Enums/Enums.js'
-import ShamsiDate from 'src/assets/ShamsiDate.js'
-import { APIGateway } from 'src/api/APIGateway.js'
-import BtnControl from 'src/components/Control/btn.vue'
-import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
-
-const BtnControlComp = shallowRef(BtnControl)
+import { mixinPageOptions } from 'src/mixin/Mixins.js'
 
 export default {
-  name: 'Admin.Event.Index',
-  components: {
-    EntityIndex,
-    DeleteBtn
-  },
-  data () {
+  name: 'Admin.Classroom.Show',
+  mixins: [mixinPageOptions],
+  data: () => {
     return {
-      mounted: false,
-      inputs: [
-        {
-          type: 'select',
-          name: 'status',
-          options: (new Event()).statusEnums,
-          value: null,
-          label: 'وضعیت رویداد',
-          placeholder: ' ',
-          col: 'col-md-2 col-12'
-        },
-        { type: 'hidden', name: 'unit__category__type', value: 'TRAINING' },
-        { type: BtnControlComp, name: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-2 col-12' }
-      ],
-      api: APIGateway.event.APIAdresses.base,
-      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.title
-          },
-          {
-            name: 'category',
-            required: true,
-            label: 'دسته بندی',
-            align: 'left',
-            field: row => (new Event(row)).category_info.label
-          },
-          {
-            name: 'title',
-            required: true,
-            label: 'نوع برگزاری',
-            align: 'left',
-            field: row => (new Event(row)).holding_type_info.label
-          },
-          {
-            name: 'status',
-            required: true,
-            label: 'وضعیت',
-            align: 'left',
-            field: row => (new Event(row)).status_info.label
-          },
-          {
-            name: 'title',
-            required: true,
-            label: 'هزینه(ریال)',
-            align: 'left',
-            field: row => (row.price === 0) ? 'رایگان' : row.price
-          },
-          {
-            name: 'title',
-            required: true,
-            label: 'تاریخ و زمان ثبت نام',
-            align: 'left',
-            field: row => row.beginning_registration_period ? ShamsiDate.getDateTime(row.beginning_registration_period) : '-'
-          },
-          {
-            name: 'action',
-            required: true,
-            label: 'عملیات',
-            align: 'left',
-            field: ''
-          }
-        ],
-        data: []
-      },
-      tableKeys: {
-        data: 'results',
-        total: 'count',
-        currentPage: 'current',
-        perPage: 'per_page',
-        pageKey: 'page'
-      }
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminClassroomList', options: { style: {}, classroomType: 'EVENT' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
     }
   },
-  mounted () {
-    this.setActionBtn()
-    this.mounted = true
-  },
-  methods: {
-    setActionBtn () {
-      this.inputs.forEach((item, index) => {
-        if (item.name === 'btn') {
-          this.inputs[index].atClick = this.search
-        }
-      })
-    },
-    search () {
-      this.$refs.entityIndex.search()
-    },
-    loadSelectOptions (name, value) {
-      const inputIndex = this.inputs.findIndex(input => input.name === name)
-      this.inputs[inputIndex].options = value
-    },
-    getSelectOptions (result, value, label) {
-      return result.map(item => {
-        return {
-          value: item[value],
-          label: item[label]
-        }
-      })
-    },
-    getRemoveMessage (row) {
-      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
-    },
-    getEventHoldingTypeTitle (type) {
-      const target = (new Event()).holding_typeEnums.find(item => item.value === type)
-      if (!target) {
-        return '-'
-      }
-
-      return target.label
-    },
-    getEventStatusesTitle (type) {
-      const target = Enums.classroomStatuses.find(item => item.value === type)
-      if (!target) {
-        return '-'
-      }
-
-      return target.label
-    }
+  created() {
+    this.currenSections = this.sections
   }
 }
 </script>
-
-<style lang="scss" scoped>
-.AdminEventIndex {
-  .add-new-action-row {
-    display: flex;
-    flex-flow: row;
-    align-items: center;
-    justify-content: flex-end;
-    margin-bottom: 22px;
-  }
-  .action-column-entity-index {
-    display: flex;
-    align-items: center;
-    justify-content: flex-start;
-  }
-}
-</style>

+ 1 - 1
src/pages/Admin/Event/show.vue

@@ -13,7 +13,7 @@ export default {
   mixins: [mixinPageOptions],
   data: () => {
     return {
-      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminEventShow', options: { style: {}, classroomType: 'Classroom' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminClassroomShow', options: { style: {}, classroomType: 'EVENT' } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '10px', alignment: { justifyContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignItems: { global: null, xl: null, lg: null, md: null, sm: null, xs: null }, alignContent: { global: null, xl: null, lg: null, md: null, sm: null, xs: null } }, style: { maxWidth: '1200px', width: '1200px' } } }] } }]
     }
   },
   created() {