diff --git a/relay/channel/task/kling/adaptor.go b/relay/channel/task/kling/adaptor.go
index 9ea58728..2995a07b 100644
--- a/relay/channel/task/kling/adaptor.go
+++ b/relay/channel/task/kling/adaptor.go
@@ -69,8 +69,8 @@ func (a *TaskAdaptor) Init(info *relaycommon.TaskRelayInfo) {
a.ChannelType = info.ChannelType
a.baseURL = info.BaseUrl
- // apiKey format: "access_key,secret_key"
- keyParts := strings.Split(info.ApiKey, ",")
+ // apiKey format: "access_key|secret_key"
+ keyParts := strings.Split(info.ApiKey, "|")
if len(keyParts) == 2 {
a.accessKey = strings.TrimSpace(keyParts[0])
a.secretKey = strings.TrimSpace(keyParts[1])
@@ -264,7 +264,7 @@ func (a *TaskAdaptor) createJWTToken() (string, error) {
}
func (a *TaskAdaptor) createJWTTokenWithKey(apiKey string) (string, error) {
- parts := strings.Split(apiKey, ",")
+ parts := strings.Split(apiKey, "|")
if len(parts) != 2 {
return "", fmt.Errorf("invalid API key format, expected 'access_key,secret_key'")
}
diff --git a/web/src/components/layout/NoticeModal.js b/web/src/components/layout/NoticeModal.js
index 456c012f..55126ad8 100644
--- a/web/src/components/layout/NoticeModal.js
+++ b/web/src/components/layout/NoticeModal.js
@@ -113,25 +113,31 @@ const NoticeModal = ({ visible, onClose, isMobile, defaultTab = 'inApp', unreadK
return (
- {processedAnnouncements.map((item, idx) => (
-
-
- {item.isUnread ? (
-
- {item.content}
-
- ) : (
- item.content
- )}
- {item.extra &&
{item.extra}
}
-
-
- ))}
+ {processedAnnouncements.map((item, idx) => {
+ const htmlContent = marked.parse(item.content || '');
+ const htmlExtra = item.extra ? marked.parse(item.extra) : '';
+ return (
+
+
+
+ {item.extra && (
+
+ )}
+
+
+ );
+ })}
);
diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json
index 70ce272d..6b982b51 100644
--- a/web/src/i18n/locales/en.json
+++ b/web/src/i18n/locales/en.json
@@ -1615,6 +1615,7 @@
"编辑公告": "Edit Notice",
"公告内容": "Notice Content",
"请输入公告内容": "Please enter the notice content",
+ "请输入公告内容(支持 Markdown/HTML)": "Please enter the notice content (supports Markdown/HTML)",
"发布日期": "Publish Date",
"请选择发布日期": "Please select the publish date",
"发布时间": "Publish Time",
@@ -1630,6 +1631,7 @@
"请输入问题标题": "Please enter the question title",
"回答内容": "Answer Content",
"请输入回答内容": "Please enter the answer content",
+ "请输入回答内容(支持 Markdown/HTML)": "Please enter the answer content (supports Markdown/HTML)",
"确定要删除此问答吗?": "Are you sure you want to delete this FAQ?",
"系统公告管理,可以发布系统通知和重要消息(最多100个,前端显示最新20条)": "System notice management, you can publish system notices and important messages (maximum 100, display latest 20 on the front end)",
"常见问答管理,为用户提供常见问题的答案(最多50个,前端显示最新20条)": "FAQ management, providing answers to common questions for users (maximum 50, display latest 20 on the front end)",
@@ -1710,5 +1712,8 @@
"可信": "Reliable",
"所有上游数据均可信": "All upstream data is reliable",
"以下上游数据可能不可信:": "The following upstream data may not be reliable: ",
- "按倍率类型筛选": "Filter by ratio type"
+ "按倍率类型筛选": "Filter by ratio type",
+ "内容": "Content",
+ "放大编辑": "Expand editor",
+ "编辑公告内容": "Edit announcement content"
}
\ No newline at end of file
diff --git a/web/src/pages/Channel/EditChannel.js b/web/src/pages/Channel/EditChannel.js
index ca38e6b9..1ef8af8c 100644
--- a/web/src/pages/Channel/EditChannel.js
+++ b/web/src/pages/Channel/EditChannel.js
@@ -64,6 +64,8 @@ function type2secretPrompt(type) {
return '按照如下格式输入:AppId|SecretId|SecretKey';
case 33:
return '按照如下格式输入:Ak|Sk|Region';
+ case 50:
+ return '按照如下格式输入: AccessKey|SecretKey';
default:
return '请输入渠道对应的鉴权密钥';
}
diff --git a/web/src/pages/Detail/index.js b/web/src/pages/Detail/index.js
index 0fd18d16..e78f0dc7 100644
--- a/web/src/pages/Detail/index.js
+++ b/web/src/pages/Detail/index.js
@@ -2,6 +2,7 @@ import React, { useContext, useEffect, useRef, useState, useMemo, useCallback }
import { initVChartSemiTheme } from '@visactor/vchart-semi-theme';
import { useNavigate } from 'react-router-dom';
import { Wallet, Activity, Zap, Gauge, PieChart, Server, Bell, HelpCircle } from 'lucide-react';
+import { marked } from 'marked';
import {
Card,
@@ -1267,10 +1268,27 @@ const Detail = (props) => {
onScroll={() => handleCardScroll(announcementScrollRef, setShowAnnouncementScrollHint)}
>
{announcementData.length > 0 ? (
-
+
+ {announcementData.map((item, idx) => (
+
+
+
+ {item.extra && (
+
+ )}
+
+
+ ))}
+
) : (
{
header={item.question}
itemKey={index.toString()}
>
- {item.answer}
+
))}
diff --git a/web/src/pages/Setting/Dashboard/SettingsAnnouncements.js b/web/src/pages/Setting/Dashboard/SettingsAnnouncements.js
index c15e2885..427edcc9 100644
--- a/web/src/pages/Setting/Dashboard/SettingsAnnouncements.js
+++ b/web/src/pages/Setting/Dashboard/SettingsAnnouncements.js
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, useRef } from 'react';
import {
Button,
Space,
@@ -9,7 +9,9 @@ import {
Divider,
Modal,
Tag,
- Switch
+ Switch,
+ TextArea,
+ Tooltip
} from '@douyinfe/semi-ui';
import {
IllustrationNoResult,
@@ -20,7 +22,8 @@ import {
Edit,
Trash2,
Save,
- Bell
+ Bell,
+ Maximize2
} from 'lucide-react';
import { API, showError, showSuccess, getRelativeTime, formatDateTimeString } from '../../../helpers';
import { useTranslation } from 'react-i18next';
@@ -33,6 +36,7 @@ const SettingsAnnouncements = ({ options, refresh }) => {
const [announcementsList, setAnnouncementsList] = useState([]);
const [showAnnouncementModal, setShowAnnouncementModal] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false);
+ const [showContentModal, setShowContentModal] = useState(false);
const [deletingAnnouncement, setDeletingAnnouncement] = useState(null);
const [editingAnnouncement, setEditingAnnouncement] = useState(null);
const [modalLoading, setModalLoading] = useState(false);
@@ -51,6 +55,8 @@ const SettingsAnnouncements = ({ options, refresh }) => {
// 面板启用状态
const [panelEnabled, setPanelEnabled] = useState(true);
+ const formApiRef = useRef(null);
+
const typeOptions = [
{ value: 'default', label: t('默认') },
{ value: 'ongoing', label: t('进行中') },
@@ -76,13 +82,16 @@ const SettingsAnnouncements = ({ options, refresh }) => {
dataIndex: 'content',
key: 'content',
render: (text) => (
-
- {text}
-
+
+
+ {text}
+
+
)
},
{
@@ -121,13 +130,17 @@ const SettingsAnnouncements = ({ options, refresh }) => {
dataIndex: 'extra',
key: 'extra',
render: (text) => (
-
- {text || '-'}
-
+
+
+ {text || '-'}
+
+
)
},
{
@@ -472,16 +485,31 @@ const SettingsAnnouncements = ({ options, refresh }) => {
className="rounded-xl"
confirmLoading={modalLoading}
>
- setAnnouncementForm({ ...announcementForm, content: value })}
/>
+ }
+ style={{ marginBottom: 16 }}
+ onClick={() => setShowContentModal(true)}
+ >
+ {t('放大编辑')}
+
{
>
{t('确定要删除此公告吗?')}
+
+ {/* 公告内容放大编辑 Modal */}
+ {
+ // 将内容同步到表单
+ if (formApiRef.current) {
+ formApiRef.current.setValue('content', announcementForm.content);
+ }
+ setShowContentModal(false);
+ }}
+ onCancel={() => setShowContentModal(false)}
+ okText={t('确定')}
+ cancelText={t('取消')}
+ className="rounded-xl"
+ width={800}
+ >
+
>
);
};
diff --git a/web/src/pages/Setting/Dashboard/SettingsFAQ.js b/web/src/pages/Setting/Dashboard/SettingsFAQ.js
index 0e029e13..b60792c0 100644
--- a/web/src/pages/Setting/Dashboard/SettingsFAQ.js
+++ b/web/src/pages/Setting/Dashboard/SettingsFAQ.js
@@ -8,7 +8,8 @@ import {
Empty,
Divider,
Modal,
- Switch
+ Switch,
+ Tooltip
} from '@douyinfe/semi-ui';
import {
IllustrationNoResult,
@@ -54,13 +55,17 @@ const SettingsFAQ = ({ options, refresh }) => {
dataIndex: 'question',
key: 'question',
render: (text) => (
-
- {text}
-
+
+
+ {text}
+
+
)
},
{
@@ -68,14 +73,17 @@ const SettingsFAQ = ({ options, refresh }) => {
dataIndex: 'answer',
key: 'answer',
render: (text) => (
-
- {text}
-
+
+
+ {text}
+
+
)
},
{
@@ -416,7 +424,7 @@ const SettingsFAQ = ({ options, refresh }) => {
{
content: ,
itemKey: 'operation',
});
+ panes.push({
+ tab: (
+
+
+ {t('仪表盘设置')}
+
+ ),
+ content: ,
+ itemKey: 'dashboard',
+ });
panes.push({
tab: (
@@ -115,16 +125,6 @@ const Setting = () => {
content: ,
itemKey: 'system',
});
- panes.push({
- tab: (
-
-
- {t('仪表盘设置')}
-
- ),
- content: ,
- itemKey: 'dashboard',
- });
panes.push({
tab: (