Переглянути джерело

Set up separate section in site management page
https://dev.wormwood.com.sg/zentao/task-view-7.html
Add manual generation button at account settlement and filter
https://dev.wormwood.com.sg/zentao/task-view-27.html
Develop voucher management - part 1
https://dev.wormwood.com.sg/zentao/task-view-10.html

vbea 2 роки тому
батько
коміт
f5370eb1b4

+ 6 - 0
Strides-Admin/src/http/api/financial.js

@@ -61,8 +61,14 @@ const financial = {
   unassignEligible(data) {
     return post('financial/billing-account/unassign-eligible', data)
   },
+  getBillingAccountOptions(data) {
+    return get("financial/billing-account/billing-account-select", data)
+  },
   getAccountSettlementPages(data) {
     return post("financial/account-settlement/account-settlement-pages", data)
+  },
+  manualGenerationSettlement(data) {
+    return post("financial/account-settlement/redo-account-settlement", data)
   }
 }
 

+ 9 - 0
Strides-Admin/src/http/api/voucher.js

@@ -0,0 +1,9 @@
+import {get, post} from '../http'
+
+const prefix = "";
+
+const voucher = {
+  
+}
+
+export default voucher;

+ 43 - 0
Strides-Admin/src/router/VoucherRouter.js

@@ -0,0 +1,43 @@
+import Layout from '@/layout'
+
+export default {
+  path: '/voucher-management',
+  redirect: '/voucher-management/voucher',
+  component: Layout,
+  meta: {
+    title: 'Voucher Management',
+    icon: 'financial'
+  },
+  children: [
+    {
+      path: '/voucher-management/voucher',
+      component: () => import('@/views/voucher/index'),
+      name: 'voucher-management',
+      meta: {
+        title: 'Vouchers',
+        icon: 'sidebar-submenu-item',
+        activeIcon: 'sidebar-submenu-item-active',
+      },
+    },
+    {
+      path: '/voucher-management/issuance',
+      component: () => import('@/views/voucher/issuance'),
+      name: 'voucher-issuance',
+      meta: {
+        title: 'Voucher Issuance',
+        icon: 'sidebar-submenu-item',
+        activeIcon: 'sidebar-submenu-item-active',
+      },
+    },
+    {
+      path: '/voucher-management/usage',
+      component: () => import('@/views/voucher/usage'),
+      name: 'voucher-usage',
+      meta: {
+        title: 'Voucher Usage',
+        icon: 'sidebar-submenu-item',
+        activeIcon: 'sidebar-submenu-item-active',
+      },
+    }
+  ]
+}

+ 2 - 0
Strides-Admin/src/router/index.js

@@ -18,6 +18,7 @@ import AccessRouter from './AccessRouter'
 import SettingsRouter from './SettingsRouter'
 import additionalRoute from './addition'
 import MarketingRouter from './MarketingRouter'
+import VoucherRouter from './VoucherRouter'
 
 Vue.use(VueRouter)
 
@@ -79,6 +80,7 @@ const constantRoutes = [
   EnergyRouter,
   FinancialRouter,
   UserRouter,
+  VoucherRouter,
   SupportRouter,
   OCPPRouter,
   ...ReportsRouter,

+ 25 - 4
Strides-Admin/src/views/settlement/AccountSetle.vue

@@ -22,6 +22,13 @@
           @change="onClickSearch"
           @keyup.enter.native="onClickSearch"
           clearable/>
+        <div class="filter-flex-button">
+          <el-button
+            type="primary"
+            @click="onClickManual">
+            Generate
+          </el-button>
+        </div>
       </div>
     </div>
     <el-table
@@ -110,13 +117,17 @@
         :limit.sync="filters.pageSize"
         @pagination="getTableData" />
     </div>
+    <ManualGenerate
+      :visible="showGenerate"
+      @hide="hideGenerate"/>
   </div>
 </template>
 
 <script>
 import financial from '@/http/api/financial';
-import TableAction from '@/components/TableAction.vue'
-import Pagination from '@/components/Pagination'
+import TableAction from '@/components/TableAction.vue';
+import Pagination from '@/components/Pagination';
+import ManualGenerate from './ManualGenerate.vue';
 export default {
   data() {
     return {
@@ -135,10 +146,11 @@ export default {
       },
       options: {
         types: []
-      }
+      },
+      showGenerate: false
     };
   },
-  components: { Pagination, TableAction },
+  components: { Pagination, TableAction, ManualGenerate },
   created() {
     this.getAccountTypeOptions();
     this.onClickSearch();
@@ -180,6 +192,15 @@ export default {
       }).finally(() => {
         this.table.loading = false;
       })
+    },
+    onClickManual() {
+      this.showGenerate = true;
+    },
+    hideGenerate(e) {
+      this.showGenerate = false;
+      if (e) {
+        this.onClickSearch();
+      }
     }
   }
 }

