diff --git a/common/constants.go b/common/constants.go index 471f6ff2..7a1694c5 100644 --- a/common/constants.go +++ b/common/constants.go @@ -14,6 +14,7 @@ var ServerAddress = "http://localhost:3000" var Footer = "" var Logo = "" var TopUpLink = "" +var ChatLink = "" var UsingSQLite = false diff --git a/controller/misc.go b/controller/misc.go index d200a239..10f1f99e 100644 --- a/controller/misc.go +++ b/controller/misc.go @@ -28,6 +28,7 @@ func GetStatus(c *gin.Context) { "turnstile_check": common.TurnstileCheckEnabled, "turnstile_site_key": common.TurnstileSiteKey, "top_up_link": common.TopUpLink, + "chat_link": common.ChatLink, }, }) return diff --git a/model/option.go b/model/option.go index 32d655ac..b53b172d 100644 --- a/model/option.go +++ b/model/option.go @@ -63,6 +63,7 @@ func InitOptionMap() { common.OptionMap["ModelRatio"] = common.ModelRatio2JSONString() common.OptionMap["GroupRatio"] = common.GroupRatio2JSONString() common.OptionMap["TopUpLink"] = common.TopUpLink + common.OptionMap["ChatLink"] = common.ChatLink common.OptionMapRWMutex.Unlock() loadOptionsFromDatabase() } @@ -191,6 +192,8 @@ func updateOptionMap(key string, value string) (err error) { err = common.UpdateGroupRatioByJSONString(value) case "TopUpLink": common.TopUpLink = value + case "ChatLink": + common.ChatLink = value case "ChannelDisableThreshold": common.ChannelDisableThreshold, _ = strconv.ParseFloat(value, 64) } diff --git a/web/src/App.js b/web/src/App.js index e404b7f3..61477141 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -23,6 +23,7 @@ import Redemption from './pages/Redemption'; import EditRedemption from './pages/Redemption/EditRedemption'; import TopUp from './pages/TopUp'; import Log from './pages/Log'; +import Chat from './pages/Chat'; const Home = lazy(() => import('./pages/Home')); const About = lazy(() => import('./pages/About')); @@ -47,6 +48,11 @@ function App() { localStorage.setItem('system_name', data.system_name); localStorage.setItem('logo', data.logo); localStorage.setItem('footer_html', data.footer_html); + if (data.chat_link) { + localStorage.setItem('chat_link', data.chat_link); + } else { + localStorage.removeItem('chat_link'); + } if ( data.version !== process.env.REACT_APP_VERSION && data.version !== 'v0.0.0' && @@ -267,6 +273,14 @@ function App() { } /> + }> + + + } + /> ); diff --git a/web/src/components/Header.js b/web/src/components/Header.js index 3f4e32c1..21ebcab6 100644 --- a/web/src/components/Header.js +++ b/web/src/components/Header.js @@ -7,57 +7,65 @@ import { API, getLogo, getSystemName, isAdmin, isMobile, showSuccess } from '../ import '../index.css'; // Header Buttons -const headerButtons = [ +let headerButtons = [ { name: '首页', to: '/', - icon: 'home', + icon: 'home' }, { name: '渠道', to: '/channel', icon: 'sitemap', - admin: true, + admin: true }, { name: '令牌', to: '/token', - icon: 'key', + icon: 'key' }, { name: '兑换', to: '/redemption', icon: 'dollar sign', - admin: true, + admin: true }, { name: '充值', to: '/topup', - icon: 'cart', + icon: 'cart' }, { name: '用户', to: '/user', icon: 'user', - admin: true, + admin: true }, { name: '日志', to: '/log', - icon: 'book', + icon: 'book' }, { name: '设置', to: '/setting', - icon: 'setting', + icon: 'setting' }, { name: '关于', to: '/about', - icon: 'info circle', - }, + icon: 'info circle' + } ]; +if (localStorage.getItem('chat_link')) { + headerButtons.splice(1, 0, { + name: '聊天', + to: '/chat', + icon: 'comments' + }); +} + const Header = () => { const [userState, userDispatch] = useContext(UserContext); let navigate = useNavigate(); @@ -112,11 +120,11 @@ const Header = () => { style={ showSidebar ? { - borderBottom: 'none', - marginBottom: '0', - borderTop: 'none', - height: '51px', - } + borderBottom: 'none', + marginBottom: '0', + borderTop: 'none', + height: '51px' + } : { borderTop: 'none', height: '52px' } } > diff --git a/web/src/components/SystemSetting.js b/web/src/components/SystemSetting.js index f771af7a..786e935b 100644 --- a/web/src/components/SystemSetting.js +++ b/web/src/components/SystemSetting.js @@ -34,6 +34,7 @@ const SystemSetting = () => { ModelRatio: '', GroupRatio: '', TopUpLink: '', + ChatLink: '', AutomaticDisableChannelEnabled: '', ChannelDisableThreshold: 0, LogConsumeEnabled: '' @@ -109,7 +110,8 @@ const SystemSetting = () => { name === 'PreConsumedQuota' || name === 'ModelRatio' || name === 'GroupRatio' || - name === 'TopUpLink' + name === 'TopUpLink' || + name === 'ChatLink' ) { setInputs((inputs) => ({ ...inputs, [name]: value })); } else { @@ -155,6 +157,9 @@ const SystemSetting = () => { if (originInputs['TopUpLink'] !== inputs.TopUpLink) { await updateOption('TopUpLink', inputs.TopUpLink); } + if (originInputs['ChatLink'] !== inputs.ChatLink) { + await updateOption('ChatLink', inputs.ChatLink); + } }; const submitSMTP = async () => { @@ -360,6 +365,15 @@ const SystemSetting = () => { min='0' placeholder='例如:100' /> + { + const chatLink = localStorage.getItem('chat_link'); + + return ( +