/* Copyright (c) 2025 Tethys Plex This file is part of Veloera. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import React, { useState, useEffect } from 'react'; import { API, isMobile, showError, showSuccess } from '../../helpers'; import Title from '@douyinfe/semi-ui/lib/es/typography/title'; import { Button, Input, SideSheet, Space, Spin, Select, TextArea, RadioGroup, Radio, Form, Table, Checkbox, Pagination } from '@douyinfe/semi-ui'; import { useTranslation } from 'react-i18next'; const CreateMessage = (props) => { const { t } = useTranslation(); const originInputs = { title: '', content: '', format: 'markdown', user_ids: [], }; const [inputs, setInputs] = useState(originInputs); const [loading, setLoading] = useState(false); const [users, setUsers] = useState([]); const [selectedUsers, setSelectedUsers] = useState([]); const [userLoading, setUserLoading] = useState(false); const [userPage, setUserPage] = useState(1); const [userPageSize] = useState(20); const [userTotal, setUserTotal] = useState(0); const [userSearchKeyword, setUserSearchKeyword] = useState(''); const [selectAll, setSelectAll] = useState(false); const { title, content, format } = inputs; const handleInputChange = (name, value) => { setInputs((inputs) => ({ ...inputs, [name]: value })); }; const loadUsers = async (page = 1, keyword = '') => { setUserLoading(true); try { let url = `/api/user/?p=${page}&page_size=${userPageSize}`; if (keyword) { url = `/api/user/search?keyword=${keyword}&p=${page}&page_size=${userPageSize}`; } const res = await API.get(url); const { success, message, data } = res.data; if (success) { setUsers(data.items || []); setUserTotal(data.total || 0); setUserPage(data.page || 1); } else { showError(message); } } catch (error) { showError(error.message); } setUserLoading(false); }; useEffect(() => { if (props.visible) { loadUsers(); } }, [props.visible]); const handleUserSelect = (userId, checked) => { if (checked) { setSelectedUsers([...selectedUsers, userId]); } else { setSelectedUsers(selectedUsers.filter(id => id !== userId)); setSelectAll(false); } }; const handleSelectAll = (checked) => { setSelectAll(checked); if (checked) { const allUserIds = users.map(user => user.id); setSelectedUsers([...new Set([...selectedUsers, ...allUserIds])]); } else { const currentPageUserIds = users.map(user => user.id); setSelectedUsers(selectedUsers.filter(id => !currentPageUserIds.includes(id))); } }; const handleUserSearch = (keyword) => { setUserSearchKeyword(keyword); setUserPage(1); loadUsers(1, keyword); }; const handleUserPageChange = (page) => { setUserPage(page); loadUsers(page, userSearchKeyword); }; const userColumns = [ { title: ( ), dataIndex: 'select', width: 50, render: (text, record) => ( handleUserSelect(record.id, checked)} /> ), }, { title: 'ID', dataIndex: 'id', width: 80, }, { title: t('用户名'), dataIndex: 'username', }, { title: t('显示名称'), dataIndex: 'display_name', render: (text) => text || '-', }, ]; const submit = async () => { setLoading(true); if (!inputs.title.trim()) { showError(t('请输入消息标题')); setLoading(false); return; } if (!inputs.content.trim()) { showError(t('请输入消息内容')); setLoading(false); return; } if (selectedUsers.length === 0) { showError(t('请选择至少一个收件人')); setLoading(false); return; } const messageData = { title: inputs.title.trim(), content: inputs.content.trim(), format: inputs.format, user_ids: selectedUsers, }; try { const res = await API.post('/api/admin/messages', messageData); const { success, message } = res.data; if (success) { showSuccess(t('消息创建成功')); setInputs(originInputs); setSelectedUsers([]); setSelectAll(false); props.refresh(); props.handleClose(); } else { showError(message); } } catch (error) { showError(error.message); } setLoading(false); }; const handleCancel = () => { setInputs(originInputs); setSelectedUsers([]); setSelectAll(false); props.handleClose(); }; return ( <> {t('创建消息')}} headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }} bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }} visible={props.visible} footer={
} closeIcon={null} onCancel={() => handleCancel()} width={isMobile() ? '100%' : 800} >
handleInputChange('title', value)} style={{ marginBottom: 20 }} />
handleInputChange('format', e.target.value)} > Markdown HTML