UserMessage.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import _React, { useState } from "react";
  2. import { Button, Input, Space, Typography } from "antd";
  3. import { EditOutlined, CopyOutlined } from "@ant-design/icons";
  4. import type { UserMessageProps } from "../../types/chat"
  5. import { VersionSwitcher } from "./VersionSwitcher";
  6. const { TextArea } = Input;
  7. const { Text } = Typography;
  8. const UserMessage = ({
  9. session,
  10. onEdit,
  11. onCopy,
  12. onVersionSwitch,
  13. }: UserMessageProps) => {
  14. const message = session.user_message;
  15. const [isEditing, setIsEditing] = useState(false);
  16. const [editContent, setEditContent] = useState(message?.content || "");
  17. const handleEdit = () => {
  18. if (onEdit && editContent.trim()) {
  19. onEdit(editContent.trim());
  20. setIsEditing(false);
  21. }
  22. };
  23. const handleCancel = () => {
  24. setEditContent(session.user_message?.content || "");
  25. setIsEditing(false);
  26. };
  27. if (!message) {
  28. return <></>;
  29. }
  30. return (
  31. <div className="user-message">
  32. <div style={{ maxWidth: "90%" }}>
  33. <div className="message-content">
  34. {isEditing ? (
  35. <div className="edit-area">
  36. <TextArea
  37. value={editContent}
  38. onChange={(e) => setEditContent(e.target.value)}
  39. autoSize={{ minRows: 2, maxRows: 8 }}
  40. autoFocus
  41. />
  42. <div className="edit-actions">
  43. <Button size="small" onClick={handleCancel}>
  44. 取消
  45. </Button>
  46. <Button size="small" type="primary" onClick={handleEdit}>
  47. 保存
  48. </Button>
  49. </div>
  50. </div>
  51. ) : (
  52. <div className="message-text">
  53. <Text>{message.content}</Text>
  54. {message.save_status === "pending" && (
  55. <span className="status-indicator pending">发送中...</span>
  56. )}
  57. {message.save_status === "failed" && (
  58. <span className="status-indicator failed">发送失败</span>
  59. )}
  60. </div>
  61. )}
  62. </div>
  63. <div className="message-header">
  64. <span className="role-label"></span>
  65. <div className="message-actions">
  66. {!isEditing && (
  67. <Space size="small">
  68. <Button
  69. size="small"
  70. type="text"
  71. icon={<EditOutlined />}
  72. onClick={() => setIsEditing(true)}
  73. />
  74. <Button
  75. size="small"
  76. type="text"
  77. icon={<CopyOutlined />}
  78. onClick={onCopy}
  79. />
  80. {/* 版本切换器 */}
  81. {session.versions && session.versions.length > 1 && (
  82. <VersionSwitcher
  83. versions={session.versions}
  84. currentVersion={session.current_version}
  85. onSwitch={(versionIndex) =>
  86. onVersionSwitch &&
  87. onVersionSwitch(session.versions[versionIndex].message_id)
  88. }
  89. />
  90. )}
  91. </Space>
  92. )}
  93. </div>
  94. </div>
  95. </div>
  96. </div>
  97. );
  98. };
  99. export default UserMessage;