-
🎯 明日计划
-
{entry.plans}
+
+
+
{entry.title}
+
+
+
+ {!hasContent ? (
+
+ ) : (
+ <>
+ {entry.completed_tasks && (
+
+
✅ 完成的任务
+
{entry.completed_tasks}
+
+ )}
+
+ {entry.learned && (
+
+
💡 学到的东西
+
{entry.learned}
+
+ )}
+
+ {entry.problems && (
+
+
🚧 遇到的问题
+
{entry.problems}
+
+ )}
+
+ {entry.reflections && (
+
+
💭 反思和想法
+
{entry.reflections}
+
+ )}
+
+ {entry.improvements && (
+
+
✨ 进步点
+
{entry.improvements}
+
+ )}
+
+ {entry.plans && (
+
+
🎯 明日计划
+
{entry.plans}
+
+ )}
+ >
)}
+
+
+ 创建于 {new Date(entry.created_at).toLocaleString('zh-CN')}
+ {entry.updated_at !== entry.created_at && ` · 更新于 ${new Date(entry.updated_at).toLocaleString('zh-CN')}`}
+
);
}
diff --git a/frontend-react/src/components/DiaryEditor.js b/frontend-react/src/components/DiaryEditor.js
new file mode 100644
index 0000000..0c9703c
--- /dev/null
+++ b/frontend-react/src/components/DiaryEditor.js
@@ -0,0 +1,233 @@
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+
+/**
+ * 日记编辑器组件
+ * 用于创建和编辑日记
+ */
+function DiaryEditor({ entry, date, onSave, onCancel }) {
+ const [formData, setFormData] = useState({
+ title: '',
+ content: '',
+ completed_tasks: '',
+ learned: '',
+ problems: '',
+ reflections: '',
+ improvements: '',
+ plans: '',
+ });
+ const [saving, setSaving] = useState(false);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ if (entry) {
+ setFormData({
+ title: entry.title || `${entry.date} 的日记`,
+ content: entry.content || '',
+ completed_tasks: entry.completed_tasks || '',
+ learned: entry.learned || '',
+ problems: entry.problems || '',
+ reflections: entry.reflections || '',
+ improvements: entry.improvements || '',
+ plans: entry.plans || '',
+ });
+ } else {
+ setFormData({
+ title: `${date} 的日记`,
+ content: '',
+ completed_tasks: '',
+ learned: '',
+ problems: '',
+ reflections: '',
+ improvements: '',
+ plans: '',
+ });
+ }
+ }, [entry, date]);
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData(prev => ({ ...prev, [name]: value }));
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setSaving(true);
+ setError(null);
+
+ try {
+ const payload = {
+ ...formData,
+ date: entry?.date || date,
+ };
+
+ let response;
+ if (entry && entry.id) {
+ // 更新已有日记
+ response = await axios.put(`/api/entries/${entry.id}/`, payload);
+ } else {
+ // 创建新日记
+ response = await axios.post('/api/entries/', payload);
+ }
+
+ onSave(response.data);
+ } catch (err) {
+ setError(err.response?.data?.message || '保存失败,请重试');
+ } finally {
+ setSaving(false);
+ }
+ };
+
+ const inputStyle = {
+ width: '100%',
+ padding: '10px',
+ border: '1px solid #ddd',
+ borderRadius: '6px',
+ fontSize: '14px',
+ fontFamily: 'inherit',
+ resize: 'vertical',
+ };
+
+ const labelStyle = {
+ display: 'block',
+ marginBottom: '8px',
+ fontWeight: '600',
+ color: '#555',
+ };
+
+ const sectionStyle = {
+ marginBottom: '20px',
+ };
+
+ return (
+
+ );
+}
+
+export default DiaryEditor;
diff --git a/frontend-react/src/components/ExperienceEditor.js b/frontend-react/src/components/ExperienceEditor.js
new file mode 100644
index 0000000..5665033
--- /dev/null
+++ b/frontend-react/src/components/ExperienceEditor.js
@@ -0,0 +1,210 @@
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+
+/**
+ * 经验总结编辑器组件
+ * 用于创建和编辑经验总结
+ */
+function ExperienceEditor({ experience, onSave, onCancel }) {
+ const [formData, setFormData] = useState({
+ title: '',
+ category: 'development',
+ problem: '',
+ solution: '',
+ lesson_learned: '',
+ date: new Date().toISOString().split('T')[0],
+ });
+ const [saving, setSaving] = useState(false);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ if (experience) {
+ setFormData({
+ title: experience.title || '',
+ category: experience.category || 'development',
+ problem: experience.problem || '',
+ solution: experience.solution || '',
+ lesson_learned: experience.lesson_learned || '',
+ date: experience.date || new Date().toISOString().split('T')[0],
+ });
+ }
+ }, [experience]);
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData(prev => ({ ...prev, [name]: value }));
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setSaving(true);
+ setError(null);
+
+ try {
+ let response;
+ if (experience && experience.id) {
+ response = await axios.put(`/api/experiences/${experience.id}/`, formData);
+ } else {
+ response = await axios.post('/api/experiences/', formData);
+ }
+
+ onSave(response.data);
+ } catch (err) {
+ setError(err.response?.data?.message || '保存失败,请重试');
+ } finally {
+ setSaving(false);
+ }
+ };
+
+ const inputStyle = {
+ width: '100%',
+ padding: '10px',
+ border: '1px solid #ddd',
+ borderRadius: '6px',
+ fontSize: '14px',
+ fontFamily: 'inherit',
+ resize: 'vertical',
+ };
+
+ const labelStyle = {
+ display: 'block',
+ marginBottom: '8px',
+ fontWeight: '600',
+ color: '#555',
+ };
+
+ const sectionStyle = {
+ marginBottom: '20px',
+ };
+
+ return (
+
+ );
+}
+
+export default ExperienceEditor;
diff --git a/frontend-react/src/components/ExperienceList.js b/frontend-react/src/components/ExperienceList.js
index 69a0a27..ab59e29 100644
--- a/frontend-react/src/components/ExperienceList.js
+++ b/frontend-react/src/components/ExperienceList.js
@@ -1,37 +1,145 @@
-import React from 'react';
+import React, { useState } from 'react';
+import ExperienceEditor from './ExperienceEditor';
/**
* 经验总结列表组件
+ * 显示经验列表,支持创建新经验
*/
-function ExperienceList({ experiences }) {
- if (!experiences || experiences.length === 0) {
- return
暂无经验总结
;
+function ExperienceList({ experiences, onRefresh }) {
+ const [creating, setCreating] = useState(false);
+ const [selectedExp, setSelectedExp] = useState(null);
+
+ const handleSave = () => {
+ setCreating(false);
+ setSelectedExp(null);
+ if (onRefresh) {
+ onRefresh();
+ }
+ };
+
+ const handleCancel = () => {
+ setCreating(false);
+ setSelectedExp(null);
+ };
+
+ const handleEdit = (exp) => {
+ setSelectedExp(exp);
+ };
+
+ const getCategoryIcon = (category) => {
+ const icons = {
+ deployment: '📦',
+ development: '💻',
+ database: '🗄️',
+ permission: '🔐',
+ network: '🌐',
+ other: '📝',
+ };
+ return icons[category] || '📝';
+ };
+
+ const boxStyle = {
+ background: 'white',
+ borderRadius: '8px',
+ padding: '20px',
+ minHeight: '200px',
+ };
+
+ const itemStyle = {
+ padding: '15px',
+ background: '#f8f9fa',
+ borderRadius: '6px',
+ marginBottom: '12px',
+ cursor: 'pointer',
+ transition: 'all 0.2s',
+ };
+
+ const buttonStyle = {
+ padding: '10px 20px',
+ background: '#667eea',
+ color: 'white',
+ border: 'none',
+ borderRadius: '6px',
+ fontSize: '14px',
+ fontWeight: '600',
+ cursor: 'pointer',
+ };
+
+ // 创建/编辑模式
+ if (creating || selectedExp) {
+ return (
+
+
+
+ );
}
+ // 列表模式
return (
-
- {experiences.map(exp => (
-
-
- {exp.title}
- {exp.category}
-
-
-
-
✅ 解决方案
-
{exp.solution}
-
- {exp.lesson_learned && (
-
-
📌 经验教训
-
{exp.lesson_learned}
-
- )}
+
+
+
💡 经验总结
+
+
+
+ {!experiences || experiences.length === 0 ? (
+
+
💡
+
还没有经验总结
+
- ))}
+ ) : (
+
+ {experiences.map((exp) => (
+
handleEdit(exp)}
+ onMouseEnter={(e) => {
+ e.currentTarget.style.background = '#e9ecef';
+ e.currentTarget.style.transform = 'translateX(5px)';
+ }}
+ onMouseLeave={(e) => {
+ e.currentTarget.style.background = '#f8f9fa';
+ e.currentTarget.style.transform = 'translateX(0)';
+ }}
+ >
+
+
{getCategoryIcon(exp.category)}
+
+
+ {exp.title}
+
+
+ {exp.problem?.substring(0, 100)}{exp.problem?.length > 100 ? '...' : ''}
+
+
+ 📅 {new Date(exp.date).toLocaleDateString('zh-CN')} ·
+ 📝 {exp.get_category_display || exp.category}
+
+
+
›
+
+
+ ))}
+
+ )}
);
}
diff --git a/frontend/asset-manifest.json b/frontend/asset-manifest.json
new file mode 100644
index 0000000..18d7c46
--- /dev/null
+++ b/frontend/asset-manifest.json
@@ -0,0 +1,13 @@
+{
+ "files": {
+ "main.css": "/static/css/main.358dee66.css",
+ "main.js": "/static/js/main.7934ac80.js",
+ "index.html": "/index.html",
+ "main.358dee66.css.map": "/static/css/main.358dee66.css.map",
+ "main.7934ac80.js.map": "/static/js/main.7934ac80.js.map"
+ },
+ "entrypoints": [
+ "static/css/main.358dee66.css",
+ "static/js/main.7934ac80.js"
+ ]
+}
\ No newline at end of file
diff --git a/frontend/index.html b/frontend/index.html
index 29f51ef..5edc649 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -1,937 +1 @@
-
-
-
-
-
-
码神的日记系统
-
-
-
-
-
-
- ⚡ 码神的日记系统
- 记录每天的进步与成长
-
-
-
-
-
-
-
-
+
码神的日记系统
\ No newline at end of file