Browse Source

fixed #380

ali 2 years ago
parent
commit
bfb7721c28

+ 1 - 1
package.json

@@ -46,7 +46,7 @@
     "process": "^0.11.10",
     "quasar": "^2.14.2",
     "quasar-app-extension-q-page-builder": "^0.4.4",
-    "quasar-crud": "^2.1.12",
+    "quasar-crud": "^2.2.0",
     "quasar-form-builder": "^2.4.7",
     "quasar-template-builder": "^1.0.23",
     "quasar-ui-q-page-builder": "^0.4.4",

+ 34 - 0
src/api/models/Basket.js

@@ -9,6 +9,7 @@ export default class BasketAPI extends APIRepository {
     this.APIAdresses = {
       base: '/store/baskets',
       checkoutReview: '/store/baskets/checkout_review',
+      listOrders: '/store/baskets/list_orders',
       byId: (id) => '/store/baskets/' + id,
       send: (id) => '/store/baskets/' + id + '/send',
       createInvoice: (id) => '/store/baskets/' + id + '/create_invoice',
@@ -61,6 +62,39 @@ export default class BasketAPI extends APIRepository {
     })
   }
 
+  listOrders(data) {
+    return this.sendRequest({
+      apiMethod: 'get',
+      api: this.api,
+      request: this.APIAdresses.listOrders,
+      data: this.getNormalizedSendData({
+        category: null, // Number
+        per_page: 10, // Number
+        page: 1 // Number
+      }, data),
+      resolveCallback: (response) => {
+        const paginate = response.data
+        const results = response.data.results
+        delete paginate.results
+        return {
+          list: new BasketList(results),
+          paginate
+          // {
+          //   "count": 1,
+          //   "num_pages": 1,
+          //   "per_page": 10,
+          //   "current": 1,
+          //   "next": null,
+          //   "previous": null,
+          // }
+        }
+      },
+      rejectCallback: (error) => {
+        return error
+      }
+    })
+  }
+
   get (id) {
     return this.sendRequest({
       apiMethod: 'get',

+ 1 - 1
src/components/Template/SideBar/AdminPanelSideBar.vue

@@ -253,7 +253,7 @@ export default {
             {
               title: 'سفارشات',
               roles: ['superuser'],
-              routeName: 'Admin.Store.Package.List',
+              routeName: 'Admin.Store.Basket.List',
               show: true,
               active: false
             },

+ 157 - 0
src/components/Widgets/Store/Basket/AdminStoreBasketList/AdminStoreBasketList.vue

@@ -0,0 +1,157 @@
+<template>
+  <div class="AdminBasketList"
+       :style="localOptions.style">
+    <div v-if="showBackBtn"
+         class="more-action">
+      <q-btn color="primary">
+        <q-icon name="file_download" />
+        دریافت
+      </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 === 'thumbnail'">
+          <q-img :src="inputData.col.value"
+                 width="100px" />
+        </template>
+        <template v-else-if="inputData.col.name === 'action'">
+          <q-btn color="primary"
+                 :to="{name: 'Admin.Store.Basket.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 { Basket } from 'src/models/Basket.js'
+import { mixinWidget } from 'src/mixin/Mixins.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import Assist from 'assets/js/Assist'
+
+export default {
+  name: 'AdminBasketList',
+  components: { EntityIndex },
+  mixins: [mixinWidget],
+  props: {
+    showBackBtn: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data () {
+    return {
+      api: APIGateway.basket.APIAdresses.listOrders,
+      tableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      },
+      inputs: [],
+      table: {
+        columns: [
+          {
+            name: 'number',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: () => ''
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'شناسه',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'owner_info',
+            required: true,
+            label: 'نام خریدار',
+            align: 'left',
+            field: row => row.owner_info?.firstname + ' ' + row.owner_info?.lastname
+          },
+          {
+            name: 'items_info_length',
+            required: true,
+            label: 'تعداد اقلام',
+            align: 'left',
+            field: row => row.items_info.length
+          },
+          {
+            name: 'order_type',
+            required: true,
+            label: 'نوع سفارش',
+            align: 'left',
+            field: () => '-'
+          },
+          {
+            name: 'overall_order_price',
+            required: true,
+            label: 'قیمت کل(تومان)',
+            align: 'left',
+            field: row => row.overall_order_price.toString().toLocaleString('fa')
+          },
+          {
+            name: 'status',
+            required: true,
+            label: 'وضعیت',
+            align: 'left',
+            field: row => (new Basket(row)).status_info.label
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'تاریخ ثبت',
+            align: 'left',
+            field: row => Assist.miladiToShamsi(row.creation_time)
+          },
+          {
+            name: 'action',
+            required: true,
+            label: 'جزییات',
+            align: 'left',
+            field: row => ''
+          }
+        ]
+      },
+      mounted: false,
+      createRouteName: ''
+    }
+  },
+  mounted() {
+    this.mounted = true
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.AdminBasketList {
+  .more-action {
+    display: flex;
+    flex-flow: row;
+    justify-content: flex-end;
+    margin-bottom: 10px;
+  }
+}
+</style>

+ 21 - 0
src/components/Widgets/Store/Basket/AdminStoreBasketList/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>

+ 288 - 0
src/components/Widgets/Store/Basket/AdminStoreBasketShow/AdminStoreBasketShow.vue

@@ -0,0 +1,288 @@
+<template>
+  <div class="AdminDiscountShow"
+       :style="localOptions.style">
+    <div class="flex justify-end">
+      <q-btn flat
+             color="grey"
+             @click="$router.go(-1)">
+        بازگشت
+        >
+      </q-btn>
+    </div>
+    <entity-show v-if="mounted"
+                 v-model:value="inputs"
+                 title="جزییات صورتحساب"
+                 :api="api"
+                 :entity-id-key="entityIdKey"
+                 :entity-param-key="entityParamKey"
+                 :show-close-button="false"
+                 :show-edit-button="false"
+                 :show-expand-button="false"
+                 :show-reload-button="false"
+                 :show-index-button="false"
+                 :after-load-input-data="afterLoadInputData">
+      <template #before-form-builder>
+        <div class="basket-form-header row">
+          <div class="col-md-4 col-12 flex justify-start items-center">
+            <q-icon name="shopping_cart" />
+            شناسه:
+            {{ basket.id }}
+          </div>
+          <div class="col-md-8 col-12">
+            <span class="text-info">
+              {{ basket.status_info.label }}
+            </span>
+            <q-linear-progress :value="basketStatusProgress"
+                               color="info"
+                               size="16px"
+                               rounded
+                               class="q-mt-سپ" />
+          </div>
+        </div>
+      </template>
+    </entity-show>
+
+    <div class="q-mt-md">
+      <entity-index v-if="basket.id"
+                    v-model:value="tableInputs"
+                    title="لیست محصولات سفارش"
+                    :table="table"
+                    :loaded-data="basket"
+                    :table-keys="tableKeys"
+                    :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 === 'thumbnail'">
+            <q-img :src="inputData.col.value"
+                   width="100px" />
+          </template>
+          <template v-else-if="inputData.col.name === 'action'">
+            <q-btn color="primary"
+                   outline
+                   :to="{name: inputData.props.row.product ? 'Admin.Store.Product.Show' : 'Admin.Store.Package.Show', params: {id: inputData.props.row.product || inputData.props.row.package}}">
+              <q-icon name="visibility"
+                      class="q-mr-sm" />
+              مشاهده
+            </q-btn>
+          </template>
+          <template v-else>
+            {{ inputData.col.value }}
+          </template>
+        </template>
+      </entity-index>
+    </div>
+  </div>
+</template>
+
+<script>
+import { shallowRef } from 'vue'
+import { Basket } from 'src/models/Basket.js'
+import { Product } from 'src/models/Product.js'
+import { mixinWidget } from 'src/mixin/Mixins.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+import BtnControl from 'components/Control/btn.vue'
+import { EntityShow, EntityIndex } from 'quasar-crud'
+import { FormBuilderAssist } from 'quasar-form-builder'
+import { Package } from 'src/models/Package'
+
+const BtnControlComp = shallowRef(BtnControl)
+
+export default {
+  name: 'AdminStoreBasketShow',
+  components: {
+    EntityShow,
+    EntityIndex
+  },
+  mixins: [mixinWidget],
+  data () {
+    return {
+      mounted: false,
+      entityLoading: true,
+      api: APIGateway.basket.APIAdresses.byId(this.$route.params.id),
+      entityIdKey: 'id',
+      entityParamKey: 'id',
+      indexRouteName: 'Admin.Store.Basket.List',
+      inputs: [
+        { type: 'separator', name: 'space1', label: 'مشخصات خریدار', className: 'custom-separator', col: 'col-12' },
+        { type: 'input', name: 'owner_info.firstname', responseKey: 'owner_info.firstname', label: 'نام', placeholder: ' ', col: 'col-md-2 col-12' },
+        { type: 'input', name: 'owner_info.lastname', responseKey: 'owner_info.lastname', label: 'نام خانوادگی', placeholder: ' ', col: 'col-md-2 col-12' },
+        { type: 'input', name: 'owner_info.national_code', responseKey: 'owner_info.national_code', label: 'کد ملی', placeholder: ' ', col: 'col-md-2 col-12' },
+        { type: 'input', name: 'owner_info.phone_number', responseKey: 'owner_info.phone_number', label: 'تلفن همراه', placeholder: ' ', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'owner_info.email', responseKey: 'owner_info.email', label: 'ایمیل', placeholder: ' ', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'owner_info.living_city', responseKey: 'owner_info.living_city', label: 'شهر', placeholder: ' ', col: 'col-md-2 col-12' },
+        { type: 'input', name: 'postal_code', responseKey: 'postal_code', label: 'کد پستی', placeholder: ' ', col: 'col-md-2 col-12' },
+        { type: 'input', name: 'owner_info.living_address', responseKey: 'owner_info.living_address', label: 'آدرس', placeholder: ' ', col: 'col-md-5 col-12' },
+        { type: BtnControlComp, name: 'btn', responseKey: 'btn', label: 'مشخصات کاربر', placeholder: ' ', outline: true, ignoreValue: true, atClick: this.showUserPage, col: 'col-md-2 col-12' },
+
+        { type: 'separator', name: 'space1', label: 'مشخصات سفارش', className: 'custom-separator', col: 'col-12' },
+        { type: 'input', name: 'id', responseKey: 'id', label: 'شناسه', placeholder: ' ', col: 'col-md-3 col-12' },
+        { type: 'input', name: 'items_info.length', responseKey: 'items_info.length', label: 'تعداد اقلام', placeholder: ' ', col: 'col-md-3 col-12' },
+        { type: 'dateTime', name: 'creation_time', responseKey: 'creation_time', outsideLabel: 'تاریخ ثبت', placeholder: ' ', disable: true, col: 'col-md-3 col-12' },
+        { type: 'input', name: 'overall_order_price', responseKey: 'overall_order_price', label: 'قیمت کل(تومان)', placeholder: ' ', col: 'col-md-3 col-12' }
+      ],
+
+      tableKeys: {
+        data: 'items_info.list',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      },
+      tableInputs: [],
+      table: {
+        columns: [
+          {
+            name: 'number',
+            required: true,
+            label: 'شماره',
+            align: 'left',
+            field: () => ''
+          },
+          {
+            name: 'id',
+            required: true,
+            label: 'شناسه',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'title',
+            required: true,
+            label: 'نام محصول',
+            align: 'left',
+            field: row => (row.product_info || row.package_info).title
+          },
+          {
+            name: 'is_package_or_product',
+            required: true,
+            label: 'نوع محصول',
+            align: 'left',
+            field: row => row.package ? 'بسته' : 'تکی'
+          },
+          {
+            name: 'content_category',
+            required: true,
+            label: 'دسته بندی اصلی',
+            align: 'left',
+            field: row => row.content_category
+          },
+          {
+            name: 'count',
+            required: true,
+            label: 'تعداد',
+            align: 'left',
+            field: row => row.count
+          },
+          {
+            name: 'is_physical_info',
+            required: true,
+            label: 'نوع جنس',
+            align: 'left',
+            field: row => row.product_info ? (new Product(row.product_info)).is_physical_info.label : (new Package(row.product_info)).is_physical_info.label
+          },
+          {
+            name: 'physical_type_info',
+            required: true,
+            label: 'نوع محصول',
+            align: 'left',
+            field: row => row.product_info ? (new Product(row.product_info)).physical_type_info.label : '-'
+          },
+          {
+            name: 'unit_price',
+            required: true,
+            label: 'قیمت',
+            align: 'left',
+            field: row => parseInt((row.product_info || row.package_info).unit_price.toString()).toLocaleString('fa')
+          },
+          {
+            name: 'action',
+            required: true,
+            label: 'عملیات',
+            align: 'left',
+            field: row => ''
+          }
+        ]
+      },
+
+      basket: new Basket()
+    }
+  },
+  computed: {
+    basketStatusProgress () {
+      if (this.basket.status === 'OPEN') {
+        return 0.1
+      }
+      if (this.basket.status === 'CANCELED') {
+        return 0
+      }
+      if (this.basket.status === 'PAID') {
+        return 0.5
+      }
+      if (this.basket.status === 'CLOSED') {
+        return 1
+      }
+      if (this.basket.status === 'SENT') {
+        return 1
+      }
+      return 0.5
+    }
+  },
+  mounted() {
+    this.mounted = true
+  },
+  methods: {
+    showUserPage () {
+      const routeData = this.$router.resolve({ name: 'Admin.User.Show', params: { id: this.basket.owner } })
+      window.open(routeData.href, '_blank')
+    },
+    afterLoadInputData (data) {
+      this.entityLoading = false
+      this.basket = new Basket(data)
+      FormBuilderAssist.setAttributeByName(this.inputs, 'overall_order_price', 'value', data.overall_order_price.toLocaleString('fa'))
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.AdminDiscountShow {
+  .title {
+    font-style: normal;
+    font-weight: 700;
+    font-size: 24px;
+    line-height: 140%;
+    color: #424242;
+    margin-bottom: 27px;
+    display: flex;
+    flex-flow: row;
+    position: relative;
+    .static-title {
+
+    }
+    .dynamic-title {
+
+    }
+    .back-action {
+      position: absolute;
+      right: 0;
+      top: 0;
+    }
+  }
+  .basket-form-header {
+    background: #FCF9F4;
+    border: 1px solid #DFE1EC;
+    margin: -16px -16px 0  -16px;
+    padding: 16px 40px;
+    .q-icon {
+      color: #AAA095;
+    }
+  }
+  :deep(.form) {
+    padding: 24px;
+  }
+}
+</style>

+ 21 - 0
src/components/Widgets/Store/Basket/AdminStoreBasketShow/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>

+ 4 - 0
src/models/Basket.js

@@ -95,6 +95,10 @@ class Basket extends Model {
           {
             label: 'پرداخت شده',
             value: 'PAID'
+          },
+          {
+            label: 'ارسال شده',
+            value: 'SENT'
           }
         ]
       }

+ 23 - 0
src/pages/Admin/StoreBasket/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.Basket.List',
+  mixins: [mixinPageOptions],
+  data: () => {
+    return {
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminStoreBasketList' }], 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/StoreBasket/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.Basket.Show',
+  mixins: [mixinPageOptions],
+  data: () => {
+    return {
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'AdminStoreBasketShow' }], 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>

+ 9 - 0
src/router/routes/Admin.js

@@ -408,6 +408,15 @@ export default {
             { path: 'create', name: 'Admin.Store.Discount.Create', component: () => import('src/pages/Admin/StoreDiscount/Create.vue') },
             { path: ':id', name: 'Admin.Store.Discount.Show', component: () => import('src/pages/Admin/StoreDiscount/Show.vue') }
           ]
+        },
+        {
+          path: 'basket',
+          name: 'Admin.Store.Basket',
+          component: () => import('layouts/bareLayout.vue'),
+          children: [
+            { path: '', name: 'Admin.Store.Basket.List', component: () => import('src/pages/Admin/StoreBasket/List.vue') },
+            { path: ':id', name: 'Admin.Store.Basket.Show', component: () => import('src/pages/Admin/StoreBasket/Show.vue') }
+          ]
         }
       ]
     },

+ 4 - 4
yarn.lock

@@ -5074,10 +5074,10 @@ quasar-app-extension-q-page-builder@^0.4.4:
   dependencies:
     quasar-ui-q-page-builder "^0.4.4"
 
-quasar-crud@^2.1.12:
-  version "2.1.12"
-  resolved "https://registry.yarnpkg.com/quasar-crud/-/quasar-crud-2.1.12.tgz#a7e8adf22cd403c3cad504930ac3e07a23c057ca"
-  integrity sha512-lcLBEmPPaHC9pXvHPq2my/W0i1mTy18pxV1gpx2Q8h7vcXDc/rgxdkiHDS+LEb8JleGytc6x4nuv2BSz+ezE2Q==
+quasar-crud@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/quasar-crud/-/quasar-crud-2.2.0.tgz#d1c8fcec8572c6ca7c311786336abe876de5c615"
+  integrity sha512-TZcK3eQ2M7Dx08wlL8DFoKIhcBaApeOcWlKEGDCCAD+HP2CnAWTHzLSpV6p4GVNdxObsNgk9mC/ix8gjOebwMA==
   dependencies:
     "@quasar/extras" "^1.16.9"
     axios "^1.6.8"