Просмотр исходного кода

Enhance monthly credit limit
https://dev.wormwood.com.sg/zentao/task-view-313.html

vbea 1 год назад
Родитель
Сommit
aa048c8ee9

+ 3 - 0
Strides-Admin/src/api/apiBase.js

@@ -9,6 +9,9 @@ const apiBase = {
   getChargerTypeOptions() {
     return get(prefix + "charger-type-select")
   },
+  getDataStatusOptions() {
+    return get(prefix + "data-status-select")
+  },
   getUserGroupOptions(groupType) {
     return get(prefix + "group-select", {groupType: groupType})
   },

+ 41 - 0
Strides-Admin/src/api/limit.js

@@ -0,0 +1,41 @@
+import { del, get, post, put } from '../http/http'
+
+const prefix = "dawn/api/v1/"
+
+const limit = {
+  getCreditLimitPages(params) {
+    return post(prefix + 'group-credit-limit-pages', params)
+  },
+  getCreditLimitPlanPages(params) {
+    return post(prefix + 'group-credit-limit-plan-pages', params)
+  },
+  getCreditLimitAssignmentPages(params) {
+    return post(prefix + 'group-credit-limit-plan-user-pages', params)
+  },
+  addCreditLimitPlan(params) {
+    return post(prefix + 'group-credit-limit-plans', params)
+  },
+  deleteCreditLimitPlan(groupCreditPlanId) {
+    return del(prefix + 'group-credit-limit-plans/' + groupCreditPlanId)
+  },
+  addCreditLimit(params) {
+    return post(prefix + 'group-credit-limits', params)
+  },
+  viewCreditLimit(groupCreditPk) {
+    return get(prefix + 'group-credit-limits/' + groupCreditPk)
+  },
+  updateCreditLimit(params) {
+    return put(prefix + 'group-credit-limits', params)
+  },
+  deleteCreditLimit(groupCreditPk) {
+    return del(prefix + 'group-credit-limits/' + groupCreditPk)
+  },
+  assignCreditLimitPlanUser(params) {
+    return post(prefix + "assign-group-credit-limit-plan-user", params)
+  },
+  unassignCreditLimitPlanUser(params) {
+    return post(prefix + "unassign-group-credit-limit-plan-user", params)
+  }
+}
+
+export default limit;

+ 39 - 0
Strides-Admin/src/router/PartnershipRouter.js

@@ -136,6 +136,45 @@ export default {
         }
       },
       hidden: true
+    },
+    //credit limit v2
+    {
+      path: '/partnership-management/monthly-credit-limit',
+      component: () => import('@/views/limit2/index'),
+      name: 'monthly-credit-management',
+      meta: {
+        title: 'Monthly Credit Limit',
+        icon: 'sidebar-submenu-item',
+        activeIcon: 'sidebar-submenu-item-active'
+      }
+    },
+    {
+      path: '/partnership-management/monthly-credit-limit/add',
+      component: () => import('@/views/limit2/detail'),
+      name: 'credit-limit-add',
+      meta: {
+        title: 'Add Credit Limit Contract',
+        activeMenu: '/partnership-management/monthly-credit-limit',
+        parent: {
+          title: 'Monthly Credit Limit',
+          path: "/partnership-management/monthly-credit-limit"
+        }
+      },
+      hidden: true
+    },
+    {
+      path: '/partnership-management/monthly-credit-limit/edit/:id',
+      component: () => import('@/views/limit2/detail'),
+      name: 'credit-limit-edit',
+      meta: {
+        title: 'Edit Credit Limit Contract',
+        activeMenu: '/partnership-management/monthly-credit-limit',
+        parent: {
+          title: 'Monthly Credit Limit',
+          path: "/partnership-management/monthly-credit-limit"
+        }
+      },
+      hidden: true
     }
   ]
 }

+ 1 - 0
Strides-Admin/src/settings.js

