ali 3 lat temu
rodzic
commit
4f0f02380e
20 zmienionych plików z 1863 dodań i 937 usunięć
  1. 3 1
      src/api/APIGateway.js
  2. 169 0
      src/components/Widgets/Classroom/AdminClassroomCreate/AdminClassroomCreate.vue
  3. 21 0
      src/components/Widgets/Classroom/AdminClassroomCreate/OptionPanel.vue
  4. 215 0
      src/components/Widgets/Classroom/AdminClassroomList/AdminClassroomList.vue
  5. 21 0
      src/components/Widgets/Classroom/AdminClassroomList/OptionPanel.vue
  6. 96 0
      src/components/Widgets/Classroom/AdminClassroomShow/AdminClassroomShow.vue
  7. 36 0
      src/components/Widgets/Classroom/AdminClassroomShow/OptionPanel.vue
  8. 168 0
      src/components/Widgets/Classroom/AdminClassroomShow/components/ActivitySheetList.vue
  9. 278 0
      src/components/Widgets/Classroom/AdminClassroomShow/components/ClassroomInfo.vue
  10. 35 0
      src/components/Widgets/Classroom/AdminClassroomShow/components/LiveStreaming.vue
  11. 225 0
      src/components/Widgets/Classroom/AdminClassroomShow/components/MembersList.vue
  12. 175 0
      src/components/Widgets/Classroom/AdminClassroomShow/components/ProjectList.vue
  13. 156 0
      src/components/Widgets/Classroom/AdminClassroomShow/components/SessionList.vue
  14. 169 0
      src/components/Widgets/SessionAttendanceSheet/AdminSessionAttendanceSheetList/AdminSessionAttendanceSheetList.vue
  15. 21 0
      src/components/Widgets/SessionAttendanceSheet/AdminSessionAttendanceSheetList/OptionPanel.vue
  16. 40 1
      src/models/SessionAttendanceSheets.js
  17. 23 0
      src/pages/Admin/Classroom/sessionActivitySheets.vue
  18. 10 934
      src/pages/Admin/Classroom/show.vue
  19. 1 1
      src/pages/Admin/Content/Show.vue
  20. 1 0
      src/router/routes.js

+ 3 - 1
src/api/APIGateway.js

@@ -26,6 +26,7 @@ import ContentCategoryAPI from 'src/api/models/ContentCategory.js'
 import InstalmentOfferAPI from 'src/api/models/InstalmentOffer.js'
 import ClassroomRegistrationAPI from 'src/api/models/ClassroomRegistration.js'
 import ProjectAttendanceSheetsAPI from 'src/api/models/ProjectAttendanceSheets.js'
+import SessionAttendanceSheetsAPI from 'src/api/models/SessionAttendanceSheets.js'
 
 /* Exporting the APIGateway object. */
 export const APIGateway = {
@@ -56,5 +57,6 @@ export const APIGateway = {
   contentCategory: new ContentCategoryAPI(),
   instalmentOffer: new InstalmentOfferAPI(),
   classroomRegistration: new ClassroomRegistrationAPI(),
-  projectAttendanceSheets: new ProjectAttendanceSheetsAPI()
+  projectAttendanceSheets: new ProjectAttendanceSheetsAPI(),
+  sessionAttendanceSheets: new SessionAttendanceSheetsAPI()
 }

+ 169 - 0
src/components/Widgets/Classroom/AdminClassroomCreate/AdminClassroomCreate.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="AdminPostCreate"
+       :style="localOptions.style">
+    <div class="flex justify-end">
+      <q-btn flat
+             color="grey"
+             @click="$router.go(-1)">
+        بازگشت
+        >
+      </q-btn>
+    </div>
+    <entity-create v-if="mounted"
+                   ref="entityCreate"
+                   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" />
+  </div>
+</template>
+
+<script>
+import { shallowRef } from 'vue'
+import { EntityCreate } from 'quasar-crud'
+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'
+
+const BtnControlComp = shallowRef(BtnControl)
+const PostCategorySelectorComp = shallowRef(PostCategorySelector)
+const FormBuilderTiptapEditorComp = shallowRef(FormBuilderTiptapEditor)
+
+export default {
+  name: 'AdminPostCreate',
+  components: { EntityCreate },
+  mixins: [mixinWidget, PostMixin],
+  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,
+      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: '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: '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: BtnControlComp, name: 'btn', responseKey: 'btn', label: 'ایجاد محتوا', placeholder: ' ', atClick: () => {}, col: 'col-md-6' }
+      ]
+    }
+  },
+  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
+  },
+  methods: {
+    setActionBtn () {
+      this.inputs.forEach((item, index) => {
+        if (item.name === 'btn') {
+          this.inputs[index].atClick = this.onSubmit
+        }
+      })
+    },
+    onSubmit () {
+      this.create()
+    },
+    create() {
+      this.entityLoading = true
+      this.$refs.entityCreate.createEntity()
+        .then(() => {
+          this.entityLoading = false
+        })
+        .catch(() => {
+          this.entityLoading = false
+        })
+    }
+  }
+}
+</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>

+ 21 - 0
src/components/Widgets/Classroom/AdminClassroomCreate/OptionPanel.vue

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

+ 215 - 0
src/components/Widgets/Classroom/AdminClassroomList/AdminClassroomList.vue

