(
+ sourceId: string,
+ field: K,
+ value: TVStreamSource[K]
+ ) => {
+ setTvSettings((prev) => {
+ if (!prev) return prev
+ const nextSources = prev.sources.map((source) => {
+ if (field === 'is_fallback' && value === true) {
+ return { ...source, is_fallback: source.id === sourceId }
+ }
+ if (source.id === sourceId) {
+ return { ...source, [field]: value }
+ }
+ return source
+ })
+
+ const nextDefaultSourceId =
+ field === 'is_enabled' && value === false && prev.default_source_id === sourceId
+ ? nextSources.find((source) => source.id !== sourceId && source.is_enabled)?.id || ''
+ : prev.default_source_id
+
+ return {
+ ...prev,
+ default_source_id: nextDefaultSourceId,
+ sources: nextSources,
+ }
+ })
+ }
+
+ const addTvSource = () => {
+ setTvSettings((prev) => {
+ if (!prev) return prev
+ const nextIndex = prev.sources.length + 1
+ const newSource: TVStreamSource = {
+ id: `manual-tv-${Date.now()}`,
+ name: `新闻直播源 ${nextIndex}`,
+ provider: 'Manual',
+ region: 'Global',
+ language: 'und',
+ source_type: 'iframe',
+ embed_url: '',
+ stream_url: '',
+ homepage_url: '',
+ poster_url: '',
+ youtube_video_id: '',
+ youtube_channel: '',
+ is_enabled: true,
+ is_fallback: false,
+ sort_order: nextIndex * 10,
+ collector_source: null,
+ notes: '',
+ }
+
+ return {
+ ...prev,
+ sources: [...prev.sources, newSource],
+ }
+ })
+ }
+
+ const removeTvSource = (sourceId: string) => {
+ setTvSettings((prev) => {
+ if (!prev) return prev
+ const nextSources = prev.sources.filter((source) => source.id !== sourceId)
+ const nextDefaultSourceId =
+ prev.default_source_id === sourceId ? nextSources[0]?.id || '' : prev.default_source_id
+ return {
+ ...prev,
+ default_source_id: nextDefaultSourceId,
+ sources: nextSources,
+ }
+ })
+ }
+
+ const saveTvSettings = async () => {
+ if (!tvSettings) return
+ try {
+ setSavingTvSettings(true)
+ await axios.put('/api/v1/settings/tv', tvSettings)
+ message.success('电视直播配置已保存')
+ await fetchSettings()
+ } catch (error) {
+ message.error('电视直播配置保存失败')
+ console.error(error)
+ } finally {
+ setSavingTvSettings(false)
+ }
+ }
+
const collectorColumns = [
{
title: '数据源',
@@ -274,6 +397,133 @@ function Settings() {
},
]
+ const tvSourceColumns = [
+ {
+ title: '频道',
+ dataIndex: 'name',
+ key: 'name',
+ width: 220,
+ render: (_: string, record: TVStreamSource) => (
+
+ updateTvSourceField(record.id, 'name', event.target.value)} />
+ updateTvSourceField(record.id, 'provider', event.target.value)}
+ />
+
+ ),
+ },
+ {
+ title: '区域 / 语言',
+ key: 'locale',
+ width: 160,
+ render: (_: unknown, record: TVStreamSource) => (
+
+ updateTvSourceField(record.id, 'region', event.target.value)}
+ />
+ updateTvSourceField(record.id, 'language', event.target.value)}
+ />
+
+ ),
+ },
+ {
+ title: '类型',
+ dataIndex: 'source_type',
+ key: 'source_type',
+ width: 120,
+ render: (value: TVStreamSource['source_type'], record: TVStreamSource) => (
+