+ 173 - 0
Strides-Admin/src/views/settlement/ManualGenerate.vue

@@ -0,0 +1,173 @@
+<template>
+  <el-dialog
+    :visible="visible"
+    title="GENERATE"
+    :before-close="onHide">
+    <el-form
+      ref="dialogForm"
+      :model="filter"
+      :rules="rules"
+      class="filter-container"
+      label-position="right"
+      label-width="160px">
+      <el-form-item
+        label="Select Account:"
+        prop="entityId">
+        <el-select
+          v-model="filter.entityId"
+          class="dialog-form-item"
+          filterable
+          remote
+          clearable
+          :remote-method="getAccountOptions">
+          <el-option
+            v-for="(item,index) in accountOptions"
+            :key="index"
+            :label="item.entityName"
+            :value="item.entityId"/>
+        </el-select>
+      </el-form-item>
+      <el-form-item
+        label="Select Date:"
+        prop="dateRange">
+        <el-date-picker
+          v-model="filter.dateRange"
+          class="dialog-form-item"
+          type="daterange"
+          value-format="yyyy-MM-dd"
+          start-placeholder="Start Date"
+          end-placeholder="End Date"
+          clearable/>
+      </el-form-item>
+      <div class="dialog-button">
+        <el-button
+          type="cancel"
+          @click="onHide">
+          CANCEL
+        </el-button>
+        <el-button
+          type="primary"
+          :loading="btnLoading"
+          @click="onSubmit">
+          SUBMIT
+        </el-button>
+      </div>
+    </el-form>
+  </el-dialog>
+</template>
+
+<script>
+import financial from '@/http/api/financial';
+export default {
+  name: "DialogManualGenerate",
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      filter: {
+        entityId: "",
+        startDate: "",
+        endDate: "",
+        dateRange: []
+      },
+      rules: {
+        entityId: {
+          required: true,
+          trigger: "change",
+          message: "Please select account"
+        },
+        dateRange: {
+          required: true,
+          trigger: "change",
+          message: "Please select date"
+        }
+      },
+      accountOptions: [],
+      btnLoading: false
+    };
+  },
+  watch: {
+    visible: {
+      handler(n, o) {
+        if (n) {
+          this.filter.entityId = "";
+          this.filter.dateRange = [];
+          this.filter.startDate = "";
+          this.filter.endDate = "";
+          this.$refs.dialogForm.clearValidate();
+        }
+      }
+    }
+  },
+  mounted() {
+    this.getAccountOptions();
+  },
+  methods: {
+    onHide(e, a) {
+      this.$emit("hide", a)
+    },
+    getAccountOptions(search) {
+      financial.getBillingAccountOptions({
+        entityName: search
+      }).then(res => {
+        if (res.data) {
+          this.accountOptions = res.data
+        } else {
+          this.accountOptions = []
+        }
+      }).catch(err => {
+        this.$message({
+          type: 'error',
+          message: err
+        })
+        this.accountOptions = []
+      })
+    },
+    onSubmit() {
+      this.$refs.dialogForm.validate(result => {
+        if (result) {
+          if (this.filter.dateRange.length == 2) {
+            this.filter.startDate = this.filter.dateRange[0]
+            this.filter.endDate = this.filter.dateRange[1]
+          }
+          this.onGenerate();
+        }
+      })
+    },
+    onGenerate() {
+      this.btnLoading = true;
+      financial.manualGenerationSettlement(this.filter).then(res => {
+        this.$message({
+          type: 'success',
+          message: "Generate success"
+        })
+        this.onHide(false, true)
+      }).catch(err => {
+        this.$message({
+          type: 'error',
+          message: err
+        })
+      }).finally(() => {
+        this.btnLoading = false;
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.dialog-form-item {
+  width: 100%;
+  max-width: 350px;
+}
+.dialog-button {
+  display: flex;
+  align-items: center;
+  padding-top: 30px;
+  justify-content: center;
+}
+</style>

+ 71 - 3
Strides-Admin/src/views/site2/detail.vue

@@ -150,7 +150,7 @@
               :currency="currencyData[siteForm.address.countryCode]"/>
           </div>
           
-          <div class="view-content" id="idSiteTypes">
+          <div class="view-content" id="idSiteTypes" v-if="false">
             <div class="section-title">Site EMAIL Configuration</div>
             <email-recipient v-model="siteForm.emails"/>
           </div>
@@ -327,7 +327,23 @@
           </el-col>
         </el-row>
       </div>
-      
+      <div class="view-content">
+        <div class="section-title">SITE EMAIL CONFIGURATION</div>
+        <div class="flexcr">
+          <email-recipient v-model="siteForm.emails"/>
+          <div class="flex1">
+            <el-checkbox-group
+              class="features-group"
+              v-model="siteForm.enabledFeatures">
+              <template v-for="(item, index) in featuresOptions">
+                <el-checkbox
+                  :key="index"
+                  :label="item.value">{{item.name}}</el-checkbox>
+              </template>
+            </el-checkbox-group>
+          </div>
+        </div>
+      </div>
       <div class="view-content flexcr">
         <div class="buttons">
           <el-button
@@ -370,6 +386,7 @@ import WhiteListUser from '../site/components/WhiteListUser'
 import SiteTypeWithTime from './components/SiteTypeWithTime'
 import waves from '@/directive/waves' // waves directive
 import site from '../../http/api/site'
+import apiSet from '../../http/api/settings'
 import { getRoleName } from '@/utils/auth'
 export default {
   directives: { waves },
@@ -389,6 +406,7 @@ export default {
       pageLoading: false,
       isMCSTUser: false,
       countryOptions: [],
+      featuresOptions: [],
       siteForm: {
         sitePk: "",
         siteName: "",
@@ -431,6 +449,7 @@ export default {
         loadBalancing: "",//负载均衡
         staticMaxAmpere: "",//负载均衡
         siteChargingProfiles: null,//负载均衡
+        enabledFeatures: []
       },
       ratesForm: {
         chargeRates: [{
@@ -545,7 +564,8 @@ export default {
   created() {
     this.pageLoading = true;
     this.isMCSTUser = getRoleName() === "MCST";
-    this.getCountryOptions()
+    this.getCountryOptions();
+    this.getFeaturesList();
     if (this.$route.params.id) {
       this.isEdit = true;
       this.getSiteInfo()
@@ -566,6 +586,27 @@ export default {
           })
           this.currencyData = sign;
         }
+      }).catch(() => {
+        this.$message({
+          message: err,
+          type: 'error',
+          duration: 3000,
+        })
+        this.pageLoading = false;
+      })
+    },
+    getFeaturesList() {
+      apiSet.getFeatures().then(res => {
+        if (res.data) {
+          this.featuresOptions = res.data;
+        }
+      }).catch(() => {
+        this.$message({
+          message: err,
+          type: 'error',
+          duration: 3000,
+        })
+        this.pageLoading = false;
       })
     },
     getSiteInfo() {
@@ -573,6 +614,9 @@ export default {
         sitePk: this.$route.params.id,
       }).then(res => {
         if (res.data) {
+          if (!res.data.enabledFeatures) {
+            res.data.enabledFeatures = []
+          }
           this.siteForm = res.data;
           this.applySiteInfo();
         } else {
@@ -754,6 +798,14 @@ export default {
           } else {
             this.siteForm.groupWhitelist = []
           }
+          if (this.siteForm.enabledFeatures.length > 0 && this.siteForm.emails.length == 0) {
+            this.$message({
+              message: "Please add at least one email recipients",
+              type: 'error',
+              duration: 3000,
+            })
+            return;
+          }
           this.pageLoading = true;
           const params = {
             ...this.siteForm,
@@ -999,4 +1051,20 @@ export default {
     position: absolute;
     transform: scale(0.8);
   }
+  .features-group {
+    min-width: 300px;
+    display: flex;
+    margin-left: 20px;
+    flex-direction: column;
+    ::v-deep .el-checkbox {
+      display: flex;
+      align-items: center;
+      padding-bottom: 5px;
+    }
+    ::v-deep .el-checkbox__label {
+      word-break: break-all;
+      white-space: normal;
+    }
+  }
+  
 </style>

+ 25 - 0
Strides-Admin/src/views/voucher/detail.vue

@@ -0,0 +1,25 @@
+<template>
+  <div>
+    
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      
+    };
+  },
+  created() {
+    
+  },
+  methods: {
+    
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 108 - 0
Strides-Admin/src/views/voucher/index.vue

@@ -0,0 +1,108 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container filter-view">
+      <div class="filter-flex-button">
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          @click="onClickAdd">
+          CREATE VOUCHER
+        </el-button>
+      </div>
+    </div>
+    <el-table
+      v-loading="table.loading"
+      :data="table.data">
+      <el-table-column
+        label="Voucher ID"
+        align="center"
+        prop="rfidNumber"
+        min-width="120"/>
+      <el-table-column
+        label="Voucher Name"
+        align="center"
+        prop="rfidNumber"
+        min-width="120"/>
+      <el-table-column
+        label="Validity Period"
+        align="center"
+        prop="rfidNumber"
+        min-width="120"/>
+      <el-table-column
+        label="Quantity"
+        align="center"
+        prop="rfidNumber"
+        min-width="120"/>
+      <el-table-column
+        label="Voucher Type"
+        align="center"
+        prop="rfidNumber"
+        min-width="120"/>
+      <el-table-column
+        label="Redemption Method"
+        align="center"
+        prop="rfidNumber"
+        min-width="160"/>
+      <el-table-column
+        label="Status"
+        align="center"
+        prop="rfidNumber"
+        min-width="100"/>
+      <el-table-column
+        label="Action"
+        align="center"
+        prop="rfidNumber"
+        min-width="80">
+        
+      </el-table-column>
+    </el-table>
+    <div class="right">
+      <Pagination
+        v-show="table.total > 0"
+        :total="table.total"
+        :page.sync="params.pageNo"
+        :limit.sync="params.pageSize"
+        @pagination="getTableData" />
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      params: {
+        pageNo: 1,
+        pageSize: 10,
+        pageVo: {
+          criteria: "",
+        }
+      },
+      table: {
+        data: [],
+        total: 0,
+        loading: false
+      },
+    };
+  },
+  created() {
+    
+  },
+  methods: {
+    toSearch() {
+      this.params.pageNo = 1;
+      this.getTableData();
+    },
+    getTableData() {
+      
+    },
+    onClickAdd() {
+      
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 25 - 0
Strides-Admin/src/views/voucher/issuance.vue

@@ -0,0 +1,25 @@
+<template>
+  <div>
+    
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      
+    };
+  },
+  created() {
+    
+  },
+  methods: {
+    
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 25 - 0
Strides-Admin/src/views/voucher/usage.vue

@@ -0,0 +1,25 @@
+<template>
+  <div>
+    
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      
+    };
+  },
+  created() {
+    
+  },
+  methods: {
+    
+  }
+}
+</script>
+
+<style scoped>
+
+</style>