Browse Source

see also #379

ali 2 năm trước cách đây
mục cha
commit
b0ea8ddbea

+ 299 - 40
src/components/Widgets/Store/Shop/Shop.vue

@@ -6,7 +6,88 @@
     </q-banner>
     <div class="shop-widget__content">
       <div class="shop-widget__sidebar">
-        shop-widget__sidebar
+        <div class="shop-widget__sidebar-header">
+          <div class="shop-widget__sidebar-header-title">
+            فیلترها
+          </div>
+          <q-btn flat
+                 class="shop-widget__sidebar-header-remove-filters">
+            <q-icon name="delete_outline" />
+            حذف فیلترها
+          </q-btn>
+        </div>
+        <div class="shop-widget__sidebar-selected-filters">
+          <div class="shop-widget__sidebar-selected-filter">
+            <div class="shop-widget__sidebar-selected-filter-title">
+              استاد مطهری
+            </div>
+            <q-btn class="shop-widget__sidebar-selected-filter-btn-remove"
+                   flat
+                   icon="close" />
+          </div>
+          <div class="shop-widget__sidebar-selected-filter">
+            <div class="shop-widget__sidebar-selected-filter-title">
+              سیر مطالعاتی
+            </div>
+            <q-btn class="shop-widget__sidebar-selected-filter-btn-remove"
+                   flat
+                   icon="close" />
+          </div>
+        </div>
+        <q-separator />
+        <div class="shop-widget__sidebar-price-filter">
+          <q-range v-model="filters.price"
+                   :min="0"
+                   :step="100"
+                   :max="1500000" />
+          <div class="shop-widget__sidebar-price-label">
+            <div class="shop-widget__sidebar-price-label-min">
+              از
+              {{ parseInt(filters.price.min.toString()).toLocaleString('fa') }}
+              تومان
+            </div>
+            <div class="shop-widget__sidebar-price-label-max">
+              تا
+              {{ parseInt(filters.price.max.toString()).toLocaleString('fa') }}
+              تومان
+            </div>
+          </div>
+        </div>
+        <q-separator />
+        <div class="shop-widget__sidebar-exist-filter">
+          <div class="shop-widget__sidebar-exist-label">
+            فقط محصولات موجود
+          </div>
+          <q-toggle v-model="filters.exist" />
+        </div>
+        <q-separator />
+        <div class="shop-widget__sidebar-category-filter">
+          <q-expansion-item expand-separator
+                            label="دسته بندی ها">
+            <q-tree v-model:ticked="filters.categories"
+                    class="col-12 col-sm-6"
+                    :nodes="simple"
+                    children-key="children"
+                    label-key="label"
+                    node-key="id"
+                    tick-strategy="leaf" />
+          </q-expansion-item>
+
+        </div>
+        <q-separator />
+        <div class="shop-widget__sidebar-type-filter">
+          <q-expansion-item expand-separator
+                            label="نوع">
+            <q-tree v-model:ticked="filters.categories"
+                    class="col-12 col-sm-6"
+                    :nodes="types"
+                    children-key="children"
+                    label-key="label"
+                    node-key="value"
+                    tick-strategy="leaf" />
+          </q-expansion-item>
+
+        </div>
       </div>
       <div class="shop-widget__main">
         <div class="shop-widget__main-top-filter">
@@ -44,7 +125,22 @@
           </div>
         </div>
         <div class="shop-widget__result">
-          shop-widget__result
+          <entity-index v-if="mounted"
+                        ref="entityIndex"
+                        v-model:value="inputs"
+                        :default-layout="false"
+                        :api="api"
+                        :table="table"
+                        :table-keys="tableKeys"
+                        :table-grid-size="true"
+                        :show-expand-button="false"
+                        :show-reload-button="false"
+                        :show-search-button="false">
+            <template #entity-index-table-item-cell="{inputData}">
+              <product-item class="shop-widget__result-product-item"
+                            :product="getProduct(inputData.props.row)" />
+            </template>
+          </entity-index>
         </div>
       </div>
     </div>
@@ -52,22 +148,129 @@
 </template>
 
 <script>
-// import { EntityIndex } from 'quasar-crud'
-import { Ticket } from 'src/models/Ticket.js'
+import { EntityIndex } from 'quasar-crud'
+import { Product } from 'src/models/Product.js'
 import { mixinWidget } from 'src/mixin/Mixins.js'
 import { APIGateway } from 'src/api/APIGateway.js'
