From 4c53cd63cbced7648b478a378044d0ab697e8946 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Mon, 30 Nov 2020 01:10:36 +0800 Subject: [PATCH] add category edit ui --- pkg/api/transaction_categories.go | 19 + pkg/errs/transaction_category.go | 8 +- src/consts/color.js | 10 +- src/consts/icon.js | 12 + src/filters/categoryIcon.js | 14 + src/locales/en.js | 33 ++ src/locales/zh_Hans.js | 33 ++ src/mobile-main.js | 2 + src/router/mobile.js | 25 ++ src/views/mobile/Settings.vue | 1 + src/views/mobile/categories/CategoryAll.vue | 15 + src/views/mobile/categories/CategoryEdit.vue | 373 ++++++++++++++++ src/views/mobile/categories/CategoryList.vue | 424 +++++++++++++++++++ 13 files changed, 962 insertions(+), 7 deletions(-) create mode 100644 src/filters/categoryIcon.js create mode 100644 src/views/mobile/categories/CategoryAll.vue create mode 100644 src/views/mobile/categories/CategoryEdit.vue create mode 100644 src/views/mobile/categories/CategoryList.vue diff --git a/pkg/api/transaction_categories.go b/pkg/api/transaction_categories.go index 62a01ed3..8fed700e 100644 --- a/pkg/api/transaction_categories.go +++ b/pkg/api/transaction_categories.go @@ -125,6 +125,25 @@ func (a *TransactionCategoriesApi) CategoryCreateHandler(c *core.Context) (inter uid := c.GetCurrentUid() + if categoryCreateReq.ParentId > 0 { + parentCategory, err := a.categories.GetCategoryByCategoryId(uid, categoryCreateReq.ParentId) + + if err != nil { + log.WarnfWithRequestId(c, "[transaction_categories.CategoryCreateHandler] failed to get parent category \"id:%d\" for user \"uid:%d\", because %s", categoryCreateReq.ParentId, uid, err.Error()) + return nil, errs.Or(err, errs.ErrOperationFailed) + } + + if parentCategory == nil { + log.WarnfWithRequestId(c, "[transaction_categories.CategoryCreateHandler] parent category \"id:%d\" does not exist for user \"uid:%d\"", categoryCreateReq.ParentId, uid) + return nil, errs.ErrParentTransactionCategoryNotFound + } + + if parentCategory.ParentCategoryId > 0 { + log.WarnfWithRequestId(c, "[transaction_categories.CategoryCreateHandler] parent category \"id:%d\" has another parent category \"id:%d\" for user \"uid:%d\"", parentCategory.CategoryId, parentCategory.ParentCategoryId, uid) + return nil, errs.ErrCannotAddToSecondaryTransactionCategory + } + } + var maxOrderId = 0 if categoryCreateReq.ParentId <= 0 { diff --git a/pkg/errs/transaction_category.go b/pkg/errs/transaction_category.go index e7503d1e..aa1b7c1d 100644 --- a/pkg/errs/transaction_category.go +++ b/pkg/errs/transaction_category.go @@ -3,7 +3,9 @@ package errs import "net/http" var ( - ErrTransactionCategoryIdInvalid = NewNormalError(NORMAL_SUBCATEGORY_CATEGORY, 0, http.StatusBadRequest, "transaction category id is invalid") - ErrTransactionCategoryNotFound = NewNormalError(NORMAL_SUBCATEGORY_CATEGORY, 1, http.StatusBadRequest, "transaction category not found") - ErrTransactionCategoryTypeInvalid = NewNormalError(NORMAL_SUBCATEGORY_CATEGORY, 2, http.StatusBadRequest, "transaction category type is invalid") + ErrTransactionCategoryIdInvalid = NewNormalError(NORMAL_SUBCATEGORY_CATEGORY, 0, http.StatusBadRequest, "transaction category id is invalid") + ErrTransactionCategoryNotFound = NewNormalError(NORMAL_SUBCATEGORY_CATEGORY, 1, http.StatusBadRequest, "transaction category not found") + ErrTransactionCategoryTypeInvalid = NewNormalError(NORMAL_SUBCATEGORY_CATEGORY, 2, http.StatusBadRequest, "transaction category type is invalid") + ErrParentTransactionCategoryNotFound = NewNormalError(NORMAL_SUBCATEGORY_CATEGORY, 3, http.StatusBadRequest, "parent transaction category not found") + ErrCannotAddToSecondaryTransactionCategory = NewNormalError(NORMAL_SUBCATEGORY_CATEGORY, 4, http.StatusBadRequest, "cannot add to secondary transaction category") ) diff --git a/src/consts/color.js b/src/consts/color.js index ea22eb2a..8c4faa3b 100644 --- a/src/consts/color.js +++ b/src/consts/color.js @@ -1,5 +1,5 @@ -const defaultAccountColor = '000000'; -const allAccountColors = [ +const defaultColor = '000000'; +const allAvailableColors = [ '000000', // black '8e8e93', // gray 'ff3b30', // red @@ -17,6 +17,8 @@ const allAccountColors = [ ]; export default { - allAccountColors: allAccountColors, - defaultAccountColor: defaultAccountColor, + allAccountColors: allAvailableColors, + defaultAccountColor: defaultColor, + allCategoryColors: allAvailableColors, + defaultCategoryColor: defaultColor, }; diff --git a/src/consts/icon.js b/src/consts/icon.js index 2e731a9d..e1408847 100644 --- a/src/consts/icon.js +++ b/src/consts/icon.js @@ -157,6 +157,15 @@ const allAccountIcons = { icon: 'lab la-weixin' } }; + +const defaultCategoryIconId = '1'; +const allCategoryIcons = { + // 1 - 99 : Expense - Food & Drink + '1': { + icon: 'las la-utensils' + } +}; + const deviceIcons = { mobile: { f7Icon: 'device_phone_portrait' @@ -179,5 +188,8 @@ export default { allAccountIcons: allAccountIcons, defaultAccountIconId: defaultAccountIconId, defaultAccountIcon: allAccountIcons[defaultAccountIconId], + allCategoryIcons: allCategoryIcons, + defaultCategoryIconId: defaultCategoryIconId, + defaultCategoryIcon: allCategoryIcons[defaultCategoryIconId], deviceIcons: deviceIcons, }; diff --git a/src/filters/categoryIcon.js b/src/filters/categoryIcon.js new file mode 100644 index 00000000..6f4c0485 --- /dev/null +++ b/src/filters/categoryIcon.js @@ -0,0 +1,14 @@ +import icons from "../consts/icon.js"; +import utils from "../lib/utils.js"; + +export default function (iconId) { + if (utils.isNumber(iconId)) { + iconId = iconId.toString(); + } + + if (!icons.allCategoryIcons[iconId]) { + return icons.defaultCategoryIcon.icon; + } + + return icons.allCategoryIcons[iconId].icon; +} diff --git a/src/locales/en.js b/src/locales/en.js index 5ed21df8..89f3f543 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -224,6 +224,8 @@ export default { 'transaction category id is invalid': 'Transaction category ID is invalid', 'transaction category not found': 'Transaction category is not found', 'transaction category type is invalid': 'Transaction category type is invalid', + 'parent transaction category not found': 'Parent transaction category is not found', + 'cannot add to secondary transaction category': 'Cannot add transaction category to secondary transaction category', }, 'parameter': { 'id': 'ID', @@ -399,6 +401,36 @@ export default { 'Current': 'Current', 'Other Device': 'Other Device', 'Unknown Device': 'Unknown Device', + 'Transaction Categories': 'Transaction Categories', + 'Expense Primary Categories': 'Expense Primary Categories', + 'Income Primary Categories': 'Income Primary Categories', + 'Transfer Primary Categories': 'Transfer Primary Categories', + 'Transaction Primary Categories': 'Transaction Primary Categories', + 'Expense Secondary Categories': 'Expense Secondary Categories', + 'Income Secondary Categories': 'Income Secondary Categories', + 'Transfer Secondary Categories': 'Transfer Secondary Categories', + 'Transaction Secondary Categories': 'Transaction Secondary Categories', + 'No available category': 'No available category', + 'Unable to get category list': 'Unable to get category list', + 'Unable to move category': 'Unable to move category', + 'Unable to hide this category': 'Unable to hide this category', + 'Unable to unhide this category': 'Unable to unhide this category', + 'Are you sure you want to delete this category?': 'Are you sure you want to delete this category?', + 'Unable to delete this category': 'Unable to delete this category', + 'Add Primary Category': 'Add Primary Category', + 'Add Secondary Category': 'Add Secondary Category', + 'Edit Category': 'Edit Category', + 'Category Name': 'Category Name', + 'Your category name': 'Your category name', + 'Category Icon': 'Category Icon', + 'Category Color': 'Category Color', + 'Your category description (optional)': 'Your category description (optional)', + 'Category name cannot be empty': 'Category name cannot be empty', + 'Unable to get category': 'Unable to get category', + 'Unable to add category': 'Unable to add category', + 'Unable to save category': 'Unable to save category', + 'You have added a new category': 'You have added a new category', + 'You have saved this category': 'You have saved this category', 'Are you sure you want to logout from this session?': 'Are you sure you want to logout from this session?', 'Unable to logout from this session': 'Unable to logout from this session', 'Are you sure you want to logout all other sessions?': 'Are you sure you want to logout all other sessions?', @@ -447,4 +479,5 @@ export default { 'Official Website': 'Official Website', 'License': 'License', 'An error has occurred': 'An error has occurred', + 'Parameter Invalid': 'Parameter Invalid', }; diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js index 0a0c2ae9..16879619 100644 --- a/src/locales/zh_Hans.js +++ b/src/locales/zh_Hans.js @@ -224,6 +224,8 @@ export default { 'transaction category id is invalid': '交易分类ID无效', 'transaction category not found': '交易分类不存在', 'transaction category type is invalid': '交易分类类型无效', + 'parent transaction category not found': '父级交易分类不存在', + 'cannot add to secondary transaction category': '不能在二级交易分类中添加', }, 'parameter': { 'id': 'ID', @@ -399,6 +401,36 @@ export default { 'Current': '当前', 'Other Device': '其他设备', 'Unknown Device': '未知设备', + 'Transaction Categories': '交易分类', + 'Expense Primary Categories': '支出一级分类', + 'Income Primary Categories': '收入一级分类', + 'Transfer Primary Categories': '转账一级分类', + 'Transaction Primary Categories': '交易一级分类', + 'Expense Secondary Categories': '支出二级分类', + 'Income Secondary Categories': '收入二级分类', + 'Transfer Secondary Categories': '转账二级分类', + 'Transaction Secondary Categories': '交易二级分类', + 'No available category': '没有可用的分类', + 'Unable to get category list': '无法获取分类列表', + 'Unable to move category': '无法移动分类', + 'Unable to hide this category': '无法隐藏该分类', + 'Unable to unhide this category': '无法取消隐藏该分类', + 'Are you sure you want to delete this category?': '您确定要删除该分类?', + 'Unable to delete this category': '无法删除该分类', + 'Add Primary Category': '添加一级分类', + 'Add Secondary Category': '添加二级分类', + 'Edit Category': '编辑分类', + 'Category Name': '分类名称', + 'Your category name': '你的分类名称', + 'Category Icon': '分类图标', + 'Category Color': '分类颜色', + 'Your category description (optional)': '你的分类描述 (可选)', + 'Category name cannot be empty': '分类名称不能为空', + 'Unable to get category': '无法获取分类', + 'Unable to add category': '无法添加分类', + 'Unable to save category': '无法保存分类', + 'You have added a new category': '您已经添加新分类', + 'You have saved this category': '您已经保存该分类', 'Are you sure you want to logout from this session?': '您确定要退出该会话?', 'Unable to logout from this session': '无法退出该会话', 'Are you sure you want to logout all other sessions?': '您确定要退出其他所有会话?', @@ -447,4 +479,5 @@ export default { 'Official Website': '官方网站', 'License': '许可协议', 'An error has occurred': '发生错误', + 'Parameter Invalid': '参数错误', }; diff --git a/src/mobile-main.js b/src/mobile-main.js index 00683c72..86e00237 100644 --- a/src/mobile-main.js +++ b/src/mobile-main.js @@ -31,6 +31,7 @@ import webauthn from './lib/webauthn.js'; import utils from './lib/utils.js'; import currencyFilter from './filters/currency.js'; import accountIconFilter from './filters/accountIcon.js'; +import categoryIconFilter from './filters/categoryIcon.js'; import tokenDeviceFilter from './filters/tokenDevice.js'; import tokenIconFilter from './filters/tokenIcon.js'; import App from './Mobile.vue'; @@ -178,6 +179,7 @@ Vue.prototype.$user = userstate; Vue.filter('currency', (value, currencyCode) => currencyFilter({ i18n }, value, currencyCode)); Vue.filter('accountIcon', (value) => accountIconFilter(value)); +Vue.filter('categoryIcon', (value) => categoryIconFilter(value)); Vue.filter('tokenDevice', (value) => tokenDeviceFilter(value)); Vue.filter('tokenIcon', (value) => tokenIconFilter(value)); diff --git a/src/router/mobile.js b/src/router/mobile.js index 94d75389..cb358c7e 100644 --- a/src/router/mobile.js +++ b/src/router/mobile.js @@ -17,10 +17,15 @@ import SettingsPage from '../views/mobile/Settings.vue'; import ApplicationLockPage from '../views/mobile/ApplicationLock.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"; import SessionListPage from "../views/mobile/users/SessionList.vue"; +import CategoryAllPage from "../views/mobile/categories/CategoryAll.vue"; +import CategoryListPage from "../views/mobile/categories/CategoryList.vue"; +import CategoryEditPage from "../views/mobile/categories/CategoryEdit.vue"; + function checkLogin(to, from, resolve, reject) { const router = this; @@ -179,6 +184,26 @@ const routes = [ component: SessionListPage, beforeEnter: checkLogin }, + { + path: '/category/all', + component: CategoryAllPage, + beforeEnter: checkLogin + }, + { + path: '/category/list', + component: CategoryListPage, + beforeEnter: checkLogin + }, + { + path: '/category/add', + component: CategoryEditPage, + beforeEnter: checkLogin + }, + { + path: '/category/edit', + component: CategoryEditPage, + beforeEnter: checkLogin + }, { path: '(.*)', redirect: '/' diff --git a/src/views/mobile/Settings.vue b/src/views/mobile/Settings.vue index f3319b04..61b364a4 100644 --- a/src/views/mobile/Settings.vue +++ b/src/views/mobile/Settings.vue @@ -7,6 +7,7 @@ + {{ $t('Log Out') }} diff --git a/src/views/mobile/categories/CategoryAll.vue b/src/views/mobile/categories/CategoryAll.vue new file mode 100644 index 00000000..a380f4f5 --- /dev/null +++ b/src/views/mobile/categories/CategoryAll.vue @@ -0,0 +1,15 @@ + diff --git a/src/views/mobile/categories/CategoryEdit.vue b/src/views/mobile/categories/CategoryEdit.vue new file mode 100644 index 00000000..ccbdee8f --- /dev/null +++ b/src/views/mobile/categories/CategoryEdit.vue @@ -0,0 +1,373 @@ + + + diff --git a/src/views/mobile/categories/CategoryList.vue b/src/views/mobile/categories/CategoryList.vue new file mode 100644 index 00000000..57c44da0 --- /dev/null +++ b/src/views/mobile/categories/CategoryList.vue @@ -0,0 +1,424 @@ + + +