当前位置: 首页 > news >正文

AI书签管理工具开发全记录(七):页面编写与接口对接

文章目录

  • AI书签管理工具开发全记录(七):页面编写与接口对接
    • 前言 📝
    • 1. 页面功能规划 📌
    • 2. 接口api编写 📡
      • 2.1 创建`.env`,设置环境变量
      • 2.2 增加`axios`拦截器
      • 2.3 创建接口
    • 2. 页面编写 📄
      • 2.1 示例代码
    • 3. 跨域问题 🌐
      • 3.1 配置cors中间件
    • 4.页面效果 ✨
      • 4.1 分类管理页面
      • 4.2 书签管理页面
    • 总结 📚

AI书签管理工具开发全记录(七):页面编写与接口对接

前言 📝

在上一篇博客中,我们完成了前端基础框架的搭建。现在,我们将实现书签和分类管理的具体页面,并与后端API进行对接,完成整个前后端交互流程。

1. 页面功能规划 📌

我们需要实现以下核心功能页面:

  1. ​书签管理页面​
    • 书签列表展示
    • 书签增删改查​
  2. ​分类管理页面​
    • 分类列表展示
    • 分类增删改查

2. 接口api编写 📡

2.1 创建.env,设置环境变量

VITE_API_BASE_URL=http://localhost:8080

2.2 增加axios拦截器

