mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-14 06:57:35 +08:00
support exchange rate
This commit is contained in:
@@ -168,6 +168,9 @@ func startWebServer(c *cli.Context) error {
|
||||
apiV1Route.POST("/accounts/hide.json", bindApi(api.Accounts.AccountHideHandler))
|
||||
apiV1Route.POST("/accounts/move.json", bindApi(api.Accounts.AccountMoveHandler))
|
||||
apiV1Route.POST("/accounts/delete.json", bindApi(api.Accounts.AccountDeleteHandler))
|
||||
|
||||
// Exchange Rates
|
||||
apiV1Route.GET("/exchange_rates/latest.json", bindApi(api.ExchangeRates.LatestExchangeRateHandler))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/mayswind/lab/pkg/core"
|
||||
"github.com/mayswind/lab/pkg/errs"
|
||||
"github.com/mayswind/lab/pkg/log"
|
||||
"github.com/mayswind/lab/pkg/models"
|
||||
)
|
||||
|
||||
const EuroCentralBankExchangeRateUrl = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
|
||||
|
||||
type ExchangeRatesApi struct {}
|
||||
|
||||
var (
|
||||
ExchangeRates = &ExchangeRatesApi{}
|
||||
)
|
||||
|
||||
func (a *ExchangeRatesApi) LatestExchangeRateHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||
uid := c.GetCurrentUid()
|
||||
resp, err := http.Get(EuroCentralBankExchangeRateUrl)
|
||||
|
||||
if err != nil {
|
||||
log.ErrorfWithRequestId(c, "[exchange_rates.LatestExchangeRateHandler] failed to request latest exchange rate data for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.ErrFailedToRequestRemoteApi
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
log.ErrorfWithRequestId(c, "[exchange_rates.LatestExchangeRateHandler] failed to get latest exchange rate data response for user \"uid:%d\", because response code is not 200", uid)
|
||||
return nil, errs.ErrFailedToRequestRemoteApi
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
euroCentralBankData := &models.EuroCentralBankExchangeRateData{}
|
||||
err = xml.Unmarshal(body, euroCentralBankData)
|
||||
|
||||
if err != nil {
|
||||
log.ErrorfWithRequestId(c, "[exchange_rates.LatestExchangeRateHandler] failed to parse xml data for user \"uid:%d\", response is %s, because %s", uid, string(body), err.Error())
|
||||
return nil, errs.ErrFailedToRequestRemoteApi
|
||||
}
|
||||
|
||||
latestExchangeRateResponse := euroCentralBankData.ToLatestExchangeRateResponse()
|
||||
|
||||
if latestExchangeRateResponse == nil {
|
||||
log.ErrorfWithRequestId(c, "[exchange_rates.LatestExchangeRateHandler] failed to parse latest exchange rate data for user \"uid:%d\", response is %s,", uid, string(body))
|
||||
return nil, errs.ErrFailedToRequestRemoteApi
|
||||
}
|
||||
|
||||
return latestExchangeRateResponse, nil
|
||||
}
|
||||
@@ -11,6 +11,7 @@ var (
|
||||
ErrRequestIdInvalid = NewNormalError(NORMAL_SUBCATEGORY_GLOBAL, 2, http.StatusInternalServerError, "request id is invalid")
|
||||
ErrCiphertextInvalid = NewNormalError(NORMAL_SUBCATEGORY_GLOBAL, 3, http.StatusInternalServerError, "ciphertext is invalid")
|
||||
ErrNothingWillBeUpdated = NewNormalError(NORMAL_SUBCATEGORY_GLOBAL, 4, http.StatusBadRequest, "nothing will be updated")
|
||||
ErrFailedToRequestRemoteApi = NewNormalError(NORMAL_SUBCATEGORY_GLOBAL, 5, http.StatusBadRequest, "failed to request third party api")
|
||||
)
|
||||
|
||||
func GetParameterInvalidMessage(field string) string {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package models
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
const EuroCentralBankDataSource = "European Central Bank"
|
||||
const EuroCentralBankBaseCurrency = "EUR"
|
||||
|
||||
type LatestExchangeRateResponse struct {
|
||||
DataSource string `json:"dataSource"`
|
||||
Date string `json:"date"`
|
||||
BaseCurrency string `json:"baseCurrency"`
|
||||
ExchangeRates []*LatestExchangeRate `json:"exchangeRates"`
|
||||
}
|
||||
|
||||
type LatestExchangeRate struct {
|
||||
Currency string `json:"currency"`
|
||||
Rate string `json:"rate"`
|
||||
}
|
||||
|
||||
type EuroCentralBankExchangeRateData struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
AllExchangeRates []*EuroCentralBankExchangeRates `xml:"Cube>Cube"`
|
||||
}
|
||||
|
||||
type EuroCentralBankExchangeRates struct {
|
||||
Date string `xml:"time,attr"`
|
||||
ExchangeRates []*EuroCentralBankExchangeRate `xml:"Cube"`
|
||||
}
|
||||
|
||||
type EuroCentralBankExchangeRate struct {
|
||||
Currency string `xml:"currency,attr"`
|
||||
Rate string `xml:"rate,attr"`
|
||||
}
|
||||
|
||||
func (e EuroCentralBankExchangeRateData) ToLatestExchangeRateResponse() *LatestExchangeRateResponse {
|
||||
if len(e.AllExchangeRates) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
latestEuroCentralBankExchangeRate := e.AllExchangeRates[0]
|
||||
|
||||
if len(latestEuroCentralBankExchangeRate.ExchangeRates) < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
exchangeRates := make([]*LatestExchangeRate, len(latestEuroCentralBankExchangeRate.ExchangeRates))
|
||||
|
||||
for i := 0; i < len(latestEuroCentralBankExchangeRate.ExchangeRates); i++ {
|
||||
exchangeRates[i] = latestEuroCentralBankExchangeRate.ExchangeRates[i].ToLatestExchangeRate()
|
||||
}
|
||||
|
||||
latestExchangeRateResp := &LatestExchangeRateResponse{
|
||||
DataSource: EuroCentralBankDataSource,
|
||||
Date: latestEuroCentralBankExchangeRate.Date,
|
||||
BaseCurrency: EuroCentralBankBaseCurrency,
|
||||
ExchangeRates: exchangeRates,
|
||||
}
|
||||
|
||||
return latestExchangeRateResp
|
||||
}
|
||||
|
||||
func (e EuroCentralBankExchangeRate) ToLatestExchangeRate() *LatestExchangeRate {
|
||||
return &LatestExchangeRate{
|
||||
Currency: e.Currency,
|
||||
Rate: e.Rate,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
const exchangeRatesLocalStorageKey = 'lab_exchange_rates';
|
||||
|
||||
function getExchangeRates() {
|
||||
const storageData = localStorage.getItem(exchangeRatesLocalStorageKey) || '{}';
|
||||
return JSON.parse(storageData);
|
||||
}
|
||||
|
||||
function setExchangeRates(value) {
|
||||
const storageData = JSON.stringify(value);
|
||||
localStorage.setItem(exchangeRatesLocalStorageKey, storageData);
|
||||
}
|
||||
|
||||
function clearExchangeRates() {
|
||||
localStorage.removeItem(exchangeRatesLocalStorageKey);
|
||||
}
|
||||
|
||||
export default {
|
||||
getExchangeRates,
|
||||
setExchangeRates,
|
||||
clearExchangeRates,
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import axios from 'axios';
|
||||
import userState from "./userstate.js";
|
||||
import exchangeRates from "./exchangeRates.js";
|
||||
|
||||
let needBlockRequest = false;
|
||||
let blockedRequests = [];
|
||||
@@ -209,4 +210,20 @@ export default {
|
||||
id
|
||||
});
|
||||
},
|
||||
getLatestExchangeRates: () => {
|
||||
return axios.get('v1/exchange_rates/latest.json');
|
||||
},
|
||||
refreshLatestExchangeRates: () => {
|
||||
return axios.get('v1/exchange_rates/latest.json', {
|
||||
ignoreError: true
|
||||
}).then(response => {
|
||||
const data = response.data;
|
||||
|
||||
if (data && data.success && data.result && data.result.exchangeRates) {
|
||||
exchangeRates.setExchangeRates(data.result);
|
||||
}
|
||||
|
||||
return data.result;
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ const serverSettingsCookieKey = 'ACP_SETTINGS';
|
||||
|
||||
const defaultSettings = {
|
||||
lang: 'en',
|
||||
autoUpdateExchangeRatesData: true,
|
||||
thousandsSeparator: true,
|
||||
currencyDisplayMode: 'code', // or 'none' or 'name'
|
||||
showAccountBalance: true,
|
||||
@@ -72,6 +73,8 @@ function clearSettings() {
|
||||
export default {
|
||||
getLanguage: () => getOriginalOption('lang'),
|
||||
setLanguage: value => setOption('lang', value),
|
||||
isAutoUpdateExchangeRatesData: () => getOption('autoUpdateExchangeRatesData'),
|
||||
setAutoUpdateExchangeRatesData: value => setOption('autoUpdateExchangeRatesData', value),
|
||||
isEnableThousandsSeparator: () => getOption('thousandsSeparator'),
|
||||
setEnableThousandsSeparator: value => setOption('thousandsSeparator', value),
|
||||
getCurrencyDisplayMode: () => getOption('currencyDisplayMode'),
|
||||
|
||||
@@ -8,6 +8,9 @@ export default {
|
||||
'currency': 'USD',
|
||||
},
|
||||
'format': {
|
||||
'date': {
|
||||
'long': 'MM/DD/YYYY'
|
||||
},
|
||||
'datetime': {
|
||||
'long': 'MM/DD/YYYY HH:mm:ss',
|
||||
}
|
||||
@@ -178,6 +181,7 @@ export default {
|
||||
'incomplete or incorrect submission': 'Incomplete or incorrect submission',
|
||||
'operation failed': 'Operation failed',
|
||||
'nothing will be updated': 'Nothing will be updated',
|
||||
'failed to request third party api': 'Failed to request third party api',
|
||||
'user id is invalid': 'User id is invalid',
|
||||
'username is empty': 'Username is empty',
|
||||
'email is empty': 'Email is empty',
|
||||
@@ -359,6 +363,7 @@ export default {
|
||||
'Unable to delete this account': 'Unable to delete this account',
|
||||
'User Profile': 'User Profile',
|
||||
'Language': 'Language',
|
||||
'Auto Update Exchange Rates Data': 'Auto Update Exchange Rates Data',
|
||||
'Enable Thousands Separator': 'Enable Thousands Separator',
|
||||
'Currency Display Mode': 'Currency Display Mode',
|
||||
'Currency Code': 'Currency Code',
|
||||
@@ -399,6 +404,14 @@ export default {
|
||||
'Log Out': 'Log Out',
|
||||
'Are you sure you want to log out?': 'Are you sure you want to log out?',
|
||||
'Unable to logout': 'Unable to logout',
|
||||
'Exchange Rates Data': 'Exchange Rates Data',
|
||||
'Base Currency': 'Base Currency',
|
||||
'Last Updated': 'Last Updated',
|
||||
'Data source': 'Data source',
|
||||
'No exchange rates data': 'No exchange rates data',
|
||||
'There is no exchange rates data for your default currency': 'There is no exchange rates data for your default currency',
|
||||
'Exchange rates data has been updated': 'Exchange rates data has been updated',
|
||||
'Unable to get exchange rates data': 'Unable to get exchange rates data',
|
||||
'About': 'About',
|
||||
'Official Website': 'Official Website',
|
||||
'License': 'License',
|
||||
|
||||
@@ -8,6 +8,9 @@ export default {
|
||||
'currency': 'CNY',
|
||||
},
|
||||
'format': {
|
||||
'date': {
|
||||
'long': 'YYYY年MM月DD日'
|
||||
},
|
||||
'datetime': {
|
||||
'long': 'YYYY年MM月DD日 HH:mm:ss',
|
||||
}
|
||||
@@ -178,6 +181,7 @@ export default {
|
||||
'incomplete or incorrect submission': '提交不完整或不正确',
|
||||
'operation failed': '操作失败',
|
||||
'nothing will be updated': '没有内容更新',
|
||||
'failed to request third party api': '请求第三方接口失败',
|
||||
'user id is invalid': '用户ID无效',
|
||||
'username is empty': '用户名为空',
|
||||
'email is empty': '电子邮箱为空',
|
||||
@@ -359,6 +363,7 @@ export default {
|
||||
'Unable to delete this account': '无法删除该账户',
|
||||
'User Profile': '用户信息',
|
||||
'Language': '语言',
|
||||
'Auto Update Exchange Rates Data': '自动更新汇率数据',
|
||||
'Enable Thousands Separator': '启用千位分隔符',
|
||||
'Currency Display Mode': '货币显示模式',
|
||||
'Currency Code': '货币代码',
|
||||
@@ -399,6 +404,14 @@ export default {
|
||||
'Log Out': '退出登录',
|
||||
'Are you sure you want to log out?': '您确定是否要退出登录?',
|
||||
'Unable to logout': '无法退出登录',
|
||||
'Exchange Rates Data': '汇率数据',
|
||||
'Base Currency': '基准货币',
|
||||
'Last Updated': '最后更新',
|
||||
'Data source': '数据来源',
|
||||
'No exchange rates data': '没有汇率数据',
|
||||
'There is no exchange rates data for your default currency': '没有您默认货币的汇率数据',
|
||||
'Exchange rates data has been updated': '汇率数据已更新',
|
||||
'Unable to get exchange rates data': '无法获取汇率数据',
|
||||
'About': '关于',
|
||||
'Official Website': '官方网站',
|
||||
'License': '许可协议',
|
||||
|
||||
@@ -22,6 +22,7 @@ import version from './lib/version.js';
|
||||
import settings from './lib/settings.js';
|
||||
import services from './lib/services.js';
|
||||
import userstate from './lib/userstate.js';
|
||||
import exchangeRates from './lib/exchangeRates.js';
|
||||
import utils from './lib/utils.js';
|
||||
import currencyFilter from './filters/currency.js';
|
||||
import accountIconFilter from './filters/accountIcon.js';
|
||||
@@ -149,6 +150,7 @@ Vue.prototype.$hideLoading = function () {
|
||||
};
|
||||
|
||||
Vue.prototype.$services = services;
|
||||
Vue.prototype.$exchangeRates = exchangeRates;
|
||||
Vue.prototype.$user = userstate;
|
||||
|
||||
Vue.filter('currency', (value, currencyCode) => currencyFilter({ i18n }, value, currencyCode));
|
||||
@@ -163,6 +165,11 @@ if (userstate.isUserLogined()) {
|
||||
services.refreshToken();
|
||||
}
|
||||
|
||||
// auto refresh exchange rates data
|
||||
if (settings.isAutoUpdateExchangeRatesData()) {
|
||||
services.refreshLatestExchangeRates();
|
||||
}
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
i18n: i18n,
|
||||
|
||||
@@ -13,6 +13,7 @@ import AccountEditPage from '../views/mobile/accounts/AccountEdit.vue';
|
||||
import StatisticsOverviewPage from '../views/mobile/statistics/Overview.vue';
|
||||
|
||||
import SettingsPage from '../views/mobile/Settings.vue';
|
||||
import ExchangeRatesPage from "../views/mobile/ExchangeRates.vue";
|
||||
import AboutPage from "../views/mobile/About.vue";
|
||||
import UserProfilePage from "../views/mobile/users/UserProfile.vue";
|
||||
import TwoFactorAuthPage from "../views/mobile/users/TwoFactorAuth.vue";
|
||||
@@ -93,6 +94,11 @@ const routes = [
|
||||
component: SettingsPage,
|
||||
beforeEnter: checkLogin
|
||||
},
|
||||
{
|
||||
path: '/exchange_rates',
|
||||
component: ExchangeRatesPage,
|
||||
beforeEnter: checkLogin
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
component: AboutPage,
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<f7-page ptr @ptr:refresh="update">
|
||||
<f7-navbar>
|
||||
<f7-nav-left :back-link="$t('Back')"></f7-nav-left>
|
||||
<f7-nav-title :title="$t('Exchange Rates Data')"></f7-nav-title>
|
||||
<f7-nav-right>
|
||||
<f7-link :class="{ 'disabled': updating }" :text="$t('Update')" @click="update(null)"></f7-link>
|
||||
</f7-nav-right>
|
||||
</f7-navbar>
|
||||
|
||||
<f7-card>
|
||||
<f7-card-content :padding="false" v-if="exchangeRatesData.exchangeRates && exchangeRatesData.exchangeRates.length">
|
||||
<f7-list>
|
||||
<f7-list-item
|
||||
:title="$t('Base Currency')"
|
||||
smart-select :smart-select-params="{ openIn: 'sheet', closeOnSelect: true, sheetCloseLinkText: $t('Done') }">
|
||||
<select v-model="baseCurrency">
|
||||
<option v-for="exchangeRate in availableExchangeRates"
|
||||
:key="exchangeRate.currencyCode"
|
||||
:value="exchangeRate.currencyCode">{{ exchangeRate.currencyDisplayName }}</option>
|
||||
</select>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-card-content>
|
||||
</f7-card>
|
||||
|
||||
<f7-card>
|
||||
<f7-card-content :padding="false" v-if="!exchangeRatesData.exchangeRates || !exchangeRatesData.exchangeRates.length">
|
||||
<f7-list>
|
||||
<f7-list-item :title="$t('No exchange rates data')"></f7-list-item>
|
||||
</f7-list>
|
||||
</f7-card-content>
|
||||
<f7-card-content :padding="false" v-if="exchangeRatesData.exchangeRates && exchangeRatesData.exchangeRates.length">
|
||||
<f7-list>
|
||||
<f7-list-item v-for="exchangeRate in availableExchangeRates" :key="exchangeRate.currencyCode"
|
||||
:title="exchangeRate.currencyDisplayName"
|
||||
:after="exchangeRate.rate | exchangeRate(exchangeRatesData.exchangeRates, exchangeRatesData.baseCurrency, baseCurrency)"></f7-list-item>
|
||||
</f7-list>
|
||||
</f7-card-content>
|
||||
<f7-card-footer v-if="exchangeRatesData.exchangeRates && exchangeRatesData.exchangeRates.length">
|
||||
<span>{{ $t('Last Updated') }}</span>
|
||||
<span>{{ exchangeRatesData.date | moment($t('format.date.long')) }}</span>
|
||||
</f7-card-footer>
|
||||
<f7-card-footer v-if="exchangeRatesData.exchangeRates && exchangeRatesData.exchangeRates.length">
|
||||
<span>{{ $t('Data source') }}</span>
|
||||
<span>{{ exchangeRatesData.dataSource }}</span>
|
||||
</f7-card-footer>
|
||||
</f7-card>
|
||||
</f7-page>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
baseCurrency: self.$user.getUserInfo() ? self.$user.getUserInfo().defaultCurrency : self.$t('default.currency'),
|
||||
exchangeRatesData: self.$exchangeRates.getExchangeRates(),
|
||||
updating: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
availableExchangeRates() {
|
||||
if (!this.exchangeRatesData || !this.exchangeRatesData.exchangeRates) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const availableExchangeRates = [];
|
||||
|
||||
for (let i = 0; i < this.exchangeRatesData.exchangeRates.length; i++) {
|
||||
const exchangeRate = this.exchangeRatesData.exchangeRates[i];
|
||||
|
||||
availableExchangeRates.push({
|
||||
currencyCode: exchangeRate.currency,
|
||||
currencyDisplayName: this.$t(`currency.${exchangeRate.currency}`),
|
||||
rate: exchangeRate.rate
|
||||
});
|
||||
}
|
||||
|
||||
availableExchangeRates.sort(function(c1, c2){
|
||||
return c1.currencyDisplayName.localeCompare(c2.currencyDisplayName);
|
||||
})
|
||||
|
||||
return availableExchangeRates;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (!this.exchangeRatesData || !this.exchangeRatesData.exchangeRates) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.exchangeRatesData.exchangeRates.length; i++) {
|
||||
const exchangeRate = this.exchangeRatesData.exchangeRates[i];
|
||||
if (exchangeRate.currency === this.baseCurrency) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.$toast('There is no exchange rates data for your default currency');
|
||||
},
|
||||
methods: {
|
||||
update(done) {
|
||||
const self = this;
|
||||
|
||||
if (self.updating) {
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
self.updating = true;
|
||||
|
||||
self.$services.getLatestExchangeRates().then(response => {
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
|
||||
self.updating = false;
|
||||
|
||||
const data = response.data;
|
||||
|
||||
if (!data || !data.success || !data.result) {
|
||||
self.$toast('Unable to get exchange rates data');
|
||||
return;
|
||||
}
|
||||
|
||||
self.exchangeRatesData = data.result;
|
||||
self.$exchangeRates.setExchangeRates(data.result);
|
||||
|
||||
self.$toast('Exchange rates data has been updated');
|
||||
}).catch(error => {
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
|
||||
self.updating = false;
|
||||
|
||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||
self.$toast({ error: error.response.data });
|
||||
} else if (!error.processed) {
|
||||
self.$toast('Unable to get exchange rates data');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
exchangeRate(oldRate, exchangeRates, baseCurrency, currentCurrency) {
|
||||
const exchangeRateMap = {};
|
||||
|
||||
for (let i = 0; i < exchangeRates.length; i++) {
|
||||
const exchangeRate = exchangeRates[i];
|
||||
exchangeRateMap[exchangeRate.currency] = exchangeRate;
|
||||
}
|
||||
|
||||
const toCurrencyExchangeRate = exchangeRateMap[currentCurrency];
|
||||
|
||||
if (!toCurrencyExchangeRate) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const newRate = parseFloat(oldRate) / parseFloat(toCurrencyExchangeRate.rate);
|
||||
const newRateStr = newRate.toString();
|
||||
|
||||
if (newRateStr.indexOf('.') < 0) {
|
||||
return newRateStr;
|
||||
} else {
|
||||
return newRateStr.substr(0, Math.max(6, newRateStr.indexOf('.') + 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -186,6 +186,11 @@ export default {
|
||||
}
|
||||
|
||||
self.$user.updateTokenAndUserInfo(data.result);
|
||||
|
||||
if (self.$settings.isAutoUpdateExchangeRatesData()) {
|
||||
self.$services.refreshLatestExchangeRates();
|
||||
}
|
||||
|
||||
router.navigate('/');
|
||||
}).catch(error => {
|
||||
self.logining = false;
|
||||
@@ -252,6 +257,11 @@ export default {
|
||||
}
|
||||
|
||||
self.$user.updateTokenAndUserInfo(data.result);
|
||||
|
||||
if (self.$settings.isAutoUpdateExchangeRatesData()) {
|
||||
self.$services.refreshLatestExchangeRates();
|
||||
}
|
||||
|
||||
self.show2faSheet = false;
|
||||
router.navigate('/');
|
||||
}).catch(error => {
|
||||
|
||||
@@ -29,6 +29,13 @@
|
||||
</select>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item :title="$t('Exchange Rates Data')" :after="exchangeRatesLastUpdateDate" link="/exchange_rates"></f7-list-item>
|
||||
|
||||
<f7-list-item>
|
||||
<span>{{ $t('Auto Update Exchange Rates Data') }}</span>
|
||||
<f7-toggle :checked="isAutoUpdateExchangeRatesData" @toggle:change="isAutoUpdateExchangeRatesData = $event"></f7-toggle>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item>
|
||||
<span>{{ $t('Enable Thousands Separator') }}</span>
|
||||
<f7-toggle :checked="isEnableThousandsSeparator" @toggle:change="isEnableThousandsSeparator = $event"></f7-toggle>
|
||||
@@ -93,6 +100,18 @@ export default {
|
||||
this.$setLanguage(value);
|
||||
}
|
||||
},
|
||||
exchangeRatesLastUpdateDate() {
|
||||
const exchangeRates = this.$exchangeRates.getExchangeRates();
|
||||
return exchangeRates && exchangeRates.date ? this.$moment(exchangeRates.date).format(this.$t('format.date.long')) : '';
|
||||
},
|
||||
isAutoUpdateExchangeRatesData: {
|
||||
get: function () {
|
||||
return this.$settings.isAutoUpdateExchangeRatesData();
|
||||
},
|
||||
set: function (value) {
|
||||
this.$settings.setAutoUpdateExchangeRatesData(value);
|
||||
}
|
||||
},
|
||||
isEnableThousandsSeparator: {
|
||||
get: function () {
|
||||
return this.$settings.isEnableThousandsSeparator();
|
||||
@@ -161,6 +180,7 @@ export default {
|
||||
|
||||
self.$user.clearTokenAndUserInfo();
|
||||
self.$settings.clearSettings();
|
||||
self.$exchangeRates.clearExchangeRates();
|
||||
router.navigate('/');
|
||||
}).catch(error => {
|
||||
self.logouting = false;
|
||||
|
||||
Reference in New Issue
Block a user