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} > -
+ (formApiRef.current = api)} + > setAnnouncementForm({ ...announcementForm, content: value })} /> + { > {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} + > +