@@ -0,0 +1,215 @@
+<template>
+  <div class="AdminInvoiceList"
+       :style="localOptions.style">
+    <entity-index v-if="mounted"
+                  ref="entityIndex"
+                  v-model:value="inputs"
+                  title="لیست صورتحساب ها"
+                  :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}">
+        <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>
+        </template>
+        <template v-else>
+          {{ inputData.col.value }}
+        </template>
+      </template>
+    </entity-index>
+  </div>
+</template>
+
+<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 { mixinWidget } from 'src/mixin/Mixins.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import BtnControl from 'src/components/Control/btn.vue'
+
+const BtnControlComp = shallowRef(BtnControl)
+
+export default {
+  name: 'AdminInvoiceList',
+  components: { EntityIndex },
+  mixins: [mixinWidget],
+  data () {
+    return {
+      api: APIGateway.invoice.APIAdresses.base,
+      tableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      },
+      inputs: [
+        {
+          type: 'dateTime',
+          name: 'creation_time__gte',
+          label: 'از تاریخ',
+          placeholder: ' ',
+          col: 'col-md-3 col-12'
+        },
+        {
+          type: 'dateTime',
+          name: 'creation_time__lt',
+          label: 'تا تاریخ',
+          placeholder: ' ',
+          col: 'col-md-3 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' }
+      ],
+      table: {
+        columns: [
+          {
+            name: 'number',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: () => ''
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'شناسه',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'سفارش دهنده',
+            align: 'left',
+            field: row => row.owner_info.firstname + ' ' + row.owner_info.lastname
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'کدملی سفارش دهنده',
+            align: 'left',
+            field: row => row.owner_info.national_code
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'عنوان',
+            align: 'left',
+            field: row => this.getInvoiceTitle(row)
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'نوع صورتحساب',
+            align: 'left',
+            field: row => (new Invoice(row)).type_info.label
+          },
+          {
+            name: 'amount',
+            required: true,
+            label: 'مبلغ تراکنش(ریال)',
+            align: 'left',
+            field: row => row.amount.toLocaleString('fa')
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'وضعیت تراکنش',
+            align: 'left',
+            field: row => (new Invoice(row)).status_info.label
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'زمان ثبت',
+            align: 'left',
+            field: row => Assist.miladiToShamsi(row.creation_time)
+          },
+          {
+            name: 'last_modification_time',
+            required: true,
+            label: 'زمان آخرین بروز رسانی',
+            align: 'left',
+            field: row => Assist.miladiToShamsi(row.last_modification_time)
+          },
+          {
+            name: 'action',
+            required: true,
+            label: 'جزییات',
+            align: 'left',
+            field: row => ''
+          }
+        ]
+      },
+      mounted: false,
+      createRouteName: ''
+    }
+  },
+  mounted() {
+    this.setActionBtn()
+    this.mounted = true
+  },
+  methods: {
+    getInvoiceTitle (invoice) {
+      if (invoice.item_info.item_type === 'CLASSROOM') {
+        return invoice.item_info.title
+      } else {
+        return invoice.item_info.title || '-'
+      }
+    },
+    setActionBtn () {
+      this.inputs.forEach((item, index) => {
+        if (item.name === 'btn') {
+          this.inputs[index].atClick = this.search
+        }
+      })
+    },
+    search () {
+      this.$refs.entityIndex.search()
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.AdminInvoiceList {
+  .title {
+    font-style: normal;
+    font-weight: 700;
+    font-size: 24px;
+    line-height: 140%;
+    color: #424242;
+    margin-bottom: 27px;
+  }
+  :deep(.list) {
+    .quasar-crud-index-table {
+      padding: 0;
+      .q-table__container {
+        background-color: transparent;
+        box-shadow: none;
+        border: none;
+        .q-table__top {
+          display: none;
+        }
+      }
+    }
+  }
+}
+</style>

+ 21 - 0
src/components/Widgets/Classroom/AdminClassroomList/OptionPanel.vue

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

+ 96 - 0
src/components/Widgets/Classroom/AdminClassroomShow/AdminClassroomShow.vue

@@ -0,0 +1,96 @@
+<template>
+  <div class="flex justify-end">
+    <q-btn flat
+           color="grey"
+           @click="$router.go(-1)">
+      بازگشت
+      >
+    </q-btn>
+  </div>
+  <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="sessions"
+             label="لیست جلسات" />
+      <q-tab name="projects"
+             label="پروژه‌ها" />
+      <q-tab name="movies2"
+             label="آزمون" />
+      <q-tab name="members"
+             label="اندیشه جویان" />
+      <q-tab name="activity_sheet"
+             label="فعالیت کلاسی" />
+      <q-tab name="live_streaming_url"
+             label="بخش آنلاین" />
+    </q-tabs>
+
+    <q-separator />
+
+    <q-tab-panels v-model="tab"
+                  animated>
+      <q-tab-panel name="classroomInfo"
+                   class="q-pa-none">
+        <classroom-info v-model:classroom="classroom"
+                        :classroom-id="$route.params.id" />
+      </q-tab-panel>
+      <q-tab-panel name="sessions"
+                   class="q-pa-none">
+        <session-list :classroom-id="$route.params.id" />
+      </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>
+      <q-tab-panel name="members"
+                   class="q-pa-none">
+        <members-list :classroom-id="$route.params.id" />
+      </q-tab-panel>
+      <q-tab-panel name="activity_sheet"
+                   class="q-pa-none">
+        <activity-sheet-list :classroom-id="$route.params.id" />
+      </q-tab-panel>
+      <q-tab-panel name="live_streaming_url">
+        <live-streaming v-model:classroom="classroom" />
+      </q-tab-panel>
+    </q-tab-panels>
+  </q-card>
+</template>
+
+<script>
+import { Classroom } from 'src/models/Classroom.js'
+import SessionList from './components/SessionList.vue'
+import ProjectList from './components/ProjectList.vue'
+import MembersList from './components/MembersList.vue'
+import ClassroomInfo from './components/ClassroomInfo.vue'
+import LiveStreaming from './components/LiveStreaming.vue'
+import ActivitySheetList from './components/ActivitySheetList.vue'
+
+export default {
+  name: 'Admin.Classroom.Show',
+  components: {
+    SessionList,
+    ProjectList,
+    MembersList,
+    ClassroomInfo,
+    LiveStreaming,
+    ActivitySheetList
+  },
+  data () {
+    return {
+      tab: 'classroomInfo',
+      classroom: new Classroom()
+    }
+  }
+}
+</script>

+ 36 - 0
src/components/Widgets/Classroom/AdminClassroomShow/OptionPanel.vue

@@ -0,0 +1,36 @@
+<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 { mixinOptionPanel } from 'quasar-ui-q-page-builder'
+import OptionPanelTabs from 'quasar-ui-q-page-builder/src/components/OptionPanelComponents/OptionPanelTabs.vue'
+
+export default defineComponent({
+  name: 'OptionPanel',
+  components: {
+    OptionPanelTabs
+  },
+  mixins: [mixinOptionPanel],
+  data () {
+    return {
+      classroomTypeOptions: [
+        {
+          label: 'دوره آموزشی',
+          value: 'Classroom'
+        },
+        {
+          label: 'حلقه مباحثاتی',
+          value: 'DiscussionCircles'
+        }
+      ]
+    }
+  }
+})
+</script>

+ 168 - 0
src/components/Widgets/Classroom/AdminClassroomShow/components/ActivitySheetList.vue

@@ -0,0 +1,168 @@
+<template>
+  <entity-index v-if="mounted"
+                ref="activitySheetList"
+                v-model:value="activitySheetListInputs"
+                title="فعالیت کلاسی"
+                :api="activitySheetListApi"
+                :table="activitySheetListTable"
+                :table-keys="activitySheetListTableKeys"
+                :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"
+                 outline
+                 label="سابقه آموزشی"
+                 class="q-mr-md" />
+          <!--                :to="{name: 'Admin.Session.Show', params: {id: inputData.props.row.id}}"-->
+          <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" />
+</template>
+
+<script>
+import { shallowRef } from 'vue'
+import { EntityIndex } from 'quasar-crud'
+import { APIGateway } from 'src/api/APIGateway.js'
+import { FormBuilderAssist } from 'quasar-form-builder'
+import BtnControl from 'src/components/Control/btn.vue'
+import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
+
+const BtnControlComp = shallowRef(BtnControl)
+
+export default {
+  name: 'ActivitySheetList',
+  components: {
+    DeleteBtn,
+    EntityIndex
+  },
+  props: {
+    classroomId: {
+      type: Number,
+      default: null
+    }
+  },
+  data () {
+    const classroomId = this.classroomId
+    return {
+      mounted: false,
+      createInvoiceLoading: false,
+
+      activitySheetListInputs: [
+        { type: 'hidden', name: 'classroom', value: classroomId },
+        { type: 'select', name: 'status', value: null, label: 'وضعیت', placeholder: ' ', col: 'col-md-3 col-12' },
+        { type: BtnControlComp, name: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-2 col-12' }
+      ],
+      activitySheetListApi: APIGateway.classroom.APIAdresses.activitySheet,
+      activitySheetListTable: {
+        columns: [
+          {
+            name: 'id',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'owner_info.fullname',
+            required: true,
+            label: 'نام و نام خانوادگی',
+            align: 'left',
+            field: row => row.owner_info.firstname + ' ' + row.owner_info.lastname
+          },
+          {
+            name: 'owner_info.fullname',
+            required: true,
+            label: 'کد ملی',
+            align: 'left',
+            field: row => row.owner_info.national_code
+          },
+          {
+            name: 'is_project_done',
+            required: true,
+            label: 'پروژه',
+            align: 'left',
+            field: row => row.is_project_done
+          },
+          {
+            name: 'done_assignment_count',
+            required: true,
+            label: 'تکالیف انجام شده',
+            align: 'left',
+            field: row => row.done_assignment_count
+          },
+          {
+            name: 'is_allowed_absence_count',
+            required: true,
+            label: 'حضور و غیاب',
+            align: 'left',
+            field: row => row.is_allowed_absence_count // bool
+          },
+          {
+            name: 'attendance_score',
+            required: true,
+            label: 'نمره حضور و غیاب',
+            align: 'left',
+            field: row => row.attendance_score
+          },
+          {
+            name: 'final_test',
+            required: true,
+            label: 'آزمون',
+            align: 'left',
+            field: row => row.final_test // number - null
+          },
+          {
+            name: 'final_status',
+            required: true,
+            label: 'وضعیت نهایی',
+            align: 'left',
+            field: row => row.final_status
+          },
+          {
+            name: 'actions',
+            required: true,
+            label: 'سابقه آموزشی',
+            align: 'left',
+            field: ''
+          }
+        ],
+        data: []
+      },
+      activitySheetListTableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
+    }
+  },
+  mounted () {
+    this.setActivitySheetListActionBtn()
+    this.mounted = true
+  },
+  methods: {
+    setActivitySheetListActionBtn () {
+      FormBuilderAssist.setAttributeByName(this.activitySheetListInputs, 'btn', 'atClick', this.searchActivitySheetList)
+    },
+    searchActivitySheetList () {
+      this.$refs.activitySheet.search()
+    },
+    getRemoveMessage (row) {
+      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
+    }
+  }
+}
+</script>

+ 278 - 0
src/components/Widgets/Classroom/AdminClassroomShow/components/ClassroomInfo.vue

@@ -0,0 +1,278 @@
+<template>
+  <entity-edit v-if="mounted"
+               ref="classroomEntityEdit"
+               :key="classroomEntityEditKey"
+               v-model:value="inputs"
+               title="مشخصات دوره آموزشی"
+               :api="api"
+               :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-mt-md">
+        <q-btn color="primary"
+               label="بروزرسانی اطلاعات"
+               @click="updateClassroom" />
+      </div>
+    </template>
+  </entity-edit>
+  <q-skeleton v-else
+              type="rect"
+              height="200px" />
+</template>
+
+<script>
+import { EntityEdit } from 'quasar-crud'
+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'
+
+export default {
+  name: 'ClassroomInfo',
+  components: {
+    EntityEdit
+  },
+  props: {
+    classroomId: {
+      type: Number,
+      default: null
+    },
+    classroom: {
+      type: Classroom,
+      default: new Classroom()
+    }
+  },
+  data () {
+    const classroomId = this.classroomId
+    return {
+      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_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.classroomGenders, 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: 'امکان حذف در بازه پیش ثبت نام', col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_adding_on_registration_period', responseKey: 'allow_adding_on_registration_period', label: 'امکان اضافه کردن در بازه ثبت نام', col: 'col-md-3 col-12' },
+        { type: 'checkbox', name: 'allow_dropping_on_registration_period', responseKey: 'allow_dropping_on_registration_period', label: 'امکان حذف ثبت نام در بازه ثبت نام', 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: 'امکان اضافه شدن در بازه حذف و اضافه', 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: '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: 'inputEditor', name: 'description', responseKey: 'description', label: 'توضیحات', col: 'col-12' },
+        { type: 'inputEditor', name: 'specification', responseKey: 'specification', label: 'مشخصات', col: 'col-12' },
+        { type: 'inputEditor', 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: false,
+      classroomEntityEditKey: Date.now(),
+      api: APIGateway.classroom.APIAdresses.byId(classroomId)
+    }
+  },
+  computed: {
+    selectedCategoryId () {
+      return FormBuilderAssist.getInputsByName(this.inputs, 'category').value
+    },
+    localClassroom: {
+      get () {
+        return this.classroom
+      },
+      det (newValue) {
+        this.$emit('update:classroom', newValue)
+      }
+    }
+  },
+  watch: {
+    selectedCategoryId () {
+      if (!this.mounted) {
+        return
+      }
+      FormBuilderAssist.setAttributeByName(this.inputs, 'unit', 'value', null)
+      this.getUnits(this.selectedCategoryId)
+    }
+  },
+  mounted () {
+    this.localClassroom.loading = true
+    this.preLoadData()
+      .then(() => {
+        this.mounted = true
+      })
+      .catch(() => {
+        this.mounted = true
+      })
+  },
+  methods: {
+    afterLoadInputData (data) {
+      this.localClassroom = new Classroom(data)
+      this.localClassroom.loading = false
+      // 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)
+    },
+    preLoadData () {
+      return new Promise((resolve, reject) => {
+        APIGateway.classroom.get(this.classroomId)
+          .then((classroom) => {
+            this.setInputAttr('category', 'value', classroom.unit_info.category_info.id)
+            this.setInputAttr('unit', 'value', classroom.unit)
+            this.beforeLoadInputData(classroom)
+              .then((classroom) => {
+                resolve(classroom)
+              })
+              .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
+    },
+    updateClassroom () {
+      this.$refs.classroomEntityEdit.editEntity()
+    }
+  }
+}
+</script>

+ 35 - 0
src/components/Widgets/Classroom/AdminClassroomShow/components/LiveStreaming.vue

@@ -0,0 +1,35 @@
+<template>
+  <div v-if="classroom.loading">
+    کمی صبر کنید...
+  </div>
+  <div v-else>
+    <q-btn class="full-width q-mb-lg"
+           color="primary"
+           @click="goToLiveStreamUrl">
+      رفتن به کلاس
+    </q-btn>
+    <iframe :src="classroom.live_streaming_url"
+            title="W3Schools Free Online Web Tutorials"
+            style="height: 80vh"
+            class="full-width" />
+  </div>
+</template>
+
+<script>
+import { Classroom } from 'src/models/Classroom.js'
+
+export default {
+  name: 'LiveStreaming',
+  props: {
+    classroom: {
+      type: Classroom,
+      default: new Classroom()
+    }
+  },
+  methods: {
+    goToLiveStreamUrl () {
+      window.open(this.classroom.live_streaming_url, '_blank')
+    }
+  }
+}
+</script>

+ 225 - 0
src/components/Widgets/Classroom/AdminClassroomShow/components/MembersList.vue

@@ -0,0 +1,225 @@
+<template>
+  <entity-index v-if="mounted"
+                ref="membersList"
+                v-model:value="membersListInputs"
+                title="لیست کاربران"
+                :api="membersListApi"
+                :table="membersListTable"
+                :table-keys="membersListTableKeys"
+                :show-search-button="false"
+                :show-reload-button="false"
+                :show-expand-button="false">
+    <template #toolbar>
+      <q-btn color="primary"
+             :loading="exportReportLoading"
+             @click="getMembersExcel">
+        خروجی اکسل
+      </q-btn>
+    </template>
+    <template v-slot:entity-index-table-cell="{inputData}">
+      <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 v-if="inputData.props.row.status !== 'DROPPED_BY_ADMIN' && inputData.props.row.status !== 'DROPPED_BY_ITSELF'"
+                 size="md"
+                 color="red"
+                 outline
+                 label="انصراف"
+                 :loading="dropClassroomByAdminLoading"
+                 class="q-mr-md"
+                 @click="dropClassroomByAdmin(inputData.props.row)" />
+          <q-btn v-if="inputData.props.row.status === 'ENROLLED'"
+                 size="md"
+                 color="primary"
+                 outline
+                 label="ایجاد صورتحساب"
+                 :loading="createInvoiceLoading"
+                 class="q-mr-md"
+                 @click="createInvoiceForClassroom(inputData.props.row)" />
+        </div>
+      </template>
+      <template v-else>
+        {{ inputData.col.value }}
+      </template>
+    </template>
+  </entity-index>
+  <q-skeleton v-else
+              type="rect"
+              height="200px" />
+</template>
+
+<script>
+import { shallowRef } from 'vue'
+import { EntityIndex } from 'quasar-crud'
+import Assist from 'src/assets/js/Assist.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import { Classroom } from 'src/models/Classroom.js'
+import { FormBuilderAssist } from 'quasar-form-builder'
+import BtnControl from 'src/components/Control/btn.vue'
+
+const BtnControlComp = shallowRef(BtnControl)
+
+export default {
+  name: 'MembersList',
+  components: {
+    EntityIndex
+  },
+  props: {
+    classroomId: {
+      type: Number,
+      default: null
+    }
+  },
+  data () {
+    const classroomId = this.classroomId
+    return {
+      mounted: false,
+      createInvoiceLoading: false,
+      classroom: new Classroom(),
+
+      dropClassroomByAdminLoading: false,
+      exportReportLoading: false,
+      membersListInputs: [
+        { type: 'hidden', name: 'classroom', value: classroomId },
+        { type: 'select', name: 'status', options: [{ label: 'ثبت نام شده', value: 'REGISTERED' }, { label: 'پیش ثبت نام شده', value: 'ENROLLED' }, { label: 'حذف توسط اندیشه جو', value: 'DROPPED_BY_ITSELF' }, { label: 'حذف توسط ادمین', value: 'DROPPED_BY_ADMIN' }], label: 'وضعیت', placeholder: ' ', col: 'col-md-3 col-12' },
+        { type: 'select', name: 'invoice__status', options: [{ label: 'پرداخت کامل', value: 'PAID_FULL' }, { label: 'پرداخت قسطی', value: 'PAYING_IN_INSTALMENT' }], label: 'نوع صورتحساب', placeholder: ' ', col: 'col-md-3 col-12' },
+        { type: BtnControlComp, name: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-2 col-12' }
+      ],
+      membersListApi: APIGateway.classroom.APIAdresses.members,
+      membersListTable: {
+        columns: [
+          {
+            name: 'number',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: () => ''
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'شناسه',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'owner_info.fullname',
+            required: true,
+            label: 'نام و نام خانوادگی',
+            align: 'left',
+            field: row => row.owner_info.firstname + ' ' + row.owner_info.lastname
+          },
+          {
+            name: 'owner_info.national_code',
+            required: true,
+            label: 'کد ملی',
+            align: 'left',
+            field: row => row.owner_info.national_code
+          },
+          {
+            name: 'owner_info.mobile_number',
+            required: true,
+            label: 'تلفن همراه',
+            align: 'left',
+            field: row => row.owner_info.mobile_number
+          },
+          {
+            name: 'owner_info.email',
+            required: true,
+            label: 'ایمیل',
+            align: 'left',
+            field: row => row.owner_info.email
+          },
+          {
+            name: 'owner_info.email',
+            required: true,
+            label: 'وضعیت',
+            align: 'left',
+            field: row => (new Classroom()).getUserRegisterInfoLabel(row.status)
+          },
+          {
+            name: 'action',
+            required: true,
+            label: ' ',
+            align: 'left',
+            field: ''
+          }
+        ],
+        data: []
+      },
+      membersListTableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
+    }
+  },
+  mounted () {
+    this.setMembersListActionBtn()
+    this.mounted = true
+  },
+  methods: {
+    setMembersListActionBtn () {
+      FormBuilderAssist.setAttributeByName(this.membersListInputs, 'btn', 'atClick', this.searchMembersList)
+    },
+    searchMembersList () {
+      this.$refs.membersList.search()
+    },
+    getMembersExcel () {
+      this.exportReportLoading = true
+      const status = FormBuilderAssist.getInputsByName(this.membersListInputs, 'status').value ? FormBuilderAssist.getInputsByName(this.membersListInputs, 'status').value : null
+      APIGateway.registration.exportReport({
+        classroom: this.$route.params.id,
+        type: 'users',
+        status
+      })
+        .then((xlsxData) => {
+          Assist.saveXlsx(xlsxData, this.classroom.title)
+          this.exportReportLoading = false
+        })
+        .catch((e) => {
+          this.exportReportLoading = false
+        })
+    },
+    dropClassroomByAdmin (row) {
+      const classroomId = row.classroom
+      const userId = row.owner
+      const message = 'آیا از انصراف (' + row.owner_info.firstname + ' ' + row.owner_info.lastname + ') اطمینان دارید؟'
+      this.$q.dialog({
+        title: 'توجه',
+        message,
+        html: true,
+        cancel: true,
+        persistent: true
+      }).onOk(() => {
+        this.dropClassroomByAdminLoading = true
+        APIGateway.classroom.dropByAdmin(classroomId, userId)
+          .then(() => {
+            this.dropClassroomByAdminLoading = false
+            this.searchMembersList()
+          })
+          .catch(() => {
+            this.dropClassroomByAdminLoading = false
+          })
+      })
+    },
+    createInvoiceForClassroom (row) {
+      const classroomId = row.classroom
+      const userId = row.owner
+      this.createInvoiceLoading = true
+      APIGateway.classroom.createInvoiceByAdmin(classroomId, userId)
+        .then((invoice) => {
+          this.$router.push({ name: 'Admin.Invoice.Show', params: { id: invoice.id } })
+          this.createInvoiceLoading = false
+        })
+        .catch(() => {
+          this.createInvoiceLoading = false
+        })
+    }
+  }
+}
+</script>

+ 175 - 0
src/components/Widgets/Classroom/AdminClassroomShow/components/ProjectList.vue

@@ -0,0 +1,175 @@
+<template>
+  <entity-index v-if="mounted"
+                ref="projectList"
+                v-model:value="projectListInputs"
+                title="لیست پروژه ها"
+                :api="projectListApi"
+                :table="projectListTable"
+                :table-keys="projectListTableKeys"
+                :show-search-button="false"
+                :show-reload-button="false"
+                :show-expand-button="false">
+    <template #toolbar>
+      <q-btn color="primary"
+             outline
+             :loading="addNewProjectLoading"
+             @click="addNewProject">
+        افزودن پروژه جدید
+      </q-btn>
+    </template>
+    <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 === 'actions'">
+        <div class="action-column-entity-index">
+          <q-btn size="md"
+                 color="primary"
+                 label="جزییات"
+                 :to="{name: 'Admin.Classroom.Project.Show', params: {id: $route.params.id, project_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-if="inputData.col.name === 'members'">
+        <div class="action-column-entity-index">
+          <q-btn size="md"
+                 color="primary"
+                 outline
+                 label="بررسی پروژه"
+                 :to="{name: 'Admin.Classroom.Project.Members', params: {id: $route.params.id, project_id: inputData.props.row.id}}"
+                 class="q-mr-md" />
+        </div>
+      </template>
+      <template v-else>
+        {{ inputData.col.value }}
+      </template>
+    </template>
+  </entity-index>
+  <q-skeleton v-else
+              type="rect"
+              height="200px" />
+</template>
+
+<script>
+import { EntityIndex } from 'quasar-crud'
+import { Project } from 'src/models/Project.js'
+import ShamsiDate from 'src/assets/ShamsiDate.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
+
+export default {
+  name: 'ProjectList',
+  components: {
+    DeleteBtn,
+    EntityIndex
+  },
+  props: {
+    classroomId: {
+      type: Number,
+      default: null
+    }
+  },
+  data () {
+    const classroomId = this.classroomId
+    return {
+      mounted: false,
+      addNewProjectLoading: false,
+
+      projectListInputs: [
+        { type: 'hidden', name: 'classroom', value: classroomId }
+      ],
+      projectListApi: APIGateway.project.APIAdresses.base,
+      projectListTable: {
+        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: 'type',
+            required: true,
+            label: 'نوع',
+            align: 'left',
+            field: row => (new Project(row)).typeEnums
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'زمان شروع پروژه',
+            align: 'left',
+            field: row => row.beginning_doing_period ? ShamsiDate.getDateTime(row.beginning_doing_period) : '-'
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'مهلت ارسال پروژه',
+            align: 'left',
+            field: row => row.ending_doing_period ? ShamsiDate.getDateTime(row.ending_doing_period) : '-'
+          },
+          {
+            name: 'members',
+            required: true,
+            label: 'بررسی',
+            align: 'left',
+            field: ''
+          },
+          {
+            name: 'actions',
+            required: true,
+            label: 'عملیات',
+            align: 'left',
+            field: ''
+          }
+        ]
+      },
+      projectListTableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
+    }
+  },
+  mounted () {
+    this.mounted = true
+  },
+  methods: {
+    addNewProject () {
+      this.addNewProjectLoading = true
+      APIGateway.project.create({
+        title: '-',
+        classroom: this.classroomId
+      })
+        .then(() => {
+          this.$refs.projectList.search()
+          this.addNewProjectLoading = false
+        })
+        .catch(() => {
+          this.addNewProjectLoading = false
+        })
+    },
+    getRemoveMessage (row) {
+      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
+    }
+  }
+}
+</script>

+ 156 - 0
src/components/Widgets/Classroom/AdminClassroomShow/components/SessionList.vue

@@ -0,0 +1,156 @@
+<template>
+  <entity-index v-if="mounted"
+                ref="sessionList"
+                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 #toolbar>
+      <q-btn color="primary"
+             outline
+             :loading="addNewSessionLoading"
+             @click="addNewSession">
+        افزودن جلسه
+      </q-btn>
+    </template>
+    <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 === 'actions'">
+        <div class="action-column-entity-index">
+          <q-btn size="md"
+                 outline
+                 color="primary"
+                 label="بررسی"
+                 :to="{name: 'Admin.Classroom.Session.AttendanceSheetList', params: {classroom_id: classroomId, session_id: inputData.props.row.id}}"
+                 class="q-mr-md" />
+          <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" />
+</template>
+
+<script>
+import { EntityIndex } from 'quasar-crud'
+import ShamsiDate from 'src/assets/ShamsiDate.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
+
+export default {
+  name: 'SessionList',
+  components: {
+    DeleteBtn,
+    EntityIndex
+  },
+  props: {
+    classroomId: {
+      type: Number,
+      default: null
+    }
+  },
+  data () {
+    const classroomId = this.classroomId
+    return {
+      mounted: false,
+      addNewSessionLoading: false,
+
+      sessionListInputs: [
+        { type: 'hidden', name: 'classroom', value: classroomId, label: 'نام دوره', col: 'col-12' }
+      ],
+      sessionListApi: APIGateway.session.APIAdresses.base,
+      sessionListTable: {
+        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: 'creation_time',
+            required: true,
+            label: 'زمان شروع جلسه',
+            align: 'left',
+            field: row => row.beginning_time ? ShamsiDate.getDateTime(row.beginning_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: ''
+          }
+        ]
+      },
+      sessionListTableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      }
+    }
+  },
+  mounted () {
+    this.mounted = true
+  },
+  methods: {
+    addNewSession () {
+      this.addNewSessionLoading = true
+      APIGateway.session.create({
+        title: '-',
+        classroom: this.classroomId
+      })
+        .then(() => {
+          this.$refs.sessionList.search()
+          this.addNewSessionLoading = false
+        })
+        .catch(() => {
+          this.addNewSessionLoading = false
+        })
+    },
+    getRemoveMessage (row) {
+      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
+    }
+  }
+}
+</script>

+ 169 - 0
src/components/Widgets/SessionAttendanceSheet/AdminSessionAttendanceSheetList/AdminSessionAttendanceSheetList.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="AdminContentList"
+       :style="localOptions.style">
+    <breadcrumbs class="q-mb-xl"
+                 style="margin-top: 29px; margin-bottom: 19px;" />
+    <div class="flex justify-end">
+      <q-btn flat
+             color="grey"
+             @click="$router.go(-1)">
+        بازگشت
+        >
+      </q-btn>
+    </div>
+    <entity-index v-if="mounted"
+                  v-model:value="inputs"
+                  title="لیست محتواها"
+                  :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}">
+        <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.Content.Show', params: {id: inputData.props.row.id}}">
+            مشاهده جزییات
+          </q-btn>
+        </template>
+        <template v-else>
+          {{ inputData.col.value }}
+        </template>
+      </template>
+    </entity-index>
+  </div>
+</template>
+
+<script>
+import { EntityIndex } from 'quasar-crud'
+import { Ticket } from 'src/models/Ticket.js'
+import { mixinWidget } from 'src/mixin/Mixins.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import { Classroom } from 'src/models/Classroom.js'
+import Breadcrumbs from 'src/components/Widgets/Breadcrumbs/Breadcrumbs.vue'
+import { SessionAttendanceSheets } from 'src/models/SessionAttendanceSheets'
+
+export default {
+  name: 'AdminSessionAttendanceSheetList',
+  components: { EntityIndex, Breadcrumbs },
+  mixins: [mixinWidget],
+  data () {
+    const sessionId = this.$route.params.session_id
+    return {
+      classroom: new Classroom(),
+      api: APIGateway.sessionAttendanceSheets.APIAdresses.base,
+      tableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      },
+      inputs: [
+        { type: 'hidden', name: 'session', value: sessionId }
+      ],
+      table: {
+        columns: [
+          {
+            name: 'number',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: () => ''
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'شناسه',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'sender',
+            required: true,
+            label: 'نام و نام خانوادگی',
+            align: 'left',
+            field: row => row.owner.firstname + ' ' + row.owner.lastname
+          },
+          {
+            name: 'sender',
+            required: true,
+            label: 'کد ملی',
+            align: 'left',
+            field: row => row.owner.national_code
+          },
+          {
+            name: 'status',
+            required: true,
+            label: 'وضعیت تکلیف',
+            align: 'left',
+            field: row => (new SessionAttendanceSheets(row)).answer_status_info.label
+          },
+          {
+            name: 'status',
+            required: true,
+            label: 'نتیجه تکلیف',
+            align: 'left',
+            field: row => (new SessionAttendanceSheets(row)).is_answer_verified_info.label
+          },
+          {
+            name: 'action',
+            required: true,
+            label: 'جزییات',
+            align: 'left',
+            field: row => ''
+          }
+        ]
+      },
+      mounted: false,
+      createRouteName: ''
+    }
+  },
+  mounted() {
+    this.mounted = true
+    this.getClassroom()
+      .then(classroom => {
+        this.classroom = new Classroom(classroom)
+        this.$store.commit('AppLayout/updateBreadcrumbs', {
+          visible: true,
+          loading: false,
+          path: [
+            {
+              label: 'دوره های آموزشی',
+              to: { name: 'Admin.Classroom.Index' }
+            },
+            {
+              label: this.classroom.title,
+              to: { name: 'Admin.Classroom.Show', params: { id: this.$route.params.classroom_id } }
+            },
+            {
+              label: 'لیست حضور و غیاب',
+              to: { name: 'Admin.Classroom.Session.AttendanceSheetList', params: { classroom_id: this.$route.params.classroom_id, session_id: this.$route.params.session_id } }
+            }
+          ]
+        })
+      })
+  },
+  methods: {
+    getClassroom () {
+      return APIGateway.classroom.get(this.$route.params.classroom_id)
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.AdminContentList {
+  .more-action {
+    display: flex;
+    flex-flow: row;
+    justify-content: flex-end;
+    margin-bottom: 10px;
+  }
+}
+</style>

+ 21 - 0
src/components/Widgets/SessionAttendanceSheet/AdminSessionAttendanceSheetList/OptionPanel.vue

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

+ 40 - 1
src/models/SessionAttendanceSheets.js

@@ -4,12 +4,51 @@ class SessionAttendanceSheets extends Model {
   constructor (data) {
     super(data, [
       { key: 'id' },
+      { key: 'is_answer_verified' },
+      { key: 'answer_status' },
       { key: 'session' },
       { key: 'is_listen_part1' },
       { key: 'is_listen_part2' },
       { key: 'is_present_read_part1' },
       { key: 'is_present_read_part2' }
-    ])
+    ], {
+      status: {
+        infoKey: 'is_answer_verified_info',
+        enumListKey: 'is_answer_verifiedEnums',
+        enums: [
+          {
+            label: 'تایید شده',
+            value: true
+          },
+          {
+            label: 'تایید نشده',
+            value: false
+          },
+          {
+            label: '-',
+            value: null
+          }
+        ]
+      },
+      type: {
+        infoKey: 'answer_status_info',
+        enumListKey: 'answer_statusEnums',
+        enums: [
+          {
+            label: 'ارسال نشده',
+            value: 'NOT_SENT'
+          },
+          {
+            label: 'ارسال شده',
+            value: 'SENT'
+          },
+          {
+            label: 'بررسی شده',
+            value: 'REVIEWED'
+          }
+        ]
+      }
+    })
   }
 
   getLabel () {

+ 23 - 0
src/pages/Admin/Classroom/sessionActivitySheets.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.Content.Show',
+  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' } } }] } }]
+    }
+  },
+  created() {
+    this.currenSections = this.sections
+  }
+}
+</script>

+ 10 - 934
src/pages/Admin/Classroom/show.vue

@@ -1,947 +1,23 @@
 <template>
-  <div class="flex justify-end">
-    <q-btn flat
-           color="grey"
-           @click="$router.go(-1)">
-      بازگشت
-      >
-    </q-btn>
-  </div>
-  <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="projects"
-             label="پروژه‌ها" />
-      <q-tab name="movies2"
-             label="آزمون" />
-      <q-tab name="members"
-             label="اندیشه جویان" />
-      <q-tab name="activity_sheet"
-             label="فعالیت کلاسی" />
-      <q-tab name="live_streaming_url"
-             label="بخش آنلاین" />
-    </q-tabs>
-
-    <q-separator />
-
-    <q-tab-panels v-model="tab"
-                  animated>
-      <q-tab-panel name="classroomInfo"
-                   class="q-pa-none">
-        <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-mt-md">
-              <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"
-                   class="q-pa-none">
-        <entity-index v-if="mounted"
-                      ref="sessionList"
-                      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 #toolbar>
-            <q-btn color="primary"
-                   outline
-                   :loading="addNewSessionLoading"
-                   @click="addNewSession">
-              افزودن جلسه
-            </q-btn>
-          </template>
-          <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 === '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="projects"
-                   class="q-pa-none">
-        <entity-index v-if="mounted"
-                      ref="projectList"
-                      v-model:value="projectListInputs"
-                      title="لیست پروژه ها"
-                      :api="projectListApi"
-                      :table="projectListTable"
-                      :table-keys="projectListTableKeys"
-                      :show-search-button="false"
-                      :show-reload-button="false"
-                      :show-expand-button="false">
-          <template #toolbar>
-            <q-btn color="primary"
-                   outline
-                   :loading="addNewProjectLoading"
-                   @click="addNewProject">
-              افزودن پروژه جدید
-            </q-btn>
-          </template>
-          <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 === 'actions'">
-              <div class="action-column-entity-index">
-                <q-btn size="md"
-                       color="primary"
-                       label="جزییات"
-                       :to="{name: 'Admin.Classroom.Project.Show', params: {id: $route.params.id, project_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-if="inputData.col.name === 'members'">
-              <div class="action-column-entity-index">
-                <q-btn size="md"
-                       color="primary"
-                       outline
-                       label="بررسی پروژه"
-                       :to="{name: 'Admin.Classroom.Project.Members', params: {id: $route.params.id, project_id: inputData.props.row.id}}"
-                       class="q-mr-md" />
-              </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="movies2">
-        آزمون
-      </q-tab-panel>
-      <q-tab-panel name="members"
-                   class="q-pa-none">
-        <entity-index v-if="mounted"
-                      ref="membersList"
-                      v-model:value="membersListInputs"
-                      title="لیست کاربران"
-                      :api="membersListApi"
-                      :table="membersListTable"
-                      :table-keys="membersListTableKeys"
-                      :show-search-button="false"
-                      :show-reload-button="false"
-                      :show-expand-button="false">
-          <template #toolbar>
-            <q-btn color="primary"
-                   :loading="exportReportLoading"
-                   @click="getMembersExcel">
-              خروجی اکسل
-            </q-btn>
-          </template>
-          <template v-slot:entity-index-table-cell="{inputData}">
-            <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 v-if="inputData.props.row.status !== 'DROPPED_BY_ADMIN' && inputData.props.row.status !== 'DROPPED_BY_ITSELF'"
-                       size="md"
-                       color="red"
-                       outline
-                       label="انصراف"
-                       :loading="dropClassroomByAdminLoading"
-                       class="q-mr-md"
-                       @click="dropClassroomByAdmin(inputData.props.row)" />
-                <q-btn v-if="inputData.props.row.status === 'ENROLLED'"
-                       size="md"
-                       color="primary"
-                       outline
-                       label="ایجاد صورتحساب"
-                       :loading="createInvoiceLoading"
-                       class="q-mr-md"
-                       @click="createInvoiceForClassroom(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="activity_sheet"
-                   class="q-pa-none">
-        <entity-index v-if="mounted"
-                      ref="activitySheetList"
-                      v-model:value="activitySheetListInputs"
-                      title="فعالیت کلاسی"
-                      :api="activitySheetListApi"
-                      :table="activitySheetListTable"
-                      :table-keys="activitySheetListTableKeys"
-                      :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"
-                       outline
-                       label="سابقه آموزشی"
-                       class="q-mr-md" />
-                <!--                :to="{name: 'Admin.Session.Show', params: {id: inputData.props.row.id}}"-->
-                <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="live_streaming_url">
-        <q-btn class="full-width q-mb-lg"
-               color="primary"
-               @click="goToLiveStreamUrl">
-          رفتن به کلاس
-        </q-btn>
-        <iframe :src="classroom.live_streaming_url"
-                title="W3Schools Free Online Web Tutorials"
-                style="height: 80vh"
-                class="full-width" />
-      </q-tab-panel>
-    </q-tab-panels>
-  </q-card>
+  <q-page-builder v-model:sections="currenSections"
+                  v-model:options="pageConfig"
+                  :editable="pageBuilderEditable"
+                  :loading="pageBuilderLoading" />
 </template>
 
 <script>
-import { shallowRef } from 'vue'
-import Assist from 'src/assets/js/Assist.js'
-import Enums from 'src/assets/Enums/Enums.js'
-import ShamsiDate from 'src/assets/ShamsiDate.js'
-import { APIGateway } from 'src/api/APIGateway.js'
-import { Classroom } from 'src/models/Classroom.js'
-import { EntityEdit, EntityIndex } from 'quasar-crud'
-import { FormBuilderAssist } from 'quasar-form-builder'
-import BtnControl from 'src/components/Control/btn.vue'
-import DeleteBtn from 'src/components/Control/DeleteBtn.vue'
-import { Project } from 'src/models/Project'
-
-const BtnControlComp = shallowRef(BtnControl)
+import { mixinPageOptions } from 'src/mixin/Mixins.js'
 
 export default {
   name: 'Admin.Classroom.Show',
-  components: {
-    EntityEdit,
-    EntityIndex,
-    DeleteBtn
-  },
-  data () {
-    const classroomId = this.$route.params.id
+  mixins: [mixinPageOptions],
+  data: () => {
     return {
-      mounted: false,
-      addNewSessionLoading: false,
-      addNewProjectLoading: false,
-      createInvoiceLoading: 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: '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_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.classroomGenders, 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: 'امکان حذف در بازه پیش ثبت نام', col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_adding_on_registration_period', responseKey: 'allow_adding_on_registration_period', label: 'امکان اضافه کردن در بازه ثبت نام', col: 'col-md-3 col-12' },
-        { type: 'checkbox', name: 'allow_dropping_on_registration_period', responseKey: 'allow_dropping_on_registration_period', label: 'امکان حذف ثبت نام در بازه ثبت نام', 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: 'امکان اضافه شدن در بازه حذف و اضافه', 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: '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: 'inputEditor', name: 'description', responseKey: 'description', label: 'توضیحات', col: 'col-12' },
-        { type: 'inputEditor', name: 'specification', responseKey: 'specification', label: 'مشخصات', col: 'col-12' },
-        { type: 'inputEditor', 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' }
-      ],
-      classroom: new Classroom(),
-
-      sessionListInputs: [
-        { type: 'hidden', name: 'classroom', value: this.$route.params.id, label: 'نام دوره', col: 'col-12' }
-      ],
-      sessionListApi: APIGateway.session.APIAdresses.base,
-      sessionListTable: {
-        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: 'creation_time',
-            required: true,
-            label: 'زمان شروع جلسه',
-            align: 'left',
-            field: row => row.beginning_time ? ShamsiDate.getDateTime(row.beginning_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: ''
-          }
-        ]
-      },
-      sessionListTableKeys: {
-        data: 'results',
-        total: 'count',
-        currentPage: 'current',
-        perPage: 'per_page',
-        pageKey: 'page'
-      },
-
-      projectListInputs: [
-        { type: 'hidden', name: 'classroom', value: this.$route.params.id }
-      ],
-      projectListApi: APIGateway.project.APIAdresses.base,
-      projectListTable: {
-        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: 'type',
-            required: true,
-            label: 'نوع',
-            align: 'left',
-            field: row => (new Project(row)).typeEnums
-          },
-          {
-            name: 'creation_time',
-            required: true,
-            label: 'زمان شروع پروژه',
-            align: 'left',
-            field: row => row.beginning_doing_period ? ShamsiDate.getDateTime(row.beginning_doing_period) : '-'
-          },
-          {
-            name: 'creation_time',
-            required: true,
-            label: 'مهلت ارسال پروژه',
-            align: 'left',
-            field: row => row.ending_doing_period ? ShamsiDate.getDateTime(row.ending_doing_period) : '-'
-          },
-          {
-            name: 'members',
-            required: true,
-            label: 'بررسی',
-            align: 'left',
-            field: ''
-          },
-          {
-            name: 'actions',
-            required: true,
-            label: 'عملیات',
-            align: 'left',
-            field: ''
-          }
-        ]
-      },
-      projectListTableKeys: {
-        data: 'results',
-        total: 'count',
-        currentPage: 'current',
-        perPage: 'per_page',
-        pageKey: 'page'
-      },
-
-      dropClassroomByAdminLoading: false,
-      exportReportLoading: false,
-      membersListInputs: [
-        { type: 'hidden', name: 'classroom', value: classroomId },
-        { type: 'select', name: 'status', options: [{ label: 'ثبت نام شده', value: 'REGISTERED' }, { label: 'پیش ثبت نام شده', value: 'ENROLLED' }, { label: 'حذف توسط اندیشه جو', value: 'DROPPED_BY_ITSELF' }, { label: 'حذف توسط ادمین', value: 'DROPPED_BY_ADMIN' }], label: 'وضعیت', placeholder: ' ', col: 'col-md-3 col-12' },
-        { type: 'select', name: 'invoice__status', options: [{ label: 'پرداخت کامل', value: 'PAID_FULL' }, { label: 'پرداخت قسطی', value: 'PAYING_IN_INSTALMENT' }], label: 'نوع صورتحساب', placeholder: ' ', col: 'col-md-3 col-12' },
-        { type: BtnControlComp, name: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-2 col-12' }
-      ],
-      membersListApi: APIGateway.classroom.APIAdresses.members,
-      membersListTable: {
-        columns: [
-          {
-            name: 'number',
-            required: true,
-            label: 'شماره',
-            align: 'left',
-            field: () => ''
-          },
-          {
-            name: 'id',
-            required: true,
-            label: 'شناسه',
-            align: 'left',
-            field: row => row.id
-          },
-          {
-            name: 'owner_info.fullname',
-            required: true,
-            label: 'نام و نام خانوادگی',
-            align: 'left',
-            field: row => row.owner_info.firstname + ' ' + row.owner_info.lastname
-          },
-          {
-            name: 'owner_info.national_code',
-            required: true,
-            label: 'کد ملی',
-            align: 'left',
-            field: row => row.owner_info.national_code
-          },
-          {
-            name: 'owner_info.mobile_number',
-            required: true,
-            label: 'تلفن همراه',
-            align: 'left',
-            field: row => row.owner_info.mobile_number
-          },
-          {
-            name: 'owner_info.email',
-            required: true,
-            label: 'ایمیل',
-            align: 'left',
-            field: row => row.owner_info.email
-          },
-          {
-            name: 'owner_info.email',
-            required: true,
-            label: 'وضعیت',
-            align: 'left',
-            field: row => (new Classroom()).getUserRegisterInfoLabel(row.status)
-          },
-          {
-            name: 'action',
-            required: true,
-            label: ' ',
-            align: 'left',
-            field: ''
-          }
-        ],
-        data: []
-      },
-      membersListTableKeys: {
-        data: 'results',
-        total: 'count',
-        currentPage: 'current',
-        perPage: 'per_page',
-        pageKey: 'page'
-      },
-
-      activitySheetListInputs: [
-        { type: 'hidden', name: 'classroom', value: classroomId },
-        { type: 'select', name: 'status', value: null, label: 'وضعیت', placeholder: ' ', col: 'col-md-3 col-12' },
-        { type: BtnControlComp, name: 'btn', label: 'جستجو', placeholder: ' ', atClick: () => {}, col: 'col-md-2 col-12' }
-      ],
-      activitySheetListApi: APIGateway.classroom.APIAdresses.activitySheet,
-      activitySheetListTable: {
-        columns: [
-          {
-            name: 'id',
-            required: true,
-            label: 'شماره',
-            align: 'left',
-            field: row => row.id
-          },
-          {
-            name: 'owner_info.fullname',
-            required: true,
-            label: 'نام و نام خانوادگی',
-            align: 'left',
-            field: row => row.owner_info.firstname + ' ' + row.owner_info.lastname
-          },
-          {
-            name: 'owner_info.fullname',
-            required: true,
-            label: 'کد ملی',
-            align: 'left',
-            field: row => row.owner_info.national_code
-          },
-          {
-            name: 'is_project_done',
-            required: true,
-            label: 'پروژه',
-            align: 'left',
-            field: row => row.is_project_done
-          },
-          {
-            name: 'done_assignment_count',
-            required: true,
-            label: 'تکالیف انجام شده',
-            align: 'left',
-            field: row => row.done_assignment_count
-          },
-          {
-            name: 'is_allowed_absence_count',
-            required: true,
-            label: 'حضور و غیاب',
-            align: 'left',
-            field: row => row.is_allowed_absence_count // bool
-          },
-          {
-            name: 'attendance_score',
-            required: true,
-            label: 'نمره حضور و غیاب',
-            align: 'left',
-            field: row => row.attendance_score
-          },
-          {
-            name: 'final_test',
-            required: true,
-            label: 'آزمون',
-            align: 'left',
-            field: row => row.final_test // number - null
-          },
-          {
-            name: 'final_status',
-            required: true,
-            label: 'وضعیت نهایی',
-            align: 'left',
-            field: row => row.final_status
-          },
-          {
-            name: 'actions',
-            required: true,
-            label: 'سابقه آموزشی',
-            align: 'left',
-            field: ''
-          }
-        ],
-        data: []
-      },
-      activitySheetListTableKeys: {
-        data: 'results',
-        total: 'count',
-        currentPage: 'current',
-        perPage: 'per_page',
-        pageKey: 'page'
-      }
-    }
-  },
-  computed: {
-    selectedCategoryId () {
-      return this.getInputValue('category')
+      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' } } }] } }]
     }
   },
-  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.setMembersListActionBtn()
-    this.setActivitySheetListActionBtn()
-    this.preLoadData()
-      .then(() => {
-        this.mounted = true
-      })
-      .catch(() => {
-        this.mounted = true
-      })
-  },
-  methods: {
-    addNewSession () {
-      this.addNewSessionLoading = true
-      APIGateway.session.create({
-        title: '-',
-        classroom: this.$route.params.id
-      })
-        .then(() => {
-          this.$refs.sessionList.search()
-          this.addNewSessionLoading = false
-        })
-        .catch(() => {
-          this.addNewSessionLoading = false
-        })
-    },
-    addNewProject () {
-      this.addNewProjectLoading = true
-      APIGateway.project.create({
-        title: '-',
-        classroom: this.$route.params.id
-      })
-        .then(() => {
-          this.$refs.projectList.search()
-          this.addNewProjectLoading = false
-        })
-        .catch(() => {
-          this.addNewProjectLoading = false
-        })
-    },
-    setMembersListActionBtn () {
-      FormBuilderAssist.setAttributeByName(this.membersListInputs, 'btn', 'atClick', this.searchMembersList)
-    },
-    setActivitySheetListActionBtn () {
-      FormBuilderAssist.setAttributeByName(this.activitySheetListInputs, 'btn', 'atClick', this.searchActivitySheetList)
-    },
-    searchMembersList () {
-      this.$refs.membersList.search()
-    },
-    searchActivitySheetList () {
-      this.$refs.activitySheet.search()
-    },
-    goToLiveStreamUrl () {
-      window.open(this.classroom.live_streaming_url, '_blank')
-    },
-    afterLoadInputData (data) {
-      this.classroom = new Classroom(data)
-      // 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()
-    },
-    getMembersExcel () {
-      this.exportReportLoading = true
-      const status = FormBuilderAssist.getInputsByName(this.membersListInputs, 'status').value ? FormBuilderAssist.getInputsByName(this.membersListInputs, 'status').value : null
-      APIGateway.registration.exportReport({
-        classroom: this.$route.params.id,
-        type: 'users',
-        status
-      })
-        .then((xlsxData) => {
-          Assist.saveXlsx(xlsxData, this.classroom.title)
-          this.exportReportLoading = false
-        })
-        .catch((e) => {
-          this.exportReportLoading = false
-        })
-    },
-    getRemoveMessage (row) {
-      return 'آیا از حذف ' + row.title + ' اطمینان دارید؟'
-    },
-    dropClassroomByAdmin (row) {
-      const classroomId = row.classroom
-      const userId = row.owner
-      const message = 'آیا از انصراف (' + row.owner_info.firstname + ' ' + row.owner_info.lastname + ') اطمینان دارید؟'
-      this.$q.dialog({
-        title: 'توجه',
-        message,
-        html: true,
-        cancel: true,
-        persistent: true
-      }).onOk(() => {
-        this.dropClassroomByAdminLoading = true
-        APIGateway.classroom.dropByAdmin(classroomId, userId)
-          .then(() => {
-            this.dropClassroomByAdminLoading = false
-            this.searchMembersList()
-          })
-          .catch(() => {
-            this.dropClassroomByAdminLoading = false
-          })
-      })
-    },
-    createInvoiceForClassroom (row) {
-      const classroomId = row.classroom
-      const userId = row.owner
-      this.createInvoiceLoading = true
-      APIGateway.classroom.createInvoiceByAdmin(classroomId, userId)
-        .then((invoice) => {
-          this.$router.push({ name: 'Admin.Invoice.Show', params: { id: invoice.id } })
-          this.createInvoiceLoading = false
-        })
-        .catch(() => {
-          this.createInvoiceLoading = false
-        })
-    }
+  created() {
+    this.currenSections = this.sections
   }
 }
 </script>
-
-<style lang="scss" scoped>
-.AdminClassroomShow {
-  .action-column-entity-index {
-    display: flex;
-    align-items: center;
-    justify-content: flex-start;
-  }
-}
-</style>

+ 1 - 1
src/pages/Admin/Content/Show.vue

@@ -9,7 +9,7 @@
 import { mixinPageOptions } from 'src/mixin/Mixins.js'
 
 export default {
-  name: 'AdminPanel.Package.Show',
+  name: 'Admin.Content.Show',
   mixins: [mixinPageOptions],
   data: () => {
     return {

+ 1 - 0
src/router/routes.js

@@ -552,6 +552,7 @@ const routes = [
               { name: 'Admin.Classroom.Index', path: '', component: () => import('src/pages/Admin/Classroom/index.vue') },
               { name: 'Admin.Classroom.Create', path: 'create', component: () => import('src/pages/Admin/Classroom/create.vue'), breadcrumbs: { title: 'ساخت دوره آموزشی' } },
               { name: 'Admin.Classroom.Show', path: ':id', component: () => import('src/pages/Admin/Classroom/show.vue'), breadcrumbs: { title: 'مشاهده اطلاعات دوره آموزشی' } },
+              { name: 'Admin.Classroom.Session.AttendanceSheetList', path: ':classroom_id/session/:session_id', component: () => import('src/pages/Admin/Classroom/sessionActivitySheets.vue') },
               // { name: 'Admin.Classroom.Project.Create', path: ':id/project/create', component: () => import('src/pages/Admin/Classroom/project/create.vue'), breadcrumbs: { title: 'ساخت دوره آموزشی' } },
               { name: 'Admin.Classroom.Project.Show', path: ':id/project/:project_id', component: () => import('src/pages/Admin/Classroom/project/show.vue'), breadcrumbs: { title: 'مشاهده اطلاعات دوره آموزشی' } },
               { name: 'Admin.Classroom.Project.Members', path: ':id/project/:project_id/members', component: () => import('src/pages/Admin/Classroom/project/members.vue'), breadcrumbs: { title: 'مشاهده اطلاعات دوره آموزشی' } },