diff --git a/.env b/.env index 033e004..395e069 100644 --- a/.env +++ b/.env @@ -1,8 +1,10 @@ VITE_BASE_URL=/ -VITE_APP_TITLE=SoybeanAdmin +VITE_APP_TITLE=Easy Retry -VITE_APP_DESC=SoybeanAdmin is a fresh and elegant admin template +VITE_APP_DESC=A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling. + +VITE_APP_VERSION=v3.1.0 # the prefix of the icon name VITE_ICON_PREFIX=icon diff --git a/.env.prod b/.env.prod index 832d4d6..4afd11e 100644 --- a/.env.prod +++ b/.env.prod @@ -1,5 +1,5 @@ # backend service base url, prod environment -VITE_SERVICE_BASE_URL=https://mock.apifox.com/m1/3109515-0-default +VITE_SERVICE_BASE_URL=/proxy-default # other backend service base url, prod environment VITE_OTHER_SERVICE_BASE_URL= `{ diff --git a/public/favicon.svg b/public/favicon.svg index 169b2ab..45b99a7 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1 +1 @@ - + diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..6f4c6ea Binary files /dev/null and b/public/logo.png differ diff --git a/src/assets/svg-icon/full-logo.svg b/src/assets/svg-icon/full-logo.svg new file mode 100644 index 0000000..c120a9a --- /dev/null +++ b/src/assets/svg-icon/full-logo.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/svg-icon/logo.svg b/src/assets/svg-icon/logo.svg index 341675d..74bfffe 100644 --- a/src/assets/svg-icon/logo.svg +++ b/src/assets/svg-icon/logo.svg @@ -1 +1,37 @@ - + + diff --git a/src/layouts/modules/global-footer/index.vue b/src/layouts/modules/global-footer/index.vue index 603cbaf..9192ab4 100644 --- a/src/layouts/modules/global-footer/index.vue +++ b/src/layouts/modules/global-footer/index.vue @@ -2,12 +2,14 @@ defineOptions({ name: 'GlobalFooter' }); + +const { VITE_APP_VERSION } = import.meta.env; diff --git a/src/layouts/modules/namespace-select/index.vue b/src/layouts/modules/namespace-select/index.vue index 51dd3ee..738d3e5 100644 --- a/src/layouts/modules/namespace-select/index.vue +++ b/src/layouts/modules/namespace-select/index.vue @@ -16,9 +16,7 @@ const options = ref( const onChange = (value: string) => { localStg.set('namespaceId', value); - setTimeout(() => { - router.go(0); - }, 500); + router.go(0); }; diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts index 3ffc7eb..bbf90b1 100644 --- a/src/locales/langs/en-us.ts +++ b/src/locales/langs/en-us.ts @@ -1,6 +1,7 @@ const local: App.I18n.Schema = { system: { - title: 'SoybeanAdmin' + title: 'Easy Retry', + desc: 'A flexible, reliable, and fast platform for distributed task retry and distributed task scheduling.' }, common: { action: 'Action', @@ -35,6 +36,10 @@ const local: App.I18n.Schema = { update: 'Update', updateSuccess: 'Update Success', userCenter: 'User Center', + success: 'Success', + fail: 'Fail', + stop: 'Stop', + running: 'Running', yesOrNo: { yes: 'Yes', no: 'No' @@ -164,6 +169,7 @@ const local: App.I18n.Schema = { confirmPasswordPlaceholder: 'Please enter password again', codeLogin: 'Verification code login', confirm: 'Confirm', + login: 'Login', back: 'Back', validateSuccess: 'Verification passed', loginSuccess: 'Login successfully', @@ -212,8 +218,30 @@ const local: App.I18n.Schema = { devDep: 'Development Dependency' }, home: { - greeting: 'Good morning, {userName}, today is another day full of vitality!', + // 问候语 + Greeting: '{userName}, welcome back.', + morningGreeting: 'Good morning, {userName}, today is another day full of vitality!', + bthGreeting: "Good morning, {userName}, how's work going? Don't be sedentary. Get up and walk around more often!", + noonGreeting: "Good noon, {userName}, it's lunchtime after a long morning at work!", + athGreeting: "Good afternoon, {userName}, it's easy to get sleepy in the late afternoon yet, time for a nap!", + duskGreeting: + "{userName}, it's evening, the view of the sunset outside the window is very beautiful, the most beautiful thing is the red sunset.", + eveningGreeting: 'Good evening, {userName}, how are you doing today? Please take care to rest early!', + earlyMorningGreeting: "{userName}, It's so late already. Get some rest. Good night.", weatherDesc: 'Today is cloudy to clear, 20℃ - 25℃!', + // 卡片统计 + retryTaskCount: 'Retry Task', + jobTaskCount: 'Job Task', + userCount: 'User', + retryTask: 'Retry Task', + retryTaskTip: 'Total task volume: retry/callback task volume', + jobTask: 'Job Task', + jobTaskTip: 'Success rate: total completion/total dispatch amount', + onlineServiceCount: 'Online Machine', + onlineServiceTip: 'Always online machines: the sum of clients and servers registered to the system', + workflow: 'Workflow', + workflowTip: 'Workflow Tip', + // ... projectCount: 'Project Count', todo: 'Todo', message: 'Message', @@ -271,6 +299,18 @@ const local: App.I18n.Schema = { disable: 'Disable' } }, + machine: { + type: { + client: 'Client', + server: 'Server' + } + }, + retryTask: { + status: { + maxRetryTimes: 'Max times', + pauseRetry: 'Pause' + } + }, role: { title: 'Role List', roleName: 'Role Name', diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts index d22501e..dcdc0ca 100644 --- a/src/locales/langs/zh-cn.ts +++ b/src/locales/langs/zh-cn.ts @@ -1,6 +1,7 @@ const local: App.I18n.Schema = { system: { - title: 'Soybean 管理系统' + title: 'Easy Retry', + desc: '灵活,可靠和快速的分布式任务重试和分布式任务调度平台' }, common: { action: '操作', @@ -35,6 +36,10 @@ const local: App.I18n.Schema = { update: '更新', updateSuccess: '更新成功', userCenter: '个人中心', + success: '成功', + fail: '失败', + stop: '停止', + running: '运行中', yesOrNo: { yes: '是', no: '否' @@ -163,6 +168,7 @@ const local: App.I18n.Schema = { passwordPlaceholder: '请输入密码', confirmPasswordPlaceholder: '请再次输入密码', codeLogin: '验证码登录', + login: '登录', confirm: '确定', back: '返回', validateSuccess: '验证成功', @@ -212,8 +218,26 @@ const local: App.I18n.Schema = { devDep: '开发依赖' }, home: { - greeting: '早安,{userName}, 今天又是充满活力的一天!', + Greeting: '{userName},欢迎回来!', + morningGreeting: '早安,{userName},今天又是充满活力的一天!', + bthGreeting: '上午好,{userName},工作顺利吗,不要久坐,多起来走动走动哦!', + noonGreeting: '中午好,{userName},工作了一个上午,现在是午餐时间!', + athGreeting: '下午好,{userName},午后很容易犯困呢,是时候该打个盹了!', + duskGreeting: '{userName},傍晚了,窗外夕阳的景色很美丽呢,最美不过夕阳红~', + eveningGreeting: '晚上好,{userName},今天过得怎么样?请注意早点休息!', + earlyMorningGreeting: '{userName},已经这么晚了呀,早点休息吧,晚安~', weatherDesc: '今日多云转晴,20℃ - 25℃!', + retryTaskCount: '重试任务', + jobTaskCount: '定时任务', + userCount: '用户', + retryTask: '重试任务', + retryTaskTip: '总任务量: 重试/回调任务量', + jobTask: '定时任务', + jobTaskTip: '成功率:总完成/总调度量', + onlineServiceCount: '总在线机器', + onlineServiceTip: '总在线机器:注册到系统的客户端和服务端之和', + workflow: '工作流', + workflowTip: '工作流提示', projectCount: '项目数', todo: '待办', message: '消息', @@ -271,6 +295,18 @@ const local: App.I18n.Schema = { disable: '禁用' } }, + machine: { + type: { + client: '客户端', + server: '服务端' + } + }, + retryTask: { + status: { + maxRetryTimes: '最大重试次数', + pauseRetry: '暂停重试' + } + }, role: { title: '角色列表', roleName: '角色名称', diff --git a/src/plugins/loading.ts b/src/plugins/loading.ts index d61bc58..1b40209 100644 --- a/src/plugins/loading.ts +++ b/src/plugins/loading.ts @@ -2,7 +2,7 @@ import { getRgbOfColor } from '@sa/utils'; import { $t } from '@/locales'; import { localStg } from '@/utils/storage'; -import systemLogo from '@/assets/svg-icon/logo.svg?raw'; +import systemLogo from '@/assets/svg-icon/full-logo.svg?raw'; export function setupLoading() { const themeColor = localStg.get('themeColor') || '#646cff'; @@ -18,7 +18,7 @@ export function setupLoading() { 'right-0 bottom-0 animate-delay-1500' ]; - const logoWithClass = systemLogo.replace(' { @@ -34,7 +34,7 @@ export function setupLoading() { ${dot} -

