mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-21 10:14:26 +08:00
support modify account
This commit is contained in:
@@ -161,7 +161,9 @@ func startWebServer(c *cli.Context) error {
|
|||||||
|
|
||||||
// Accounts
|
// Accounts
|
||||||
apiV1Route.GET("/accounts/list.json", bindApi(api.Accounts.AccountListHandler))
|
apiV1Route.GET("/accounts/list.json", bindApi(api.Accounts.AccountListHandler))
|
||||||
|
apiV1Route.GET("/accounts/get.json", bindApi(api.Accounts.AccountGetHandler))
|
||||||
apiV1Route.POST("/accounts/add.json", bindApi(api.Accounts.AccountCreateHandler))
|
apiV1Route.POST("/accounts/add.json", bindApi(api.Accounts.AccountCreateHandler))
|
||||||
|
apiV1Route.POST("/accounts/modify.json", bindApi(api.Accounts.AccountModifyHandler))
|
||||||
apiV1Route.POST("/accounts/hide.json", bindApi(api.Accounts.AccountHideHandler))
|
apiV1Route.POST("/accounts/hide.json", bindApi(api.Accounts.AccountHideHandler))
|
||||||
apiV1Route.POST("/accounts/move.json", bindApi(api.Accounts.AccountMoveHandler))
|
apiV1Route.POST("/accounts/move.json", bindApi(api.Accounts.AccountMoveHandler))
|
||||||
apiV1Route.POST("/accounts/delete.json", bindApi(api.Accounts.AccountDeleteHandler))
|
apiV1Route.POST("/accounts/delete.json", bindApi(api.Accounts.AccountDeleteHandler))
|
||||||
|
|||||||
@@ -68,6 +68,48 @@ func (a *AccountsApi) AccountListHandler(c *core.Context) (interface{}, *errs.Er
|
|||||||
return userFinalAccountResps, nil
|
return userFinalAccountResps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AccountsApi) AccountGetHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||||
|
var accountGetReq models.AccountGetRequest
|
||||||
|
err := c.ShouldBindQuery(&accountGetReq)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.WarnfWithRequestId(c, "[accounts.AccountGetHandler] parse request failed, because %s", err.Error())
|
||||||
|
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
uid := c.GetCurrentUid()
|
||||||
|
accountAndSubAccounts, err := a.accounts.GetAccountByAccountId(uid, accountGetReq.Id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorfWithRequestId(c, "[accounts.AccountGetHandler] failed to get account \"id:%d\" for user \"uid:%d\", because %s", accountGetReq.Id, uid, err.Error())
|
||||||
|
return nil, errs.ErrOperationFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
accountRespMap := make(map[int64]*models.AccountInfoResponse)
|
||||||
|
|
||||||
|
for i := 0; i < len(accountAndSubAccounts); i++ {
|
||||||
|
acccountResp := accountAndSubAccounts[i].ToAccountInfoResponse()
|
||||||
|
accountRespMap[acccountResp.Id] = acccountResp
|
||||||
|
}
|
||||||
|
|
||||||
|
accountResp := accountRespMap[accountGetReq.Id]
|
||||||
|
|
||||||
|
if accountResp == nil {
|
||||||
|
return nil, errs.ErrAccountNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(accountAndSubAccounts); i++ {
|
||||||
|
if accountAndSubAccounts[i].ParentAccountId == accountResp.Id {
|
||||||
|
subAccountResp := accountAndSubAccounts[i].ToAccountInfoResponse()
|
||||||
|
accountResp.SubAccounts = append(accountResp.SubAccounts, subAccountResp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(accountResp.SubAccounts)
|
||||||
|
|
||||||
|
return accountResp, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *AccountsApi) AccountCreateHandler(c *core.Context) (interface{}, *errs.Error) {
|
func (a *AccountsApi) AccountCreateHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||||
var accountCreateReq models.AccountCreateRequest
|
var accountCreateReq models.AccountCreateRequest
|
||||||
err := c.ShouldBindJSON(&accountCreateReq)
|
err := c.ShouldBindJSON(&accountCreateReq)
|
||||||
@@ -144,6 +186,79 @@ func (a *AccountsApi) AccountCreateHandler(c *core.Context) (interface{}, *errs.
|
|||||||
return accountInfoResp, nil
|
return accountInfoResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AccountsApi) AccountModifyHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||||
|
var accountModifyReq models.AccountModifyRequest
|
||||||
|
err := c.ShouldBindJSON(&accountModifyReq)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.WarnfWithRequestId(c, "[accounts.AccountModifyHandler] parse request failed, because %s", err.Error())
|
||||||
|
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
uid := c.GetCurrentUid()
|
||||||
|
accountAndSubAccounts, err := a.accounts.GetAccountByAccountId(uid, accountModifyReq.Id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorfWithRequestId(c, "[accounts.AccountModifyHandler] failed to get account \"id:%d\" for user \"uid:%d\", because %s", accountModifyReq.Id, uid, err.Error())
|
||||||
|
return nil, errs.ErrOperationFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
accountMap := make(map[int64]*models.Account)
|
||||||
|
|
||||||
|
for i := 0; i < len(accountAndSubAccounts); i++ {
|
||||||
|
acccount := accountAndSubAccounts[i]
|
||||||
|
accountMap[acccount.AccountId] = acccount
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists := accountMap[accountModifyReq.Id]; !exists {
|
||||||
|
return nil, errs.ErrAccountNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(accountModifyReq.SubAccounts)+1 != len(accountAndSubAccounts) {
|
||||||
|
return nil, errs.ErrCannotAddOrDeleteSubAccountsWhenModify
|
||||||
|
}
|
||||||
|
|
||||||
|
anythingUpdate := false
|
||||||
|
var toUpdateAccounts []*models.Account
|
||||||
|
|
||||||
|
toUpdateAccount := a.getToUpdateAccount(uid, &accountModifyReq, accountMap[accountModifyReq.Id])
|
||||||
|
|
||||||
|
if toUpdateAccount != nil {
|
||||||
|
anythingUpdate = true
|
||||||
|
toUpdateAccounts = append(toUpdateAccounts, toUpdateAccount)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(accountModifyReq.SubAccounts); i++ {
|
||||||
|
subAcccountReq := accountModifyReq.SubAccounts[i]
|
||||||
|
|
||||||
|
if _, exists := accountMap[subAcccountReq.Id]; !exists {
|
||||||
|
return nil, errs.ErrAccountNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
toUpdateSubAccount := a.getToUpdateAccount(uid, subAcccountReq, accountMap[subAcccountReq.Id])
|
||||||
|
|
||||||
|
if toUpdateSubAccount != nil {
|
||||||
|
anythingUpdate = true
|
||||||
|
toUpdateAccounts = append(toUpdateAccounts, toUpdateSubAccount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !anythingUpdate {
|
||||||
|
return nil, errs.ErrNothingWillBeUpdated
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.accounts.ModifyAccounts(uid, toUpdateAccounts)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorfWithRequestId(c, "[accounts.AccountModifyHandler] failed to update account \"id:%d\" for user \"uid:%d\", because %s", accountModifyReq.Id, uid, err.Error())
|
||||||
|
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.InfofWithRequestId(c, "[accounts.AccountModifyHandler] user \"uid:%d\" has updated account \"id:%d\" successfully", uid, accountModifyReq.Id)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *AccountsApi) AccountHideHandler(c *core.Context) (interface{}, *errs.Error) {
|
func (a *AccountsApi) AccountHideHandler(c *core.Context) (interface{}, *errs.Error) {
|
||||||
var accountHideReq models.AccountHideRequest
|
var accountHideReq models.AccountHideRequest
|
||||||
err := c.ShouldBindJSON(&accountHideReq)
|
err := c.ShouldBindJSON(&accountHideReq)
|
||||||
@@ -246,3 +361,25 @@ func (a *AccountsApi) createSubAccounts(uid int64, accountCreateReq *models.Acco
|
|||||||
|
|
||||||
return childrenAccounts
|
return childrenAccounts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AccountsApi) getToUpdateAccount(uid int64, accountModifyReq *models.AccountModifyRequest, oldAccount *models.Account) *models.Account {
|
||||||
|
newAccount := &models.Account{
|
||||||
|
AccountId: oldAccount.AccountId,
|
||||||
|
Uid: uid,
|
||||||
|
Name: accountModifyReq.Name,
|
||||||
|
Category: accountModifyReq.Category,
|
||||||
|
Icon: accountModifyReq.Icon,
|
||||||
|
Comment: accountModifyReq.Comment,
|
||||||
|
Hidden: accountModifyReq.Hidden,
|
||||||
|
}
|
||||||
|
|
||||||
|
if newAccount.Name != oldAccount.Name ||
|
||||||
|
newAccount.Category != oldAccount.Category ||
|
||||||
|
newAccount.Icon != oldAccount.Icon ||
|
||||||
|
newAccount.Comment != oldAccount.Comment ||
|
||||||
|
newAccount.Hidden != oldAccount.Hidden {
|
||||||
|
return newAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ var (
|
|||||||
ErrParentAccountCannotSetCurrency = NewNormalError(NORMAL_SUBCATEGORY_ACCOUNT, 5, http.StatusBadRequest, "parent account cannot set currency")
|
ErrParentAccountCannotSetCurrency = NewNormalError(NORMAL_SUBCATEGORY_ACCOUNT, 5, http.StatusBadRequest, "parent account cannot set currency")
|
||||||
ErrSubAccountCategoryNotEqualsToParent = NewNormalError(NORMAL_SUBCATEGORY_ACCOUNT, 6, http.StatusBadRequest, "sub account category not equals to parent")
|
ErrSubAccountCategoryNotEqualsToParent = NewNormalError(NORMAL_SUBCATEGORY_ACCOUNT, 6, http.StatusBadRequest, "sub account category not equals to parent")
|
||||||
ErrSubAccountTypeInvalid = NewNormalError(NORMAL_SUBCATEGORY_ACCOUNT, 7, http.StatusBadRequest, "sub account type invalid")
|
ErrSubAccountTypeInvalid = NewNormalError(NORMAL_SUBCATEGORY_ACCOUNT, 7, http.StatusBadRequest, "sub account type invalid")
|
||||||
|
ErrCannotAddOrDeleteSubAccountsWhenModify = NewNormalError(NORMAL_SUBCATEGORY_ACCOUNT, 8, http.StatusBadRequest, "cannot add or delete sub accounts when modify account")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -51,6 +51,20 @@ type AccountCreateRequest struct {
|
|||||||
SubAccounts []*AccountCreateRequest `json:"subAccounts" binding:"omitempty"`
|
SubAccounts []*AccountCreateRequest `json:"subAccounts" binding:"omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccountGetRequest struct {
|
||||||
|
Id int64 `form:"id,string" binding:"required,min=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccountModifyRequest struct {
|
||||||
|
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||||
|
Name string `json:"name" binding:"required,notBlank,max=32"`
|
||||||
|
Category AccountCategory `json:"category" binding:"required"`
|
||||||
|
Icon int64 `json:"icon,string" binding:"min=1"`
|
||||||
|
Comment string `json:"comment" binding:"max=255"`
|
||||||
|
Hidden bool `json:"hidden"`
|
||||||
|
SubAccounts []*AccountModifyRequest `json:"subAccounts" binding:"omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccountHideRequest struct {
|
type AccountHideRequest struct {
|
||||||
Id int64 `json:"id,string" binding:"required,min=1"`
|
Id int64 `json:"id,string" binding:"required,min=1"`
|
||||||
Hidden bool `json:"hidden"`
|
Hidden bool `json:"hidden"`
|
||||||
|
|||||||
@@ -38,6 +38,21 @@ func (s *AccountService) GetAllAccountsByUid(uid int64) ([]*models.Account, erro
|
|||||||
return accounts, err
|
return accounts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *AccountService) GetAccountByAccountId(uid int64, accountId int64) ([]*models.Account, error) {
|
||||||
|
if uid <= 0 {
|
||||||
|
return nil, errs.ErrUserIdInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
if accountId <= 0 {
|
||||||
|
return nil, errs.ErrAccountIdInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
var accounts []*models.Account
|
||||||
|
err := s.UserDataDB(uid).Where("uid=? AND deleted=? AND (account_id=? OR parent_account_id=?)", uid, false, accountId, accountId).OrderBy("parent_account_id asc, display_order asc").Find(&accounts)
|
||||||
|
|
||||||
|
return accounts, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *AccountService) GetMaxDisplayOrder(uid int64, category models.AccountCategory) (int, error) {
|
func (s *AccountService) GetMaxDisplayOrder(uid int64, category models.AccountCategory) (int, error) {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return 0, errs.ErrUserIdInvalid
|
return 0, errs.ErrUserIdInvalid
|
||||||
@@ -122,6 +137,31 @@ func (s *AccountService) CreateAccounts(mainAccount *models.Account, childrenAcc
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *AccountService) ModifyAccounts(uid int64, accounts []*models.Account) error {
|
||||||
|
if uid <= 0 {
|
||||||
|
return errs.ErrUserIdInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().Unix()
|
||||||
|
|
||||||
|
for i := 0; i < len(accounts); i++ {
|
||||||
|
accounts[i].UpdatedUnixTime = now
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.UserDataDB(uid).DoTransaction(func(sess *xorm.Session) error {
|
||||||
|
for i := 0; i < len(accounts); i++ {
|
||||||
|
account := accounts[i]
|
||||||
|
_, err := sess.Cols("name", "category", "icon", "comment", "hidden", "updated_unix_time").Where("account_id=? AND uid=? AND deleted=?", account.AccountId, uid, false).Update(account)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *AccountService) HideAccount(uid int64, ids []int64, hidden bool) error {
|
func (s *AccountService) HideAccount(uid int64, ids []int64, hidden bool) error {
|
||||||
if uid <= 0 {
|
if uid <= 0 {
|
||||||
return errs.ErrUserIdInvalid
|
return errs.ErrUserIdInvalid
|
||||||
|
|||||||
@@ -166,6 +166,9 @@ export default {
|
|||||||
getAllAccounts: () => {
|
getAllAccounts: () => {
|
||||||
return axios.get('v1/accounts/list.json');
|
return axios.get('v1/accounts/list.json');
|
||||||
},
|
},
|
||||||
|
getAccount: ({ id }) => {
|
||||||
|
return axios.get('v1/accounts/get.json?id=' + id);
|
||||||
|
},
|
||||||
addAccount: ({ category, type, name, icon, currency, comment, subAccounts }) => {
|
addAccount: ({ category, type, name, icon, currency, comment, subAccounts }) => {
|
||||||
return axios.post('v1/accounts/add.json', {
|
return axios.post('v1/accounts/add.json', {
|
||||||
category,
|
category,
|
||||||
@@ -177,6 +180,17 @@ export default {
|
|||||||
subAccounts
|
subAccounts
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
modifyAccount: ({ id, category, name, icon, comment, hidden, subAccounts }) => {
|
||||||
|
return axios.post('v1/accounts/modify.json', {
|
||||||
|
id,
|
||||||
|
category,
|
||||||
|
name,
|
||||||
|
icon,
|
||||||
|
comment,
|
||||||
|
hidden,
|
||||||
|
subAccounts
|
||||||
|
});
|
||||||
|
},
|
||||||
hideAccount: ({ id, hidden }) => {
|
hideAccount: ({ id, hidden }) => {
|
||||||
return axios.post('v1/accounts/hide.json', {
|
return axios.post('v1/accounts/hide.json', {
|
||||||
id,
|
id,
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ export default {
|
|||||||
'parent account cannot set currency': 'Parent account cannot set currency',
|
'parent account cannot set currency': 'Parent account cannot set currency',
|
||||||
'sub account category not equals to parent': 'Sub account category does not equal to parent',
|
'sub account category not equals to parent': 'Sub account category does not equal to parent',
|
||||||
'sub account type invalid': 'Sub account type is invalid',
|
'sub account type invalid': 'Sub account type is invalid',
|
||||||
|
'cannot add or delete sub accounts when modify account': 'You cannot add or delete sub accounts when modify account',
|
||||||
},
|
},
|
||||||
'parameter': {
|
'parameter': {
|
||||||
'id': 'ID',
|
'id': 'ID',
|
||||||
@@ -250,6 +251,7 @@ export default {
|
|||||||
'Enabled': 'Enabled',
|
'Enabled': 'Enabled',
|
||||||
'Disable': 'Disable',
|
'Disable': 'Disable',
|
||||||
'Disabled': 'Disabled',
|
'Disabled': 'Disabled',
|
||||||
|
'Visible': 'Visible',
|
||||||
'Version': 'Version',
|
'Version': 'Version',
|
||||||
'Edit': 'Edit',
|
'Edit': 'Edit',
|
||||||
'Delete': 'Delete',
|
'Delete': 'Delete',
|
||||||
@@ -312,6 +314,7 @@ export default {
|
|||||||
'Unable to get account list': 'Unable to get account list',
|
'Unable to get account list': 'Unable to get account list',
|
||||||
'No available account': 'No available account',
|
'No available account': 'No available account',
|
||||||
'Add Account': 'Add Account',
|
'Add Account': 'Add Account',
|
||||||
|
'Edit Account': 'Edit Account',
|
||||||
'Account Category': 'Account Category',
|
'Account Category': 'Account Category',
|
||||||
'Single Account': 'Single Account',
|
'Single Account': 'Single Account',
|
||||||
'Multi Sub Accounts': 'Multi Sub Accounts',
|
'Multi Sub Accounts': 'Multi Sub Accounts',
|
||||||
@@ -333,7 +336,10 @@ export default {
|
|||||||
'Account name cannot be empty': 'Account name cannot be empty',
|
'Account name cannot be empty': 'Account name cannot be empty',
|
||||||
'Account currency cannot be empty': 'Account currency cannot be empty',
|
'Account currency cannot be empty': 'Account currency cannot be empty',
|
||||||
'You have added a new account': 'You have added a new account',
|
'You have added a new account': 'You have added a new account',
|
||||||
|
'You have saved this account': 'You have saved this account',
|
||||||
'Unable to add account': 'Unable to add account',
|
'Unable to add account': 'Unable to add account',
|
||||||
|
'Unable to save account': 'Unable to save account',
|
||||||
|
'Unable to get account': 'Unable to get account',
|
||||||
'Unable to hide this account': 'Unable to hide this account',
|
'Unable to hide this account': 'Unable to hide this account',
|
||||||
'Unable to unhide this account': 'Unable to unhide this account',
|
'Unable to unhide this account': 'Unable to unhide this account',
|
||||||
'Unable to move account': 'Unable to move account',
|
'Unable to move account': 'Unable to move account',
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ export default {
|
|||||||
'parent account cannot set currency': '父账户不能设置货币',
|
'parent account cannot set currency': '父账户不能设置货币',
|
||||||
'sub account category not equals to parent': '子账户类别与父账户不同',
|
'sub account category not equals to parent': '子账户类别与父账户不同',
|
||||||
'sub account type invalid': '子账户类型无效',
|
'sub account type invalid': '子账户类型无效',
|
||||||
|
'cannot add or delete sub accounts when modify account': '您不能在修改账户时添加或删除子账户',
|
||||||
},
|
},
|
||||||
'parameter': {
|
'parameter': {
|
||||||
'id': 'ID',
|
'id': 'ID',
|
||||||
@@ -250,6 +251,7 @@ export default {
|
|||||||
'Enabled': '启用',
|
'Enabled': '启用',
|
||||||
'Disable': '禁用',
|
'Disable': '禁用',
|
||||||
'Disabled': '禁用',
|
'Disabled': '禁用',
|
||||||
|
'Visible': '可见',
|
||||||
'Version': '版本',
|
'Version': '版本',
|
||||||
'Edit': '编辑',
|
'Edit': '编辑',
|
||||||
'Delete': '删除',
|
'Delete': '删除',
|
||||||
@@ -312,6 +314,7 @@ export default {
|
|||||||
'Unable to get account list': '无法获取账户列表',
|
'Unable to get account list': '无法获取账户列表',
|
||||||
'No available account': '没有可用的账户',
|
'No available account': '没有可用的账户',
|
||||||
'Add Account': '添加账户',
|
'Add Account': '添加账户',
|
||||||
|
'Edit Account': '编辑账户',
|
||||||
'Account Category': '账户分类',
|
'Account Category': '账户分类',
|
||||||
'Single Account': '单一账户',
|
'Single Account': '单一账户',
|
||||||
'Multi Sub Accounts': '多个子账户',
|
'Multi Sub Accounts': '多个子账户',
|
||||||
@@ -333,7 +336,10 @@ export default {
|
|||||||
'Account name cannot be empty': '账户名称不能为空',
|
'Account name cannot be empty': '账户名称不能为空',
|
||||||
'Account currency cannot be empty': '账户货币不能为空',
|
'Account currency cannot be empty': '账户货币不能为空',
|
||||||
'You have added a new account': '您已经添加新账户',
|
'You have added a new account': '您已经添加新账户',
|
||||||
|
'You have saved this account': '您已经保存该账户',
|
||||||
'Unable to add account': '无法添加账户',
|
'Unable to add account': '无法添加账户',
|
||||||
|
'Unable to save account': '无法保存账户',
|
||||||
|
'Unable to get account': '无法获取账户',
|
||||||
'Unable to hide this account': '无法隐藏账户',
|
'Unable to hide this account': '无法隐藏账户',
|
||||||
'Unable to unhide this account': '无法取消隐藏账户',
|
'Unable to unhide this account': '无法取消隐藏账户',
|
||||||
'Unable to move account': '无法移动账户',
|
'Unable to move account': '无法移动账户',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import TransactionDetailPage from '../views/mobile/transactions/Detail.vue'
|
|||||||
import TransactionNewPage from '../views/mobile/transactions/New.vue'
|
import TransactionNewPage from '../views/mobile/transactions/New.vue'
|
||||||
|
|
||||||
import AccountListPage from '../views/mobile/accounts/AccountList.vue'
|
import AccountListPage from '../views/mobile/accounts/AccountList.vue'
|
||||||
import AccountAddPage from '../views/mobile/accounts/AccountAdd.vue'
|
import AccountEditPage from '../views/mobile/accounts/AccountEdit.vue'
|
||||||
|
|
||||||
import StatisticsOverviewPage from '../views/mobile/statistics/Overview.vue'
|
import StatisticsOverviewPage from '../views/mobile/statistics/Overview.vue'
|
||||||
|
|
||||||
@@ -75,7 +75,12 @@ const routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/account/add',
|
path: '/account/add',
|
||||||
component: AccountAddPage,
|
component: AccountEditPage,
|
||||||
|
beforeEnter: checkLogin
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/account/edit',
|
||||||
|
component: AccountEditPage,
|
||||||
beforeEnter: checkLogin
|
beforeEnter: checkLogin
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+168
-19
@@ -2,13 +2,22 @@
|
|||||||
<f7-page>
|
<f7-page>
|
||||||
<f7-navbar>
|
<f7-navbar>
|
||||||
<f7-nav-left :back-link="$t('Back')"></f7-nav-left>
|
<f7-nav-left :back-link="$t('Back')"></f7-nav-left>
|
||||||
<f7-nav-title :title="$t('Add Account')"></f7-nav-title>
|
<f7-nav-title :title="$t(title)"></f7-nav-title>
|
||||||
<f7-nav-right>
|
<f7-nav-right>
|
||||||
<f7-link :class="{ 'disabled': isInputEmpty() || submitting }" :text="$t('Add')" @click="add"></f7-link>
|
<f7-link :class="{ 'disabled': isInputEmpty() || submitting }" :text="$t(saveButtonTitle)" @click="save"></f7-link>
|
||||||
</f7-nav-right>
|
</f7-nav-right>
|
||||||
</f7-navbar>
|
</f7-navbar>
|
||||||
|
|
||||||
<f7-card>
|
<f7-card class="skeleton-text" v-if="loading">
|
||||||
|
<f7-card-content :padding="false">
|
||||||
|
<f7-list>
|
||||||
|
<f7-list-input label="Account Category" placeholder="Category"></f7-list-input>
|
||||||
|
<f7-list-input label="Account Type" placeholder="Account Type"></f7-list-input>
|
||||||
|
</f7-list>
|
||||||
|
</f7-card-content>
|
||||||
|
</f7-card>
|
||||||
|
|
||||||
|
<f7-card v-else-if="!loading">
|
||||||
<f7-card-content :padding="false">
|
<f7-card-content :padding="false">
|
||||||
<f7-list>
|
<f7-list>
|
||||||
<f7-list-input
|
<f7-list-input
|
||||||
@@ -24,6 +33,7 @@
|
|||||||
|
|
||||||
<f7-list-input
|
<f7-list-input
|
||||||
type="select"
|
type="select"
|
||||||
|
:class="{ 'disabled': editAccountId }"
|
||||||
:label="$t('Account Type')"
|
:label="$t('Account Type')"
|
||||||
:value="account.type"
|
:value="account.type"
|
||||||
@input="account.type = $event.target.value"
|
@input="account.type = $event.target.value"
|
||||||
@@ -35,7 +45,18 @@
|
|||||||
</f7-card-content>
|
</f7-card-content>
|
||||||
</f7-card>
|
</f7-card>
|
||||||
|
|
||||||
<f7-card v-if="account.type === $constants.account.allAccountTypes.SingleAccount.toString()">
|
<f7-card class="skeleton-text" v-if="loading">
|
||||||
|
<f7-card-content :padding="false">
|
||||||
|
<f7-list>
|
||||||
|
<f7-list-input label="Account Name" placeholder="Your account name"></f7-list-input>
|
||||||
|
<f7-list-item header="Account Icon" after="Icon"></f7-list-item>
|
||||||
|
<f7-list-input label="Currency" placeholder="Currency"></f7-list-input>
|
||||||
|
<f7-list-input type="textarea" label="Description" placeholder="Your account description (optional)"></f7-list-input>
|
||||||
|
</f7-list>
|
||||||
|
</f7-card-content>
|
||||||
|
</f7-card>
|
||||||
|
|
||||||
|
<f7-card v-else-if="!loading && account.type === $constants.account.allAccountTypes.SingleAccount.toString()">
|
||||||
<f7-card-content :padding="false">
|
<f7-card-content :padding="false">
|
||||||
<f7-list>
|
<f7-list>
|
||||||
<f7-list-input
|
<f7-list-input
|
||||||
@@ -47,13 +68,14 @@
|
|||||||
@input="account.name = $event.target.value"
|
@input="account.name = $event.target.value"
|
||||||
></f7-list-input>
|
></f7-list-input>
|
||||||
|
|
||||||
<f7-list-item :header="$t('Account Icon')" link="#"
|
<f7-list-item :header="$t('Account Icon')" key="singleTypeAccountIconSelection" link="#"
|
||||||
@click="showIconSelectionSheet(account)">
|
@click="showIconSelectionSheet(account)">
|
||||||
<f7-icon slot="after" :f7="account.icon | accountIcon"></f7-icon>
|
<f7-icon slot="after" :f7="account.icon | accountIcon"></f7-icon>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
<f7-list-input
|
<f7-list-input
|
||||||
type="select"
|
type="select"
|
||||||
|
:class="{ 'disabled': editAccountId }"
|
||||||
:label="$t('Currency')"
|
:label="$t('Currency')"
|
||||||
:value="account.currency"
|
:value="account.currency"
|
||||||
@input="account.currency = $event.target.value"
|
@input="account.currency = $event.target.value"
|
||||||
@@ -70,11 +92,15 @@
|
|||||||
:value="account.comment"
|
:value="account.comment"
|
||||||
@input="account.comment = $event.target.value"
|
@input="account.comment = $event.target.value"
|
||||||
></f7-list-input>
|
></f7-list-input>
|
||||||
|
|
||||||
|
<f7-list-item :header="$t('Visible')" v-if="editAccountId">
|
||||||
|
<f7-toggle :checked="account.visible" @toggle:change="account.visible = $event"></f7-toggle>
|
||||||
|
</f7-list-item>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
</f7-card-content>
|
</f7-card-content>
|
||||||
</f7-card>
|
</f7-card>
|
||||||
|
|
||||||
<f7-card v-else-if="account.type === $constants.account.allAccountTypes.MultiSubAccounts.toString()">
|
<f7-card v-else-if="!loading && account.type === $constants.account.allAccountTypes.MultiSubAccounts.toString()">
|
||||||
<f7-card-content :padding="false">
|
<f7-card-content :padding="false">
|
||||||
<f7-list>
|
<f7-list>
|
||||||
<f7-list-input
|
<f7-list-input
|
||||||
@@ -86,7 +112,7 @@
|
|||||||
@input="account.name = $event.target.value"
|
@input="account.name = $event.target.value"
|
||||||
></f7-list-input>
|
></f7-list-input>
|
||||||
|
|
||||||
<f7-list-item :header="$t('Account Icon')" link="#"
|
<f7-list-item :header="$t('Account Icon')" key="multiTypeAccountIconSelection" link="#"
|
||||||
@click="showIconSelectionSheet(account)">
|
@click="showIconSelectionSheet(account)">
|
||||||
<f7-icon slot="after" :f7="account.icon | accountIcon"></f7-icon>
|
<f7-icon slot="after" :f7="account.icon | accountIcon"></f7-icon>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
@@ -98,14 +124,19 @@
|
|||||||
:value="account.comment"
|
:value="account.comment"
|
||||||
@input="account.comment = $event.target.value"
|
@input="account.comment = $event.target.value"
|
||||||
></f7-list-input>
|
></f7-list-input>
|
||||||
|
|
||||||
|
<f7-list-item :header="$t('Visible')" v-if="editAccountId">
|
||||||
|
<f7-toggle :checked="account.visible" @toggle:change="account.visible = $event"></f7-toggle>
|
||||||
|
</f7-list-item>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
</f7-card-content>
|
</f7-card-content>
|
||||||
<f7-card-footer>
|
<f7-card-footer>
|
||||||
<f7-button large fill :text="$t('Add Sub Account')" @click="addSubAccount"></f7-button>
|
<f7-button large fill :class="{ 'disabled': editAccountId }"
|
||||||
|
:text="$t('Add Sub Account')" @click="addSubAccount"></f7-button>
|
||||||
</f7-card-footer>
|
</f7-card-footer>
|
||||||
</f7-card>
|
</f7-card>
|
||||||
|
|
||||||
<f7-block class="no-padding no-margin" v-if="account.type === $constants.account.allAccountTypes.MultiSubAccounts.toString()">
|
<f7-block class="no-padding no-margin" v-if="!loading && account.type === $constants.account.allAccountTypes.MultiSubAccounts.toString()">
|
||||||
<f7-card v-for="(subAccount, idx) in subAccounts" :key="idx">
|
<f7-card v-for="(subAccount, idx) in subAccounts" :key="idx">
|
||||||
<f7-card-content :padding="false">
|
<f7-card-content :padding="false">
|
||||||
<f7-list>
|
<f7-list>
|
||||||
@@ -118,13 +149,14 @@
|
|||||||
@input="subAccount.name = $event.target.value"
|
@input="subAccount.name = $event.target.value"
|
||||||
></f7-list-input>
|
></f7-list-input>
|
||||||
|
|
||||||
<f7-list-item :header="$t('Sub Account Icon')" link="#"
|
<f7-list-item :header="$t('Sub Account Icon')" key="subAccountIconSelection" link="#"
|
||||||
@click="showIconSelectionSheet(subAccount)">
|
@click="showIconSelectionSheet(subAccount)">
|
||||||
<f7-icon slot="after" :f7="subAccount.icon | accountIcon"></f7-icon>
|
<f7-icon slot="after" :f7="subAccount.icon | accountIcon"></f7-icon>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
<f7-list-input
|
<f7-list-input
|
||||||
type="select"
|
type="select"
|
||||||
|
:class="{ 'disabled': editAccountId }"
|
||||||
:label="$t('Currency')"
|
:label="$t('Currency')"
|
||||||
:value="subAccount.currency"
|
:value="subAccount.currency"
|
||||||
@input="subAccount.currency = $event.target.value"
|
@input="subAccount.currency = $event.target.value"
|
||||||
@@ -141,10 +173,15 @@
|
|||||||
:value="subAccount.comment"
|
:value="subAccount.comment"
|
||||||
@input="subAccount.comment = $event.target.value"
|
@input="subAccount.comment = $event.target.value"
|
||||||
></f7-list-input>
|
></f7-list-input>
|
||||||
|
|
||||||
|
<f7-list-item :header="$t('Visible')" v-if="editAccountId">
|
||||||
|
<f7-toggle :checked="subAccount.visible" @toggle:change="subAccount.visible = $event"></f7-toggle>
|
||||||
|
</f7-list-item>
|
||||||
</f7-list>
|
</f7-list>
|
||||||
</f7-card-content>
|
</f7-card-content>
|
||||||
<f7-card-footer>
|
<f7-card-footer>
|
||||||
<f7-button large fill color="red" :text="$t('Remove Sub Account')" @click="removeSubAccount(subAccount)"></f7-button>
|
<f7-button large fill :class="{ 'disabled': editAccountId }"
|
||||||
|
color="red" :text="$t('Remove Sub Account')" @click="removeSubAccount(subAccount)"></f7-button>
|
||||||
</f7-card-footer>
|
</f7-card-footer>
|
||||||
</f7-card>
|
</f7-card>
|
||||||
</f7-block>
|
</f7-block>
|
||||||
@@ -179,13 +216,16 @@ export default {
|
|||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
editAccountId: null,
|
||||||
|
loading: false,
|
||||||
account: {
|
account: {
|
||||||
category: '1',
|
category: '1',
|
||||||
type: self.$constants.account.allAccountTypes.SingleAccount.toString(),
|
type: self.$constants.account.allAccountTypes.SingleAccount.toString(),
|
||||||
name: '',
|
name: '',
|
||||||
icon: self.$constants.icons.defaultAccountIconId,
|
icon: self.$constants.icons.defaultAccountIconId,
|
||||||
currency: self.$user.getUserInfo() ? self.$user.getUserInfo().defaultCurrency : self.$t('default.currency'),
|
currency: self.$user.getUserInfo() ? self.$user.getUserInfo().defaultCurrency : self.$t('default.currency'),
|
||||||
comment: ''
|
comment: '',
|
||||||
|
visible: true
|
||||||
},
|
},
|
||||||
subAccounts: [],
|
subAccounts: [],
|
||||||
accountChoosingIcon: null,
|
accountChoosingIcon: null,
|
||||||
@@ -194,6 +234,20 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
title() {
|
||||||
|
if (!this.editAccountId) {
|
||||||
|
return 'Add Account';
|
||||||
|
} else {
|
||||||
|
return 'Edit Account';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
saveButtonTitle() {
|
||||||
|
if (!this.editAccountId) {
|
||||||
|
return 'Add';
|
||||||
|
} else {
|
||||||
|
return 'Save';
|
||||||
|
}
|
||||||
|
},
|
||||||
allAccountCategories() {
|
allAccountCategories() {
|
||||||
return this.$constants.account.allCategories;
|
return this.$constants.account.allCategories;
|
||||||
},
|
},
|
||||||
@@ -229,6 +283,70 @@ export default {
|
|||||||
return this.$getAllCurrencies();
|
return this.$getAllCurrencies();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
const self = this;
|
||||||
|
const query = self.$f7route.query;
|
||||||
|
const router = self.$f7router;
|
||||||
|
|
||||||
|
if (query.id) {
|
||||||
|
self.loading = true;
|
||||||
|
|
||||||
|
self.editAccountId = query.id;
|
||||||
|
self.$services.getAccount({
|
||||||
|
id: self.editAccountId
|
||||||
|
}).then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
if (!data || !data.success || !data.result) {
|
||||||
|
self.$alert('Unable to get account', () => {
|
||||||
|
router.back();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = data.result;
|
||||||
|
self.account.id = account.id;
|
||||||
|
self.account.category = account.category.toString();
|
||||||
|
self.account.type = account.type.toString();
|
||||||
|
self.account.name = account.name;
|
||||||
|
self.account.icon = account.icon;
|
||||||
|
self.account.currency = account.currency;
|
||||||
|
self.account.comment = account.comment;
|
||||||
|
self.account.visible = !account.hidden;
|
||||||
|
|
||||||
|
if (account.subAccounts && account.subAccounts.length > 0) {
|
||||||
|
for (let i = 0; i < account.subAccounts.length; i++) {
|
||||||
|
const subAccount = account.subAccounts[i];
|
||||||
|
|
||||||
|
self.subAccounts.push({
|
||||||
|
id: subAccount.id,
|
||||||
|
category: subAccount.category.toString(),
|
||||||
|
type: subAccount.type.toString(),
|
||||||
|
name: subAccount.name,
|
||||||
|
icon: subAccount.icon,
|
||||||
|
currency: subAccount.currency,
|
||||||
|
comment: subAccount.comment,
|
||||||
|
visible: !subAccount.hidden
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.loading = false;
|
||||||
|
}).catch(error => {
|
||||||
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
|
self.$alert({ error: error.response.data }, () => {
|
||||||
|
router.back();
|
||||||
|
});
|
||||||
|
} else if (!error.processed) {
|
||||||
|
self.$alert('Unable to get account', () => {
|
||||||
|
router.back();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addSubAccount() {
|
addSubAccount() {
|
||||||
const self = this;
|
const self = this;
|
||||||
@@ -255,7 +373,7 @@ export default {
|
|||||||
},
|
},
|
||||||
showIconSelectionSheet(account) {
|
showIconSelectionSheet(account) {
|
||||||
this.accountChoosingIcon = account;
|
this.accountChoosingIcon = account;
|
||||||
this.showIconSelection = true
|
this.showIconSelection = true;
|
||||||
},
|
},
|
||||||
setSelectedIcon(accountIcon) {
|
setSelectedIcon(accountIcon) {
|
||||||
if (!this.accountChoosingIcon) {
|
if (!this.accountChoosingIcon) {
|
||||||
@@ -270,7 +388,7 @@ export default {
|
|||||||
this.accountChoosingIcon = null;
|
this.accountChoosingIcon = null;
|
||||||
this.showIconSelection = false;
|
this.showIconSelection = false;
|
||||||
},
|
},
|
||||||
add() {
|
save() {
|
||||||
const self = this;
|
const self = this;
|
||||||
const router = self.$f7router;
|
const router = self.$f7router;
|
||||||
|
|
||||||
@@ -289,19 +407,25 @@ export default {
|
|||||||
if (self.account.type === self.$constants.account.allAccountTypes.MultiSubAccounts.toString()) {
|
if (self.account.type === self.$constants.account.allAccountTypes.MultiSubAccounts.toString()) {
|
||||||
for (let i = 0; i < self.subAccounts.length; i++) {
|
for (let i = 0; i < self.subAccounts.length; i++) {
|
||||||
const subAccount = self.subAccounts[i];
|
const subAccount = self.subAccounts[i];
|
||||||
|
const submitAccount = {
|
||||||
subAccounts.push({
|
|
||||||
category: parseInt(self.account.category),
|
category: parseInt(self.account.category),
|
||||||
type: self.$constants.account.allAccountTypes.SingleAccount,
|
type: self.$constants.account.allAccountTypes.SingleAccount,
|
||||||
name: subAccount.name,
|
name: subAccount.name,
|
||||||
icon: subAccount.icon,
|
icon: subAccount.icon,
|
||||||
currency: subAccount.currency,
|
currency: subAccount.currency,
|
||||||
comment: subAccount.comment
|
comment: subAccount.comment
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (self.editAccountId) {
|
||||||
|
submitAccount.id = subAccount.id;
|
||||||
|
submitAccount.hidden = !subAccount.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
subAccounts.push(submitAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.$services.addAccount({
|
const submitAccount = {
|
||||||
category: parseInt(self.account.category),
|
category: parseInt(self.account.category),
|
||||||
type: parseInt(self.account.type),
|
type: parseInt(self.account.type),
|
||||||
name: self.account.name,
|
name: self.account.name,
|
||||||
@@ -309,17 +433,38 @@ export default {
|
|||||||
currency: self.account.type === self.$constants.account.allAccountTypes.SingleAccount.toString() ? self.account.currency : self.$constants.currency.parentAccountCurrencyPlacehodler,
|
currency: self.account.type === self.$constants.account.allAccountTypes.SingleAccount.toString() ? self.account.currency : self.$constants.currency.parentAccountCurrencyPlacehodler,
|
||||||
comment: self.account.comment,
|
comment: self.account.comment,
|
||||||
subAccounts: self.account.type === self.$constants.account.allAccountTypes.SingleAccount.toString() ? null : subAccounts,
|
subAccounts: self.account.type === self.$constants.account.allAccountTypes.SingleAccount.toString() ? null : subAccounts,
|
||||||
}).then(response => {
|
};
|
||||||
|
|
||||||
|
let promise = null;
|
||||||
|
|
||||||
|
if (!self.editAccountId) {
|
||||||
|
promise = self.$services.addAccount(submitAccount);
|
||||||
|
} else {
|
||||||
|
submitAccount.id = self.account.id;
|
||||||
|
submitAccount.hidden = !self.account.visible;
|
||||||
|
promise = self.$services.modifyAccount(submitAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
promise.then(response => {
|
||||||
self.submitting = false;
|
self.submitting = false;
|
||||||
self.$hideLoading();
|
self.$hideLoading();
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
|
|
||||||
if (!data || !data.success || !data.result) {
|
if (!data || !data.success || !data.result) {
|
||||||
|
if (!self.editAccountId) {
|
||||||
self.$alert('Unable to add account');
|
self.$alert('Unable to add account');
|
||||||
|
} else {
|
||||||
|
self.$alert('Unable to save account');
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!self.editAccountId) {
|
||||||
self.$toast('You have added a new account');
|
self.$toast('You have added a new account');
|
||||||
|
} else {
|
||||||
|
self.$toast('You have saved this account');
|
||||||
|
}
|
||||||
|
|
||||||
router.back('/account/list', { force: true });
|
router.back('/account/list', { force: true });
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
self.submitting = false;
|
self.submitting = false;
|
||||||
@@ -328,7 +473,11 @@ export default {
|
|||||||
if (error.response && error.response.data && error.response.data.errorMessage) {
|
if (error.response && error.response.data && error.response.data.errorMessage) {
|
||||||
self.$alert({ error: error.response.data });
|
self.$alert({ error: error.response.data });
|
||||||
} else if (!error.processed) {
|
} else if (!error.processed) {
|
||||||
|
if (!self.editAccountId) {
|
||||||
self.$alert('Unable to add account');
|
self.$alert('Unable to add account');
|
||||||
|
} else {
|
||||||
|
self.$alert('Unable to save account');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -318,8 +318,8 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
edit() {
|
edit(account) {
|
||||||
|
this.$f7router.navigate('/account/edit?id=' + account.id);
|
||||||
},
|
},
|
||||||
hide(account, hidden) {
|
hide(account, hidden) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|||||||
Reference in New Issue
Block a user