@@ -17,6 +17,7 @@ module.exports = {
   enableWebPos: true,
   enableTopup: false,
   enableEVCPID: true,
+  enableOCPIToken: false,
   /**
    * @type {string}
    * @description API url base service

+ 316 - 0
Strides-Admin/src/views/limit2/assignment.vue

@@ -0,0 +1,316 @@
+<template>
+  <el-dialog
+    :title="title"
+    :visible="visible"
+    :before-close="onHide"
+    class="assign-label-dialog">
+    <div class="filter-container filter-view">
+      <el-select
+        style="min-width: 70px; max-width: 120px;"
+        clearable
+        v-model="filter.pageCriteria.assignmentStatus"
+        placeholder="Status"
+        @change="onSearch">
+        <el-option
+          v-for="(item, index) in statusOptions"
+          :key="index"
+          :label="item"
+          :value="item"/>
+      </el-select>
+      <div style="flex: 1; min-width: 150px; max-width: 300px;">
+        <el-input
+          clearable
+          v-model="filter.pageCriteria.criteria"
+          placeholder="Search by Site Name or Service Provider"
+          @keyup.enter.native="onSearch"/>
+      </div>
+      <el-button
+        type="primary"
+        @click="onSearch">
+        Search
+      </el-button>
+    </div>
+    <div class="assign-label-actions">
+      <el-button
+        type="danger"
+        :disabled="selectRow.length == 0"
+        :loading="loading.unassign"
+        @click="onClickUnassign">
+        Batch Un-assign
+      </el-button>
+      <el-button
+        type="accent"
+        :disabled="selectRow.length == 0"
+        :loading="loading.assign"
+        @click="onClickAssign">
+        Batch Assign
+      </el-button>
+    </div>
+    <div class="table-view" v-loading="table.loading">
+      <el-table
+        :data="table.data"
+        height="100%"
+        class="no-border"
+        @selection-change="changeSelection">
+        <el-table-column
+          align="center"
+          label="User Name"
+          prop="userName"
+          min-width="120"/>
+        <el-table-column
+          align="center"
+          label="Contact Number"
+          prop="contactNumber"
+          min-width="120"/>
+        <el-table-column
+          align="center"
+          label="E-Mail"
+          prop="email"
+          min-width="120"/>
+        <el-table-column
+          align="center"
+          label="Assignment Status"
+          prop="assignmentStatus"
+          min-width="120"/>
+        <el-table-column
+          align="center"
+          label="Select"
+          type="selection"/>
+      </el-table>
+    </div>
+    <div class="center" style="margin-bottom: -20px;">
+      <Pagination
+        v-show="table.total"
+        :total="table.total"
+        :page.sync="filter.pageNo"
+        :limit.sync="filter.pageSize"
+        @pagination="getTableData"/>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import api from '@/api/limit.js'
+import apiBase from '@/api/apiBase';
+import Pagination from '@/components/Pagination'
+export default {
+  name: "AssignmentPlan",
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    item: {
+      type: Object,
+      default: () => ({})
+    },
+    groupPk: {
+      type: Number|String,
+      default: ""
+    }
+  },
+  data() {
+    return {
+      filter: {
+        pageNum: 1,
+        pageSize: 10,
+        pageCriteria: {
+          criteria: "",
+          groupPk: "",
+          groupCreditPlanId: "",
+          assignmentStatus: ""
+        }
+      },
+      table: {
+        data: [],
+        total: 0,
+        loading: false
+      },
+      loading: {
+        assign: false,
+        unassign: false
+      },
+      statusOptions: [],
+      selectRow: []
+    };
+  },
+  components: {Pagination},
+  computed: {
+    title() {
+      return "ASSIGN USER"
+    }
+  },
+  watch: {
+    visible: {
+      handler(n, o) {
+        console.log("watch.visible", n, o);
+        if (n) {
+          this.filter.pageCriteria.groupCreditPlanId = this.item.groupCreditPlanId;
+          this.filter.pageCriteria.assignmentStatus = "";
+          this.filter.pageCriteria.groupPk = this.groupPk;
+          this.onSearch()
+        }
+      }
+    }
+  },
+  mounted() {
+    this.getStatusOptions();
+  },
+  methods: {
+    onHide() {
+      this.$emit("hide", true);
+    },
+    onSearch() {
+      this.filter.pageNo = 1;
+      this.getTableData();
+    },
+    getStatusOptions() {
+      apiBase.getAssignStatusOptions().then(res => {
+        if (res.data) {
+          this.statusOptions = res.data
+        }
+      }).catch(error => {
+        this.$message({
+          type: 'error',
+          message: error
+        })
+      })
+    },
+    getTableData() {
+      this.table.loading = true;
+      api.getCreditLimitAssignmentPages(this.filter).then(res => {
+        if (res.data.totalRow && res.data.records) {
+          this.table.total = res.data.totalRow;
+          this.table.data = res.data.records;
+        } else {
+          this.table.total = 0;
+          this.table.data = [];
+        }
+        this.table.loading = false;
+      }).catch(error => {
+        this.$message({
+          type: 'error',
+          message: error
+        })
+        this.table.total = 0;
+        this.table.data = [];
+        this.table.loading = false;
+      })
+    },
+    changeSelection(val) {
+      this.selectRow = val;
+    },
+    getSelectIds() {
+      const ids = [];
+      this.selectRow.forEach(item => {
+        ids.push(item.userPk)
+      })
+      return ids;
+    },
+    onClickAssign() {
+      const params = {
+        groupCreditPlanId: this.item.groupCreditPlanId,
+        userPks: this.getSelectIds()
+      }
+      this.loading.assign = true;
+      api.assignCreditLimitPlanUser(params).then(res => {
+        this.$message({
+          type: 'success',
+          message: res.msg || "Success"
+        })
+        this.getTableData()
+      }).catch(error => {
+        this.$message({
+          type: 'error',
+          message: error
+        })
+      }).finally(() => {
+        this.loading.assign = false;
+      })
+    },
+    onClickUnassign() {
+      const params = {
+        groupCreditPlanId: this.item.groupCreditPlanId,
+        userPks: this.getSelectIds()
+      }
+      this.loading.unassign = true;
+      api.unassignCreditLimitPlanUser(params).then(res => {
+        this.$message({
+          type: 'success',
+          message: res.msg || "Success"
+        })
+        this.getTableData()
+      }).catch(error => {
+        this.$message({
+          type: 'error',
+          message: error
+        })
+      }).finally(() => {
+        this.loading.unassign = false;
+      })
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.assign-label-dialog
+  ::v-deep .el-dialog {
+    width: 65vw;
+    height: 90vh;
+    display: flex;
+    max-width: 1200px;
+    flex-direction: column;
+    margin-top: 5vh !important;
+  .el-dialog__header {
+    padding: 20px 20px 0;
+    font-weight: bold;
+  }
+  .el-dialog__body {
+    flex: 1;
+    padding: 20px;
+    display: flex;
+    overflow: hidden;
+    flex-direction: column;
+  }
+  @media screen and (max-width: 1200px) {
+    & {
+      width: 70vw;
+    }
+  }
+  @media screen and (max-width: 1000px) {
+    & {
+      width: 80vw;
+    }
+  }
+  @media screen and (max-width: 800px) {
+    & {
+      width: 90vw;
+    }
+  }
+  @media screen and (max-width: 700px) {
+    & {
+      width: 99vw;
+    }
+  }
+  @media screen and (max-width: 320px) {
+    & {
+      width: 100%;
+      min-width: 300px;
+    }
+  }
+}
+.assign-label-dialog .table-view {
+  flex: 1;
+  overflow-y: auto;
+  padding-top: 10px;
+  margin-bottom: -10px;
+}
+.assign-label-actions {
+  display: flex;
+  padding-top: 5px;
+  flex-wrap: wrap-reverse;
+  align-items: center;
+  justify-content: flex-end;
+}
+</style>

+ 387 - 0
Strides-Admin/src/views/limit2/detail.vue

@@ -0,0 +1,387 @@
+<template>
+  <div class="container" v-loading="loading.page">
+    <el-form
+      ref="limitForm"
+      :model="form"
+      :rules="rules"
+      label-width="165px"
+      label-position="right">
+      <div class="content">
+        <div class="section-title">CREDIT LIMIT CONTRACT</div>
+        <div class="flexr">
+          <div class="form-left">
+            <el-form-item
+              label="Group:"
+              prop="groupPk">
+              <el-select
+                class="add-text"
+                v-model="form.groupPk"
+                placeholder="Select with search">
+                <el-option
+                  v-for="(item, index) in options.group"
+                  :key="index"
+                  :label="item.groupName"
+                  :value="item.groupPk"/>
+              </el-select>
+            </el-form-item>
+            <el-form-item
+              label="Service Provider:"
+              prop="providerPk">
+              <el-select
+                class="add-text"
+                v-model="form.providerPk"
+                placeholder="Select">
+                <el-option
+                  v-for="(item, index) in options.provider"
+                  :key="index"
+                  :label="item.providerName"
+                  :value="''+item.providerPk"/>
+              </el-select>
+            </el-form-item>
+            <el-form-item
+              label="Effective Period:"
+              prop="effectivePeriod">
+              <el-date-picker
+                class="add-text"
+                v-model="form.effectivePeriod"
+                type="daterange"
+                format="dd/MM/yyyy"
+                value-format="dd/MM/yyyy"
+                placeholder="Select date"/>
+            </el-form-item>
+            <el-form-item
+              label="Monthly Credit Limit:"
+              prop="creditLimitAmount">
+              <span class="item-unit">(S$)</span>
+              <el-input
+                class="add-text"
+                v-model="form.creditLimitAmount"
+                placeholder=""
+                maxlength="10"/>
+            </el-form-item>
+          </div>
+          <div class="form-right" v-if="isEdit">
+            <el-form-item
+              label="Status:"
+              prop="dataStatus">
+              <el-select
+                class="add-text"
+                v-model="form.dataStatus"
+                placeholder="Select"
+                disabled>
+                <el-option
+                  v-for="(item, index) in options.status"
+                  :key="index"
+                  :label="item.key"
+                  :value="item.value"/>
+              </el-select>
+            </el-form-item>
+            <el-form-item
+              label="Approved Users:">
+              <el-input
+                class="add-text"
+                v-model="form.approvedUsers"
+                readonly/>
+            </el-form-item>
+            <el-form-item
+              label="Group Credit:">
+              <el-input
+                class="add-text"
+                v-model="form.groupCredit"
+                readonly/>
+            </el-form-item>
+            <el-form-item
+              label="Individual Credit:">
+              <el-input
+                class="add-text"
+                v-model="form.individualCredit"
+                readonly/>
+            </el-form-item>
+          </div>
+        </div>
+      </div>
+      <div class="content" v-if="isEdit">
+        <div class="section-title">Individual Plans</div>
+        <plans
+          :id="form.groupCreditPk"
+          :groupPk="form.groupPk"
+          v-if="form.groupCreditPk"/>
+      </div>
+      <div class="content flexcr">
+        <div class="buttons">
+          <el-button
+            type="primary"
+            class="cancel-button"
+            @click="onBack">
+            Cancel
+          </el-button>
+          <el-button
+            style="margin-left: 20px;"
+            type="primary"
+            :loading="loading.save"
+            @click="onSaveClick">
+            Save
+          </el-button>
+        </div>
+        <div
+          class="flex1"
+          style="margin-left: 20px;"
+          v-if="isEdit">
+          <span
+            class="add-text"
+            :title='"CREATED BY " + form.createdBy + " ON " + form.createdOn'>
+            LAST UPDATED BY {{form.updatedBy}} TIMESTAMP: {{form.updatedOn}}
+          </span>
+        </div>
+      </div>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import apiBase from '@/api/apiBase';
+import limit from '@/api/limit.js'
+import provider from '@/http/api/provider'
+import group from '@/http/api/group'
+import plans from './plans.vue'
+export default {
+  data() {
+    return {
+      isEdit: false,
+      loading: {
+        page: true,
+        save: false
+      },
+      form: {
+        groupCreditPk: "",
+        groupPk: "",
+        providerPk: "",
+        effectivePeriod: ["", ""],
+        creditLimitAmount: ""
+      },
+      rules: {
+        groupPk: {
+          required: true,
+          trigger: 'change',
+          message: 'Please select a group'
+        },
+        providerPk: {
+          required: true,
+          trigger: 'change',
+          message: 'Please select a provider'
+        },
+        creditLimitAmount: [{
+          required: true,
+          trigger: 'blur',
+          message: 'Please type Monthly Credit Limit'
+        }, {
+          pattern: /^\d+(.{0,1}\d{1,})?$/,
+          trigger: 'blur',
+          message: 'Please type a number of amount'
+        }],
+        effectivePeriod: {
+          required: true,
+          trigger: 'change',
+          validator: (rule, value, callback) => {
+            if (value && value.length > 0) {
+              if (value[0] && value[1]) {
+                callback()
+              } else {
+                callback("Please select effective period")
+              }
+            } else {
+              callback("Please select effective period")
+            }
+          }
+        },
+      },
+      options: {
+        group: [],
+        status: [],
+        provider: []
+      },
+      companyParams: {
+        "pageSize": 50,
+        "pageNo": 1,
+        "pageVo": {
+          "criteria": ""
+        }
+      },
+    };
+  },
+  components: {plans},
+  created() {
+    this.getGroupOptions();
+    if (this.$route.params.id) {
+      this.isEdit = true;
+      this.getStatusOptions();
+      this.getLimitInfo();
+    }
+    
+  },
+  methods: {
+    onBack() {
+      this.$nextTick(() => {
+        this.$router.push({
+          path: "/partnership-management/monthly-credit-limit"
+        })
+      })
+    },
+    getStatusOptions() {
+      apiBase.getDataStatusOptions().then(res => {
+        if (res.data && res.data.length > 0) {
+          this.options.status = res.data
+        }
+      }).catch(err => {
+        this.$message.error(err);
+      })
+    },
+    getGroupOptions() {
+      group.getGroupPages(this.companyParams).then(res => {
+        if (res.data) {
+          this.options.group = res.data
+        }
+      }).catch(err => {
+        this.$message({
+          message: err,
+          type: 'error'
+        })
+      }).finally(() => {
+        this.getAllProvider();
+      });
+    },
+    getAllProvider() {
+      provider.getAllServiceProvider().then(res => {
+        if (res.data && res.data.length > 0) {
+          this.options.provider = res.data
+          if (!this.form.providerPk)
+            this.form.providerPk = res.data[0].providerPk + ""
+        }
+      }).finally(() => {
+        this.loading.page = false;
+      });
+    },
+    getLimitInfo() {
+      limit.viewCreditLimit(this.$route.params.id).then(res => {
+        if (res.data) {
+          this.form = res.data
+        }
+      }).catch(err => {
+        this.loading.page = false;
+        this.$message({
+          message: err,
+          type: 'error'
+        })
+      });
+    },
+    onSaveClick() {
+      this.$refs['limitForm'].validate(result => {
+        if (result) {
+          this.loading.save = true;
+          this.isEdit ? this.updateLimites() : this.addLimites();
+        }
+      })
+    },
+    addLimites() {
+      limit.addCreditLimit(this.form).then(res => {
+        this.$message({
+          message: 'Add credit limit successfully',
+          type: 'success'
+        })
+        this.onBack();
+      }).catch(err => {
+        this.$message({
+          message: err,
+          type: 'error'
+        })
+      }).finally(() => {
+        this.loading.save = false;
+      });
+    },
+    updateLimites() {
+      limit.updateCreditLimit(this.form).then(res => {
+        this.$message({
+          message: 'Update credit limit successfully',
+          type: 'success'
+        })
+        this.onBack();
+      }).catch(err => {
+        this.$message({
+          message: err,
+          type: 'error'
+        })
+      }).finally(() => {
+        this.loading.save = false;
+      });
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import '../../styles/variables.scss';
+  .container {
+    width: 100%;
+    padding: 20px 60px;
+    min-height: $mainAppMinHeight;
+    background-color: #F0F5FC;
+  }
+  .content {
+    margin: 0 8px 16px;
+    padding: 15px 50px;
+    border-radius: 6px;
+    background-color: white;
+  }
+  
+  .section-title {
+    color: #333;
+    margin-top: 20px;
+    margin-bottom: 30px;
+    font-size: 15px;
+    user-select: none;
+    line-height: 24px;
+    font-weight: bold;
+    font-family: sans-serif;
+    text-transform: uppercase;
+  }
+  .add-text {
+    width: 100%;
+    min-width: 150px;
+    max-width: 300px;
+  }
+  .add-text ::v-deep .el-textarea__inner {
+    font-family: sans-serif;
+  }
+  .hr {
+    height: 2px;
+    margin: 10px -40px;
+    background-color: #F0F5FC;
+  }
+  .buttons {
+    padding-top: 15px;
+    padding-bottom: 15px;
+  }
+  .form-left,.form-right {
+    flex: 1;
+    min-width: 300px;
+  }
+  .item-unit {
+    top: 12px;
+    left: -40px;
+    font-size: 12px;
+    user-select: none;
+    position: absolute;
+  }
+  @media screen and (max-width: 500px) {
+    .container {
+      padding: 0px;
+    }
+    .content {
+      padding: 15px 30px;
+    }
+    .form-left,.form-right {
+      width: 100%;
+      min-width: auto;
+    }
+  }
+</style>

+ 215 - 0
Strides-Admin/src/views/limit2/index.vue

@@ -0,0 +1,215 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container filter-view">
+      <el-select
+        class="filter-view-item"
+        v-model="filters.pageCriteria.dataStatus"
+        placeholder="Status"
+        @change="toSearch">
+        <el-option
+          v-for="(item, index) in statusOptions"
+          :key="index"
+          :label="item.key"
+          :value="item.value"/>
+      </el-select>
+      <div style="flex: 1; max-width: 300px;">
+        <el-input
+          v-model="filters.pageCriteria.criteria"
+          class="filter-view-item"
+          prefix-icon="el-icon-search"
+          placeholder="Search by Group Name"
+          @keyup.enter.native="toSearch"
+          @change="toSearch"
+          clearable/>
+      </div>
+      <div class="filter-flex-button">
+        <el-button
+          v-if="!$route.meta.onlyView"
+          class="filter-item"
+          type="primary"
+          icon="el-icon-plus"
+          @click="creatLimit">
+          Credit Limit Contract
+        </el-button>
+      </div>
+    </div>
+    <el-table
+      v-loading="table.loading"
+      :data="table.list">
+      <el-table-column
+        align="center"
+        label="Group"
+        prop="groupName"
+        min-width="120"/>
+      <el-table-column
+        align="center"
+        label="Service Provider"
+        prop="providerName"
+        min-width="140"/>
+      <el-table-column
+        align="center"
+        label="Monthly Credit Set"
+        prop="creditLimitAmount"
+        min-width="150"/>
+      <el-table-column
+        align="center"
+        label="Current Useage"
+        prop="creditLimitRemainingAmount"
+        min-width="140"/>
+      <el-table-column
+        align="center"
+        label="Approved Users"
+        prop="approvedUsers"
+        min-width="140"/>
+      <el-table-column
+        align="center"
+        label="Effective Period"
+        prop="effectivePeriod"
+        min-width="140"/>
+      <el-table-column
+        align="center"
+        label="Status"
+        prop="dataStatus"
+        min-width="80"/>
+      <el-table-column
+        align="center"
+        label="Action"
+        min-width="80"
+        v-if="!$route.meta.onlyView">
+        <template slot-scope="{row}">
+          <el-dropdown
+            class="action-dropdown"
+            @command="(v) => handleCommand(v, row)"
+            v-if="row.dataStatus == 'Active'">
+            <i class="el-icon-more icon-action"></i>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item
+                command="editLimit">
+                Edit
+              </el-dropdown-item>
+              <el-dropdown-item
+                command="deleteLimit">
+                Delete
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="right">
+      <Pagination
+        v-show="table.total > 0"
+        :total="table.total"
+        :page.sync="filters.pageNum"
+        :limit.sync="filters.pageSize"
+        @pagination="getTableData" />
+    </div>
+  </div>
+</template>
+
+<script>
+import apiBase from '@/api/apiBase';
+import limit from '@/api/limit';
+import Pagination from '@/components/Pagination'
+export default {
+  data() {
+    return {
+      table: {
+        loading: false,
+        total: 0,
+        list: []
+      },
+      filters: {
+        pageNum: 1,
+        pageSize: 10,
+        pageCriteria: {
+          dataStatus: "A",
+          criteria: ""
+        }
+      },
+      statusOptions: []
+    };
+  },
+  components: { Pagination },
+  created() {
+    this.getStatusOptions();
+    this.toSearch();
+  },
+  methods: {
+    toSearch() {
+      this.filters.pageNum = 1;
+      this.getTableData();
+    },
+    getStatusOptions() {
+      apiBase.getDataStatusOptions().then(res => {
+        if (res.data && res.data.length > 0) {
+          this.statusOptions = res.data
+        }
+      }).catch(err => {
+        this.$message.error(err);
+      })
+    },
+    handleCommand(fuc, item) {
+      this[fuc](item)
+    },
+    getTableData() {
+      this.table.loading = true;
+      limit.getCreditLimitPages(this.filters).then(res => {
+        if (res.data.totalRow && res.data.records) {
+          this.table.list = res.data.records
+          this.table.total = res.data.totalRow
+        } else {
+          this.table.list = []
+          this.table.total = 0
+        }
+      }).catch(err => {
+        this.$message({
+          type: 'error',
+          message: err
+        });
+        this.table.list = []
+        this.table.total = 0
+      }).finally(() => {
+        this.table.loading = false;
+      });
+    },
+    creatLimit() {
+      this.$router.push({
+        path: '/partnership-management/monthly-credit-limit/add'
+      });
+    },
+    editLimit(row) {
+      this.$router.push({
+        path: '/partnership-management/monthly-credit-limit/edit/' + row.groupCreditPk
+      });
+    },
+    deleteLimit(row) {
+      this.$confirm('Are you sure you want to delete this credit limit?', 'Delete', {
+        confirmButtonText: 'OK',
+        cancelButtonText: 'Cancel',
+        type: 'warning'
+      }).then(res => {
+        this.handleDeleteLimit(row.groupCreditPk)
+      })
+    },
+    handleDeleteLimit(id) {
+      limit.deleteCreditLimit(id).then(res => {
+        this.$message({
+          message: 'Delete credit limit successfully',
+          type: 'success'
+        });
+        this.getTableData();
+      }).catch(err => {
+        this.$message({
+          message: err,
+          type: 'error'
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 258 - 0
Strides-Admin/src/views/limit2/plans.vue

@@ -0,0 +1,258 @@
+<template>
+  <div class="plans-content">
+    <div class="button-right">
+      <el-button
+        type="primary"
+        icon="el-icon-plus"
+        @click="showAddPlan">
+        Individual Plan
+      </el-button>
+    </div>
+    <el-table
+      v-loading="table.loading"
+      :data="table.data">
+      <el-table-column
+        align="center"
+        label="Amount"
+        prop="currentRemainCredit"
+        min-width="100"/>
+      <el-table-column
+        align="center"
+        label="Date Created"
+        prop="createTime"
+        min-width="120"/>
+      <el-table-column
+        align="center"
+        label="Assigned Users"
+        prop="assignedUsers"
+        min-width="120"/>
+      <el-table-column
+        align="center"
+        label="Current Consumption"
+        prop="currentTotalCredit"
+        min-width="140"/>
+      <el-table-column
+        align="center"
+        label="Action"
+        min-width="80">
+        <template slot-scope="{row, $index}">
+          <el-dropdown
+            class="action-dropdown"
+            @command="(v) => handleCommand(v, row)">
+            <i class="el-icon-more icon-action"></i>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item
+                command="assignPlan">
+                Assign Users
+              </el-dropdown-item>
+              <el-dropdown-item
+                command="deletePlan">
+                Delete
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </template>
+      </el-table-column>
+    </el-table>
+    <div class="right">
+      <Pagination
+        v-show="table.total"
+        :total="table.total"
+        :page.sync="filter.pageNum"
+        :limit.sync="filter.pageSize"
+        @pagination="getPlanList"/>
+    </div>
+    <el-dialog
+      title="Individual Plan"
+      :visible="addPlan.visible"
+      :before-close="hideAddPlan"
+      :close-on-click-modal="false"
+      class="individual-plan-dialog">
+      <div class="bold" style="padding-bottom: 15px;">Set Amount</div>
+      <el-input
+        class="add-text"
+        v-model.number="addPlan.form.planCredit"
+        maxlength="9"/>
+      <div class="buttons">
+        <el-button
+          type="primary"
+          class="cancel-button flex1"
+          @click="hideAddPlan">
+          Cancel
+        </el-button>
+        <el-button
+          class="flex1"
+          style="margin-left: 10px;"
+          type="primary"
+          :loading="addPlan.loading"
+          @click="addPlanRow">
+          Add
+        </el-button>
+      </div>
+    </el-dialog>
+    <assignment
+      v-bind="dialogAssign"
+      @hide="hideAssignDialog"/>
+  </div>
+</template>
+
+<script>
+import limit from '@/api/limit.js'
+import Pagination from '@/components/Pagination'
+import assignment from './assignment.vue'
+export default {
+  name: "plans",
+  props: {
+    id: {
+      type: Number|String,
+      default: ""
+    },
+    groupPk: {
+      type: Number|String,
+      default: ""
+    }
+  },
+  data() {
+    return {
+      table: {
+        total: 0,
+        data: [],
+        loading: false
+      },
+      filter: {
+        pageNum: 1,
+        pageSize: 10,
+        pageCriteria: {
+          criteria: "",
+          groupCreditPk: ""
+        }
+      },
+      addPlan: {
+        visible: false,
+        loading: false,
+        form: {
+          planCredit: "",
+          groupCreditPk: ""
+        }
+      },
+      dialogAssign: {
+        item: {},
+        groupPk: "",
+        visible: false
+      }
+    };
+  },
+  components: {Pagination, assignment},
+  mounted() {
+    if (this.id) {
+      this.addPlan.form.groupCreditPk = this.id;
+      this.filter.pageCriteria.groupCreditPk =  this.id;
+      this.getPlanList();
+    }
+  },
+  methods: {
+    getPlanList() {
+      this.table.loading = true;
+      limit.getCreditLimitPlanPages(this.filter).then(res => {
+        if (res.data.totalRow && res.data.records) {
+          this.table.data = res.data.records
+          this.table.total = res.data.totalRow
+        } else {
+          this.table.data = []
+          this.table.total = 0
+        }
+        this.table.loading = false;
+      }).catch(err => {
+        this.table.loading = false;
+        this.table.data = [];
+        this.table.total = 0;
+      })
+    },
+    handleCommand(fuc, item) {
+      this[fuc](item)
+    },
+    showAddPlan() {
+      this.addPlan.visible = true;
+    },
+    hideAddPlan() {
+      this.addPlan.visible = false;
+    },
+    addPlanRow() {
+      this.addPlan.loading = true;
+      limit.addCreditLimitPlan(this.addPlan.form).then(res => {
+        this.$message.success("Added successfully.")
+        this.hideAddPlan();
+        this.getPlanList();
+      }).catch(err => {
+        this.$message({
+          message: err,
+          type: 'error'
+        })
+      }).finally(() => {
+        this.addPlan.loading = false;
+      });
+    },
+    assignPlan(item) {
+      this.dialogAssign.item = item;
+      this.dialogAssign.groupPk = this.groupPk;
+      this.dialogAssign.visible = true;
+    },
+    deletePlan(item) {
+      this.$confirm('Are you sure you want to delete this plan?', 'Delete', {
+        confirmButtonText: 'OK',
+        cancelButtonText: 'Cancel',
+        type: 'warning'
+      }).then(res => {
+        this.handleDeletePlan(item.groupCreditPlanId)
+      })
+    },
+    handleDeletePlan(id) {
+      limit.deleteCreditLimitPlan(id).then(res => {
+        this.$message({
+          message: 'Delete successfully',
+          type: 'success'
+        });
+        this.getPlanList();
+      }).catch(err => {
+        this.$message({
+          message: err,
+          type: 'error'
+        })
+      })
+    },
+    hideAssignDialog(e) {
+      this.dialogAssign.item = {};
+      this.dialogAssign.visible = false;
+      if (e) {
+        this.getPlanList();
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.plans-content {
+  position: relative;
+}
+.button-right {
+  top: -55px;
+  right: 0;
+  position: absolute;
+}
+.individual-plan-dialog {
+  padding-bottom: 120px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.individual-plan-dialog >>> .el-dialog {
+  width: 100%;
+  max-width: 450px;
+}
+.buttons {
+  display: flex;
+  padding-top: 25px;
+  align-items: center;
+}
+</style>

+ 4 - 2
Strides-Admin/src/views/ocpi/configs.vue

@@ -48,7 +48,8 @@
         align="center"
         label="Token"
         prop="token"
-        min-width="150"/>
+        min-width="150"
+        v-if="showToken"/>
       <el-table-column
         align="center"
         label="Date Created"
@@ -128,7 +129,8 @@ export default {
         visible: false,
         info: {},
         isEdit: false
-      }
+      },
+      showToken: setting.enableOCPIToken
     };
   },
   components: { Pagination, DialogConfigs },

+ 17 - 2
Strides-Admin/src/views/ocpi/dialog/DialogConfigs.vue

@@ -26,7 +26,7 @@
         class="form-item"
         label="Token:">
         <el-input
-          v-model="form.token"
+          :value="getToken"
           class="flex-item"
           readonly>
           <el-button
@@ -66,6 +66,7 @@
 
 <script>
 import ocpi from '../../../http/api/ocpi.js';
+import setting from '../../../settings.js';
 export default {
   name: "DialogConfigs",
   props: {
@@ -101,7 +102,8 @@ export default {
           message: "Remarks is required",
           trigger: "blur"
         }
-      }
+      },
+      showToken: setting.enableOCPIToken
     };
   },
   watch: {
@@ -119,6 +121,19 @@ export default {
       }
     }
   },
+  computed: {
+    getToken() {
+      if (this.showToken) {
+        return this.form.token;
+      } else if (this.form.token) {
+        const tk1 = this.form.token.substring(0, 6);
+        const tk2 = this.form.token.substring(this.form.token.length - 5);
+        return tk1 + "********************" + tk2;
+      } else {
+        return "";
+      }
+    }
+  },
   mounted() {
     
   },

+ 8 - 1
Strides-Admin/src/views/ocpi/views/DetailOperators.vue

@@ -59,7 +59,8 @@
           </el-form-item>
           <el-form-item
             label=""
-            label-width="30px">
+            label-width="40px"
+            class="ocpi-data-content">
             <div class="status-row" v-for="(item, index) in Object.keys(form.countConnectorStatus)" :key="index">
               <div class="status-icon">●</div>
               <div class="status-name">{{item}}: </div>
@@ -264,6 +265,12 @@ export default {
   ::v-deep .el-form-item {
     margin-bottom: 0;
   }
+  .ocpi-data-content {
+    padding: 15px 0;
+    margin-top: 10px;
+    border-radius: 16px;
+    background-color: #F0F0F0;
+  }
   @media screen and (max-width: 500px) {
     .container {
       padding: 0px;

+ 1 - 0
Strides-Admin/src/views/site-label/assignment.vue

@@ -173,6 +173,7 @@ export default {
       })
     },
     getTableData() {
+      this.table.loading = true;
       api.getLabelAssignPages(this.filter).then(res => {
         if (res.total && res.data) {
           this.table.total = res.total;