Преглед изворни кода

feat:添加作物品类列表接口

wangsisi пре 1 дан
родитељ
комит
0b8243d115

+ 2 - 2
app.js

@@ -6,7 +6,7 @@ const logger = require('morgan');
 const cors = require('cors')
 
 const indexRouter = require('./routes/index');
-const usersRouter = require('./routes/users');
+const categoryRouter = require('./routes/category');
 
 //文章路由文件
 const adminArticlesRouter = require('./routes/admin/articles');
@@ -30,9 +30,9 @@ app.use(cookieParser());
 app.use(express.static(path.join(__dirname, 'public')));
 
 app.use('/', indexRouter);
-app.use('/users', usersRouter);
 
 //文章路由文件
 app.use('/admin/articles', adminArticlesRouter);
+app.use('/category', categoryRouter);
 
 module.exports = app;

+ 4 - 4
config/config.json

@@ -1,9 +1,9 @@
 {
   "development": {
-    "username": "root",
-    "password": "wss123",
+    "username": "feiniao_site_node_development",
+    "password": "NXrdGDHTjZENL7XA",
     "database": "feiniao_site_node_development",
-    "host": "127.0.0.1",
+    "host": "8.210.65.64",
     "dialect": "mysql",
     "timezone":"+08:00",
     "logQueryParameters":true
@@ -16,7 +16,7 @@
     "dialect": "mysql",
     "timezone":"+08:00"
   },
-  "production": {
+  "production": { 
     "username": "feiniao_site_node_development",
     "password": "NXrdGDHTjZENL7XA",
     "database": "feiniao_site_node_development",

BIN
data/mysgl/#ib_16384_0.dblwr


BIN
data/mysgl/#innodb_redo/#ib_redo10


BIN
data/mysgl/#innodb_temp/temp_1.ibt


BIN
data/mysgl/#innodb_temp/temp_10.ibt


BIN
data/mysgl/#innodb_temp/temp_2.ibt


BIN
data/mysgl/#innodb_temp/temp_3.ibt


BIN
data/mysgl/#innodb_temp/temp_4.ibt


BIN
data/mysgl/#innodb_temp/temp_5.ibt


BIN
data/mysgl/#innodb_temp/temp_6.ibt


BIN
data/mysgl/#innodb_temp/temp_7.ibt


BIN
data/mysgl/#innodb_temp/temp_8.ibt


BIN
data/mysgl/#innodb_temp/temp_9.ibt


BIN
data/mysgl/binlog.000001


BIN
data/mysgl/binlog.000002


BIN
data/mysgl/binlog.000003


BIN
data/mysgl/binlog.000004


BIN
data/mysgl/binlog.000005


+ 2 - 3
data/mysgl/binlog.index

@@ -1,3 +1,2 @@
-./binlog.000001
-./binlog.000002
-./binlog.000003
+./binlog.000004
+./binlog.000005

BIN
data/mysgl/feiniao_site_node_development/articles.ibd


BIN
data/mysgl/feiniao_site_node_development/sequelizemeta.ibd


+ 227 - 214
data/mysgl/ib_buffer_pool

@@ -1,217 +1,6 @@
-4294967294,420
-4294967294,106
-4294967294,166
-4294967294,24
-4294967294,184
-4294967294,398
-4294967294,185
-4294967294,182
-4294967294,1159
-4294967294,1160
-4294967278,158
-4294967279,302
-4294967279,0
-4294967279,260
-4294967278,299
-4294967278,156
-4294967278,298
-4294967279,301
-4294967278,154
-4294967294,20
-4294967278,152
-5,4
-4294967278,151
-5,3
-5,2
-5,1
-4294967278,297
-4294967278,150
-4,5
-4,4
-4,3
-4,2
-4,1
-4294967279,300
-0,7
-4294967294,61
-4294967278,296
-4294967279,299
-4294967294,96
-4294967294,94
-4294967278,295
-4294967294,8
-4294967278,294
-4294967279,298
-4294967279,297
-4294967278,293
-4294967278,292
-4294967279,140
-4294967294,81
-4294967294,7
-4294967278,291
-4294967278,260
-4294967278,132
-4294967278,131
-4294967278,130
-4294967278,129
-4294967278,128
-4294967278,127
-4294967278,126
-4294967278,125
-4294967278,124
-4294967278,123
-4294967278,122
-4294967278,121
-4294967278,120
-4294967278,119
-4294967278,118
-4294967278,117
-4294967278,116
-4294967278,115
-4294967278,114
-4294967278,113
-4294967278,112
-4294967278,111
-4294967278,110
-4294967278,109
-4294967278,108
-4294967278,107
-4294967278,106
-4294967278,105
-4294967278,104
-4294967278,103
-4294967278,102
-4294967278,101
-4294967278,100
-4294967278,99
-4294967278,98
-4294967278,97
-4294967278,96
-4294967278,95
-4294967278,94
-4294967278,93
-4294967278,92
-4294967278,91
-4294967278,90
-4294967278,89
-4294967278,87
-4294967278,86
-4294967278,85
-4294967278,84
-4294967278,83
-4294967278,82
-4294967278,81
-4294967278,80
-4294967278,79
-4294967278,78
-4294967278,77
-4294967278,76
-4294967278,75
-4294967278,74
-4294967278,73
-4294967278,72
-4294967278,71
-4294967278,70
-4294967278,69
-4294967278,68
-4294967278,67
-4294967278,66
-4294967278,65
-4294967278,64
-4294967278,63
-4294967278,62
-4294967278,61
-4294967278,60
-4294967278,59
-4294967278,58
-4294967278,57
-4294967278,56
-4294967278,55
-4294967278,54
-4294967278,53
-4294967278,52
-4294967278,51
-4294967278,50
-4294967278,49
-4294967278,48
-4294967278,47
-4294967278,46
-4294967278,45
-4294967278,44
-4294967278,43
-4294967278,42
-4294967278,41
-4294967278,40
-4294967278,39
-4294967278,38
-4294967279,275
-4294967279,23
-4294967279,22
-4294967279,289
-4294967279,15
-4294967279,286
-4294967279,13
-4294967279,11
-4294967279,10
-4294967279,9
-4294967279,8
-4294967279,7
-4294967279,6
-4294967279,5
-4294967279,4
-0,5
-4294967294,12
-4294967294,50
-4294967294,68
-4294967294,11
-4294967294,1073
-4294967294,186
-4294967294,0
-4294967294,22
-4294967294,17
-4294967294,9
-4294967294,67
-4294967294,42
-4294967294,1
-4294967279,296
-4294967279,24
-4294967294,91
-4294967294,87
-4294967294,85
-4294967294,83
-4294967294,1087
-4294967294,1246
-4294967294,28
-4294967294,1216
-4294967294,27
-4294967294,470
-4294967294,25
-4294967294,1218
-4294967294,26
-4294967294,51
-4294967294,428
-4294967294,82
-4294967279,295
-4294967294,6
-4294967294,93
-4294967294,95
-4294967278,290
-4294967279,294
-4294967279,293
-3,4
-3,3
-3,2
-3,1
-4294967279,292
-4294967279,291
-2,4
-2,2
-2,1
-4294967294,472
-4294967279,281
-4294967278,289
-4294967279,280
-4294967278,288
+4294967279,315
+4294967294,473
+4294967278,315
 4294967293,131
 4294967293,130
 4294967293,129
@@ -293,3 +82,227 @@
 4294967293,53
 4294967293,52
 4294967293,51
+4294967293,50
+4294967293,49
+4294967293,48
+4294967293,47
+4294967293,46
+4294967293,45
+4294967293,44
+4294967293,43
+4294967293,42
+4294967293,41
+4294967293,40
+4294967293,39
+4294967293,38
+4294967293,37
+4294967293,36
+4294967293,35
+4294967293,34
+4294967293,33
+4294967293,32
+4294967293,31
+4294967293,30
+4294967293,29
+4294967293,28
+4294967293,27
+4294967293,26
+4294967293,25
+4294967293,24
+4294967293,23
+4294967293,22
+4294967293,21
+4294967293,20
+4294967293,19
+4294967293,18
+4294967293,17
+4294967293,16
+4294967293,15
+4294967293,14
+4294967293,13
+4294967293,12
+4294967293,11
+4294967293,10
+4294967293,9
+4294967293,8
+4294967293,7
+4294967293,6
+4294967293,5
+4294967293,4
+4294967293,3
+4294967293,2
+4243767290,0
+4243767289,0
+4243767288,0
+4243767287,0
+4243767286,0
+4243767285,0
+4243767284,0
+4243767283,0
+4243767282,0
+4243767281,0
+4294967293,0
+4294967279,157
+4294967279,302
+4294967279,44
+4294967279,309
+4294967279,159
+4294967279,45
+4294967279,310
+4294967279,160
+4294967279,46
+4294967279,161
+4294967279,162
+4294967279,47
+4294967279,48
+4294967279,49
+4294967279,311
+4294967279,312
+4294967279,313
+4294967279,163
+4294967279,314
+4294967279,164
+4294967279,166
+4294967279,50
+4294967279,165
+4294967279,51
+4294967279,52
+4294967279,53
+4294967279,167
+4294967279,168
+4294967279,169
+4294967279,54
+4294967279,170
+4294967279,55
+4294967279,171
+4294967279,56
+4294967279,57
+4294967279,172
+4294967279,175
+4294967279,58
+4294967279,173
+4294967279,59
+4294967279,60
+4294967279,176
+4294967279,61
+4294967279,177
+4294967279,179
+4294967279,62
+4294967279,178
+4294967279,63
+4294967279,64
+4294967279,180
+4294967279,181
+4294967279,65
+4294967279,183
+4294967279,66
+4294967279,182
+4294967279,67
+4294967279,68
+4294967279,69
+4294967279,184
+4294967279,185
+4294967279,187
+4294967279,70
+4294967279,186
+4294967279,71
+4294967279,72
+4294967279,189
+4294967279,188
+4294967279,73
+4294967279,74
+4294967279,191
+4294967279,75
+4294967279,190
+4294967279,76
+4294967279,192
+4294967279,77
+4294967279,193
+4294967279,194
+4294967279,78
+4294967279,79
+4294967279,195
+4294967279,80
+4294967279,196
+4294967279,197
+4294967279,81
+4294967279,82
+4294967279,198
+4294967279,83
+4294967279,199
+4294967279,84
+4294967279,201
+4294967279,85
+4294967279,200
+4294967279,202
+4294967279,86
+4294967279,87
+4294967279,203
+4294967279,89
+4294967279,205
+4294967279,204
+4294967279,90
+4294967279,207
+4294967279,206
+4294967279,91
+4294967279,92
+4294967279,209
+4294967279,93
+4294967279,94
+4294967279,208
+4294967279,211
+4294967279,210
+4294967279,95
+4294967279,96
+4294967279,97
+4294967279,98
+4294967279,212
+4294967279,213
+4294967279,99
+4294967279,214
+4294967279,277
+4294967279,100
+4294967279,101
+4294967279,215
+4294967279,220
+4294967279,216
+4294967279,218
+4294967279,102
+4294967279,103
+4294967279,219
+4294967279,222
+4294967279,217
+4294967279,104
+4294967279,105
+4294967279,224
+4294967279,221
+4294967279,223
+4294967279,226
+4294967279,106
+4294967279,228
+4294967279,227
+4294967279,225
+4294967279,107
+4294967279,230
+4294967279,232
+4294967279,108
+4294967279,109
+4294967279,229
+4294967279,236
+4294967279,234
+4294967279,110
+4294967279,231
+4294967279,235
+4294967279,233
+4294967279,111
+4294967279,237
+4294967279,239
+4294967279,112
+4294967279,113
+4294967279,114
+4294967279,243
+4294967279,241
+4294967279,245
+4294967279,238
+4294967279,242
+4294967279,240

BIN
data/mysgl/ibdata1


BIN
data/mysgl/ibtmp1


BIN
data/mysgl/mysql.ibd


BIN
data/mysgl/undo_001


BIN
data/mysgl/undo_002


+ 59 - 0
migrations/20250912075346-create-category.js

@@ -0,0 +1,59 @@
+// migrations/20250225000000-create-categories-table.js
+'use strict';
+
+module.exports = {
+  async up(queryInterface, Sequelize) {
+    await queryInterface.createTable('categories', {
+      id: {
+        type: Sequelize.INTEGER,
+        primaryKey: true,
+        autoIncrement: true
+      },
+      name: {
+        type: Sequelize.STRING,
+        allowNull: false
+      },
+      level: {
+        type: Sequelize.INTEGER,
+        defaultValue: 1
+      },
+      description: {
+        type: Sequelize.TEXT,
+        allowNull: true
+      },
+      parentId: {
+        type: Sequelize.INTEGER,
+        allowNull: true,
+        references: {
+          model: 'categories',
+          key: 'id'
+        },
+        onDelete: 'CASCADE'
+      },
+      order: {
+        type: Sequelize.INTEGER,
+        defaultValue: 0
+      },
+      isActive: {
+        type: Sequelize.BOOLEAN,
+        defaultValue: true
+      },
+      createdAt: {
+        type: Sequelize.DATE,
+        allowNull: false
+      },
+      updatedAt: {
+        type: Sequelize.DATE,
+        allowNull: false
+      }
+    });
+
+    // 添加索引
+    await queryInterface.addIndex('categories', ['parentId']);
+    await queryInterface.addIndex('categories', ['name']);
+  },
+
+  async down(queryInterface, Sequelize) {
+    await queryInterface.dropTable('categories');
+  }
+};

+ 5 - 0
models/article.js

@@ -34,6 +34,11 @@ module.exports = (sequelize, DataTypes) => {
     type:DataTypes.INTEGER,
     img:DataTypes.TEXT,
     date:DataTypes.DATE,
+    author:DataTypes.TEXT,
+    category:DataTypes.INTEGER,
+    crop:DataTypes.INTEGER,
+    seoKeyword:DataTypes.TEXT,
+    seoDescription:DataTypes.TEXT,
   }, {
     sequelize,
     modelName: 'Article',

+ 67 - 0
models/category.js

@@ -0,0 +1,67 @@
+// models/Category.js
+module.exports = (sequelize, DataTypes) => {
+  const Category = sequelize.define('Category', {
+  id: {
+    type: DataTypes.INTEGER.UNSIGNED,
+    primaryKey: true,
+    autoIncrement: true
+  },
+  name: {
+    type: DataTypes.STRING,
+    allowNull: false,
+    comment: '品类名称'
+  },
+  level: {
+    type: DataTypes.INTEGER,
+    defaultValue: 1,
+    comment: '层级深度'
+  },
+  description: {
+    type: DataTypes.TEXT,
+    comment: '品类描述'
+  },
+  parentId: {
+    type: DataTypes.INTEGER.UNSIGNED,
+    allowNull: true,
+    comment: '父级品类ID'
+  },
+  order: {
+    type: DataTypes.INTEGER.UNSIGNED,
+    defaultValue: 0,
+    comment: '排序顺序'
+  },
+  isActive: {
+    type: DataTypes.BOOLEAN,
+    defaultValue: true,
+    comment: '是否启用'
+  }
+}, {
+  tableName: 'categories',
+  timestamps: true,
+  indexes: [
+    {
+      fields: ['parentId']
+    },
+    {
+      fields: ['name']
+    }
+  ]
+});
+
+// 添加associate方法
+Category.associate = function(models) {
+  // 自关联关系
+  Category.hasMany(Category, {
+    as: 'children',
+    foreignKey: 'parentId',
+    onDelete: 'CASCADE'
+  });
+
+  Category.belongsTo(Category, {
+    as: 'parent',
+    foreignKey: 'parentId'
+  });
+};
+
+  return Category;
+};

+ 6 - 1
routes/admin/articles.js

@@ -203,7 +203,12 @@ function filterBody(req){
         content:req.body.content,
         type:req.body.type,
         img:req.body.img,
-        date:req.body.date
+        date:req.body.date,
+        author:req.body.author,
+        category:req.body.category,
+        crop:req.body.crop,
+        seoKeyword:req.body.seoKeyword,
+        seoDescription:req.body.seoDescription
     }
 }
 

+ 81 - 0
routes/category.js

@@ -0,0 +1,81 @@
+const express = require('express');
+const router = express.Router();
+const { Category } = require('../models');
+
+// 获取所有顶级品类及其子类
+router.get('/tree', async (req, res) => {
+  try {
+    const categories = await Category.findAll({
+      where: { level: 1 },
+      include: [{
+        model: Category,
+        as: 'children'
+      }],
+      order: [
+        ['order', 'ASC'],
+        [{ model: Category, as: 'children' }, 'order', 'ASC']
+      ]
+    });
+    res.json(categories);
+  } catch (error) {
+    res.status(500).json({ error: error.message });
+  }
+});
+
+// 根据ID获取品类及其所有子类
+router.get('/:id', async (req, res) => {
+  try {
+    const category = await Category.findByPk(req.params.id, {
+      include: [{
+        model: Category,
+        as: 'children'
+      }]
+    });
+    if (!category) {
+      return res.status(404).json({ error: '品类不存在' });
+    }
+    res.json(category);
+  } catch (error) {
+    res.status(500).json({ error: error.message });
+  }
+});
+
+// 添加新品类
+router.post('/', async (req, res) => {
+  try {
+    const category = await Category.create(req.body);
+    res.status(201).json(category);
+  } catch (error) {
+    res.status(500).json({ error: error.message });
+  }
+});
+
+// 更新品类
+router.put('/:id', async (req, res) => {
+  try {
+    const category = await Category.findByPk(req.params.id);
+    if (!category) {
+      return res.status(404).json({ error: '品类不存在' });
+    }
+    await category.update(req.body);
+    res.json(category);
+  } catch (error) {
+    res.status(500).json({ error: error.message });
+  }
+});
+
+// 删除品类(会级联删除子类)
+router.delete('/:id', async (req, res) => {
+  try {
+    const category = await Category.findByPk(req.params.id);
+    if (!category) {
+      return res.status(404).json({ error: '品类不存在' });
+    }
+    await category.destroy();
+    res.status(204).send();
+  } catch (error) {
+    res.status(500).json({ error: error.message });
+  }
+});
+
+module.exports = router;

+ 0 - 9
routes/users.js

@@ -1,9 +0,0 @@
-const express = require('express');
-const router = express.Router();
-
-/* GET users listing. */
-router.get('/api/articles', function(req, res, next) {
-  res.json('respond with a resource');
-});
-
-module.exports = router;

+ 4 - 0
seeders/20250225034424-article.js

@@ -10,6 +10,10 @@ module.exports = {
       const article = {
         title:`文章的标题${i}`,
         content:`文章的内容${i}`,
+        author:`文章的作者${i}`,
+        category:`文章的分类${i}`,
+        crop:`文章的作物${i}`,
+        img:`文章的图片${i}`,
         createdAt:new Date(),
         updatedAt:new Date()
       }

+ 138 - 0
seeders/20250912080428-categories.js

@@ -0,0 +1,138 @@
+// seeders/20250225000000-demo-categories.js
+'use strict';
+
+module.exports = {
+  async up(queryInterface, Sequelize) {
+    // 先清空现有数据
+    await queryInterface.bulkDelete('categories', {});
+    
+    // 插入顶级品类(一级)
+    await queryInterface.bulkInsert('categories', [
+      {
+        name: '蔬菜',
+        level: 1,
+        description: '各类蔬菜',
+        order: 1,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      },
+      {
+        name: '水果',
+        level: 1,
+        description: '各类水果',
+        order: 2,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      },
+      {
+        name: '谷物',
+        level: 1,
+        description: '各类谷物',
+        order: 3,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      }
+    ]);
+
+    // 查询获取插入的顶级品类ID
+    const topCategories = await queryInterface.sequelize.query(
+      "SELECT id FROM categories WHERE level = 1 ORDER BY `order` ASC",
+      { type: queryInterface.sequelize.QueryTypes.SELECT }
+    );
+    
+    const vegetableId = topCategories[0].id;
+    const fruitId = topCategories[1].id;
+    const grainId = topCategories[2].id;
+
+    // 插入二级品类
+    await queryInterface.bulkInsert('categories', [
+      // 蔬菜的子品类
+      {
+        name: '叶菜类',
+        level: 2,
+        parentId: vegetableId,
+        description: '绿叶蔬菜',
+        order: 1,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      },
+      {
+        name: '根茎类',
+        level: 2,
+        parentId: vegetableId,
+        description: '根茎蔬菜',
+        order: 2,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      },
+      // 水果的子品类
+      {
+        name: '浆果类',
+        level: 2,
+        parentId: fruitId,
+        description: '浆果水果',
+        order: 1,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      },
+      {
+        name: '柑橘类',
+        level: 2,
+        parentId: fruitId,
+        description: '柑橘水果',
+        order: 2,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      },
+      // 谷物的子品类
+      {
+        name: '稻谷类',
+        level: 2,
+        parentId: grainId,
+        description: '稻谷类谷物',
+        order: 1,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      },
+      {
+        name: '麦类',
+        level: 2,
+        parentId: grainId,
+        description: '麦类谷物',
+        order: 2,
+        isActive: true,
+        createdAt: new Date(),
+        updatedAt: new Date()
+      }
+    ]);
+
+    // 不需要插入三级品类,只保留一级和二级品类
+
+    console.log('作物品类数据插入完成!');
+  },
+
+  async down(queryInterface, Sequelize) {
+    // 先删除子级数据,再删除父级数据
+    await queryInterface.bulkDelete('categories', {
+      level: 3
+    });
+    
+    await queryInterface.bulkDelete('categories', {
+      level: 2
+    });
+    
+    await queryInterface.bulkDelete('categories', {
+      level: 1
+    });
+    
+    console.log('作物品类数据已回滚!');
+  }
+};