更换backend和platform的编辑器
This commit is contained in:
@@ -1 +1 @@
|
|||||||
{"pid":47768,"startedAt":1784001651405}
|
{"pid":54204,"startedAt":1784192140605}
|
||||||
+1
-15
@@ -10,21 +10,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.2",
|
"@element-plus/icons-vue": "^2.3.2",
|
||||||
"@tiptap/extension-color": "^3.27.4",
|
"@umoteam/editor": "^10.2.1",
|
||||||
"@tiptap/extension-highlight": "^3.27.4",
|
|
||||||
"@tiptap/extension-image": "^3.27.4",
|
|
||||||
"@tiptap/extension-link": "^3.27.4",
|
|
||||||
"@tiptap/extension-placeholder": "^3.27.4",
|
|
||||||
"@tiptap/extension-table": "^3.27.4",
|
|
||||||
"@tiptap/extension-table-cell": "^3.27.4",
|
|
||||||
"@tiptap/extension-table-header": "^3.27.4",
|
|
||||||
"@tiptap/extension-table-row": "^3.27.4",
|
|
||||||
"@tiptap/extension-text-align": "^3.27.4",
|
|
||||||
"@tiptap/extension-text-style": "^3.27.4",
|
|
||||||
"@tiptap/extension-underline": "^3.27.4",
|
|
||||||
"@tiptap/pm": "^3.27.4",
|
|
||||||
"@tiptap/starter-kit": "^3.27.4",
|
|
||||||
"@tiptap/vue-3": "^3.27.4",
|
|
||||||
"axios": "^1.13.1",
|
"axios": "^1.13.1",
|
||||||
"chart": "^0.1.2",
|
"chart": "^0.1.2",
|
||||||
"chart.js": "^4.5.1",
|
"chart.js": "^4.5.1",
|
||||||
|
|||||||
+3
-3
@@ -14,12 +14,12 @@ import { createPinia } from 'pinia'
|
|||||||
import { useAuthStore } from './stores/auth'
|
import { useAuthStore } from './stores/auth'
|
||||||
// import { initTheme } from './utils/theme'
|
// import { initTheme } from './utils/theme'
|
||||||
// 导入全局组件
|
// 导入全局组件
|
||||||
import TiptapEditor from '@/views/components/TiptapEditor.vue';
|
import UmoEditor from '@/views/components/UmoEditor.vue';
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
// 全局注册 TiptapEditor 组件
|
// 全局注册 UmoEditor 组件
|
||||||
app.component('TiptapEditor', TiptapEditor);
|
app.component('UmoEditor', UmoEditor);
|
||||||
|
|
||||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||||
app.component(key, component)
|
app.component(key, component)
|
||||||
|
|||||||
@@ -141,7 +141,7 @@
|
|||||||
|
|
||||||
<el-form-item label="内容" prop="content">
|
<el-form-item label="内容" prop="content">
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
<TiptapEditor v-model="form.content" />
|
<UmoEditor v-model="form.content" />
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="产品内容" prop="content">
|
<el-form-item label="产品内容" prop="content">
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
<TiptapEditor v-model="formData.content" style="height: 450px;" />
|
<UmoEditor v-model="formData.content" style="height: 450px;" />
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="产品图片" prop="thumb">
|
<el-form-item label="产品图片" prop="thumb">
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<umo-editor
|
||||||
|
ref="editorRef"
|
||||||
|
v-bind="options"
|
||||||
|
@changed="onChanged"
|
||||||
|
@created="onCreated"
|
||||||
|
@file-upload="onFileUpload"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import { UmoEditor } from '@umoteam/editor'
|
||||||
|
import { uploadFile } from '@/api/file'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const content = ref(props.modelValue)
|
||||||
|
const editorRef = ref(null)
|
||||||
|
const isCreated = ref(false)
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
height: '100%',
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFileUpload = async (file) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
const res = await uploadFile(formData)
|
||||||
|
return {
|
||||||
|
id: res.data.id,
|
||||||
|
url: res.data.url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCreated = () => {
|
||||||
|
isCreated.value = true
|
||||||
|
if (content.value) {
|
||||||
|
editorRef.value.setContent(content.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChanged = ({ editor }) => {
|
||||||
|
const html = editor.getHTML()
|
||||||
|
content.value = html
|
||||||
|
emit('update:modelValue', html)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => {
|
||||||
|
if (val !== content.value && isCreated.value && editorRef.value) {
|
||||||
|
editorRef.value.setContent(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
# 记事本模块使用说明
|
|
||||||
|
|
||||||
## 功能概述
|
|
||||||
|
|
||||||
这是一个完整的记事本应用模块,支持富文本编辑、笔记管理等功能。
|
|
||||||
|
|
||||||
## 目录结构
|
|
||||||
|
|
||||||
```
|
|
||||||
notebook/
|
|
||||||
├── index.vue # 主页面(列表+编辑器)
|
|
||||||
├── components/
|
|
||||||
│ ├── edit.vue # 编辑器组件
|
|
||||||
│ └── TiptapEditor.vue # Tiptap富文本编辑器(已全局注册)
|
|
||||||
└── README.md # 说明文档
|
|
||||||
```
|
|
||||||
|
|
||||||
## 数据库
|
|
||||||
|
|
||||||
### 表名
|
|
||||||
`yz_platform_notebook`
|
|
||||||
|
|
||||||
### 表结构
|
|
||||||
- `id` - 主键ID
|
|
||||||
- `title` - 笔记标题
|
|
||||||
- `content` - 笔记内容(HTML格式)
|
|
||||||
- `user_id` - 创建用户ID
|
|
||||||
- `user_name` - 创建用户名
|
|
||||||
- `is_deleted` - 是否删除(0-否 1-是)
|
|
||||||
- `create_time` - 创建时间
|
|
||||||
- `update_time` - 更新时间
|
|
||||||
- `delete_time` - 删除时间
|
|
||||||
|
|
||||||
### SQL文件位置
|
|
||||||
`sql/yz_platform_notebook.sql`
|
|
||||||
|
|
||||||
## 后端接口
|
|
||||||
|
|
||||||
### 模型文件
|
|
||||||
`go/models/platform_notebook.go`
|
|
||||||
|
|
||||||
### 控制器文件
|
|
||||||
`go/controllers/platform_notebook.go`
|
|
||||||
|
|
||||||
### API端点
|
|
||||||
|
|
||||||
1. **获取笔记列表**
|
|
||||||
- URL: `GET /platform/notebook/list`
|
|
||||||
- 参数:
|
|
||||||
- `page`: 页码(默认1)
|
|
||||||
- `pageSize`: 每页数量(默认20,最大100)
|
|
||||||
- `keyword`: 搜索关键词(可选)
|
|
||||||
- 返回: 笔记列表和总数
|
|
||||||
|
|
||||||
2. **获取笔记详情**
|
|
||||||
- URL: `GET /platform/notebook/detail/:id`
|
|
||||||
- 参数: `id` - 笔记ID
|
|
||||||
- 返回: 笔记详细信息
|
|
||||||
|
|
||||||
3. **创建笔记**
|
|
||||||
- URL: `POST /platform/notebook/create`
|
|
||||||
- 参数:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "笔记标题",
|
|
||||||
"content": "<p>笔记内容</p>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- 返回: 创建的笔记信息
|
|
||||||
|
|
||||||
4. **更新笔记**
|
|
||||||
- URL: `POST /platform/notebook/update/:id`
|
|
||||||
- 参数:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "更新的标题",
|
|
||||||
"content": "<p>更新的内容</p>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- 返回: 更新后的笔记信息
|
|
||||||
|
|
||||||
5. **删除笔记**
|
|
||||||
- URL: `DELETE /platform/notebook/delete/:id`
|
|
||||||
- 参数: `id` - 笔记ID
|
|
||||||
- 返回: 删除结果
|
|
||||||
|
|
||||||
## 前端API
|
|
||||||
|
|
||||||
### API文件
|
|
||||||
`platform/src/api/notebook.js`
|
|
||||||
|
|
||||||
### 方法说明
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 获取笔记列表
|
|
||||||
getNotebookList({ page, pageSize, keyword })
|
|
||||||
|
|
||||||
// 获取笔记详情
|
|
||||||
getNotebookDetail(id)
|
|
||||||
|
|
||||||
// 创建笔记
|
|
||||||
createNotebook({ title, content })
|
|
||||||
|
|
||||||
// 更新笔记
|
|
||||||
updateNotebook(id, { title, content })
|
|
||||||
|
|
||||||
// 删除笔记
|
|
||||||
deleteNotebook(id)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 使用步骤
|
|
||||||
|
|
||||||
### 1. 初始化数据库
|
|
||||||
```bash
|
|
||||||
# 在MySQL中执行SQL文件
|
|
||||||
mysql -u用户名 -p数据库名 < sql/yz_platform_notebook.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 启动后端服务
|
|
||||||
后端已自动注册模型和路由,直接启动即可:
|
|
||||||
```bash
|
|
||||||
cd go
|
|
||||||
go run main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 访问前端
|
|
||||||
在浏览器中访问笔记本页面(路由需要在菜单中配置)
|
|
||||||
|
|
||||||
## 功能特性
|
|
||||||
|
|
||||||
### 列表功能
|
|
||||||
- ✅ 显示所有笔记
|
|
||||||
- ✅ 搜索笔记(按标题)
|
|
||||||
- ✅ 创建新笔记
|
|
||||||
- ✅ 删除笔记
|
|
||||||
- ✅ 查看笔记预览
|
|
||||||
- ✅ 显示更新时间
|
|
||||||
|
|
||||||
### 编辑器功能
|
|
||||||
- ✅ 富文本编辑(基于Tiptap)
|
|
||||||
- ✅ 标题编辑
|
|
||||||
- ✅ 内容编辑
|
|
||||||
- ✅ 保存笔记
|
|
||||||
- ✅ 自动识别新建/编辑模式
|
|
||||||
- ✅ 加载状态显示
|
|
||||||
|
|
||||||
### TiptapEditor支持的功能
|
|
||||||
- 文本样式(加粗、斜体、下划线等)
|
|
||||||
- 标题(H1-H6)
|
|
||||||
- 引用
|
|
||||||
- 代码块
|
|
||||||
- 有序/无序列表
|
|
||||||
- 表格
|
|
||||||
- 链接
|
|
||||||
- 图片上传(需配置上传接口)
|
|
||||||
- 视频嵌入
|
|
||||||
|
|
||||||
## 权限说明
|
|
||||||
|
|
||||||
- 所有接口都需要平台用户登录(JWT Token验证)
|
|
||||||
- 每个用户只能查看、编辑、删除自己创建的笔记
|
|
||||||
- 删除操作为软删除,数据仍保留在数据库中
|
|
||||||
|
|
||||||
## 扩展功能(可选)
|
|
||||||
|
|
||||||
如需添加以下功能,可以扩展:
|
|
||||||
|
|
||||||
1. **笔记分类**
|
|
||||||
- 添加分类表和分类字段
|
|
||||||
- 支持笔记分类管理
|
|
||||||
|
|
||||||
2. **笔记标签**
|
|
||||||
- 添加标签表和关联表
|
|
||||||
- 支持多标签筛选
|
|
||||||
|
|
||||||
3. **笔记分享**
|
|
||||||
- 添加分享链接生成功能
|
|
||||||
- 支持公开/私密设置
|
|
||||||
|
|
||||||
4. **笔记导出**
|
|
||||||
- 支持导出为PDF
|
|
||||||
- 支持导出为Markdown
|
|
||||||
|
|
||||||
5. **版本历史**
|
|
||||||
- 记录笔记的修改历史
|
|
||||||
- 支持版本回退
|
|
||||||
|
|
||||||
6. **协作编辑**
|
|
||||||
- 支持多人协作编辑
|
|
||||||
- 实时同步功能
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. 图片上传需要配置文件上传接口
|
|
||||||
2. 富文本内容存储为HTML格式,注意XSS防护
|
|
||||||
3. 数据库content字段使用longtext类型,支持大容量内容
|
|
||||||
4. 建议定期清理软删除的数据
|
|
||||||
5. 生产环境建议添加内容审核机制
|
|
||||||
|
|
||||||
## 技术栈
|
|
||||||
|
|
||||||
- **前端**: Vue 3 + Element Plus + Tiptap
|
|
||||||
- **后端**: Go + Beego + MySQL
|
|
||||||
- **编辑器**: Tiptap (基于ProseMirror)
|
|
||||||
|
|
||||||
## 开发调试
|
|
||||||
|
|
||||||
### 前端调试
|
|
||||||
```bash
|
|
||||||
cd platform
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### 后端调试
|
|
||||||
```bash
|
|
||||||
cd go
|
|
||||||
go run main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
### 查看API请求
|
|
||||||
打开浏览器开发者工具 -> Network 标签页,查看API请求和响应
|
|
||||||
|
|
||||||
## 问题排查
|
|
||||||
|
|
||||||
1. **笔记列表为空**
|
|
||||||
- 检查数据库表是否创建成功
|
|
||||||
- 检查用户是否已登录
|
|
||||||
- 查看浏览器Console是否有错误
|
|
||||||
|
|
||||||
2. **保存失败**
|
|
||||||
- 检查JWT Token是否有效
|
|
||||||
- 检查标题是否为空
|
|
||||||
- 查看后端日志
|
|
||||||
|
|
||||||
3. **编辑器显示异常**
|
|
||||||
- 检查Tiptap是否正确安装
|
|
||||||
- 查看浏览器Console错误信息
|
|
||||||
- 检查CSS样式是否正确加载
|
|
||||||
|
|
||||||
## 更新日志
|
|
||||||
|
|
||||||
### v1.0.0 (2024)
|
|
||||||
- ✅ 完成基础功能
|
|
||||||
- ✅ 支持笔记CRUD操作
|
|
||||||
- ✅ 集成Tiptap富文本编辑器
|
|
||||||
- ✅ 响应式设计支持
|
|
||||||
- ✅ 暗色模式支持
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-body">
|
<div class="editor-body">
|
||||||
<TiptapEditor v-model="noteContent" />
|
<UmoEditor v-model="noteContent" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
+2
-1
@@ -18,7 +18,8 @@ maxmemory = 10485760
|
|||||||
# MySQL - 远程连接配置
|
# MySQL - 远程连接配置
|
||||||
mysqluser = go-platform
|
mysqluser = go-platform
|
||||||
mysqlpass = FSmJCSJ5wk8pjjDC
|
mysqlpass = FSmJCSJ5wk8pjjDC
|
||||||
mysqlurls = 10.31.100.3:3306
|
# mysqlurls = 10.31.100.3:3306
|
||||||
|
mysqlurls = 212.64.112.158:3388
|
||||||
mysqldb = go-platform
|
mysqldb = go-platform
|
||||||
|
|
||||||
# ORM配置
|
# ORM配置
|
||||||
|
|||||||
Generated
+2636
-14
File diff suppressed because it is too large
Load Diff
+2
-16
@@ -11,21 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.2",
|
"@element-plus/icons-vue": "^2.3.2",
|
||||||
"@tiptap/extension-color": "^3.27.4",
|
"@umoteam/editor": "^10.2.1",
|
||||||
"@tiptap/extension-highlight": "^3.27.4",
|
|
||||||
"@tiptap/extension-image": "^3.27.4",
|
|
||||||
"@tiptap/extension-link": "^3.27.4",
|
|
||||||
"@tiptap/extension-placeholder": "^3.27.4",
|
|
||||||
"@tiptap/extension-table": "^3.27.4",
|
|
||||||
"@tiptap/extension-table-cell": "^3.27.4",
|
|
||||||
"@tiptap/extension-table-header": "^3.27.4",
|
|
||||||
"@tiptap/extension-table-row": "^3.27.4",
|
|
||||||
"@tiptap/extension-text-align": "^3.27.4",
|
|
||||||
"@tiptap/extension-text-style": "^3.27.4",
|
|
||||||
"@tiptap/extension-underline": "^3.27.4",
|
|
||||||
"@tiptap/pm": "^3.27.4",
|
|
||||||
"@tiptap/starter-kit": "^3.27.4",
|
|
||||||
"@tiptap/vue-3": "^3.27.4",
|
|
||||||
"axios": "^1.13.1",
|
"axios": "^1.13.1",
|
||||||
"chart": "^0.1.2",
|
"chart": "^0.1.2",
|
||||||
"chart.js": "^4.5.1",
|
"chart.js": "^4.5.1",
|
||||||
@@ -44,7 +30,7 @@
|
|||||||
"xlsx": "^0.18.5"
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^24.10.7",
|
"@types/node": "^24.13.3",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"unplugin-auto-import": "^20.2.0",
|
"unplugin-auto-import": "^20.2.0",
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ import { createPinia } from 'pinia'
|
|||||||
import { useAuthStore } from './stores/auth'
|
import { useAuthStore } from './stores/auth'
|
||||||
// import { initTheme } from './utils/theme'
|
// import { initTheme } from './utils/theme'
|
||||||
// 导入全局组件
|
// 导入全局组件
|
||||||
import TiptapEditor from '@/views/components/TiptapEditor.vue';
|
import UmoEditor from '@/views/components/UmoEditor.vue';
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
// 全局注册 TiptapEditor 组件
|
// 全局注册 UmoEditor 组件
|
||||||
app.component('TiptapEditor', TiptapEditor);
|
app.component('UmoEditor', UmoEditor);
|
||||||
|
|
||||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||||
app.component(key, component)
|
app.component(key, component)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<umo-editor
|
||||||
|
ref="editorRef"
|
||||||
|
v-bind="options"
|
||||||
|
@changed="onChanged"
|
||||||
|
@created="onCreated"
|
||||||
|
@file-upload="onFileUpload"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import { UmoEditor } from '@umoteam/editor'
|
||||||
|
import { uploadFile } from '@/api/file'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const content = ref(props.modelValue)
|
||||||
|
const editorRef = ref(null)
|
||||||
|
const isCreated = ref(false)
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
height: '100%',
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFileUpload = async (file) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
const res = await uploadFile(formData)
|
||||||
|
return {
|
||||||
|
id: res.data.id,
|
||||||
|
url: res.data.url,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onCreated = () => {
|
||||||
|
isCreated.value = true
|
||||||
|
if (content.value) {
|
||||||
|
editorRef.value.setContent(content.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChanged = ({ editor }) => {
|
||||||
|
const html = editor.getHTML()
|
||||||
|
content.value = html
|
||||||
|
emit('update:modelValue', html)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => {
|
||||||
|
if (val !== content.value && isCreated.value && editorRef.value) {
|
||||||
|
editorRef.value.setContent(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
# 记事本模块使用说明
|
|
||||||
|
|
||||||
## 功能概述
|
|
||||||
|
|
||||||
这是一个完整的记事本应用模块,支持富文本编辑、笔记管理等功能。
|
|
||||||
|
|
||||||
## 目录结构
|
|
||||||
|
|
||||||
```
|
|
||||||
notebook/
|
|
||||||
├── index.vue # 主页面(列表+编辑器)
|
|
||||||
├── components/
|
|
||||||
│ ├── edit.vue # 编辑器组件
|
|
||||||
│ └── TiptapEditor.vue # Tiptap富文本编辑器(已全局注册)
|
|
||||||
└── README.md # 说明文档
|
|
||||||
```
|
|
||||||
|
|
||||||
## 数据库
|
|
||||||
|
|
||||||
### 表名
|
|
||||||
`yz_platform_notebook`
|
|
||||||
|
|
||||||
### 表结构
|
|
||||||
- `id` - 主键ID
|
|
||||||
- `title` - 笔记标题
|
|
||||||
- `content` - 笔记内容(HTML格式)
|
|
||||||
- `user_id` - 创建用户ID
|
|
||||||
- `user_name` - 创建用户名
|
|
||||||
- `is_deleted` - 是否删除(0-否 1-是)
|
|
||||||
- `create_time` - 创建时间
|
|
||||||
- `update_time` - 更新时间
|
|
||||||
- `delete_time` - 删除时间
|
|
||||||
|
|
||||||
### SQL文件位置
|
|
||||||
`sql/yz_platform_notebook.sql`
|
|
||||||
|
|
||||||
## 后端接口
|
|
||||||
|
|
||||||
### 模型文件
|
|
||||||
`go/models/platform_notebook.go`
|
|
||||||
|
|
||||||
### 控制器文件
|
|
||||||
`go/controllers/platform_notebook.go`
|
|
||||||
|
|
||||||
### API端点
|
|
||||||
|
|
||||||
1. **获取笔记列表**
|
|
||||||
- URL: `GET /platform/notebook/list`
|
|
||||||
- 参数:
|
|
||||||
- `page`: 页码(默认1)
|
|
||||||
- `pageSize`: 每页数量(默认20,最大100)
|
|
||||||
- `keyword`: 搜索关键词(可选)
|
|
||||||
- 返回: 笔记列表和总数
|
|
||||||
|
|
||||||
2. **获取笔记详情**
|
|
||||||
- URL: `GET /platform/notebook/detail/:id`
|
|
||||||
- 参数: `id` - 笔记ID
|
|
||||||
- 返回: 笔记详细信息
|
|
||||||
|
|
||||||
3. **创建笔记**
|
|
||||||
- URL: `POST /platform/notebook/create`
|
|
||||||
- 参数:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "笔记标题",
|
|
||||||
"content": "<p>笔记内容</p>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- 返回: 创建的笔记信息
|
|
||||||
|
|
||||||
4. **更新笔记**
|
|
||||||
- URL: `POST /platform/notebook/update/:id`
|
|
||||||
- 参数:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "更新的标题",
|
|
||||||
"content": "<p>更新的内容</p>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- 返回: 更新后的笔记信息
|
|
||||||
|
|
||||||
5. **删除笔记**
|
|
||||||
- URL: `DELETE /platform/notebook/delete/:id`
|
|
||||||
- 参数: `id` - 笔记ID
|
|
||||||
- 返回: 删除结果
|
|
||||||
|
|
||||||
## 前端API
|
|
||||||
|
|
||||||
### API文件
|
|
||||||
`platform/src/api/notebook.js`
|
|
||||||
|
|
||||||
### 方法说明
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// 获取笔记列表
|
|
||||||
getNotebookList({ page, pageSize, keyword })
|
|
||||||
|
|
||||||
// 获取笔记详情
|
|
||||||
getNotebookDetail(id)
|
|
||||||
|
|
||||||
// 创建笔记
|
|
||||||
createNotebook({ title, content })
|
|
||||||
|
|
||||||
// 更新笔记
|
|
||||||
updateNotebook(id, { title, content })
|
|
||||||
|
|
||||||
// 删除笔记
|
|
||||||
deleteNotebook(id)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 使用步骤
|
|
||||||
|
|
||||||
### 1. 初始化数据库
|
|
||||||
```bash
|
|
||||||
# 在MySQL中执行SQL文件
|
|
||||||
mysql -u用户名 -p数据库名 < sql/yz_platform_notebook.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 启动后端服务
|
|
||||||
后端已自动注册模型和路由,直接启动即可:
|
|
||||||
```bash
|
|
||||||
cd go
|
|
||||||
go run main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 访问前端
|
|
||||||
在浏览器中访问笔记本页面(路由需要在菜单中配置)
|
|
||||||
|
|
||||||
## 功能特性
|
|
||||||
|
|
||||||
### 列表功能
|
|
||||||
- ✅ 显示所有笔记
|
|
||||||
- ✅ 搜索笔记(按标题)
|
|
||||||
- ✅ 创建新笔记
|
|
||||||
- ✅ 删除笔记
|
|
||||||
- ✅ 查看笔记预览
|
|
||||||
- ✅ 显示更新时间
|
|
||||||
|
|
||||||
### 编辑器功能
|
|
||||||
- ✅ 富文本编辑(基于Tiptap)
|
|
||||||
- ✅ 标题编辑
|
|
||||||
- ✅ 内容编辑
|
|
||||||
- ✅ 保存笔记
|
|
||||||
- ✅ 自动识别新建/编辑模式
|
|
||||||
- ✅ 加载状态显示
|
|
||||||
|
|
||||||
### TiptapEditor支持的功能
|
|
||||||
- 文本样式(加粗、斜体、下划线等)
|
|
||||||
- 标题(H1-H6)
|
|
||||||
- 引用
|
|
||||||
- 代码块
|
|
||||||
- 有序/无序列表
|
|
||||||
- 表格
|
|
||||||
- 链接
|
|
||||||
- 图片上传(需配置上传接口)
|
|
||||||
- 视频嵌入
|
|
||||||
|
|
||||||
## 权限说明
|
|
||||||
|
|
||||||
- 所有接口都需要平台用户登录(JWT Token验证)
|
|
||||||
- 每个用户只能查看、编辑、删除自己创建的笔记
|
|
||||||
- 删除操作为软删除,数据仍保留在数据库中
|
|
||||||
|
|
||||||
## 扩展功能(可选)
|
|
||||||
|
|
||||||
如需添加以下功能,可以扩展:
|
|
||||||
|
|
||||||
1. **笔记分类**
|
|
||||||
- 添加分类表和分类字段
|
|
||||||
- 支持笔记分类管理
|
|
||||||
|
|
||||||
2. **笔记标签**
|
|
||||||
- 添加标签表和关联表
|
|
||||||
- 支持多标签筛选
|
|
||||||
|
|
||||||
3. **笔记分享**
|
|
||||||
- 添加分享链接生成功能
|
|
||||||
- 支持公开/私密设置
|
|
||||||
|
|
||||||
4. **笔记导出**
|
|
||||||
- 支持导出为PDF
|
|
||||||
- 支持导出为Markdown
|
|
||||||
|
|
||||||
5. **版本历史**
|
|
||||||
- 记录笔记的修改历史
|
|
||||||
- 支持版本回退
|
|
||||||
|
|
||||||
6. **协作编辑**
|
|
||||||
- 支持多人协作编辑
|
|
||||||
- 实时同步功能
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. 图片上传需要配置文件上传接口
|
|
||||||
2. 富文本内容存储为HTML格式,注意XSS防护
|
|
||||||
3. 数据库content字段使用longtext类型,支持大容量内容
|
|
||||||
4. 建议定期清理软删除的数据
|
|
||||||
5. 生产环境建议添加内容审核机制
|
|
||||||
|
|
||||||
## 技术栈
|
|
||||||
|
|
||||||
- **前端**: Vue 3 + Element Plus + Tiptap
|
|
||||||
- **后端**: Go + Beego + MySQL
|
|
||||||
- **编辑器**: Tiptap (基于ProseMirror)
|
|
||||||
|
|
||||||
## 开发调试
|
|
||||||
|
|
||||||
### 前端调试
|
|
||||||
```bash
|
|
||||||
cd platform
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### 后端调试
|
|
||||||
```bash
|
|
||||||
cd go
|
|
||||||
go run main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
### 查看API请求
|
|
||||||
打开浏览器开发者工具 -> Network 标签页,查看API请求和响应
|
|
||||||
|
|
||||||
## 问题排查
|
|
||||||
|
|
||||||
1. **笔记列表为空**
|
|
||||||
- 检查数据库表是否创建成功
|
|
||||||
- 检查用户是否已登录
|
|
||||||
- 查看浏览器Console是否有错误
|
|
||||||
|
|
||||||
2. **保存失败**
|
|
||||||
- 检查JWT Token是否有效
|
|
||||||
- 检查标题是否为空
|
|
||||||
- 查看后端日志
|
|
||||||
|
|
||||||
3. **编辑器显示异常**
|
|
||||||
- 检查Tiptap是否正确安装
|
|
||||||
- 查看浏览器Console错误信息
|
|
||||||
- 检查CSS样式是否正确加载
|
|
||||||
|
|
||||||
## 更新日志
|
|
||||||
|
|
||||||
### v1.0.0 (2024)
|
|
||||||
- ✅ 完成基础功能
|
|
||||||
- ✅ 支持笔记CRUD操作
|
|
||||||
- ✅ 集成Tiptap富文本编辑器
|
|
||||||
- ✅ 响应式设计支持
|
|
||||||
- ✅ 暗色模式支持
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-body">
|
<div class="editor-body">
|
||||||
<TiptapEditor v-model="noteContent" />
|
<UmoEditor v-model="noteContent" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -179,9 +179,5 @@ onMounted(() => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
:deep(.tiptap-editor-wrapper) {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"strict": false,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": false,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["src/**/*", "vite.config.js"],
|
||||||
|
"exclude": ["node_modules", "output"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user