From 69d4a1cc741d4f3c3c44a77b3ac8d49b774ad6d4 Mon Sep 17 00:00:00 2001 From: engigu Date: Wed, 17 Jan 2024 23:15:47 +0800 Subject: [PATCH] feat : add site custom setting --- README.md | 9 +++++ main.go | 6 +-- middleware/jwt.go | 1 + migrate/migrate.go | 9 +++++ models/settings.go | 2 +- pkg/constant/constant.go | 7 ++-- pkg/constant/release_log.go | 3 +- pkg/logging/logger.go | 4 +- routers/api/v1/user_settings.go | 26 ++++++++++++- routers/router.go | 1 + service/cron_service/cron_service.go | 19 +++++----- .../init_site.go} | 21 ++++------- web/src/constant.js | 5 ++- web/src/store/page_sate.js | 3 ++ web/src/util/localSiteConfig.js | 37 +++++++++++++++++++ web/src/views/home/index.vue | 15 +++++++- web/src/views/home/login.vue | 14 ++++--- web/src/views/tabsTools/sendLogs/sendLogs.vue | 6 ++- .../views/tabsTools/sendTasks/sendTasks.vue | 4 +- web/src/views/tabsTools/sendWays/sendWays.vue | 4 +- web/src/views/tabsTools/settings/settings.vue | 10 ++--- .../tabsTools/settings/view/siteCustom.vue | 29 ++++++++++++--- 22 files changed, 174 insertions(+), 61 deletions(-) rename service/{env_service/env_service.go => settings_service/init_site.go} (67%) create mode 100644 web/src/util/localSiteConfig.js diff --git a/README.md b/README.md index 800207f..c7efd2e 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,15 @@ Message Nest 是一个灵活而强大的消息推送整合平台,旨在简化 关于日志,考虑到目前多数服务以收集控制台输出为主,暂时不支持写出日志文件。 +2024.01.07 +- [x] 支持站点信息自定义 + +---- +2024.01.03 +- [x] 支持企业微信 + +---- + - [x] 单应用打包 - [x] 支持邮件发送 - [x] 用户密码设置 diff --git a/main.go b/main.go index 78106ed..59eb139 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,6 @@ import ( "message-nest/pkg/setting" "message-nest/routers" "message-nest/service/cron_service" - "message-nest/service/env_service" "net/http" "os" ) @@ -26,13 +25,12 @@ func init() { logging.Setup() migrate.Setup() models.Setup() - env_service.Setup() - cron_service.Setup() } func main() { - gin.SetMode(setting.ServerSetting.RunMode) + cron_service.StartLogsCronRun() + gin.SetMode(setting.ServerSetting.RunMode) routersInit := routers.InitRouter(f) readTimeout := setting.ServerSetting.ReadTimeout writeTimeout := setting.ServerSetting.WriteTimeout diff --git a/middleware/jwt.go b/middleware/jwt.go index 54095e1..f498fda 100644 --- a/middleware/jwt.go +++ b/middleware/jwt.go @@ -13,6 +13,7 @@ import ( var ExcludedRoutes = []string{ "/api/v1/message/send", + "/api/v1/settings/getsetting", } // JWT is jwt middleware diff --git a/migrate/migrate.go b/migrate/migrate.go index 9ea9e8d..b473063 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -7,8 +7,10 @@ import ( "github.com/sirupsen/logrus" "message-nest/models" "message-nest/pkg/setting" + "message-nest/service/settings_service" ) +// 初始化admin账户 func InitAuthTableData() { initSection := "init" initAuthKey := "account" @@ -74,5 +76,12 @@ func Setup() { entry.Infof("Init Account data...") InitAuthTableData() + entry.Infof("Init Custom Site data...") + ss := settings_service.InitSettingService{} + ss.InitSiteConfig() + + entry.Infof("Init Cron data...") + ss.InitLogConfig() + entry.Infof("All table data init done.") } diff --git a/models/settings.go b/models/settings.go index a76d7bc..38c5415 100644 --- a/models/settings.go +++ b/models/settings.go @@ -10,7 +10,7 @@ type Settings struct { Section string `json:"section" gorm:"type:varchar(100) comment '实例类型';default:'';index:section"` Key string `json:"key" gorm:"type:varchar(100) comment '实例类型';default:'';"` - Value string `json:"value" gorm:"type:varchar(4096) comment '实例类型';default:'';"` + Value string `json:"value" gorm:"type:text comment '实例类型';default:'';"` } // AddOneSetting 添加一条设置 diff --git a/pkg/constant/constant.go b/pkg/constant/constant.go index 9b9e0ff..28d4c18 100644 --- a/pkg/constant/constant.go +++ b/pkg/constant/constant.go @@ -9,9 +9,10 @@ const SiteSettingSectionName = "site_config" // 站点信息默认值 var SiteSiteDefaultValueMap = map[string]string{ - "title": "Message Nest", - "slogan": "A Message Way Hosted Site", - "logo": "", + "title": "Message Nest", + "pagesize": "10", + "slogan": "A Message Way Hosted Site", + "logo": "", } // 日志清理自定义 diff --git a/pkg/constant/release_log.go b/pkg/constant/release_log.go index 1c55976..e545a93 100644 --- a/pkg/constant/release_log.go +++ b/pkg/constant/release_log.go @@ -75,7 +75,7 @@ var LatestVersion = map[string]string{} //13. 支持更多的api接入示例 //` -var LatestVersionS = "v0.0.7" +var LatestVersionS = "v0.0.8" var LatestVersionDesc = ` 1. 单应用打包 2. 支持邮件发送 @@ -92,6 +92,7 @@ var LatestVersionDesc = ` 13. 支持更多的api接入示例 14. 支持发送实例的暂停与开启 15. 支持企业微信消息发送 +16. 支持站点信息自定义 ` func init() { diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go index 5d03cbe..47486e7 100644 --- a/pkg/logging/logger.go +++ b/pkg/logging/logger.go @@ -21,7 +21,7 @@ func getFuncOutStr(funcStr string) string { } } -func CallerFormatter(funcStr string, fileStr string) string { +func CustomCallerFormatter(funcStr string, fileStr string) string { fName := filepath.Base(fileStr) funcOut := getFuncOutStr(funcStr) return fmt.Sprintf(" [%s %s]", fName, funcOut) @@ -35,7 +35,7 @@ func Setup() { formatter.ForceColors = true formatter.ForceFormatting = true formatter.FullTimestamp = true - formatter.CallerFormatter = CallerFormatter + formatter.CallerFormatter = CustomCallerFormatter formatter.TimestampFormat = "2006-01-02 15:04:05.000" formatter.SetColorScheme(&prefixed.ColorScheme{ TimestampStyle: "cyan", diff --git a/routers/api/v1/user_settings.go b/routers/api/v1/user_settings.go index d8fed8a..67bd795 100644 --- a/routers/api/v1/user_settings.go +++ b/routers/api/v1/user_settings.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/gin-gonic/gin" "message-nest/pkg/app" + "message-nest/pkg/constant" "message-nest/pkg/e" "message-nest/service/settings_service" "net/http" @@ -93,11 +94,32 @@ func EditSettings(c *gin.Context) { for key, value := range req.Data { err := settingService.EditSettings(req.Section, key, value, currentUser) if err != nil { - appG.CResponse(http.StatusBadRequest, fmt.Sprintf("修改密码失败!错误原因:%s", err), nil) + appG.CResponse(http.StatusBadRequest, fmt.Sprintf("修改站点设置失败!错误原因:%s", err), nil) return } } - appG.CResponse(http.StatusOK, "修改成功!", nil) + appG.CResponse(http.StatusOK, "修改站点设置成功!", nil) + +} + +// RestDefaultSettings 重设默认设置 +func RestDefaultSettings(c *gin.Context) { + var ( + appG = app.Gin{C: c} + ) + + currentUser := app.GetCurrentUserName(c) + settingService := settings_service.UserSettings{} + + for key, value := range constant.SiteSiteDefaultValueMap { + err := settingService.EditSettings(constant.SiteSettingSectionName, key, value, currentUser) + if err != nil { + appG.CResponse(http.StatusBadRequest, fmt.Sprintf("重设站点设置失败!错误原因:%s", err), nil) + return + } + } + + appG.CResponse(http.StatusOK, "重设站点设置成功!", nil) } diff --git a/routers/router.go b/routers/router.go index 327a2f2..9fa698e 100644 --- a/routers/router.go +++ b/routers/router.go @@ -78,6 +78,7 @@ func InitRouter(f embed.FS) *gin.Engine { // settings apiV1.POST("/settings/setpasswd", v1.EditPasswd) apiV1.POST("/settings/set", v1.EditSettings) + apiV1.POST("/settings/reset", v1.RestDefaultSettings) apiV1.GET("/settings/getsetting", v1.GetUserSetting) } diff --git a/service/cron_service/cron_service.go b/service/cron_service/cron_service.go index b6b8274..5a74b48 100644 --- a/service/cron_service/cron_service.go +++ b/service/cron_service/cron_service.go @@ -10,12 +10,9 @@ import ( "message-nest/service/send_message_service" ) -type CronService struct { -} - var ClearLogsTaskId cron.EntryID -// 清除日志的定时任务 +// ClearLogs 清除日志的定时任务 func ClearLogs() { var errStr string sm := send_message_service.SendMessageService{TaskID: constant.CleanLogsTaskId} @@ -42,8 +39,11 @@ func ClearLogs() { sm.RecordSendLog() } -// 启动注册清除任务定时任务 -func (cs *CronService) InitLogsCronRun() { +type CronService struct { +} + +// StartLogsCronRun 启动注册清除任务定时任务 +func (cs *CronService) StartLogsCronRun() { // 注册任务 setting, err := models.GetSettingByKey(constant.LogsCleanSectionName, constant.LogsCleanCronKeyName) if err != nil { @@ -61,7 +61,7 @@ func (cs *CronService) InitLogsCronRun() { } } -// 更新清除任务定时任务 +// UpdateLogsCronRun 更新清除任务定时任务 func (cs *CronService) UpdateLogsCronRun(cron string) { RemoveTask(ClearLogsTaskId) ClearLogsTaskId = AddTask(ScheduledTask{ @@ -73,7 +73,8 @@ func (cs *CronService) UpdateLogsCronRun(cron string) { } -func Setup() { +// StartLogsCronRun 启动的时候开启定时任务 +func StartLogsCronRun() { cs := CronService{} - cs.InitLogsCronRun() + cs.StartLogsCronRun() } diff --git a/service/env_service/env_service.go b/service/settings_service/init_site.go similarity index 67% rename from service/env_service/env_service.go rename to service/settings_service/init_site.go index 455e2d1..d940c0a 100644 --- a/service/env_service/env_service.go +++ b/service/settings_service/init_site.go @@ -1,4 +1,4 @@ -package env_service +package settings_service import ( "github.com/sirupsen/logrus" @@ -6,10 +6,11 @@ import ( "message-nest/pkg/constant" ) -type EnvService struct { +// 初始化环境的设置数据 +type InitSettingService struct { } -func (es *EnvService) CommonAdd(section string, key string, value string) { +func (es *InitSettingService) CommonAddSetting(section string, key string, value string) { setting, _ := models.GetSettingByKey(section, key) if setting.ID <= 0 { err := models.AddOneSetting(models.Settings{ @@ -26,23 +27,17 @@ func (es *EnvService) CommonAdd(section string, key string, value string) { } // InitSiteConfig 初始化、重置站点信息设置 -func (es *EnvService) InitSiteConfig() { +func (es *InitSettingService) InitSiteConfig() { section := constant.SiteSettingSectionName for key, value := range constant.SiteSiteDefaultValueMap { - es.CommonAdd(section, key, value) + es.CommonAddSetting(section, key, value) } } // InitLogConfig 初始化日志清理设置 -func (es *EnvService) InitLogConfig() { +func (es *InitSettingService) InitLogConfig() { section := constant.LogsCleanSectionName for key, value := range constant.LogsCleanDefaultValueMap { - es.CommonAdd(section, key, value) + es.CommonAddSetting(section, key, value) } } - -func Setup() { - es := EnvService{} - es.InitSiteConfig() - es.InitLogConfig() -} diff --git a/web/src/constant.js b/web/src/constant.js index 1ec7768..6a0d686 100644 --- a/web/src/constant.js +++ b/web/src/constant.js @@ -4,10 +4,12 @@ import { ApiStrGenerate } from "@/util/viewApi.js"; // 定义一些常量名 const CONSTANT = { PAGE: 1, - PAGE_SIZE: 8, + // PAGE_SIZE: 8, TOTAL: 0, + DEFALUT_SITE_CONFIG: JSON.stringify({ "logo": "", "pagesize": "8", "slogan": "A Message Way Hosted Site", "title": "Message Nest" }), LOG_TASK_ID: "00000000-0000-0000-0000-000000000001", STORE_TOKEN_NAME: '__message_nest_token__', + STORE_CUSTOM_NAME: '__message_nest_custom_site__', NO_AUTH_URL: [ '/auth', ], @@ -83,7 +85,6 @@ const CONSTANT = { ], }, ], - LOGO: ``, API_VIEW_DATA: [ { label: "curl", class: "language-shell line-numbers", code: "", func: ApiStrGenerate.getCurlString }, { label: "python", class: "language-python line-numbers", code: "", func: ApiStrGenerate.getPythonString }, diff --git a/web/src/store/page_sate.js b/web/src/store/page_sate.js index 78142d3..1fcaeec 100644 --- a/web/src/store/page_sate.js +++ b/web/src/store/page_sate.js @@ -1,5 +1,7 @@ import { defineStore } from 'pinia'; +import { LocalStieConfigUtils } from '@/util/localSiteConfig' + export const usePageState = defineStore({ id: 'pageState', @@ -7,6 +9,7 @@ export const usePageState = defineStore({ isLogin: false, // 全局的登录状态 Token: '', // 全局的登录状态 isShowAddWayDialog: false, + siteConfigData: LocalStieConfigUtils.getLocalConfig(), ShowDialogData: {} }), actions: { diff --git a/web/src/util/localSiteConfig.js b/web/src/util/localSiteConfig.js new file mode 100644 index 0000000..2e08a3e --- /dev/null +++ b/web/src/util/localSiteConfig.js @@ -0,0 +1,37 @@ +import { CONSTANT } from '@/constant' +import { request } from '@/api/api' + + +class LocalStieConfigUtils { + + + // 更新本地的site设置 + static updateLocalConfig = (data) => { + localStorage.setItem(CONSTANT.STORE_CUSTOM_NAME, JSON.stringify(data)); + } + + // 更新本地的site设置 + static getLocalConfig = () => { + let d = localStorage.getItem(CONSTANT.STORE_CUSTOM_NAME); + if (!d) { + d = CONSTANT.DEFALUT_SITE_CONFIG; + } + let data = JSON.parse(d); + data.pagesize = Number(data.pagesize); + return data + } + + // 获取最新的本地的site设置 + static getLatestLocalConfig = async () => { + let params = { params: { section: "site_config" } }; + const rsp = await request.get('/settings/getsetting', params); + if (await rsp.data.code == 200) { + let data = await rsp.data.data; + LocalStieConfigUtils.updateLocalConfig(data); + } + return LocalStieConfigUtils.getLocalConfig(); + } + +} + +export { LocalStieConfigUtils }; diff --git a/web/src/views/home/index.vue b/web/src/views/home/index.vue index fcc7c05..72af947 100644 --- a/web/src/views/home/index.vue +++ b/web/src/views/home/index.vue @@ -3,6 +3,7 @@ + @@ -30,7 +31,7 @@ export default { const router = useRouter(); const isCollapse = ref(false); const state = reactive({ - titleLogo: 'data:image/svg+xml;utf8,' + CONSTANT.LOGO, + titleLogo: '', }); const menuData = reactive([ { @@ -76,10 +77,16 @@ export default { return result; } + const setSiteConfig = () => { + document.title = pageState.siteConfigData.title; + state.titleLogo = 'data:image/svg+xml;base64,' + btoa(pageState.siteConfigData.logo); + } + onMounted(() => { changeFavicon(); checkIsLogin(); loadLocalToken(); + setSiteConfig(); }); const changeFavicon = () => { @@ -87,7 +94,7 @@ export default { if (link) { link.type = 'image/svg+xml'; link.rel = 'icon'; - link.href = 'data:image/svg+xml;utf8,' + CONSTANT.LOGO; + link.href = 'data:image/svg+xml;base64,' + btoa(pageState.siteConfigData.logo) document.getElementsByTagName('head')[0].appendChild(link); } } @@ -118,6 +125,10 @@ export default { margin: 0 auto; } +.title-logo svg { + height: 50px; +} + .logout-btn { margin: auto 40px auto 40px; float: right; diff --git a/web/src/views/home/login.vue b/web/src/views/home/login.vue index 5609587..eb2f40d 100644 --- a/web/src/views/home/login.vue +++ b/web/src/views/home/login.vue @@ -4,7 +4,7 @@
-

A Message Way Hosted Site

+

{{ slogan }}

@@ -50,11 +50,13 @@ import { request } from '../../../api/api' import { copyToClipboard } from '../../../util/clipboard.js'; import { useRoute } from 'vue-router'; import { CONSTANT } from '@/constant' +import { usePageState } from '@/store/page_sate.js'; export default { components: { }, setup() { + const pageState = usePageState(); const router = useRoute(); const state = reactive({ search: '', @@ -63,7 +65,7 @@ export default { drawer: false, tableData: [], total: CONSTANT.TOTAL, - pageSize: CONSTANT.PAGE_SIZE, + pageSize: pageState.siteConfigData.pagesize, currPage: CONSTANT.PAGE, }); diff --git a/web/src/views/tabsTools/sendTasks/sendTasks.vue b/web/src/views/tabsTools/sendTasks/sendTasks.vue index bbf63cd..786f29b 100644 --- a/web/src/views/tabsTools/sendTasks/sendTasks.vue +++ b/web/src/views/tabsTools/sendTasks/sendTasks.vue @@ -38,7 +38,7 @@
- 共{{ total }}条 + 每页{{ pageSize }}条,共{{ total }}条
@@ -83,7 +83,7 @@ export default { // confirmBtnVisible: false, tableData: [], total: CONSTANT.TOTAL, - pageSize: CONSTANT.PAGE_SIZE, + pageSize: pageState.siteConfigData.pagesize, currPage: CONSTANT.PAGE, displayCols: [ { 'col': 'id', 'label': '任务ID' }, diff --git a/web/src/views/tabsTools/sendWays/sendWays.vue b/web/src/views/tabsTools/sendWays/sendWays.vue index db35820..5ae2fe4 100644 --- a/web/src/views/tabsTools/sendWays/sendWays.vue +++ b/web/src/views/tabsTools/sendWays/sendWays.vue @@ -43,7 +43,7 @@
- 共{{ total }}条 + 每页{{ pageSize }}条,共{{ total }}条
@@ -83,7 +83,7 @@ export default { // confirmBtnVisible: false, tableData: [], total: CONSTANT.TOTAL, - pageSize: CONSTANT.PAGE_SIZE, + pageSize: pageState.siteConfigData.pagesize, currPage: CONSTANT.PAGE, displayCols: [ { 'col': 'id', 'label': '渠道ID' }, diff --git a/web/src/views/tabsTools/settings/settings.vue b/web/src/views/tabsTools/settings/settings.vue index 2ce49b6..b5bd877 100644 --- a/web/src/views/tabsTools/settings/settings.vue +++ b/web/src/views/tabsTools/settings/settings.vue @@ -10,9 +10,9 @@ 日志清理 - + 站点关于 @@ -82,9 +82,9 @@ hr { margin-top: -10vh; } -/* .setting-main { - -} */ +:deep(.el-input ) { + margin-top: 14px; +} .setting-right { width: 100%; diff --git a/web/src/views/tabsTools/settings/view/siteCustom.vue b/web/src/views/tabsTools/settings/view/siteCustom.vue index 96d031f..698dcbf 100644 --- a/web/src/views/tabsTools/settings/view/siteCustom.vue +++ b/web/src/views/tabsTools/settings/view/siteCustom.vue @@ -4,12 +4,15 @@ - + - + + + +
@@ -27,7 +30,7 @@
- 恢复默认 + 恢复默认 确定
@@ -40,6 +43,8 @@ import { QuestionFilled } from '@element-plus/icons-vue' import { useRouter } from 'vue-router'; import { request } from '@/api/api' import { CONSTANT } from '@/constant' +import { LocalStieConfigUtils } from '@/util/localSiteConfig' + export default defineComponent({ components: { @@ -55,6 +60,7 @@ export default defineComponent({ title: '', slogan: '', logo: '', + pagesize: '', section: 'site_config', }); @@ -65,6 +71,7 @@ export default defineComponent({ title: state.title.trim(), slogan: state.slogan.trim(), logo: state.logo.trim(), + pagesize: state.pagesize, }, }; const rsp = await request.post('/settings/set', postData); @@ -73,8 +80,15 @@ export default defineComponent({ ElMessage({ message: msg, type: 'success' }) } } - const handleView = async () => { - router.push('/sendlogs?taskid=' + CONSTANT.LOG_TASK_ID, { replace: true }); + + const handleSubmitReset = async () => { + const rsp = await request.post('/settings/reset', {}); + if (await rsp.data.code == 200) { + let msg = await rsp.data.msg; + ElMessage({ message: msg, type: 'success' }); + // 重新获取设置 + await getSiteConfig(); + } } const getSiteConfig = async () => { @@ -85,6 +99,9 @@ export default defineComponent({ state.title = data.title; state.logo = data.logo; state.slogan = data.slogan; + state.pagesize = data.pagesize; + + LocalStieConfigUtils.updateLocalConfig(data); } } @@ -93,7 +110,7 @@ export default defineComponent({ }) return { - ...toRefs(state), handleSubmit, handleView + ...toRefs(state), handleSubmit, handleSubmitReset } }