Jelajahi Sumber

DiscussionCircles

ali 3 tahun lalu
induk
melakukan
f9c63d660c

+ 28 - 0
src/components/Template/SideBard/AdminPanelSideBar.vue

@@ -48,6 +48,34 @@ export default {
             }
           ]
         },
+        {
+          title: 'حلقه های مباحثاتی',
+          icon: 'isax:book',
+          routeName: null,
+          show: true,
+          open: true,
+          active: false,
+          children: [
+            {
+              title: 'دسته بندی ها',
+              routeName: 'Admin.Category.DiscussionCircles.Index',
+              show: true,
+              active: false
+            },
+            {
+              title: 'حلقه های مباحثاتی',
+              routeName: 'Admin.Classroom.DiscussionCircles.Index',
+              show: true,
+              active: false
+            },
+            {
+              title: 'درخواست ها',
+              routeName: 'Classroom.DiscussionCircles.Ticket',
+              show: true,
+              active: false
+            }
+          ]
+        },
         {
           title: 'محتوا',
           icon: 'isax:video',

+ 83 - 0
src/pages/Admin/DiscussionCirclesCategory/create.vue

@@ -0,0 +1,83 @@
+<template>
+  <div class="ddd">
+    <entity-create v-if="mounted"
+                   ref="classroomEntityCreate"
+                   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"
+                   @onInputClick="onInputClick">
+      <template #after-form-builder>
+        <div class="row q-col-gutter-md q-mb-md">
+          <div class="col-md-3">
+            <q-input v-model="newUnitName"
+                     label="درس ها"
+                     :disable="true" />
+          </div>
+          <div class="col-md-3">
+            <q-input v-model="newUnitSessionCount"
+                     label="تعداد جلسات"
+                     type="number"
+                     :disable="true" />
+          </div>
+          <div class="col-md-3">
+            <q-btn color="primary"
+                   label="افزودن"
+                   :disable="true" />
+          </div>
+        </div>
+      </template>
+    </entity-create>
+  </div>
+</template>
+
+<script>
+import { shallowRef } from 'vue'
+import { EntityCreate } from 'quasar-crud'
+import { APIGateway } from 'src/api/APIGateway.js'
+import BtnControl from 'src/components/Control/btn.vue'
+
+const BtnControlComp = shallowRef(BtnControl)
+
+export default {
+  name: 'Admin.Classroom.Create',
+  components: {
+    EntityCreate
+  },
+  data () {
+    return {
+      mounted: false,
+      newUnitLoading: false,
+      newUnitName: null,
+      newUnitSessionCount: null,
+      api: APIGateway.unitCategory.APIAdresses.base,
+      entityIdKey: 'id',
+      entityParamKey: 'id',
+      showRouteName: 'Admin.Category.DiscussionCircles.Show',
+      inputs: [
+        { type: 'input', name: 'title', responseKey: 'title', label: 'نام دسته بندی', col: 'col-md-6' },
+        { type: 'hidden', name: 'type', value: 'DISCUSSION_CIRCLE' },
+        { type: BtnControlComp, name: 'btn', responseKey: 'btn', label: 'تایید', col: 'col-md-6' }
+      ]
+    }
+  },
+  mounted() {
+    this.mounted = true
+  },
+  methods: {
+    onInputClick (data) {
+      if (data.input.name !== 'btn') {
+        return
+      }
+      this.$refs.classroomEntityCreate.createEntity()
+    }
+  }
+}
+</script>

+ 147 - 0
src/pages/Admin/DiscussionCirclesCategory/index.vue

@@ -0,0 +1,147 @@
+<template>
+  <div class="AdminCategoryIndex">
+    <div class="add-new-action-row">
+      <q-btn color="primary"
+             label="ایجاد دسته بندی جدید"
+             :to="{name: 'Admin.Category.DiscussionCircles.Create'}" />
+    </div>
+    <entity-index v-if="mounted"
+                  ref="entityIndex"
+                  v-model:value="inputs"
+                  title="لیست دسته بندی ها"
+                  :api="api"
+                  :table="table"
+                  :table-keys="tableKeys"
+                  :show-search-button="false"
+                  :show-reload-button="false"
+                  :show-expand-button="false">
+      <template v-slot:entity-index-table-cell="{inputData, showConfirmRemoveDialog}">
+        <template v-if="inputData.col.name === 'actions'">
+          <div class="action-column-entity-index">
+            <q-btn size="md"
+                   color="primary"
+                   label="جزییات"
+                   :to="{name: 'Admin.Category.DiscussionCircles.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>
+</template>
+
+<script>
+import { shallowRef } from 'vue'
+import { EntityIndex } from 'quasar-crud'
+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)
+
+export default {
+  name: 'Admin.Category.Index',
+  components: {
+    EntityIndex,
+    DeleteBtn
+  },
+  data () {
+    return {
+      mounted: false,
+      inputs: [
+        { type: 'input', name: 'title', value: null, label: 'نام', col: 'col-md-2' },
+        { type: 'hidden', name: 'type', value: 'DISCUSSION_CIRCLE' },
+        { type: BtnControlComp, name: 'btn', responseKey: 'btn', label: 'جستجو', props: { atClick: this.search }, col: 'col-md-2' }
+      ],
+      api: APIGateway.unitCategory.APIAdresses.base,
+      table: {
+        columns: [
+          {
+            name: 'id',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'title',
+            required: true,
+            label: 'نام',
+            align: 'left',
+            field: row => row.title
+          },
+          {
+            name: 'count',
+            required: true,
+            label: 'تعداد درس های دسته',
+            align: 'left',
+            field: () => '...'
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'تاریخ ایجاد',
+            align: 'left',
+            field: row => ShamsiDate.getDateTime(row.creation_time)
+          },
+          {
+            name: 'last_modification_time',
+            required: true,
+            label: 'تاریخ آخرین تغییر',
+            align: 'left',
+            field: row => ShamsiDate.getDateTime(row.last_modification_time)
+          },
+          {
+            name: 'actions',
+            required: true,
+            label: 'عملیات',
+            align: 'left',
+            field: ''
+          }
+        ],
+        data: []
+      },
+      tableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
+    }
+  },
+  mounted() {
+    this.mounted = true
+  },
+  methods: {
+    search () {
+      this.$refs.entityIndex.search()
+    },
+    getRemoveMessage (row) {
+      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.AdminCategoryIndex {
+  .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>

+ 212 - 0
src/pages/Admin/DiscussionCirclesCategory/show.vue

@@ -0,0 +1,212 @@
+<template>
+  <div class="AdminCategoryIndex">
+    <entity-edit v-if="mounted"
+                 ref="categoryEntityEdit"
+                 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="row q-col-gutter-md q-mb-md">
+          <div class="col-md-3">
+            <q-input v-model="newUnitName"
+                     label="درس ها"
+                     :disable="newUnitLoading"
+                     :loading="newUnitLoading" />
+          </div>
+          <div class="col-md-3">
+            <q-input v-model="newUnitSessionCount"
+                     label="تعداد جلسات"
+                     type="number"
+                     :disable="newUnitLoading"
+                     :loading="newUnitLoading" />
+          </div>
+          <div class="col-md-3">
+            <q-btn color="primary"
+                   label="افزودن"
+                   @click="createUnit" />
+          </div>
+        </div>
+        <div class="row ">
+          <div class="col">
+            <entity-index ref="unitEntityIndex"
+                          v-model:value="unitFilterInputs"
+                          title="لیست درس ها"
+                          :api="unitApi"
+                          :table="unitTable"
+                          :table-keys="unitTableKeys"
+                          :show-reload-button="false"
+                          :show-search-button="false"
+                          :show-expand-button="false"
+                          :default-layout="false">
+              <template v-slot:entity-index-table-cell="{inputData, showConfirmRemoveDialog}">
+                <template v-if="inputData.col.name === 'actions'">
+                  <div class="action-column-entity-index">
+                    <q-btn size="md"
+                           color="primary"
+                           label="تعیین جزییات"
+                           :to="{name: 'Admin.Unit.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>
+        </div>
+      </template>
+    </entity-edit>
+  </div>
+</template>
+
+<script>
+import { shallowRef } from 'vue'
+import ShamsiDate from 'src/assets/ShamsiDate.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import { EntityEdit, EntityIndex } from 'quasar-crud'
+import BtnControl from 'src/components/Control/btn.vue'
+import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
+
+const BtnControlComp = shallowRef(BtnControl)
+
+export default {
+  name: 'Admin.Category.Index',
+  components: {
+    EntityEdit,
+    EntityIndex,
+    DeleteBtn
+  },
+  data () {
+    return {
+      mounted: false,
+      newUnitLoading: false,
+      newUnitName: null,
+      newUnitSessionCount: null,
+      api: null,
+      entityIdKey: 'id',
+      entityParamKey: 'id',
+      showRouteName: 'Admin.Category.Show',
+      inputs: [
+        { type: 'input', name: 'title', responseKey: 'title', label: 'نام دسته بندی', col: 'col-md-6' },
+        { type: BtnControlComp, name: 'btn', responseKey: 'btn', label: 'بروزرسانی', props: { atClick: this.updateCategory }, col: 'col-md-6' },
+        { type: 'hidden', name: 'id', responseKey: 'id', label: 'id' }
+      ],
+
+      unitFilterInputs: [
+        // { type: 'hidden', name: 'category', value: null }
+      ],
+
+      unitApi: APIGateway.unit.APIAdresses.base + '?category=' + this.$route.params.id,
+      unitTable: {
+        columns: [
+          {
+            name: 'id',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'title',
+            required: true,
+            label: 'نام درس',
+            align: 'left',
+            field: row => row.title
+          },
+          {
+            name: 'count',
+            required: true,
+            label: 'تعداد جلسات',
+            align: 'left',
+            field: () => '...'
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'تاریخ ایجاد',
+            align: 'left',
+            field: row => ShamsiDate.getDateTime(row.creation_time)
+          },
+          {
+            name: 'last_modification_time',
+            required: true,
+            label: 'تاریخ آخرین تغییر',
+            align: 'left',
+            field: row => ShamsiDate.getDateTime(row.last_modification_time)
+          },
+          {
+            name: 'actions',
+            required: true,
+            label: 'عملیات',
+            align: 'left',
+            field: ''
+          }
+        ],
+        data: []
+      },
+      unitTableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
+
+    }
+  },
+  mounted () {
+    // this.unitFilterInputs[0].value = this.$route.params.id
+    this.api = APIGateway.unitCategory.APIAdresses.byId(this.$route.params.id)
+    this.mounted = true
+  },
+  methods: {
+    updateCategory () {
+      if (!this.$refs.categoryEntityEdit) {
+        return
+      }
+      this.$refs.categoryEntityEdit.editEntity()
+    },
+    getRemoveMessage (row) {
+      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
+    },
+    reloadUnits () {
+      this.$refs.unitEntityIndex.reload()
+    },
+    createUnit () {
+      this.newUnitLoading = true
+      APIGateway.unit.create({
+        title: this.newUnitName,
+        category: this.$route.params.id,
+        default_session_count: this.newUnitSessionCount
+      })
+        .then(() => {
+          this.newUnitLoading = false
+          this.reloadUnits()
+        })
+        .catch(() => {
+          this.newUnitLoading = false
+        })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.AdminCategoryIndex {
+  .action-column-entity-index {
+    display: flex;
+    align-items: center;
+    justify-content: flex-start;
+  }
+}
+</style>

+ 23 - 0
src/pages/Admin/DiscussionCirclesClassroom/Ticket.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: 'AdminPanel.Package.List',
+  mixins: [mixinPageOptions],
+  data: () => {
+    return {
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminTicketList' }, { name: 'AdminTicketCreate', options: { style: { marginTop: '32px' } } }], options: { style: { paddingTop: '' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '30px', style: { maxWidth: '1200px', width: '1200px' } } }] }, options: { fullHeight: false, backgrounds: { xs: { size: null, color: null, image: null, repeat: null, position: null, attachment: null }, sm: { size: null, color: null, image: null, repeat: null, position: null, attachment: null }, md: { size: null, color: null, image: null, repeat: null, position: null, attachment: null }, lg: { size: null, color: null, image: null, repeat: null, position: null, attachment: null }, xl: { size: null, color: null, image: null, repeat: null, position: null, attachment: null } }, verticalAlign: null, style: { minHeight: 'auto' } } }]
+    }
+  },
+  created() {
+    this.currenSections = this.sections
+  }
+}
+</script>

+ 245 - 0
src/pages/Admin/DiscussionCirclesClassroom/create.vue

@@ -0,0 +1,245 @@
+<template>
+  <div class="AdminClassroomCreate">
+    <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-btn color="primary"
+                 label="ایجاد دوره آموزشی جدید"
+                 @click="createClassroom" />
+        </div>
+      </template>
+    </entity-create>
+  </div>
+</template>
+
+<script>
+import { EntityCreate } from 'quasar-crud'
+import Enums from 'src/assets/Enums/Enums.js'
+import { APIGateway } from 'src/api/APIGateway'
+
+export default {
+  name: 'Admin.Classroom.Create',
+  components: {
+    EntityCreate
+  },
+  data () {
+    return {
+      mounted: 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: '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: 'inputEditor', 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: 'maximum_failing_mark', responseKey: 'maximum_failing_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_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان انصراف در بازه ثبت نام', col: 'col-md-9 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_dropping_on_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان انصراف در بازه ثبت نام', col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان انصراف در بازه ثبت نام', col: 'col-md-6 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: 'inputEditor', name: 'rules', responseKey: 'rules', 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: 'inputEditor', name: 'description', responseKey: 'description', label: '??توضیحات', col: 'col-12' },
+
+        { type: 'hidden', name: 'id', responseKey: 'id', label: 'id', col: 'col-md-3 col-12' }
+      ]
+    }
+  },
+  computed: {
+    selectedCategoryId () {
+      return this.getInputValue('category')
+    }
+  },
+  watch: {
+    selectedCategoryId () {
+      this.setInputValue('unit', null)
+      this.getUnits(this.selectedCategoryId)
+    }
+  },
+  mounted () {
+    this.mounted = true
+    this.preLoadData()
+  },
+  methods: {
+    setInputAttr (name, attr, value) {
+      this.$refs.classroomEntityCreate.setInputAttributeByName(name, attr, value)
+    },
+    preLoadData () {
+      this.beforeLoadInputData()
+    },
+    beforeLoadInputData () {
+      const promise1 = this.getProfessors()
+      const promise2 = this.getCategories()
+      const promise3 = this.getUnits()
+      this.$nextTick(() => {
+        Promise.all([promise1, promise2, promise3])
+          .then(() => {
+            // this.setInputAttr('category', 'value', responseData.unit_info.category)
+            // this.setInputAttr('unit', 'value', responseData.unit)
+            this.classroomEntityCreateKey = Date.now()
+          })
+          .catch(() => {})
+      })
+    },
+    getProfessors () {
+      return APIGateway.user.index({ per_page: 9999, role: 'professor' })
+        .then((users) => {
+          this.setInputAttr('professor', 'options', users.list.list.map(item => {
+            return {
+              value: item.id,
+              label: this.getUserFullname(item)
+            }
+          }))
+        })
+        .catch(() => {})
+    },
+    getCategories () {
+      return APIGateway.unitCategory.index({ per_page: 9999 })
+        .then((categories) => {
+          this.setInputAttr('category', 'options', categories.list.list.map(item => {
+            return {
+              value: item.id,
+              label: item.title
+            }
+          }))
+        })
+        .catch(() => {})
+    },
+    getUnits (selectedcategoryId = null) {
+      return APIGateway.unit.index({ per_page: 9999, category: selectedcategoryId })
+        .then((units) => {
+          this.setInputAttr('unit', 'options', units.list.list.map(item => {
+            return {
+              value: item.id,
+              label: item.title
+            }
+          }))
+        })
+        .catch(() => {})
+    },
+
+    getUserFullname (user) {
+      return user.firstname + ' ' + user.lastname
+    },
+    getSelectOptions (result, value, label) {
+      return result.map(item => {
+        return {
+          value: item[value],
+          label: item[label]
+        }
+      })
+    },
+    setInputValue (name, value) {
+      const inputIndex = this.inputs.findIndex(input => input.name === name)
+      this.inputs[inputIndex].value = value
+    },
+    loadSelectOptions (name, value, setNewInputData) {
+      const inputIndex = this.inputs.findIndex(input => input.name === name)
+      this.inputs[inputIndex].options = value
+      if (typeof setNewInputData === 'function') {
+        setNewInputData(this.inputs)
+      }
+    },
+    createClassroom () {
+      this.$refs.classroomEntityCreate.createEntity()
+    },
+    getInputValue (name) {
+      const inputIndex = this.inputs.findIndex(input => input.name === name)
+      return this.inputs[inputIndex].value
+    }
+  }
+}
+</script>

+ 252 - 0
src/pages/Admin/DiscussionCirclesClassroom/index.vue

@@ -0,0 +1,252 @@
+<template>
+  <div class="AdminClassroomIndex">
+    <div class="add-new-action-row">
+      <q-btn color="primary"
+             :to="{name: 'Admin.Classroom.DiscussionCircles.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 === 'actions'">
+          <div class="action-column-entity-index">
+            <q-btn size="md"
+                   color="primary"
+                   label="جزییات"
+                   :to="{name: 'Admin.Classroom.DiscussionCircles.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>
+</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)
+
+export default {
+  name: 'Admin.Classroom.Index',
+  components: {
+    EntityIndex,
+    DeleteBtn
+  },
+  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: 'type', value: 'DISCUSSION_CIRCLE' },
+        { type: 'unit__category__type', name: 'type', value: 'DISCUSSION_CIRCLE' },
+        { type: BtnControlComp, name: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-2 col-12' }
+      ],
+      api: APIGateway.classroom.APIAdresses.base,
+      table: {
+        columns: [
+          {
+            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
+          },
+          {
+            name: 'title',
+            required: true,
+            label: 'تاریخ و زمان ثبت نام',
+            align: 'left',
+            field: row => 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: 'actions',
+            required: true,
+            label: 'عملیات',
+            align: 'left',
+            field: ''
+          }
+        ],
+        data: []
+      },
+      tableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
+    }
+  },
+  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
+    }
+  }
+}
+</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>