+import ProductItem from './components/productItem.vue'
 
 export default {
   name: 'ContentList',
-  // components: { EntityIndex },
+  components: { EntityIndex, ProductItem },
   mixins: [mixinWidget],
-  data: () => {
+  data () {
     return {
       searchTab: 'product',
       filters: {
         search: null,
-        sort: 'sort1'
+        exist: false,
+        sort: 'sort1',
+        categories: [], // content_category
+        price: {
+          min: 100, // unit_price__gte
+          max: 1000000 // unit_price__lt
+        }
       },
+      simple: [
+        {
+          label: 'شهید مطهری',
+          id: 1,
+          children: [
+            {
+              label: 'سطح 6',
+              id: 11
+            },
+            {
+              label: 'سطح ۱',
+              id: 3,
+              children: [
+                {
+                  label: 'سطح ۲',
+                  id: 4,
+                  children: [
+                    {
+                      label: 'سطح ۳',
+                      id: 5
+                    },
+                    {
+                      label: 'سطح 4',
+                      id: 9
+                    },
+                    {
+                      label: 'سطح 5',
+                      id: 10
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        },
+        {
+          label: 'جریان شناسی',
+          id: 2,
+          children: [
+            {
+              label: 'سطح ۱',
+              id: 6,
+              children: [
+                {
+                  label: 'سطح ۲',
+                  id: 7,
+                  children: [
+                    {
+                      label: 'سطح ۳',
+                      id: 8
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        }
+      ],
+      types: [
+        {
+          label: 'مجازی',
+          value: 'virtual',
+          children: [
+            {
+              label: 'ویدیو',
+              value: 'VIDEO'
+            },
+            {
+              label: 'صوت',
+              value: 'SOUND'
+            },
+            {
+              label: 'متن',
+              value: 'TEXT'
+            },
+            {
+              label: 'تصویر',
+              value: 'IMAGE'
+            }
+          ]
+        },
+        {
+          label: 'فیزیکی',
+          value: 'physical',
+          children: [
+            {
+              label: 'کتاب',
+              value: 'BOOK'
+            },
+            {
+              label: 'جزوه',
+              value: 'MANUSCRIPT'
+            },
+            {
+              label: 'لوج فشرده',
+              value: 'CD'
+            }
+          ]
+        }
+      ],
       sortOptions: [
         {
           label: 'پرفروش ترین',
@@ -82,7 +285,7 @@ export default {
           value: 'sort3'
         }
       ],
-      api: APIGateway.ticket.APIAdresses.base,
+      api: APIGateway.product.APIAdresses.base,
       tableKeys: {
         data: 'results',
         total: 'count',
@@ -92,36 +295,7 @@ export default {
       },
       inputs: [],
       table: {
-        columns: [
-          {
-            name: 'title',
-            required: true,
-            label: 'موضوع پیام',
-            align: 'left',
-            field: row => row.title
-          },
-          {
-            name: 'sender',
-            required: true,
-            label: 'فرستنده',
-            align: 'left',
-            field: row => row.creator_info.firstname + ' ' + row.creator_info.lastname
-          },
-          {
-            name: 'status',
-            required: true,
-            label: 'وضعیت',
-            align: 'left',
-            field: row => (new Ticket(row)).status_info.label
-          },
-          {
-            name: 'action',
-            required: true,
-            label: 'جزییات',
-            align: 'left',
-            field: row => ''
-          }
-        ]
+        columns: []
       },
       mounted: false,
       createRouteName: ''
@@ -129,6 +303,11 @@ export default {
   },
   mounted() {
     this.mounted = true
+  },
+  methods: {
+    getProduct (data) {
+      return new Product(data)
+    }
   }
 }
 </script>
@@ -145,6 +324,77 @@ export default {
       background: #F6F6F6;
       border-radius: 20px;
       padding: 24px;
+      .shop-widget__sidebar-header {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        margin-bottom: 15px;
+        .shop-widget__sidebar-header-title {
+          font: normal normal medium 16px/21px AzarMehr;
+          letter-spacing: 0;
+        }
+        .shop-widget__sidebar-header-remove-filters {
+          color: #FF3D3D;
+        }
+      }
+      .shop-widget__sidebar-selected-filters {
+        display: flex;
+        gap: 8px;
+        justify-content: flex-start;
+        .shop-widget__sidebar-selected-filter {
+          border: 1px solid #ABABAB;
+          border-radius: 20px;
+          padding: 8px;
+          display: flex;
+          justify-content: space-between;
+          gap: 8px;
+          align-items: center;
+          background: #FFFFFF;
+          .shop-widget__sidebar-selected-filter-title {
+            font-size: 14px;
+            color: #212121;
+          }
+          :deep(.shop-widget__sidebar-selected-filter-btn-remove) {
+            @mixin set-btn-min-max () {
+              $btn-size: 20px;
+              max-height: $btn-size;
+              max-width: $btn-size;
+              min-width: $btn-size;
+              min-height: $btn-size;
+            }
+            padding: 1px;
+            @include set-btn-min-max;
+            .q-focus-helper {
+              @include set-btn-min-max;
+            }
+            .q-btn__content {
+              @include set-btn-min-max;
+              .q-icon {
+                font-size: 18px;
+              }
+            }
+          }
+        }
+      }
+      .q-separator {
+        margin: 18px 0;
+      }
+      .shop-widget__sidebar-price-filter {
+        .shop-widget__sidebar-price-label {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          font-size: 14px;
+          color: #212121;
+          .shop-widget__sidebar-price-label-min {}
+          .shop-widget__sidebar-price-label-max {}
+        }
+      }
+      .shop-widget__sidebar-exist-filter {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+      }
     }
     .shop-widget__main {
       width: calc( 100% - #{$sidebar-width} );
@@ -195,6 +445,7 @@ export default {
           padding: 12px 20px;
           border: 1px solid #DFE1EC;
           border-radius: 8px 8px 0 0;
+          margin-bottom: 27px;
           :deep(.q-tabs) {
             .q-tabs__content {
               .q-tab {
@@ -209,8 +460,16 @@ export default {
           }
         }
       }
-      .shop-widget__result {
-
+      :deep(.shop-widget__result) {
+        .quasar-crud-index-table {
+          .q-table__grid-content {
+            gap: 36px;
+            .shop-widget__result-product-item {
+              width: 33%;
+              flex: 0 0 auto;
+            }
+          }
+        }
       }
     }
   }

+ 113 - 0
src/components/Widgets/Store/Shop/components/productItem.vue

@@ -0,0 +1,113 @@
+<template>
+  <div class="product-item">
+    <div class="product-item__thumbnail">
+      <q-img :src="product.thumbnail" />
+    </div>
+    <div class="product-item__title">
+      {{ product.title }}
+    </div>
+    <div class="product-item__price">
+      <div class="product-item__price-base">
+        {{ parseInt(product.unit_price).toLocaleString('fa') }}
+        تومان
+      </div>
+      <div class="product-item__price-final">
+        {{ product.getFinalPrice() }}
+        تومان
+      </div>
+    </div>
+    <div class="product-item__actions">
+      <q-btn class="product-item__actions-view"
+             color="primary"
+             outline>
+        مشاهده جزییات
+      </q-btn>
+      <q-btn class="product-item__actions-add-to-cart"
+             color="primary">
+        افزودن به سبد
+      </q-btn>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Product } from 'src/models/Product.js'
+
+export default {
+  name: 'productItem',
+  props: {
+    product: {
+      type: Product,
+      default: new Product()
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.product-item {
+  background: #F6F6F6;
+  border: 1px solid #DFE1EC;
+  border-radius: 8px;
+  :deep(.product-item__thumbnail) {
+    transition: all 0.5s;
+    margin: 15px 58px 12px 58px;
+    .q-img {
+      width: 100%;
+    }
+  }
+  .product-item__title {
+    color: #212121;
+    width: 100%;
+    padding: 0 4px;
+    text-align: center;
+    font-size: 18px;
+    margin-bottom: 52px;
+  }
+  .product-item__price {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 0 20px;
+    margin-bottom: 43px;
+    .product-item__price-final {
+      font-size: 20px;
+      color: #475F4A;
+    }
+    .product-item__price-base {
+      font-size: 16px;
+      color: #FF3D3D;
+    }
+  }
+  .product-item__actions {
+    display: none;
+    margin: 0 25px 25px 25px;
+    .product-item__actions-view {
+      background: white;
+      margin-bottom: 20px;
+      width: 100%;
+    }
+    .product-item__actions-add-to-cart {
+      width: 100%;
+    }
+  }
+  &:hover {
+    :deep(.product-item__thumbnail) {
+      margin: 10px 105px 4px 105px;
+      .q-img {
+        width: 100%;
+      }
+    }
+    .product-item__title {
+      margin-bottom: 44px;
+    }
+    .product-item__price {
+      margin-bottom: 27px;
+    }
+    .product-item__actions {
+      display: flex;
+      flex-flow: column;
+    }
+  }
+}
+</style>

+ 13 - 3
src/models/Product.js

@@ -9,8 +9,14 @@ class Product extends Model {
       { key: 'inventory' },
       { key: 'store_category' },
       { key: 'content_category' },
-      { key: 'unit_price' },
-      { key: 'discount_percent' },
+      {
+        key: 'unit_price',
+        default: 0
+      },
+      {
+        key: 'discount_percent',
+        default: 0
+      },
       { key: 'description' },
       { key: 'maximum_order_count' },
       { key: 'is_physical' },
@@ -37,7 +43,7 @@ class Product extends Model {
         enumListKey: 'physical_typeEnums',
         enums: [
           {
-            label: 'سی دی',
+            label: 'لوج فشرده',
             value: 'CD'
           },
           {
@@ -56,6 +62,10 @@ class Product extends Model {
       this.thumbnail = '/img/sample-post-thumbnail.jpg'
     }
   }
+
+  getFinalPrice () {
+    return parseInt(this.unit_price * (100 - this.discount_percent)).toLocaleString('fa')
+  }
 }
 
 class ProductList extends Collection {

+ 23 - 0
src/pages/Admin/StorePackage/Create.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.Store.Package.Create',
+  mixins: [mixinPageOptions],
+  data: () => {
+    return {
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminStorePackageCreate' }], options: {} }], 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>

+ 23 - 0
src/pages/Admin/StorePackage/List.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.Store.Package.List',
+  mixins: [mixinPageOptions],
+  data: () => {
+    return {
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminStorePackageList' }], options: {} }], 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>

+ 23 - 0
src/pages/Admin/StorePackage/Show.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.Store.Package.Show',
+  mixins: [mixinPageOptions],
+  data: () => {
+    return {
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminStorePackageShow' }], options: {} }], 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>