Jelajahi Sumber

deposit wallet

ali 3 tahun lalu
induk
melakukan
dc39f42693

+ 2 - 0
src/api/APIGateway.js

@@ -7,6 +7,7 @@ import WalletAPI from 'src/api/models/Wallet.js'
 import InvoiceAPI from 'src/api/models/Invoice.js'
 import SessionAPI from 'src/api/models/Session.js'
 import ClassroomAPI from 'src/api/models/Classroom.js'
+import TransactionAPI from 'src/api/models/Transaction.js'
 import PageSettingAPI from 'src/api/models/PageSetting.js'
 import RegistrationAPI from 'src/api/models/Registration.js'
 import UnitCategoryAPI from 'src/api/models/UnitCategory.js'
@@ -24,6 +25,7 @@ export const APIGateway = {
   invoice: new InvoiceAPI(),
   session: new SessionAPI(),
   classroom: new ClassroomAPI(),
+  transaction: new TransactionAPI(),
   pageSetting: new PageSettingAPI(),
   registration: new RegistrationAPI(),
   unitCategory: new UnitCategoryAPI(),

+ 130 - 0
src/api/models/Transaction.js

@@ -0,0 +1,130 @@
+import { appApi } from 'src/boot/axios.js'
+import APIRepository from '../classes/APIRepository.js'
+import { Transaction, TransactionList } from 'src/models/Transaction.js'
+
+export default class TransactionAPI extends APIRepository {
+  constructor() {
+    super('invoice', appApi)
+    this.APIAdresses = {
+      base: '/accounting/invoices',
+      byId: (id) => '/accounting/invoices/' + id,
+      pay: (id) => '/accounting/invoices/' + id + '/pay'
+    }
+    this.CacheList = {
+      base: this.name + this.APIAdresses.base
+    }
+    this.restUrl = (id) => this.APIAdresses.base + '/' + id
+    /* Setting the callback functions for the CRUD operations. */
+    this.setCrudCallbacks({
+      get: (response) => { return new Transaction(response.data) },
+      post: (response) => { return new Transaction(response.data) },
+      put: (response) => { return new Transaction(response.data) },
+      delete: (response) => { return response.data }
+    })
+  }
+
+  index(data) {
+    return this.sendRequest({
+      apiMethod: 'get',
+      api: this.api,
+      request: this.APIAdresses.base,
+      data: this.getNormalizedSendData({
+        page: 1 // Number
+      }, data),
+      resolveCallback: (response) => {
+        const paginate = response.data
+        const results = response.data.results
+        delete paginate.results
+        return {
+          list: new TransactionList(results),
+          paginate
+          // {
+          //   "count": 1,
+          //   "num_pages": 1,
+          //   "per_page": 10,
+          //   "current": 1,
+          //   "next": null,
+          //   "previous": null,
+          // }
+        }
+      },
+      rejectCallback: (error) => {
+        return error
+      }
+    })
+  }
+
+  pay(invoiceId) {
+    return this.sendRequest({
+      apiMethod: 'put',
+      api: this.api,
+      request: this.APIAdresses.pay(invoiceId),
+      resolveCallback: (response) => {
+        return response.data.detail // String : message
+      },
+      rejectCallback: (error) => {
+        return error
+      }
+    })
+  }
+
+  createService (products = []) {
+    return this.sendRequest({
+      apiMethod: 'post',
+      api: this.api,
+      request: this.APIAdresses.base,
+      data: {
+        type: 'SERVICE', // String
+        products // Array of Object
+      },
+      resolveCallback: (response) => {
+        return new Transaction(response.data)
+      },
+      rejectCallback: (error) => {
+        return error
+      }
+    })
+  }
+
+  createBasket (basketType, basketId) {
+    return this.sendRequest({
+      apiMethod: 'post',
+      api: this.api,
+      request: this.APIAdresses.base,
+      data: {
+        type: basketType.toUpperCase(), // String
+        products: [
+          {
+            product_type: basketType + '_basket',
+            product_id: basketId,
+            count: 1
+          }
+        ]
+      },
+      resolveCallback: (response) => {
+        return new Transaction(response.data)
+      },
+      rejectCallback: (error) => {
+        return error
+      }
+    })
+  }
+
+  create (type, products = []) {
+    return this.sendRequest({
+      apiMethod: 'post',
+      api: this.api,
+      request: this.APIAdresses.base,
+      data: {
+        type, // String
+        products // Array of Object
+      },
+      resolveCallback: (response) => {
+        return new Transaction(response.data)
+      },
+      rejectCallback: (error) => {
+        return error
+      }
+    })
+  }
+}

+ 1 - 2
src/components/Template/SideBard/UserPanelSideBar.vue

@@ -111,8 +111,7 @@ export default {
             },
             {
               title: 'کیف پول الکترونیک',
-              scrollTo: '#introSection',
-              // routeName: 'Admin.User.Index',
+              routeName: 'UserPanel.Wallet',
               show: true,
               active: false
             }

+ 21 - 0
src/components/Widgets/Transaction/TransactionList/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>

+ 146 - 0
src/components/Widgets/Transaction/TransactionList/TransactionList.vue

@@ -0,0 +1,146 @@
+<template>
+  <div class="TransactionList"
+       :style="localOptions.style">
+    <div class="title">
+      لیست تراکنش ها
+    </div>
+    <q-card class="list"
+            flat>
+      <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"
+                    :default-layout="false">
+        <template #entity-index-table-cell="{inputData}">
+          <template v-if="inputData.col.name === 'action'">
+            <q-btn flat
+                   color="primary"
+                   :to="{name: 'UserPanel.Invoice.Show', params: {id: inputData.props.row.id}}">
+              مشاهده جزییات
+            </q-btn>
+          </template>
+          <template v-else>
+            {{ inputData.col.value }}
+          </template>
+        </template>
+      </entity-index>
+    </q-card>
+  </div>
+</template>
+
+<script>
+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'
+
+export default {
+  name: 'TransactionList',
+  components: { EntityIndex },
+  mixins: [mixinWidget],
+  data: () => {
+    return {
+      api: APIGateway.invoice.APIAdresses.base,
+      tableKeys: {
+        data: 'results',
+        total: 'count',
+        currentPage: 'current',
+        perPage: 'per_page',
+        pageKey: 'page'
+      },
+      inputs: [],
+      table: {
+        columns: [
+          {
+            name: 'id',
+            required: true,
+            label: 'صورت‌حساب',
+            align: 'left',
+            field: row => row.id
+          },
+          {
+            name: 'title',
+            required: true,
+            label: 'پکیج یا خدمت',
+            align: 'left',
+            field: row => row.title
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'تاریخ صورت‌حساب',
+            align: 'left',
+            field: row => Assist.miladiToShamsi(row.creation_time)
+          },
+          {
+            name: 'creation_time',
+            required: true,
+            label: 'تاریخ سررسید',
+            align: 'left',
+            field: row => Assist.miladiToShamsi(row.creation_time)
+          },
+          {
+            name: 'amount',
+            required: true,
+            label: 'کل',
+            align: 'left',
+            field: row => row.amount.toLocaleString('fa')
+          },
+          {
+            name: 'status',
+            required: true,
+            label: 'وضعیت',
+            align: 'left',
+            field: row => (new Invoice(row)).status_info.label
+          },
+          {
+            name: 'action',
+            required: true,
+            label: 'جزییات',
+            align: 'left',
+            field: row => ''
+          }
+        ]
+      },
+      mounted: false,
+      createRouteName: ''
+    }
+  },
+  mounted() {
+    this.mounted = true
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.TransactionList {
+  .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>

+ 175 - 0
src/components/Widgets/Wallet/MyWallet/MyWallet.vue

@@ -0,0 +1,175 @@
+<template>
+  <div class="MyWallet"
+       :style="localOptions.style">
+    <div class="header">
+      جزییات کیف پول
+    </div>
+    <div class="body">
+      <div class="card-column">
+        <div class="card">
+          <div class="photo">
+            <q-img src="/assets/images/web/user-top-menu-logo.png"
+                   width="33px" />
+          </div>
+          <div class="title">
+            کیف پول پالیزوانی
+          </div>
+          <div class="inventory">
+            {{ wallet.inventory.toLocaleString('fa') }}
+            <span class="unit">
+              ریال
+            </span>
+          </div>
+        </div>
+      </div>
+      <div class="actions-column">
+        <div class="deposit-section">
+          <div class="row q-col-gutter-md">
+            <div class="col-md-5 col-12">
+              <div>افزایش موجودی</div>
+              <q-input v-model="depositAmount"
+                       dense
+                       placeholder="لطفا مبلغ مورد نظر خود را مشخص کنید" />
+            </div>
+            <div class="col-md-7 col-12">
+              <q-btn class="btn-deposit"
+                     color="primary"
+                     :loading="wallet.loading"
+                     @click="deposit">
+                <q-icon name="isax:add" />
+                افزایش موجودی
+              </q-btn>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { User } from 'src/models/User.js'
+import { Wallet } from 'src/models/Wallet.js'
+import { mixinWidget } from 'src/mixin/Mixins.js'
+import { APIGateway } from 'src/api/APIGateway.js'
+
+export default {
+  name: 'MyWallet',
+  mixins: [mixinWidget],
+  data: () => {
+    return {
+      user: new User(),
+      wallet: new Wallet(),
+      depositAmount: null
+    }
+  },
+  mounted() {
+    this.loadAuthData()
+  },
+  methods: {
+    loadAuthData() { // prevent Hydration node mismatch
+      this.user = this.$store.getters['Auth/user']
+    },
+    getMyWallet () {
+      this.wallet.loading = true
+      APIGateway.wallet.getMyWallet(this.user.id)
+        .then((wallet) => {
+          this.wallet = new Wallet(wallet)
+          this.wallet.loading = false
+        })
+        .catch(() => {
+          this.wallet.loading = false
+        })
+    },
+    deposit () {
+      if (isNaN(this.depositAmount) || this.depositAmount === 0) {
+        return
+      }
+      this.wallet.loading = true
+      APIGateway.wallet.deposit({ amount: this.depositAmount })
+        .then((url) => {
+          window.location.href = url
+        })
+        .catch(() => {
+          this.wallet.loading = false
+        })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.MyWallet {
+  background: #FFFFFF;
+  border: 1px solid #DFE1EC;
+  border-radius: 8px;
+  .header {
+    padding-left: 21px;
+    display: flex;
+    flex-flow: row;
+    justify-content: flex-start;
+    align-items: center;
+    font-size: 16px;
+    letter-spacing: 0;
+    color: #212121;
+    height: 70px;
+    border-bottom: 1px solid #DFE1EC;
+  }
+  .body {
+    display: flex;
+    flex-flow: row;
+    justify-content: flex-start;
+    align-items: center;
+    padding: 45px 58px;
+    .card-column {
+      width: 427px;
+      .card {
+        max-width: 357px;
+        width: 100%;
+        height: 165px;
+        background: transparent linear-gradient(-242deg, #8AB890 0%, #5B7A5F 100%) 0 0 no-repeat padding-box;
+        border-radius: 20px;
+        position: relative;
+        .photo {
+          position: absolute;
+          top: 20px;
+          left: 20px;
+          width: 60px;
+          height: 60px;
+          background: white;
+          border-radius: 10px;
+          display: flex;
+          flex-flow: row;
+          justify-content: center;
+          align-items: center;
+        }
+        .title {
+          position: absolute;
+          top: 41px;
+          left: 90px;
+          color: #FFFFFF;
+          font-size: 16px;
+        }
+        .inventory {
+          position: absolute;
+          top: 108px;
+          left: 105px;
+          color: #FFFFFF;
+          font-size: 24px;
+          .unit {
+            font-size: 18px;
+          }
+        }
+      }
+    }
+    .actions-column {
+      width: calc( 100% - 427px);
+      .deposit-section {
+        .btn-deposit {
+          margin-top: 25px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 21 - 0
src/components/Widgets/Wallet/MyWallet/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>

+ 37 - 0
src/models/Transaction.js

@@ -0,0 +1,37 @@
+import { Model, Collection } from 'js-abstract-model'
+import { User } from 'src/models/User'
+
+class Transaction extends Model {
+  constructor (data) {
+    super(data, [
+      { key: 'id' },
+      { key: 'is_active' },
+      { key: 'is_deleted' },
+      { key: 'inventory' },
+      { key: 'description' },
+      {
+        key: 'additional_data',
+        default: []
+      },
+      { key: 'creation_time' },
+      { key: 'last_modification_time' },
+      { key: 'creator' },
+      {
+        key: 'creator_info',
+        relatedModel: User
+      },
+      { key: 'owner' },
+      {
+        key: 'owner',
+        relatedModel: User
+      }
+    ])
+  }
+}
+
+class TransactionList extends Collection {
+  model () {
+    return Transaction
+  }
+}
+export { Transaction, TransactionList }

+ 24 - 0
src/pages/User/Wallet/Show.vue

@@ -0,0 +1,24 @@
+<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: 'UserPanel.Wallet',
+  mixins: [mixinPageOptions],
+  data: () => {
+    return {
+      sections: [{ data: { rows: [{ cols: [{ widgets: [{ name: 'MyWallet' }], options: { style: { paddingTop: '124px' } } }], options: { className: '', height: 'auto', boxed: true, boxedWidth: 1200, gutterXSize: 'md', gutterYSize: 'md', absolute: 'none', paddingOfBoxedInFullWidth: '30px', style: { maxWidth: '1200px', width: '1200px' } } }] } }]
+    }
+  },
+  created() {
+    this.currenSections = this.sections
+    this.pageBuilderLoading = false
+  }
+}
+</script>

+ 5 - 0
src/router/routes.js

@@ -187,6 +187,11 @@ const routes = [
                 component: () => import('src/pages/User/Ticket/Create.vue')
               }
             ]
+          },
+          {
+            path: 'wallet',
+            name: 'UserPanel.Wallet',
+            component: () => import('src/pages/User/Wallet/Show.vue')
           }
         ]
       },