寻求Express+Sequelize查询及React前端实现单词-分类列表方案
后端实现(Express + Sequelize)
1. 模型关联配置
先确保Word和Category模型建立正确的关联(每个单词对应一个分类,属于belongsTo关系):
Word模型(models/Word.js)
module.exports = (sequelize, DataTypes) => { const Word = sequelize.define('Word', { word: { type: DataTypes.STRING, allowNull: false }, categoryId: { type: DataTypes.INTEGER, allowNull: false, references: { model: 'Categories', key: 'id' } } }, {}); Word.associate = function(models) { Word.belongsTo(models.Category, { foreignKey: 'categoryId' }); }; return Word; };
Category模型(models/Category.js)
module.exports = (sequelize, DataTypes) => { const Category = sequelize.define('Category', { name: { type: DataTypes.STRING, allowNull: false, unique: true } }, {}); Category.associate = function(models) { Category.hasMany(models.Word, { foreignKey: 'categoryId' }); }; return Category; };
2. GET路由实现
在管理员路由文件(如routes/admin/words.js)中添加获取单词-分类列表的接口:
const express = require('express'); const router = express.Router(); const { Word, Category } = require('../../models'); // 获取单词-分类列表(需管理员权限) router.get('/words-with-categories', async (req, res) => { try { // 这里可加入权限校验逻辑,比如验证用户是否为管理员 // if (!req.user.isAdmin) return res.status(403).json({ message: '无访问权限' }); const wordsWithCategories = await Word.findAll({ attributes: ['id', 'word'], include: [{ model: Category, attributes: ['name'], required: true // 只返回有对应分类的单词 }], order: [[Category, 'name', 'ASC'], ['word', 'ASC']] // 按分类、单词排序 }); // 格式化数据,简化前端处理 const formattedData = wordsWithCategories.map(item => ({ word: item.word, category: item.Category.name })); res.status(200).json(formattedData); } catch (error) { console.error('获取数据失败:', error); res.status(500).json({ message: '服务器内部错误' }); } }); module.exports = router;
在主app.js中注册路由:
const adminRoutes = require('./routes/admin/words'); app.use('/api/admin', adminRoutes);
前端实现(React + Axios)
1. 数据获取与表格渲染
创建AdminWordList组件,负责请求数据并渲染表格:
import React, { useState, useEffect } from 'react'; import axios from 'axios'; const AdminWordList = () => { const [wordCategoryList, setWordCategoryList] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { // 携带管理员权限token(需根据实际权限系统调整) const config = { headers: { 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` } }; const response = await axios.get('/api/admin/words-with-categories', config); setWordCategoryList(response.data); } catch (err) { setError(err.response?.data?.message || '获取数据失败'); } finally { setLoading(false); } }; fetchData(); }, []); if (loading) return <div>加载中...</div>; if (error) return <div className="error-text">{error}</div>; return ( <div className="s-table-container"> <table className="s-table"> <thead> <tr> <th>Words</th> <th>Category</th> </tr> </thead> <tbody> {wordCategoryList.map((item, idx) => ( <tr key={idx}> <td>{item.word}</td> <td>{item.category}</td> </tr> ))} </tbody> </table> </div> ); }; export default AdminWordList;
2. 基础样式(可选)
添加CSS让表格更美观:
.s-table-container { margin: 2rem; overflow-x: auto; } .s-table { width: 100%; border-collapse: collapse; border: 1px solid #e0e0e0; } .s-table th, .s-table td { padding: 1rem; text-align: left; border-bottom: 1px solid #e0e0e0; } .s-table th { background-color: #f5f5f5; font-weight: 600; } .s-table tr:hover { background-color: #fafafa; } .error-text { color: #dc2626; padding: 2rem; text-align: center; }
内容的提问来源于stack exchange,提问作者Maksim Momcilovic
相关产品推荐
相关产品推荐