import axios from 'axios'
import { ElMessage } from 'element-plus'// 创建 axios 实例
const service = axios.create({baseURL: import.meta.env.VITE_API_BASE_URL,timeout: 10000
})// 请求拦截器
service.interceptors.request.use((config) => {// 在这里可以添加请求前的处理逻辑return config},(error) => {return Promise.reject(error)}
)// 响应拦截器
service.interceptors.response.use((response) => {// 在这里可以添加响应后的处理逻辑const res = response.data// 如果返回的状态码不是200,说明接口请求有误if (response.status !== 200) {ElMessage.error(res.message || '请求失败')return Promise.reject(new Error(res.message || '请求失败'))}return res},(error) => {ElMessage.error(error.message || '请求失败')return Promise.reject(error)}
)export default service

2.3 创建接口

以分类为例,书签相似。

// src/api/category/index.js
import request from '/@/utils/request'// 创建分类
export function createCategory(data) {return request({url: '/api/categories',method: 'post',data})
}// 获取分类列表
export function listCategories(params) {return request({url: '/api/categories',method: 'get',params})
}// 获取单个分类
export function getCategory(id) {return request({url: `/api/categories/${id}`,method: 'get'})
}// 更新分类
export function updateCategory(id, data) {return request({url: `/api/categories/${id}`,method: 'put',data})
}// 删除分类
export function deleteCategory(id) {return request({url: `/api/categories/${id}`,method: 'delete'})
}

2. 页面编写 📄

2.1 示例代码

以分类为例

<!--/src/views/category/index.vue -->
<template><div class="category-container"><div class="header"><h2>分类管理</h2></div><div class="toolbar"><div class="search-row"><el-inputv-model="searchName"placeholder="请输入分类名称"class="search-input"clearable@clear="handleSearch"@keyup.enter="handleSearch"><template #append><el-button @click="handleSearch"><el-icon><Search /></el-icon></el-button></template></el-input></div><div class="button-row"><el-button type="primary" @click="handleAdd">新增分类</el-button></div></div><el-table :data="categoryList" style="width: 100%" v-loading="loading"><el-table-column prop="id" label="ID" width="80" /><el-table-column prop="name" label="分类名称" /><el-table-column prop="description" label="描述" /><el-table-column label="操作" width="200"><template #default="{ row }"><el-button type="primary" link @click="handleEdit(row)">编辑</el-button><el-button type="danger" link @click="handleDelete(row)">删除</el-button></template></el-table-column></el-table><div class="pagination"><el-paginationv-model:current-page="currentPage"v-model:page-size="pageSize":page-sizes="[10, 20, 50, 100]"layout="total, sizes, prev, pager, next":total="total"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></div><!-- 新增/编辑对话框 --><el-dialogv-model="dialogVisible":title="dialogType === 'add' ? '新增分类' : '编辑分类'"width="500px"><el-formref="formRef":model="form":rules="rules"label-width="80px"><el-form-item label="分类名称" prop="name"><el-input v-model="form.name" placeholder="请输入分类名称" /></el-form-item><el-form-item label="描述" prop="description"><el-inputv-model="form.description"type="textarea"placeholder="请输入分类描述"/></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="handleSubmit">确定</el-button></span></template></el-dialog></div>
</template><script setup>
import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import { listCategories, createCategory, updateCategory, deleteCategory } from '/@/api/category'// 数据列表
const categoryList = ref([])
const loading = ref(false)
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(0)
const searchName = ref('')// 对话框相关
const dialogVisible = ref(false)
const dialogType = ref('add')
const formRef = ref(null)
const form = ref({name: '',description: ''
})// 表单验证规则
const rules = {name: [{ required: true, message: '请输入分类名称', trigger: ['blur', 'change'] },{ min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: ['blur', 'change'] }],description: [{ max: 200, message: '长度不能超过 200 个字符', trigger: ['blur', 'change'] }]
}// 获取分类列表
const getList = async () => {loading.value = truetry {const res = await listCategories({page: currentPage.value,size: pageSize.value,name: searchName.value})categoryList.value = res.datatotal.value = res.total} catch (error) {ElMessage.error('获取分类列表失败')} finally {loading.value = false}
}// 处理搜索
const handleSearch = () => {currentPage.value = 1getList()
}// 处理新增
const handleAdd = () => {dialogType.value = 'add'form.value = {name: '',description: ''}dialogVisible.value = true
}// 处理编辑
const handleEdit = (row) => {dialogType.value = 'edit'form.value = {id: row.id,name: row.name,description: row.description}dialogVisible.value = true
}// 处理删除
const handleDelete = (row) => {ElMessageBox.confirm('确认删除该分类吗?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async () => {try {await deleteCategory(row.id)ElMessage.success('删除成功')getList()} catch (error) {ElMessage.error('删除失败')}})
}// 处理提交
const handleSubmit = async () => {if (!formRef.value) returnawait formRef.value.validate(async (valid) => {if (valid) {try {if (dialogType.value === 'add') {await createCategory(form.value)ElMessage.success('新增成功')} else {await updateCategory(form.value.id, form.value)ElMessage.success('更新成功')}dialogVisible.value = falsegetList()} catch (error) {ElMessage.error(dialogType.value === 'add' ? '新增失败' : '更新失败')}}})
}// 处理分页
const handleSizeChange = (val) => {pageSize.value = valgetList()
}const handleCurrentChange = (val) => {currentPage.value = valgetList()
}// 初始化
onMounted(() => {getList()
})
</script><style scoped>
.category-container {padding: 20px;
}.header {margin-bottom: 16px;
}.header h2 {margin: 0;font-size: 20px;font-weight: 500;
}.toolbar {margin-bottom: 16px;
}.search-row {margin-bottom: 12px;
}.search-input {width: 240px;
}.pagination {margin-top: 20px;display: flex;justify-content: flex-end;
}
</style>

3. 跨域问题 🌐

3.1 配置cors中间件

// internal/api/api.go:NewServer// 配置CORS
router.Use(func(c *gin.Context) {c.Writer.Header().Set("Access-Control-Allow-Origin", "*")c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")if c.Request.Method == "OPTIONS" {c.AbortWithStatus(204)return}c.Next()
})

4.页面效果 ✨

4.1 分类管理页面

image.png

4.2 书签管理页面

image.png

总结 📚

本文详细介绍了AI书签管理工具的前端页面实现和接口对接过程,主要完成了:

  1. ​书签管理页面​​:实现列表展示、搜索、分页、增删改查
  2. ​分类管理页面​​:实现分类的CRUD操作
  3. ​接口对接​​:封装API请求,处理跨域问题
  4. ​表单验证​​:实现表单验证逻辑

在下一篇文章中,我们将实现Ai创建书签功能。

相关文章:

  • 手写HashMap
  • AE已禁用刷新请释放Caps Lock
  • 现代网络安全攻防技术与发展现状
  • 头歌java课程实验(学习-Java字符串之正则表达式之元字符之判断字符串是否符合规则)
  • 使用Python实现Windows系统垃圾清理
  • Webug4.0靶场通关笔记16- 第16关MySQL配置文件下载
  • 项目日记 -Qt音乐播放器 -搜索模块
  • Linux研学-用户解析
  • 【Java笔记】Spring IoC DI
  • ApiHug 1.3.9 支持 Spring 3.5.0 + Plugin 0.7.4 内置小插件升级!儿童节快乐!!!
  • 新闻数据加载(鸿蒙App开发实战)
  • flowable候选人及候选人组(Candidate Users 、Candidate Groups)的应用包含拾取、归还、交接
  • neo4j 5.19.0安装、apoc csv导入导出 及相关问题处理
  • 内容中台构建数字化管理新路径
  • 每日c/c++题 备战蓝桥杯(P1204 [USACO1.2] 挤牛奶 Milking Cows)
  • 【多线程初阶】死锁的产生 如何避免死锁
  • 每日c/c++题 备战蓝桥杯(P2240 【深基12.例1】部分背包问题)
  • 湖北理元理律师事务所:债务管理中的人本主义实践
  • 如何在 Ubuntu22.04 上安装并开始使用 RabbitMQ
  • 【代码坏味道】无用物Dispensables
  • 网站诊断报告案例/优化人员是什么意思
  • 无锡建设局评职称网站/百度推广一年大概多少钱
  • 北京公司注册代理/聊城seo
  • 网站被k还能不能在百度做推广/网络营销与直播电商就业前景
  • 那些网站是php开发的/怎么关键词优化网站
  • 东莞效果好的网站建设/厦门推广平台较好的