${$t('system.title')}

+

${$t('system.desc')}

`; const app = document.getElementById('app'); diff --git a/src/service/api/dashboard.ts b/src/service/api/dashboard.ts new file mode 100644 index 0000000..ab0493a --- /dev/null +++ b/src/service/api/dashboard.ts @@ -0,0 +1,9 @@ +import { request } from '../request'; + +/** Version */ +export function fetchCardCount() { + return request({ + url: '/dashboard/task-retry-job', + method: 'get' + }); +} diff --git a/src/service/api/index.ts b/src/service/api/index.ts index c9d31d1..888f20f 100644 --- a/src/service/api/index.ts +++ b/src/service/api/index.ts @@ -1,3 +1,5 @@ export * from './auth'; export * from './route'; +export * from './system'; +export * from './dashboard'; export * from './system-manage'; diff --git a/src/service/api/system.ts b/src/service/api/system.ts new file mode 100644 index 0000000..b390661 --- /dev/null +++ b/src/service/api/system.ts @@ -0,0 +1,9 @@ +import { request } from '../request'; + +/** Version */ +export function fetchVersion() { + return request({ + url: '/system/version', + method: 'get' + }); +} diff --git a/src/theme/settings.ts b/src/theme/settings.ts index bba9617..b7d86c7 100644 --- a/src/theme/settings.ts +++ b/src/theme/settings.ts @@ -1,7 +1,7 @@ /** Default theme settings */ export const themeSettings: App.Theme.ThemeSetting = { themeScheme: 'light', - themeColor: '#646cff', + themeColor: '#22aae3', otherColor: { info: '#2080f0', success: '#52c41a', diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts index afe0d3e..7cebeb5 100644 --- a/src/typings/api.d.ts +++ b/src/typings/api.d.ts @@ -95,6 +95,48 @@ declare namespace Api { } } + /** + * namespace Dashboard + * + * backend api module: "dashboard" + */ + namespace Dashboard { + type CardCount = { + jobTask: JobTask; + retryTask: RetryTask; + retryTaskBarList: RetryTaskBarList[]; + onLineService: OnlineService; + }; + + type OnlineService = { + total: number; + clientTotal: number; + serverTotal: number; + }; + + type RetryTaskBarList = { + x: string; + taskTotal: number; + }; + + type RetryTask = { + totalNum: number; + runningNum: number; + finishNum: number; + maxCountNum: number; + suspendNum: number; + }; + + type JobTask = { + successNum: number; + failNum: number; + cancelNum: number; + stopNum: number; + totalNum: number; + successRate: number; + }; + } + /** * namespace SystemManage * diff --git a/src/typings/app.d.ts b/src/typings/app.d.ts index 55f1f12..0961009 100644 --- a/src/typings/app.d.ts +++ b/src/typings/app.d.ts @@ -247,6 +247,7 @@ declare namespace App { type Schema = { system: { title: string; + desc: string; }; common: { action: string; @@ -281,6 +282,10 @@ declare namespace App { update: string; updateSuccess: string; userCenter: string; + success: string; + fail: string; + stop: string; + running: string; yesOrNo: { yes: string; no: string; @@ -346,6 +351,7 @@ declare namespace App { passwordPlaceholder: string; confirmPasswordPlaceholder: string; codeLogin: string; + login: string; confirm: string; back: string; validateSuccess: string; @@ -395,7 +401,25 @@ declare namespace App { devDep: string; }; home: { - greeting: string; + Greeting: string; + morningGreeting: string; + bthGreeting: string; + noonGreeting: string; + athGreeting: string; + duskGreeting: string; + eveningGreeting: string; + earlyMorningGreeting: string; + retryTaskCount: string; + jobTaskCount: string; + userCount: string; + retryTask: string; + retryTaskTip: string; + jobTask: string; + jobTaskTip: string; + onlineServiceCount: string; + onlineServiceTip: string; + workflow: string; + workflowTip: string; weatherDesc: string; projectCount: string; todo: string; @@ -454,6 +478,18 @@ declare namespace App { disable: string; }; }; + machine: { + type: { + client: string; + server: string; + }; + }; + retryTask: { + status: { + maxRetryTimes: string; + pauseRetry: string; + }; + }; role: { title: string; roleName: string; diff --git a/src/typings/components.d.ts b/src/typings/components.d.ts index 1917d6e..bed5ace 100644 --- a/src/typings/components.d.ts +++ b/src/typings/components.d.ts @@ -16,14 +16,21 @@ declare module 'vue' { FullScreen: typeof import('./../components/common/full-screen.vue')['default'] IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default'] IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default'] + IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default'] IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default'] IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default'] + IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default'] + IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default'] + IconIcRoundRefresh: typeof import('~icons/ic/round-refresh')['default'] + IconIcRoundSearch: typeof import('~icons/ic/round-search')['default'] IconLocalBanner: typeof import('~icons/local/banner')['default'] IconLocalLogo: typeof import('~icons/local/logo')['default'] IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default'] IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default'] + IconMdiDrag: typeof import('~icons/mdi/drag')['default'] IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default'] IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default'] + IconMdiRefresh: typeof import('~icons/mdi/refresh')['default'] IconUilSearch: typeof import('~icons/uil/search')['default'] LangSwitch: typeof import('./../components/common/lang-switch.vue')['default'] LookForward: typeof import('./../components/custom/look-forward.vue')['default'] @@ -34,6 +41,9 @@ declare module 'vue' { NCard: typeof import('naive-ui')['NCard'] NCheckbox: typeof import('naive-ui')['NCheckbox'] NColorPicker: typeof import('naive-ui')['NColorPicker'] + NDataTable: typeof import('naive-ui')['NDataTable'] + NDescriptions: typeof import('naive-ui')['NDescriptions'] + NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem'] NDialogProvider: typeof import('naive-ui')['NDialogProvider'] NDivider: typeof import('naive-ui')['NDivider'] NDrawer: typeof import('naive-ui')['NDrawer'] @@ -42,6 +52,7 @@ declare module 'vue' { NEmpty: typeof import('naive-ui')['NEmpty'] NForm: typeof import('naive-ui')['NForm'] NFormItem: typeof import('naive-ui')['NFormItem'] + NFormItemGi: typeof import('naive-ui')['NFormItemGi'] NGi: typeof import('naive-ui')['NGi'] NGrid: typeof import('naive-ui')['NGrid'] NInput: typeof import('naive-ui')['NInput'] @@ -54,13 +65,21 @@ declare module 'vue' { NMessageProvider: typeof import('naive-ui')['NMessageProvider'] NModal: typeof import('naive-ui')['NModal'] NNotificationProvider: typeof import('naive-ui')['NNotificationProvider'] + NPopconfirm: typeof import('naive-ui')['NPopconfirm'] + NPopover: typeof import('naive-ui')['NPopover'] + NProgress: typeof import('naive-ui')['NProgress'] + NRadio: typeof import('naive-ui')['NRadio'] + NRadioGroup: typeof import('naive-ui')['NRadioGroup'] NScrollbar: typeof import('naive-ui')['NScrollbar'] NSelect: typeof import('naive-ui')['NSelect'] + NSkeleton: typeof import('naive-ui')['NSkeleton'] NSpace: typeof import('naive-ui')['NSpace'] + NSpin: typeof import('naive-ui')['NSpin'] NStatistic: typeof import('naive-ui')['NStatistic'] NSwitch: typeof import('naive-ui')['NSwitch'] NTab: typeof import('naive-ui')['NTab'] NTabs: typeof import('naive-ui')['NTabs'] + NTag: typeof import('naive-ui')['NTag'] NThing: typeof import('naive-ui')['NThing'] NTooltip: typeof import('naive-ui')['NTooltip'] PinToggler: typeof import('./../components/common/pin-toggler.vue')['default'] diff --git a/src/typings/env.d.ts b/src/typings/env.d.ts index d1f1d49..2516a63 100644 --- a/src/typings/env.d.ts +++ b/src/typings/env.d.ts @@ -15,6 +15,8 @@ declare namespace Env { readonly VITE_APP_TITLE: string; /** The description of the application */ readonly VITE_APP_DESC: string; + /** The version of the application */ + readonly VITE_APP_VERSION: string; /** The router history mode */ readonly VITE_ROUTER_HISTORY_MODE?: RouterHistoryMode; /** The prefix of the iconify icon */ diff --git a/src/views/_builtin/login/index.vue b/src/views/_builtin/login/index.vue index a2e8e56..e1db4b7 100644 --- a/src/views/_builtin/login/index.vue +++ b/src/views/_builtin/login/index.vue @@ -3,14 +3,11 @@ import { computed } from 'vue'; import type { Component } from 'vue'; import { getColorPalette, mixColor } from '@sa/utils'; import { $t } from '@/locales'; +import GlobalFooter from '@/layouts/modules/global-footer/index.vue'; import { useAppStore } from '@/store/modules/app'; import { useThemeStore } from '@/store/modules/theme'; import { loginModuleRecord } from '@/constants/app'; import PwdLogin from './modules/pwd-login.vue'; -import CodeLogin from './modules/code-login.vue'; -import Register from './modules/register.vue'; -import ResetPwd from './modules/reset-pwd.vue'; -import BindWechat from './modules/bind-wechat.vue'; interface Props { /** The login module */ @@ -21,6 +18,8 @@ const props = withDefaults(defineProps(), { module: 'pwd-login' }); +const { VITE_APP_VERSION } = import.meta.env; + const appStore = useAppStore(); const themeStore = useThemeStore(); @@ -30,13 +29,7 @@ interface LoginModule { component: Component; } -const modules: LoginModule[] = [ - { key: 'pwd-login', label: loginModuleRecord['pwd-login'], component: PwdLogin }, - { key: 'code-login', label: loginModuleRecord['code-login'], component: CodeLogin }, - { key: 'register', label: loginModuleRecord.register, component: Register }, - { key: 'reset-pwd', label: loginModuleRecord['reset-pwd'], component: ResetPwd }, - { key: 'bind-wechat', label: loginModuleRecord['bind-wechat'], component: BindWechat } -]; +const modules: LoginModule[] = [{ key: 'pwd-login', label: loginModuleRecord['pwd-login'], component: PwdLogin }]; const activeModule = computed(() => { const findItem = modules.find(item => item.key === props.module); @@ -63,7 +56,10 @@ const bgColor = computed(() => {
-

{{ $t('system.title') }}

+

+ {{ $t('system.title') }} + {{ VITE_APP_VERSION }} +

{
-

{{ $t(activeModule.label) }}

-
+ +
+
+ + + +
+
diff --git a/src/views/_builtin/login/modules/pwd-login.vue b/src/views/_builtin/login/modules/pwd-login.vue index 06c520d..a6301e6 100644 --- a/src/views/_builtin/login/modules/pwd-login.vue +++ b/src/views/_builtin/login/modules/pwd-login.vue @@ -2,8 +2,6 @@ import { computed, reactive } from 'vue'; import { Md5 } from 'ts-md5'; import { $t } from '@/locales'; -import { loginModuleRecord } from '@/constants/app'; -import { useRouterPush } from '@/hooks/common/router'; import { useFormRules, useNaiveForm } from '@/hooks/common/form'; import { useAuthStore } from '@/store/modules/auth'; @@ -12,7 +10,6 @@ defineOptions({ }); const authStore = useAuthStore(); -const { toggleLoginModule } = useRouterPush(); const { formRef, validate } = useNaiveForm(); interface FormModel { @@ -56,21 +53,9 @@ async function handleSubmit() { /> -
- {{ $t('page.login.pwdLogin.rememberMe') }} - {{ $t('page.login.pwdLogin.forgetPassword') }} -
- {{ $t('common.confirm') }} + {{ $t('page.login.common.login') }} -
- - {{ $t(loginModuleRecord['code-login']) }} - - - {{ $t(loginModuleRecord.register) }} - -
diff --git a/src/views/home/index.vue b/src/views/home/index.vue index bd69cf5..c82db39 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -1,6 +1,7 @@ - + diff --git a/src/views/home/modules/header-banner.vue b/src/views/home/modules/header-banner.vue index daf3a30..27b1f65 100644 --- a/src/views/home/modules/header-banner.vue +++ b/src/views/home/modules/header-banner.vue @@ -22,41 +22,65 @@ interface StatisticData { const statisticData = computed(() => [ { id: 0, - label: $t('page.home.projectCount'), - value: '25' + label: $t('page.home.userCount'), + value: '2' }, { id: 1, - label: $t('page.home.todo'), - value: '4/16' + label: $t('page.home.jobTaskCount'), + value: '8' }, { id: 2, - label: $t('page.home.message'), - value: '12' + label: $t('page.home.retryTaskCount'), + value: '3' } ]); + +const timeFix = () => { + const time = new Date(); + const hour = time.getHours(); + let text = ''; + if (hour > 5 && hour <= 8) { + text = 'morning'; + } else if (hour > 8 && hour <= 11) { + text = 'bth'; + } else if (hour > 11 && hour <= 14) { + text = 'noon'; + } else if (hour > 14 && hour <= 17) { + text = 'ath'; + } else if (hour > 17 && hour <= 19) { + text = 'dusk'; + } else if (hour > 19 && hour <= 21) { + text = 'evening'; + } else if (hour > 21 && hour <= 5) { + text = 'earlyMorning'; + } + return text; +};