From 081d46029e4660e653f3c3b0ab4f1a90d05267a9 Mon Sep 17 00:00:00 2001 From: wangjie52 Date: Mon, 21 Jul 2025 19:07:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=86=85=E5=AE=B9=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=EF=BC=8C=E5=8C=85=E6=8B=AC=E5=88=86?= =?UTF-8?q?=E7=B1=BB=E7=AE=A1=E7=90=86=E3=80=81=E6=A0=87=E7=AD=BE=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=92=8CBanner=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E7=9B=B8=E5=85=B3API=E5=92=8C?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E9=A1=B5=E9=9D=A2=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/CONTENT_MODULE_README.md | 168 +++++++++ ruoyi-ui/src/api/content/banner.js | 73 ++++ ruoyi-ui/src/api/content/category.js | 69 ++++ ruoyi-ui/src/api/content/tag.js | 44 +++ ruoyi-ui/src/utils/image.js | 34 ++ ruoyi-ui/src/views/content/banner/index.vue | 336 ++++++++++++++++++ ruoyi-ui/src/views/content/category/index.vue | 320 +++++++++++++++++ ruoyi-ui/src/views/content/tag/index.vue | 215 +++++++++++ ruoyi-ui/vue.config.js | 2 +- 9 files changed, 1260 insertions(+), 1 deletion(-) create mode 100644 ruoyi-ui/CONTENT_MODULE_README.md create mode 100644 ruoyi-ui/src/api/content/banner.js create mode 100644 ruoyi-ui/src/api/content/category.js create mode 100644 ruoyi-ui/src/api/content/tag.js create mode 100644 ruoyi-ui/src/utils/image.js create mode 100644 ruoyi-ui/src/views/content/banner/index.vue create mode 100644 ruoyi-ui/src/views/content/category/index.vue create mode 100644 ruoyi-ui/src/views/content/tag/index.vue diff --git a/ruoyi-ui/CONTENT_MODULE_README.md b/ruoyi-ui/CONTENT_MODULE_README.md new file mode 100644 index 0000000..7d41d5e --- /dev/null +++ b/ruoyi-ui/CONTENT_MODULE_README.md @@ -0,0 +1,168 @@ +# 内容管理模块 + +## 功能概述 + +内容管理模块包含以下三个子模块: +- **分类管理**:管理内容分类,支持分类名称和分类图片 +- **标签管理**:管理内容标签,支持标签名称 +- **Banner管理**:管理轮播图,支持名称、排序、跳转链接和图片 + +## 文件结构 + +``` +src/ +├── api/content/ +│ ├── category.js # 分类管理API +│ ├── tag.js # 标签管理API +│ └── banner.js # Banner管理API +└── views/content/ + ├── category/ + │ └── index.vue # 分类管理页面 + ├── tag/ + │ └── index.vue # 标签管理页面 + └── banner/ + └── index.vue # Banner管理页面 +``` + +## 后端接口 + +### 分类管理接口 +- 列表查询:`GET /back/category/list` +- 新增分类:`POST /back/category` (FormData格式) +- 修改分类:`PUT /back/category` (FormData格式) +- 删除分类:`DELETE /back/category/{id}` + +### 标签管理接口 +- 列表查询:`GET /back/tag/list` +- 新增标签:`POST /back/tag` +- 修改标签:`PUT /back/tag` +- 删除标签:`DELETE /back/tag/{id}` + +### Banner管理接口 +- 列表查询:`GET /back/banner/list` +- 新增Banner:`POST /back/banner/add` (FormData格式) +- 修改Banner:`PUT /back/banner` (FormData格式) +- 删除Banner:`DELETE /back/banner/{id}` + +## 图片处理说明 + +### 图片上传方式 +- **不再预先上传**:图片不会先上传到服务器 +- **直接提交**:图片作为二进制文件直接随表单提交到后端 +- **本地预览**:使用 `URL.createObjectURL()` 创建本地预览 +- **FormData格式**:使用 `multipart/form-data` 格式提交 + +### 图片显示方式 +- **字段映射**: + - 分类管理:使用 `backImg` 字段 + - Banner管理:使用 `imageUrl` 字段 +- **URL拼接**:后端返回图片路径,前端拼接完整URL +- **工具方法**:使用 `src/utils/image.js` 中的 `getImageUrl()` 方法 + +### 请求格式示例 +```javascript +// 分类新增请求 +const formData = new FormData() +formData.append('name', '分类名称') +formData.append('file', fileObject) // 文件对象 + +// Banner新增请求 +const formData = new FormData() +formData.append('name', 'Banner名称') +formData.append('sort', '1') +formData.append('jumpUrl', 'https://example.com') +formData.append('file', fileObject) // 文件对象 +``` + +### 图片URL处理示例 +```javascript +// 后端返回数据 +{ + "id": 1, + "name": "分类名称", + "backImg": "/upload/category/image.jpg" // 图片路径 +} + +// 前端显示 +const fullUrl = getImageUrl(backImg) +// 结果: "http://60.205.107.210:8080/upload/category/image.jpg" +``` + +## 安装步骤 + +### 1. 执行菜单SQL +在数据库中执行 `content_menu.sql` 文件,创建菜单和权限配置。 + +### 2. 重启前端服务 +```bash +npm run dev +``` + +### 3. 分配权限 +登录系统后,在角色管理中为相应角色分配内容管理模块的权限。 + +## 功能特性 + +### 分类管理 +- ✅ 分类列表展示(支持分页) +- ✅ 分类搜索(按名称) +- ✅ 新增分类(支持图片上传) +- ✅ 编辑分类 +- ✅ 删除分类 +- ✅ 图片预览 + +### 标签管理 +- ✅ 标签列表展示(支持分页) +- ✅ 标签搜索(按名称) +- ✅ 新增标签 +- ✅ 编辑标签 +- ✅ 删除标签 + +### Banner管理 +- ✅ Banner列表展示(支持分页) +- ✅ Banner搜索(按名称) +- ✅ 新增Banner(支持图片上传) +- ✅ 编辑Banner +- ✅ 删除Banner +- ✅ 图片预览 +- ✅ 排序功能 + +## 注意事项 + +1. **图片上传**:分类和Banner模块支持图片上传,图片直接作为二进制流传给后端。 + +2. **FormData格式**:分类和Banner的新增/修改接口使用FormData格式,标签管理使用JSON格式。 + +3. **权限控制**:所有操作都有相应的权限控制,需要在角色管理中分配权限。 + +4. **分页支持**:所有列表都支持分页查询。 + +5. **文件大小限制**:图片大小限制为2MB,支持JPG/PNG/GIF格式。 + +## 常见问题 + +### Q: 图片上传失败怎么办? +A: 检查以下几点: +- 图片格式是否为JPG/PNG/GIF +- 图片大小是否超过2MB +- 网络连接是否正常 +- 后端接口是否正常接收FormData格式 + +### Q: 菜单不显示怎么办? +A: 检查以下几点: +- 是否执行了菜单SQL +- 当前用户角色是否有相应权限 +- 是否刷新了页面 + +### Q: 接口调用失败怎么办? +A: 检查以下几点: +- 后端服务是否正常运行 +- 接口地址是否正确 +- 网络连接是否正常 +- 请求参数格式是否正确 + +### Q: 图片预览不显示怎么办? +A: 检查以下几点: +- 文件是否成功选择 +- 浏览器是否支持 `URL.createObjectURL()` +- 图片格式是否正确 \ No newline at end of file diff --git a/ruoyi-ui/src/api/content/banner.js b/ruoyi-ui/src/api/content/banner.js new file mode 100644 index 0000000..e01a472 --- /dev/null +++ b/ruoyi-ui/src/api/content/banner.js @@ -0,0 +1,73 @@ +import request from '@/utils/request' + +// 查询Banner列表 +export function listBanner(query) { + return request({ + url: '/back/banner/list', + method: 'get', + params: query + }) +} + +// 查询Banner详细 +export function getBanner(id) { + return request({ + url: '/back/banner/' + id, + method: 'get' + }) +} + +// 新增Banner +export function addBanner(data) { + const formData = new FormData() + formData.append('name', data.name) + formData.append('sort', data.sort) + formData.append('jumpUrl', data.jumpUrl || '') + if (data.file) { + formData.append('file', data.file) + } + return request({ + url: '/back/banner/add', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 修改Banner +export function updateBanner(data) { + const formData = new FormData() + formData.append('id', data.id) + formData.append('name', data.name) + formData.append('sort', data.sort) + formData.append('jumpUrl', data.jumpUrl || '') + + // 如果有新图片文件,上传新图片 + if (data.file) { + formData.append('file', data.file) + } + + // 传递图片路径(原图片或新图片的路径) + if (data.bannerAddr) { + formData.append('bannerAddr', data.bannerAddr) + } + + return request({ + url: '/back/banner/update', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 删除Banner +export function delBanner(id) { + return request({ + url: '/back/banner/' + id, + method: 'delete' + }) +} \ No newline at end of file diff --git a/ruoyi-ui/src/api/content/category.js b/ruoyi-ui/src/api/content/category.js new file mode 100644 index 0000000..27c65a7 --- /dev/null +++ b/ruoyi-ui/src/api/content/category.js @@ -0,0 +1,69 @@ +import request from '@/utils/request' + +// 查询分类列表 +export function listCategory(query) { + return request({ + url: '/back/category/list', + method: 'get', + params: query + }) +} + +// 查询分类详细 +export function getCategory(id) { + return request({ + url: '/back/category/' + id, + method: 'get' + }) +} + +// 新增分类 +export function addCategory(data) { + const formData = new FormData() + formData.append('name', data.name) + if (data.file) { + formData.append('file', data.file) + } + return request({ + url: '/back/category', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 修改分类 +export function updateCategory(data) { + const formData = new FormData() + formData.append('id', data.id) + formData.append('name', data.name) + + // 如果有新图片文件,上传新图片 + if (data.file) { + formData.append('file', data.file) + } + + // 传递图片路径(原图片或新图片的路径) + if (data.backImg) { + formData.append('backImg', data.backImg) + } + + return request({ + url: '/back/category/update', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 删除分类 +export function delCategory(id) { + return request({ + url: '/back/category/' + id, + method: 'delete' + }) +} \ No newline at end of file diff --git a/ruoyi-ui/src/api/content/tag.js b/ruoyi-ui/src/api/content/tag.js new file mode 100644 index 0000000..ed23476 --- /dev/null +++ b/ruoyi-ui/src/api/content/tag.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询标签列表 +export function listTag(query) { + return request({ + url: '/back/tag/list', + method: 'get', + params: query + }) +} + +// 查询标签详细 +export function getTag(id) { + return request({ + url: '/back/tag/' + id, + method: 'get' + }) +} + +// 新增标签 +export function addTag(data) { + return request({ + url: '/back/tag', + method: 'post', + data: data + }) +} + +// 修改标签 +export function updateTag(data) { + return request({ + url: '/back/tag', + method: 'put', + data: data + }) +} + +// 删除标签 +export function delTag(id) { + return request({ + url: '/back/tag/' + id, + method: 'delete' + }) +} \ No newline at end of file diff --git a/ruoyi-ui/src/utils/image.js b/ruoyi-ui/src/utils/image.js new file mode 100644 index 0000000..74a37bb --- /dev/null +++ b/ruoyi-ui/src/utils/image.js @@ -0,0 +1,34 @@ +/** + * 图片工具类 + */ + +/** + * 获取图片完整URL + * @param {string} imagePath 图片路径 + * @returns {string} 完整的图片URL + */ +export function getImageUrl(imagePath) { + if (!imagePath) { + return ''; + } + + // 如果已经是完整URL,直接返回 + if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) { + return imagePath; + } + + // 使用项目的API前缀配置 + const baseApi = process.env.VUE_APP_BASE_API || '/dev-api'; + return baseApi + imagePath; +} + +/** + * 获取图片完整URL(带默认图片) + * @param {string} imagePath 图片路径 + * @param {string} defaultImage 默认图片路径 + * @returns {string} 完整的图片URL + */ +export function getImageUrlWithDefault(imagePath, defaultImage = '') { + const url = getImageUrl(imagePath); + return url || defaultImage; +} \ No newline at end of file diff --git a/ruoyi-ui/src/views/content/banner/index.vue b/ruoyi-ui/src/views/content/banner/index.vue new file mode 100644 index 0000000..a20d197 --- /dev/null +++ b/ruoyi-ui/src/views/content/banner/index.vue @@ -0,0 +1,336 @@ + + + + + \ No newline at end of file diff --git a/ruoyi-ui/src/views/content/category/index.vue b/ruoyi-ui/src/views/content/category/index.vue new file mode 100644 index 0000000..2a95cf1 --- /dev/null +++ b/ruoyi-ui/src/views/content/category/index.vue @@ -0,0 +1,320 @@ + + + + + \ No newline at end of file diff --git a/ruoyi-ui/src/views/content/tag/index.vue b/ruoyi-ui/src/views/content/tag/index.vue new file mode 100644 index 0000000..4d762e2 --- /dev/null +++ b/ruoyi-ui/src/views/content/tag/index.vue @@ -0,0 +1,215 @@ + + + \ No newline at end of file diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js index 40e140d..cdec3f1 100644 --- a/ruoyi-ui/vue.config.js +++ b/ruoyi-ui/vue.config.js @@ -9,7 +9,7 @@ const CompressionPlugin = require('compression-webpack-plugin') const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题 -const baseUrl = 'http://localhost:8080' // 后端接口 +const baseUrl = 'http://60.205.107.210:8080' // 后端接口 const port = process.env.port || process.env.npm_config_port || 80 // 端口