|
|
@@ -0,0 +1,561 @@
|
|
|
+<template>
|
|
|
+ <div class="container" v-loading="loading">
|
|
|
+ <el-form
|
|
|
+ ref="userRef"
|
|
|
+ :model="userForm"
|
|
|
+ :rules="rules"
|
|
|
+ label-width="140px"
|
|
|
+ label-position="right">
|
|
|
+ <div class="content">
|
|
|
+ <div class="section-title">PROFILE DETAILS</div>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ prop='nickName'
|
|
|
+ label="Display Name:"
|
|
|
+ class="flex1">
|
|
|
+ <el-input
|
|
|
+ class="input-text"
|
|
|
+ v-model="userForm.nickName"/>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Phone Number:"
|
|
|
+ prop="phone"
|
|
|
+ class="flex1">
|
|
|
+ <div class="input-text flexc">
|
|
|
+ <el-select
|
|
|
+ v-model="userForm.callingCode"
|
|
|
+ class="area-code">
|
|
|
+ <el-option
|
|
|
+ v-for="areaCode in options.callingCode"
|
|
|
+ :label="'+'+areaCode.callingCode"
|
|
|
+ :value="areaCode.callingCode"
|
|
|
+ :key="areaCode.callingCode" />
|
|
|
+ </el-select>
|
|
|
+ <el-input
|
|
|
+ class="phone-number"
|
|
|
+ v-model="userForm.phone" />
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Email Address:"
|
|
|
+ prop="email"
|
|
|
+ class="flex1">
|
|
|
+ <el-input
|
|
|
+ class="input-text"
|
|
|
+ v-model="userForm.email" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <div class="section-title">Address</div>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Country:">
|
|
|
+ <el-select
|
|
|
+ v-model="userForm.address.country"
|
|
|
+ class="input-text">
|
|
|
+ <el-option
|
|
|
+ v-for="item in options.country"
|
|
|
+ :key="item.name"
|
|
|
+ :label="item.name"
|
|
|
+ :value="item.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Street:">
|
|
|
+ <el-input
|
|
|
+ class="input-text"
|
|
|
+ v-model="userForm.address.street" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="City:">
|
|
|
+ <el-input
|
|
|
+ class="input-text"
|
|
|
+ v-model="userForm.address.city" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Postal Code:">
|
|
|
+ <el-input
|
|
|
+ class="input-text"
|
|
|
+ v-model="userForm.address.zipCode" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div class="content">
|
|
|
+ <div class="section-title">ACCOUNT DETAILS</div>
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Account Type:"
|
|
|
+ class="flex1">
|
|
|
+ <el-select
|
|
|
+ v-model="userForm.accountType"
|
|
|
+ class="input-text">
|
|
|
+ <el-option
|
|
|
+ v-for="item in options.userType"
|
|
|
+ :key="item"
|
|
|
+ :label="item"
|
|
|
+ :value="item" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <template v-if="isEdit">
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Charging History:"
|
|
|
+ class="flex1">
|
|
|
+ <div class="flexc input-text">
|
|
|
+ <el-input
|
|
|
+ class="input-text-1"
|
|
|
+ v-model="userForm.chargingCount"
|
|
|
+ readonly/>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ @click="toHistoryCharge">
|
|
|
+ VIEW HISTORY
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Credit Amount:">
|
|
|
+ <div class="flexc input-text">
|
|
|
+ <el-input
|
|
|
+ class="input-text-1"
|
|
|
+ :value="userForm.currencySymbol + ' ' + userForm.credit"
|
|
|
+ readonly/>
|
|
|
+ <el-button
|
|
|
+ type="success"
|
|
|
+ @click="showTopupModal">
|
|
|
+ TOP UP
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :xs="24" :md="12">
|
|
|
+ <el-form-item
|
|
|
+ label="Top-up History:"
|
|
|
+ class="flex1">
|
|
|
+ <div class="flexc input-text">
|
|
|
+ <el-input
|
|
|
+ class="input-text-1"
|
|
|
+ v-model="userForm.topUpCount"
|
|
|
+ readonly/>
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ @click="toHistoryTopup">
|
|
|
+ VIEW HISTORY
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </template>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ <div class="content">
|
|
|
+ <div class="section-title">VEHICLE DETIALS</div>
|
|
|
+ <ListVehicle v-model="userForm.vehicles"/>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="content"
|
|
|
+ v-show="userForm.accountType == 'MEMBER'">
|
|
|
+ <div class="section-title">Memberships</div>
|
|
|
+ <ListMember
|
|
|
+ v-model="userForm.members"/>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="content"
|
|
|
+ v-show="userForm.accountType == 'FLEET'">
|
|
|
+ <div class="section-title">Fleet</div>
|
|
|
+ <ListMember
|
|
|
+ v-model="userForm.fleets"
|
|
|
+ :isFleet="true"/>
|
|
|
+ </div>
|
|
|
+ <div class="content flexcr">
|
|
|
+ <div class="buttons">
|
|
|
+ <el-button
|
|
|
+ class="cancel-button"
|
|
|
+ type="primary"
|
|
|
+ @click="handleClickCancleButton">
|
|
|
+ Cancel
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ class="confirm-button"
|
|
|
+ type="primary"
|
|
|
+ @click="handleClickConfirmButton">
|
|
|
+ Save
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ <div class="update-by" v-if="isEdit">
|
|
|
+ <span
|
|
|
+ class="add-text"
|
|
|
+ :title='"CREATED BY " + userForm.createdBy + " ON " + userForm.createdOn'>
|
|
|
+ LAST UPDATED BY {{userForm.updatedBy}} TIMESTAMP: {{userForm.updatedOn}}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ <TopUp
|
|
|
+ :visible="showTopup"
|
|
|
+ :userInfo="userForm"
|
|
|
+ @hide="hideTopupModal"
|
|
|
+ @success="hideTopupModal(true)"/>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import api from '@/http/api/apiUser'
|
|
|
+import site from '../../http/api/site'
|
|
|
+import {getCountryList} from '../../utils/index.js'
|
|
|
+import TopUp from './views/TopUp.vue'
|
|
|
+import settings from '../../settings.js'
|
|
|
+import ListMember from './views/ListMember.vue'
|
|
|
+import ListVehicle from './views/ListVehicle.vue'
|
|
|
+export default {
|
|
|
+ components: {ListMember,ListVehicle,TopUp},
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ loading: false,
|
|
|
+ options: {
|
|
|
+ country: [],
|
|
|
+ userType: [],
|
|
|
+ callingCode: []
|
|
|
+ },
|
|
|
+ userForm: {
|
|
|
+ userPk: '',
|
|
|
+ email: '',
|
|
|
+ nickName: '',
|
|
|
+ phone: '',
|
|
|
+ callingCode: settings.defaultCalling,
|
|
|
+ countryCode: settings.defaultCountry,
|
|
|
+ accountType: "PUBLIC",
|
|
|
+ address: {
|
|
|
+ zipCode: '',
|
|
|
+ street: '',
|
|
|
+ city: '',
|
|
|
+ country: settings.defaultCountry,
|
|
|
+ addressPk: '',
|
|
|
+ houseNumber: ''
|
|
|
+ },
|
|
|
+ fleet: {
|
|
|
+ groupPk: "",
|
|
|
+ cardFront: "",
|
|
|
+ membershipNo: ""
|
|
|
+ },
|
|
|
+ fleets: [],
|
|
|
+ members: [],
|
|
|
+ vehicles: [],
|
|
|
+ chargingCount: "",
|
|
|
+ topUpCount: "",
|
|
|
+ credit: 0,
|
|
|
+ currencySymbol: "$"
|
|
|
+ },
|
|
|
+ rules: {
|
|
|
+ nickName: [{
|
|
|
+ required: true,
|
|
|
+ trigger: 'blur',
|
|
|
+ message: 'Display Name is required',
|
|
|
+ }],
|
|
|
+ email: [{
|
|
|
+ required: true,
|
|
|
+ trigger: 'blur',
|
|
|
+ message: 'Email is required',
|
|
|
+ }],
|
|
|
+ phone: [{
|
|
|
+ required: true,
|
|
|
+ trigger: 'blur',
|
|
|
+ message: 'Phone Number is required',
|
|
|
+ }],
|
|
|
+ address: {
|
|
|
+ zipCode: [{
|
|
|
+ required: true,
|
|
|
+ trigger: 'blur',
|
|
|
+ message: 'Postal Code is required',
|
|
|
+ }],
|
|
|
+ street: [{
|
|
|
+ required: true,
|
|
|
+ trigger: 'blur',
|
|
|
+ message: 'Street is required',
|
|
|
+ }],
|
|
|
+ city: [{
|
|
|
+ required: true,
|
|
|
+ trigger: 'blur',
|
|
|
+ message: 'City is required',
|
|
|
+ }],
|
|
|
+ country: [{
|
|
|
+ required: true,
|
|
|
+ trigger: 'blur',
|
|
|
+ message: 'Country is required',
|
|
|
+ }]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ isEdit: false,
|
|
|
+ showTopup: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.loading = true;
|
|
|
+ this.getCountryList()
|
|
|
+ if (this.$route.params.id) {
|
|
|
+ this.isEdit = true;
|
|
|
+ this.getUserInfo()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handleClickCancleButton() {
|
|
|
+ this.$router.replace({
|
|
|
+ path: "/user-management"
|
|
|
+ })
|
|
|
+ },
|
|
|
+ getCountryList() {
|
|
|
+ site.getCountryList().then(res => {
|
|
|
+ if (res.data) {
|
|
|
+ this.options.country = res.data
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ this.$message({
|
|
|
+ message: error,
|
|
|
+ type: 'error'
|
|
|
+ })
|
|
|
+ this.loading = false;
|
|
|
+ })
|
|
|
+ getCountryList(list => {
|
|
|
+ this.options.callingCode = list
|
|
|
+ })
|
|
|
+ this.getUserTypeOption();
|
|
|
+ },
|
|
|
+ getUserTypeOption() {
|
|
|
+ api.getUserTypeOptions().then(res => {
|
|
|
+ if (res.data) {
|
|
|
+ this.options.userType = res.data
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ this.$message({
|
|
|
+ message: error,
|
|
|
+ type: 'error'
|
|
|
+ })
|
|
|
+ }).finally(() => {
|
|
|
+ this.loading = false;
|
|
|
+ })
|
|
|
+ },
|
|
|
+ getUserInfo() {
|
|
|
+ api.getAppUserInfo(this.$route.params.id).then(res => {
|
|
|
+ if (res.data) {
|
|
|
+ this.userForm = res.data
|
|
|
+ this.userForm.fleets = []
|
|
|
+ if (res.data.fleet) {
|
|
|
+ this.userForm.fleets.push(res.data.fleet)
|
|
|
+ }
|
|
|
+ if (!res.data.address) {
|
|
|
+ this.userForm.address = {
|
|
|
+ zipCode: '',
|
|
|
+ street: '',
|
|
|
+ city: '',
|
|
|
+ country: settings.defaultCountry,
|
|
|
+ addressPk: '',
|
|
|
+ houseNumber: ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ this.$message.error(err)
|
|
|
+ }).finally(() => {
|
|
|
+ this.loading = false;
|
|
|
+ })
|
|
|
+ },
|
|
|
+ handleClickConfirmButton() {
|
|
|
+ this.$refs.userRef.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ if (this.userForm.accountType == "FLEET") {
|
|
|
+ this.userForm.fleet = this.userForm.fleets[0]
|
|
|
+ } else {
|
|
|
+ this.userForm.fleet = null;
|
|
|
+ }
|
|
|
+ if (this.userForm.accountType != "MEMBER") {
|
|
|
+ this.userForm.members = []
|
|
|
+ }
|
|
|
+ var list = this.userForm.vehicles.filter(item => (item.brand && item.model && item.licensePlate))
|
|
|
+ if (list.length == 0) {
|
|
|
+ list = null;
|
|
|
+ }
|
|
|
+ this.userForm.vehicles = list;
|
|
|
+ if (this.isEdit) {
|
|
|
+ this.updateUser()
|
|
|
+ } else {
|
|
|
+ this.addUser();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ updateUser() {
|
|
|
+ this.loading = true
|
|
|
+ api.updateAppUser(this.userForm).then(() => {
|
|
|
+ this.$message({
|
|
|
+ message: 'Update user successfully',
|
|
|
+ type: 'success'
|
|
|
+ })
|
|
|
+ this.handleClickCancleButton();
|
|
|
+ }).catch((error) => {
|
|
|
+ this.$message({
|
|
|
+ message: error,
|
|
|
+ type: 'error'
|
|
|
+ })
|
|
|
+ }).finally(() => {
|
|
|
+ this.loading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ addUser() {
|
|
|
+ this.loading = true
|
|
|
+ api.addAppUser(this.userForm).then(() => {
|
|
|
+ this.$message({
|
|
|
+ message: 'Add user successfully',
|
|
|
+ type: 'success'
|
|
|
+ })
|
|
|
+ this.handleClickCancleButton();
|
|
|
+ }).catch((error) => {
|
|
|
+ this.$message({
|
|
|
+ message: error,
|
|
|
+ type: 'error'
|
|
|
+ })
|
|
|
+ }).finally(() => {
|
|
|
+ this.loading = false
|
|
|
+ })
|
|
|
+ },
|
|
|
+ showTopupModal() {
|
|
|
+ this.showTopup = true
|
|
|
+ },
|
|
|
+ hideTopupModal(success) {
|
|
|
+ this.showTopup = false;
|
|
|
+ if (success) {
|
|
|
+ this.getUserInfo()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ toHistoryCharge() {
|
|
|
+ this.$router.push("/user-management/charging-history/" + this.$route.params.id)
|
|
|
+ },
|
|
|
+ toHistoryTopup() {
|
|
|
+ this.$router.push("/user-management/topup-history/" + this.$route.params.id)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang='scss'>
|
|
|
+ @import '../../styles/variables.scss';
|
|
|
+ .container {
|
|
|
+ width: 100%;
|
|
|
+ padding: 20px 60px;
|
|
|
+ min-height: $mainAppMinHeight;
|
|
|
+ background-color: #F0F5FC;
|
|
|
+ }
|
|
|
+ .content {
|
|
|
+ margin: 0 8px 16px;
|
|
|
+ padding: 15px 80px;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ .input-text {
|
|
|
+ width: 100%;
|
|
|
+ min-width: 150px;
|
|
|
+ }
|
|
|
+ .input-text ::v-deep .el-textarea__inner {
|
|
|
+ font-family: sans-serif;
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-text-1 {
|
|
|
+ flex: 1;
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .area-code {
|
|
|
+ width: 80px;
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .phone-number {
|
|
|
+ flex: 1;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-photo {
|
|
|
+ flex: 1;
|
|
|
+ ::v-deep .el-form-item__label {
|
|
|
+ padding: 12px;
|
|
|
+ line-height: 16px;
|
|
|
+ }
|
|
|
+ .photo-uploader {
|
|
|
+ margin-right: 10px;
|
|
|
+ .uploader-image {
|
|
|
+ width: 180px;
|
|
|
+ height: 120px;
|
|
|
+ text-align: left;
|
|
|
+ }
|
|
|
+ ::v-deep img {
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+ .avatar-uploader-icon {
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 28px;
|
|
|
+ color: #8c939d;
|
|
|
+ width: 120px;
|
|
|
+ height: 120px;
|
|
|
+ line-height: 120px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .hr {
|
|
|
+ height: 2px;
|
|
|
+ margin: 10px -40px;
|
|
|
+ background-color: #F0F5FC;
|
|
|
+ }
|
|
|
+ .buttons {
|
|
|
+ padding-top: 15px;
|
|
|
+ padding-bottom: 15px;
|
|
|
+ }
|
|
|
+ @media screen and (max-width: 800px) {
|
|
|
+ .container {
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+ .content {
|
|
|
+ padding: 15px 30px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @media screen and (max-width: 500px) {
|
|
|
+ .container {
|
|
|
+ padding: 0px;
|
|
|
+ }
|
|
|
+ .content {
|
|
|
+ padding: 15px 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|