+ 416 - 0
src/pages/Admin/DiscussionCirclesClassroom/show.vue

@@ -0,0 +1,416 @@
+<template>
+  <q-card class="AdminClassroomShow">
+    <q-tabs v-model="tab"
+            dense
+            class="text-grey"
+            active-color="primary"
+            indicator-color="primary"
+            align="justify"
+            narrow-indicator>
+      <q-tab name="classroomInfo"
+             label="مشخصات" />
+      <q-tab name="educations"
+             label="لیست جلسات" />
+      <q-tab name="movies1"
+             label="پروژه‌ها" />
+      <q-tab name="movies2"
+             label="آزمون" />
+      <q-tab name="movies3"
+             label="کاربران" />
+    </q-tabs>
+
+    <q-separator />
+
+    <q-tab-panels v-model="tab"
+                  animated>
+      <q-tab-panel name="classroomInfo">
+        <entity-edit v-if="mounted"
+                     ref="classroomEntityEdit"
+                     :key="classroomEntityEditKey"
+                     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"
+                     :after-load-input-data="afterLoadInputData">
+          <template #after-form-builder>
+            <div class="flex justify-end">
+              <q-btn color="primary"
+                     label="بروزرسانی اطلاعات"
+                     @click="updateClassroom" />
+            </div>
+          </template>
+        </entity-edit>
+        <q-skeleton v-else
+                    type="rect"
+                    height="200px" />
+      </q-tab-panel>
+      <q-tab-panel name="educations">
+        <entity-index v-if="mounted"
+                      v-model:value="sessionListInputs"
+                      title="لیست جلسات"
+                      :api="sessionListApi"
+                      :table="sessionListTable"
+                      :table-keys="sessionListTableKeys"
+                      :show-search-button="false"
+                      :show-reload-button="false"
+                      :show-expand-button="false">
+          <template v-slot:entity-index-table-cell="{inputData, showConfirmRemoveDialog}">
+            <template v-if="inputData.col.name === 'actions'">
+              <div class="action-column-entity-index">
+                <q-btn size="md"
+                       color="primary"
+                       label="جزییات"
+                       :to="{name: 'Admin.Session.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>
+        <q-skeleton v-else
+                    type="rect"
+                    height="200px" />
+      </q-tab-panel>
+
+      <q-tab-panel name="movies1">
+        پروژه‌ها
+      </q-tab-panel>
+      <q-tab-panel name="movies2">
+        آزمون
+      </q-tab-panel>
+      <q-tab-panel name="movies3">
+        کاربران
+      </q-tab-panel>
+    </q-tab-panels>
+  </q-card>
+</template>
+
+<script>
+import Enums from 'src/assets/Enums/Enums.js'
+import ShamsiDate from 'src/assets/ShamsiDate.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import { EntityEdit, EntityIndex } from 'quasar-crud'
+import { FormBuilderAssist } from 'quasar-form-builder'
+import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
+
+export default {
+  name: 'Admin.Classroom.Show',
+  components: {
+    EntityEdit,
+    EntityIndex,
+    DeleteBtn
+  },
+  data () {
+    return {
+      mounted: false,
+      classroomEntityEditKey: Date.now(),
+      tab: 'classroomInfo',
+      api: null,
+      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: 'separator', name: 'space', size: '0', col: 'col-md-12' },
+        { type: 'select', name: 'category', responseKey: 'unit_info.category_info.id', 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: 'inputEditor', 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_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان انصراف در بازه ثبت نام', col: 'col-md-9 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_dropping_on_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان انصراف در بازه ثبت نام', col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_drop_add_period', responseKey: 'allow_dropping_on_drop_add_period', label: 'امکان انصراف در بازه ثبت نام', col: 'col-md-6 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: 'inputEditor', name: 'rules', responseKey: 'rules', 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: 'inputEditor', name: 'description', responseKey: 'description', label: '??توضیحات', col: 'col-12' },
+
+        { type: 'hidden', name: 'id', responseKey: 'id', label: 'id', col: 'col-md-3 col-12' }
+      ],
+
+      sessionListInputs: [
+        { type: 'hidden', name: 'classroom', value: this.$route.params.id, label: 'نام دوره', col: 'col-12' }
+      ],
+      sessionListApi: APIGateway.session.APIAdresses.base,
+      sessionListTable: {
+        columns: [
+          {
+            name: 'id',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'title',
+            required: true,
+            label: 'عنوان جلسه',
+            align: 'left',
+            field: row => row.title
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'زمان شروع جلسه',
+            align: 'left',
+            field: row => row.starting_time ? ShamsiDate.getDateTime(row.starting_time) : '-'
+          },
+          {
+            name: 'last_modification_time',
+            required: true,
+            label: 'زمان پایان جلسه',
+            align: 'left',
+            field: row => row.ending_time ? ShamsiDate.getDateTime(row.ending_time) : '-'
+          },
+          {
+            name: 'actions',
+            required: true,
+            label: 'عملیات',
+            align: 'left',
+            field: ''
+          }
+        ],
+        data: []
+      },
+      sessionListTableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
+    }
+  },
+  computed: {
+    selectedCategoryId () {
+      return this.getInputValue('category')
+    }
+  },
+  watch: {
+    selectedCategoryId () {
+      if (!this.mounted) {
+        return
+      }
+      this.setInputValue('unit', null)
+      this.getUnits(this.selectedCategoryId)
+    }
+  },
+  mounted () {
+    this.api = APIGateway.classroom.APIAdresses.byId(this.$route.params.id)
+    this.preLoadData()
+      .then(() => {
+        this.mounted = true
+      })
+      .catch(() => {
+      })
+  },
+  methods: {
+    afterLoadInputData () {
+      // const gg = data.beginning_enrollment_period.replace('T', ' ')
+      // this.setInputAttr('beginning_enrollment_period', 'value', gg)
+    },
+    setInputAttr (name, attr, value) {
+      FormBuilderAssist.setAttributeByName(this.inputs, name, attr, value)
+      // this.$refs.classroomEntityEdit.setInputAttributeByName(name, attr, value)
+    },
+    preLoadData () {
+      return new Promise((resolve, reject) => {
+        APIGateway.classroom.get(this.$route.params.id)
+          .then((classroom) => {
+            this.setInputAttr('category', 'value', classroom.unit_info.category_info.id)
+            this.setInputAttr('unit', 'value', classroom.unit)
+            this.beforeLoadInputData(classroom)
+              .then((classroom) => {
+                resolve()
+              })
+              .catch(() => {
+                reject()
+              })
+          })
+          .catch(() => {
+            reject()
+          })
+      })
+    },
+    beforeLoadInputData (responseData) {
+      return new Promise((resolve, reject) => {
+        const promise1 = this.getProfessors()
+        const promise2 = this.getCategories()
+        const promise3 = this.getUnits(responseData.unit_info.category)
+        this.$nextTick(() => {
+          Promise.all([promise1, promise2, promise3])
+            .then(() => {
+            // this.setInputAttr('category', 'value', responseData.unit_info.category)
+            // this.setInputAttr('unit', 'value', responseData.unit)
+              this.classroomEntityEditKey = Date.now()
+              resolve()
+            })
+            .catch(() => {
+              reject()
+            })
+        })
+      })
+    },
+    getProfessors () {
+      return APIGateway.user.index({ per_page: 9999, role: 'professor' })
+        .then((users) => {
+          this.setInputAttr('professor', 'options', users.list.list.map(item => {
+            return {
+              value: item.id,
+              label: this.getUserFullname(item)
+            }
+          }))
+        })
+        .catch(() => {})
+    },
+    getCategories () {
+      return APIGateway.unitCategory.index({ per_page: 9999 })
+        .then((categories) => {
+          this.setInputAttr('category', 'options', categories.list.list.map(item => {
+            return {
+              value: item.id,
+              label: item.title
+            }
+          }))
+        })
+        .catch(() => {})
+    },
+    getUnits (selectedcategoryId) {
+      return APIGateway.unit.index({ per_page: 9999, category: selectedcategoryId })
+        .then((units) => {
+          this.setInputAttr('unit', 'options', units.list.list.map(item => {
+            return {
+              value: item.id,
+              label: item.title
+            }
+          }))
+        })
+        .catch(() => {})
+    },
+    getUserFullname (user) {
+      return user.firstname + ' ' + user.lastname
+    },
+    getSelectOptions (result, value, label) {
+      return result.map(item => {
+        return {
+          value: item[value],
+          label: item[label]
+        }
+      })
+    },
+    getInputValue (name) {
+      const inputIndex = this.inputs.findIndex(input => input.name === name)
+      return this.inputs[inputIndex].value
+    },
+    setInputValue (name, value) {
+      const inputIndex = this.inputs.findIndex(input => input.name === name)
+      this.inputs[inputIndex].value = value
+    },
+    loadSelectOptions (name, value, setNewInputData) {
+      const inputIndex = this.inputs.findIndex(input => input.name === name)
+      this.inputs[inputIndex].options = value
+      if (typeof setNewInputData === 'function') {
+        setNewInputData(this.inputs)
+      }
+    },
+    updateClassroom () {
+      this.$refs.classroomEntityEdit.editEntity()
+    },
+    getRemoveMessage (row) {
+      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.AdminClassroomShow {
+  .action-column-entity-index {
+    display: flex;
+    align-items: center;
+    justify-content: flex-start;
+  }
+}
+</style>

+ 23 - 0
src/router/routes.js

@@ -264,6 +264,17 @@ const routes = [
               { name: 'Admin.Category.Show', path: ':id', component: () => import('src/pages/Admin/Category/show.vue') }
             ]
           },
+          {
+            name: 'Admin.Category.DiscussionCircles',
+            path: 'discussion-circles-categories',
+            component: () => import('layouts/bareLayout.vue'),
+            breadcrumbs: { title: 'دسته بندی ها' },
+            children: [
+              { name: 'Admin.Category.DiscussionCircles.Index', path: '', component: () => import('src/pages/Admin/DiscussionCirclesCategory/index.vue') },
+              { name: 'Admin.Category.DiscussionCircles.Create', path: 'create', component: () => import('src/pages/Admin/DiscussionCirclesCategory/create.vue') },
+              { name: 'Admin.Category.DiscussionCircles.Show', path: ':id', component: () => import('src/pages/Admin/DiscussionCirclesCategory/show.vue') }
+            ]
+          },
           {
             name: 'Admin.Unit',
             path: 'units',
@@ -320,6 +331,18 @@ const routes = [
               { name: 'Admin.Classroom.Ticket', path: 'ticket', component: () => import('src/pages/Admin/Classroom/Ticket.vue'), breadcrumbs: { title: 'درخواست ها دوره های آموزشی' } }
             ]
           },
+          {
+            name: 'Admin.Classroom.DiscussionCircles',
+            path: 'discussion-circles-classrooms',
+            component: () => import('layouts/bareLayout.vue'),
+            breadcrumbs: { title: 'دوره های آموزشی', route: { name: 'Admin.Classroom.DiscussionCircles.Index' } },
+            children: [
+              { name: 'Admin.Classroom.DiscussionCircles.Index', path: '', component: () => import('src/pages/Admin/DiscussionCirclesClassroom/index.vue') },
+              { name: 'Admin.Classroom.DiscussionCircles.Create', path: 'create', component: () => import('src/pages/Admin/DiscussionCirclesClassroom/create.vue'), breadcrumbs: { title: 'ساخت دوره آموزشی' } },
+              { name: 'Admin.Classroom.DiscussionCircles.Show', path: ':id', component: () => import('src/pages/Admin/DiscussionCirclesClassroom/show.vue'), breadcrumbs: { title: 'مشاهده اطلاعات دوره آموزشی' } },
+              { name: 'Admin.Classroom.DiscussionCircles.Ticket', path: 'ticket', component: () => import('src/pages/Admin/DiscussionCirclesClassroom/Ticket.vue'), breadcrumbs: { title: 'درخواست ها دوره های آموزشی' } }
+            ]
+          },
           {
             path: 'content',
             name: 'Admin.Content',