从0打1 用node express vite搭建一个博客系统系列(完结)

项目使用了Node后端、Express和Vite搭建的全栈博客系统系列,将Vue 2项目重构为Vue 3版本。该系统包含了以下主要模块和功能:

登录和注册功能:用户可以通过注册账号和登录来访问博客系统。

分类列表:展示不同分类的文章,包括技术栈、精品短文和热门文章。

更多功能:

数据分析:提供文章数据的统计和分析功能。
评论审查:对用户评论进行审查和管理。
回收站:将已删除的文章移至回收站,可以进行恢复或永久删除。
浏览历史:记录用户的浏览历史,方便查看之前浏览过的文章。
搜索:提供文章标题搜索功能,方便用户查找感兴趣的文章。
详情:点击文章标题可以查看文章的详细内容。
评论:允许用户在文章下发表评论。
点赞:用户可以给喜欢的文章点赞。
基本的增删改查功能:支持对文章进行基本的增加、删除、修改和查询操作。

通过这个博客系统,用户可以方便地管理和浏览文章,以及与其他用户进行互动和讨论。系统使用了最新的Vue 3版本,提供了更好的性能和开发体验。

项目开源地址:https://gitee.com/hailang123/kao2-vite-mysql
从0打1 用node express vite搭建一个博客系统系列(完结)_第1张图片

从0打1 用node express vite搭建一个博客系统系列(完结)_第2张图片
从0打1 用node express vite搭建一个博客系统系列(完结)_第3张图片
从0打1 用node express vite搭建一个博客系统系列(完结)_第4张图片
从0打1 用node express vite搭建一个博客系统系列(完结)_第5张图片
从0打1 用node express vite搭建一个博客系统系列(完结)_第6张图片
从0打1 用node express vite搭建一个博客系统系列(完结)_第7张图片

从0打1 用node express vite搭建一个博客系统系列(完结)_第8张图片
从0打1 用node express vite搭建一个博客系统系列(完结)_第9张图片

路由

import { createRouter, createWebHistory } from "vue-router";

const routes = [
  {
    path: "/login",
    name: "login",
    component: () => import("../views/login.vue"),
  },
  {
    path: "/register",
    name: "register",
    component: () => import("../views/register.vue"),
  },
  {
    path: "/",
    name: "index",
    component: () => import("../views/index.vue"),
    children: [
      {
        // 详情页,通过id来获取文章信息
        path: "/detail/:id",
        name: "detail",
        component: () => import("../views/detail.vue"),
      },

      {
        path: "/fabu",
        name: "fabu",
        component: () => import("../views/fabu.vue"),
      },
      {
        path: "/biaoqian",
        name: "biaoqian",
        component: () => import("../views/biaoqian.vue"),
      },
      {
        path: "/fenlei",
        name: "fenlei",
        component: () => import("../views/fenlei.vue"),
      },
      {
        path: "/shouye",
        name: "shouye",
        component: () => import("../views/shouye.vue"),
      },
      {
        path: "/lixiang",
        name: "lixiang",
        component: () => import("../views/lixiang.vue"),
      },
      {
        path: "/jishuzhan",
        name: "jishuzhan",
        component: () => import("../views/jishuzhan.vue"),
      },
      {
        path: "/fenxi",
        name: "fenxi",
        component: () => import("../views/fenxi.vue"),
      },
      {
        path: "/duanwen",
        name: "duanwen",
        component: () => import("../views/duanwen.vue"),
      },

      {
        path: "/labcloud",
        name: "labcloud",
        component: () => import("../views/labcloud.vue"),
      },
      {
        path: "/hotpage",
        name: "hotpage",
        component: () => import("../views/hotpage.vue"),
      },
      {
        path: "/newping",
        name: "newping",
        component: () => import("../views/newping.vue"),
      },
      {
        path: "/history",
        name: "history",
        component: () => import("../views/history.vue"),
      },
      {
        path: "/huishou",
        name: "huishou",
        component: () => import("../views/huishou.vue"),
      }
    ],
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

详情

<template>
  <div class="main">
    <div>
      <div class="title">{{ state.title }}</div>
      <div class="content">{{ state.content }}</div>
      <div class="author">作者:{{ state.author }}</div>
      <div><Dianzan :articleId=state.id></Dianzan></div>
      <div class="created_at">创建时间:{{ state.created_at }}</div>
    </div>
    <div>
      <a-button @click="bankFn" type="primary" :size="size" class="bank"
        >返回</a-button
      >
      <a-button @click="preFn" type="primary" :size="size" class="pre"
        >上一篇</a-button
      >
      <a-button
        @click="nestFn"
        :disabled="isLastPage"
        type="primary"
        :size="size"
        class="next"
        >下一篇</a-button
      >
    </div>
    <div>
      <Pinglun :articleId="route.params.id" />
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, computed } from "vue";
import { getArticleById, showPassageApi } from "../utils/api";
import { useRoute, useRouter } from "vue-router";
import Pinglun from "../components/pinglun.vue";
import Dianzan from "../components/dianzan.vue";

const state = ref({});
const route = useRoute();
const router = useRouter();

const result = async () => {
  const articleId = route.params.id;
  const res = await getArticleById({ id: articleId });
  state.value = res.data[0];
  console.log(state.value);

  // 获取当前浏览的时间
  const time = new Date().toLocaleString();

  // 将当前浏览详的时间添加到浏览详情数据中
  state.value.time = time;

  // 从localStorage获取已有的浏览记录
  let history = JSON.parse(localStorage.getItem("history")) || [];

  // 将当前浏览详情数据添加到浏览记录中
  history.push(state.value);

  // 将更新后的浏览记录保存回localStorage
  localStorage.setItem("history", JSON.stringify(history));
};

result();

// 返回到首页
const bankFn = () => {
  router.push("/shouye");
};

const preFn = async () => {
  const articleId = route.params.id;
  const res = await getArticleById({ id: articleId });
  console.log(res.data[0].id);
  if (res.data[0].id == 1) {
    alert("已经是第一篇了");
  } else {
    router.push(`/detail/${res.data[0].id - 1}`);
    state.value = res.data[0];
  }
};

const nestFn = async () => {
  const articleId = route.params.id;
  const res = await getArticleById({ id: articleId });
  console.log(res.code);
  if (res.data.length === 0) {
    //   阻止下一篇按钮的点击事件
    return;
    alert("已经是最后一篇了");
  } else {
    router.push(`/detail/${res.data[0].id + 1}`);
    state.value = res.data[0];
  }
};

const isLastPage = computed(() => {
  showPassageApi().then((res) => {
    // 计算一共有多少条数据
    const total = res.data.length;
    return state.value.id === total;
  });
});
</script>

<style lang="less" scoped>
.main {
  width: 100%;
  height: 100%;
  background-color: antiquewhite;

  .title {
    width: 100%;
    height: 50px;
    font-size: 20px;
    font-weight: bold;
    margin: 0 auto;
    text-align: center;
    padding: 15px;
  }
  .content {
    width: 100%;
    height: 100%;
    font-size: 15px;
    font-family: "微软雅黑";
    margin: 0 auto;
    padding: 15px;
    // 文字缩进2
    text-indent: 2em;
  }
  .author {
    width: 100%;
    height: 50px;
    font-size: 15px;
    font-family: "微软雅黑";
    margin: 0 auto;
    padding: 15px;
    text-align: right;
  }
  .created_at {
    width: 100%;
    height: 50px;
    font-size: 15px;
    font-family: "微软雅黑";
    margin: 0 auto;
    padding: 15px;
    text-align: right;
  }
}
</style>

首页

<template>
  <a-layout>
    <a-layout-header class="header">
      <a-menu
        v-model:selectedKeys="selectedKeys1"
        theme="dark"
        mode="horizontal"
        :style="{ lineHeight: '64px' }"
      >
        <a-menu-item key="1">
          <router-link to="/shouye"> 首页 </router-link>
        </a-menu-item>
        <a-menu-item key="2">
          <router-link to="/fenlei">文章分类 </router-link>
        </a-menu-item>
        <a-menu-item key="3">
          <router-link to="/biaoqian"> 标签 </router-link>
        </a-menu-item>
        <a-menu-item key="4">
          <router-link to="/fabu"> 发布 </router-link>
        </a-menu-item>
        <a-menu-item key="5" class="yidong">
          <router-link to="/login">登录</router-link>
        </a-menu-item>
        <a-menu-item key="6">
          <router-link to="/register">注册</router-link>
        </a-menu-item>
      </a-menu>
    </a-layout-header>
    <a-layout>
      <a-layout-sider width="200" style="background: #fff">
        <a-menu
          v-model:selectedKeys="selectedKeys2"
          v-model:openKeys="openKeys"
          mode="inline"
          :style="{ height: '100%', borderRight: 0 }"
        >
          <a-sub-menu key="sub1">
            <template #title>
              <span>
                <user-outlined />
                分类列表
              </span>
            </template>
            <a-menu-item key="1">
              <router-link to="/jishuzhan"> 技术栈 </router-link>
            </a-menu-item>
            <a-menu-item key="2">
              <router-link to="/duanwen"> 精品短文 </router-link>
            </a-menu-item>
            <a-menu-item key="3">
              <router-link to="/hotpage"> 热门文章 </router-link>
            </a-menu-item>
          </a-sub-menu>
          <a-sub-menu key="sub2">
            <template #title>
              <span>
                <laptop-outlined />
                更多
              </span>
            </template>
            <a-menu-item key="5">
              <router-link to="/fenxi"> 数据分析 </router-link>
            </a-menu-item>
            <a-menu-item key="6">
              <router-link to="/newping"> 评论审查 </router-link>
            </a-menu-item>
            <a-menu-item key="7">
              <router-link to="/history"> 浏览历史 </router-link>
            </a-menu-item>
            <a-menu-item key="8">
              <router-link to="/huishou"> 回收站 </router-link>
            </a-menu-item>
          </a-sub-menu>
          <a-sub-menu key="sub3">
            <template #title>
              <span>
                <notification-outlined />
                关于作者
              </span>
            </template>
            <a-menu-item key="9">个人简介</a-menu-item>
            <a-menu-item key="10">联系方式</a-menu-item>
            <a-menu-item key="11">友情链接</a-menu-item>
            <a-menu-item key="12">
              <router-link to="/lixiang"> 立项要求 </router-link>
            </a-menu-item>
          </a-sub-menu>
        </a-menu>
      </a-layout-sider>
      <a-layout style="padding: 0 24px 24px">
        <a-breadcrumb style="margin: 16px 0">
          <a-breadcrumb-item>
            <router-link to="/shouye">首页</router-link>
          </a-breadcrumb-item>
          <a-breadcrumb-item>
            {{ breadcrumbNameMap[$route.path] }}
          </a-breadcrumb-item>
        </a-breadcrumb>
        <a-layout-content
          :style="{
            background: '#fff',
            padding: '24px',
            margin: 0,
            minHeight: '280px',
          }"
        >
          <router-view />
        </a-layout-content>
      </a-layout>
    </a-layout>
    <Footer class="main" />
  </a-layout>
</template>
<script setup>
import { ref, computed } from "vue";
import Footer from "../components/footer.vue";

const selectedKeys1 = ref(["1"]);
const selectedKeys2 = ref(["2"]);
const collapsed = ref(false);
const openKeys = ref(["sub1"]);

// 定义面包屑
const breadcrumbNameMap = {
  "/shouye": "首页",
  "/fenlei": "文章分类",
  "/biaoqian": "标签",
  "/fabu": "发布",
  "/login": "登录",
  "/register": "注册",
  "/lixiang": "立项要求",
};

const currentBreadcrumb = computed(() => breadcrumbNameMap[$route.path]);
</script>
<style>
.yidong {
  margin-left: 900px;
}

#components-layout-demo-top-side-2 .logo {
  float: left;
  width: 120px;
  height: 31px;
  margin: 16px 24px 16px 0;
  background: rgba(255, 255, 255, 0.3);
}

.ant-row-rtl #components-layout-demo-top-side-2 .logo {
  float: right;
  margin: 16px 0 16px 24px;
}

.site-layout-background {
  background: #fff;
}

.main {
  margin: 0 auto;
  /* 固定底部 */
}
</style>

回收站模块

<template>
  <div class="main">
    <h1>回收站</h1>
    <div v-for="item in state" :key="item.id">
      <h4>标题:{{ item.title }}</h4>
      <p>内容:{{ item.content }}</p>
      <p>作者:{{ item.author }}</p>
      <p>创建时间:{{ item.created_at }}</p>
      <!-- 其他需要展示的内容 -->
      <a-button @click="bankFn(item.id)">恢复</a-button>
      <a-button>彻底删除</a-button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import { showPassageApi, recoverPassageApi } from "../utils/api";

const state = ref({});

// 获取showPassageApi
const data = async () => {
  const res = await showPassageApi();
  console.log(res);
  // 将过滤后的数据添加到state中
  res.data.forEach((item) => {
    // 过滤数据is_deleted为1的数据
    if (item.is_deleted === 1) {
      state.value[item.id] = item;
      console.log(item);
    }
  });
};

onMounted(() => {
  data();
});

// 恢复
const bankFn = (id) => {
  console.log(id);
  recoverPassageApi({ id: id }).then((res) => {
    console.log(res);
  });
// 删除当前行
  delete state.value[id];
};
</script>

<style lang="less" scoped>
.main {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  h3 {
    margin-top: 20px;
  }
  div {
    width: 100%;
    height: 220px;
    border: 1px solid #ccc;
    margin-top: 20px;
    padding: 10px;
    h4 {
      font-size: 20px;
    }
    p {
      font-size: 16px;
    }
  }
}
</style>

历史记录模块

<template>
  <div>
    <h2>浏览记录</h2>
    <ul v-for="page in history" :key="page">
      <li >{{ page.title }}</li>
      <li>{{ page.author }}</li>
      <li>{{ page.content }}</li>
      <li>{{ page.time }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      history: [],
    };
  },
  created() {
    // 读取本地存储的浏览记录
    const savedHistory = localStorage.getItem("history");
    if (savedHistory) {
      this.history = JSON.parse(savedHistory);
    }
  },
  methods: {
    addToHistory(page) {
      this.history.push(page);
      // 存储浏览记录到localStorage
      localStorage.setItem("history", JSON.stringify(this.history));
    },
  },
};
</script>

发布模块

<template>
  <a-form :form="form" @submit="handleSubmit">
    <a-form-item label="标题" name="title">
      <a-input v-model:value="form.title" />
    </a-form-item>
    <a-form-item label="内容" name="content">
      <a-textarea v-model:value="form.content" />
    </a-form-item>
    <a-form-item label="作者" name="author_id">
      <a-select v-model:value="form.author_name">
        <a-select-option
          v-for="author in authors"
          :key="author.id"
          :value="author.name"
        >
          {{ author.name }}
        </a-select-option>
      </a-select>
    </a-form-item>
    <a-form-item label="分类" name="category_id">
      <a-select v-model:value="form.category_id">
        <a-select-option
          v-for="category in categories"
          :key="category.id"
          :value="category.id"
        >
          {{ category.name }}
        </a-select-option>
      </a-select>
    </a-form-item>
    <a-form-item>
      <a-button type="primary" html-type="submit">发布</a-button>
    </a-form-item>
  </a-form>
</template>

<script setup>
import { ref } from "vue";
import { message } from "ant-design-vue";
import { addPassageApi, showCategoryApi } from "../utils/api.js";

// 获取浏览器当前登录用户的信息
const currentUser = localStorage.getItem("username");
const currentUserId = localStorage.getItem("id");

const authors = [{ id: currentUserId, name: currentUser }];

const categories = ref([]);

const formatDate = (date) => {
  const year = date.getFullYear();
  const month = (date.getMonth() + 1).toString().padStart(2, "0");
  const day = date.getDate().toString().padStart(2, "0");
  const hours = date.getHours().toString().padStart(2, "0");
  const minutes = date.getMinutes().toString().padStart(2, "0");
  const seconds = date.getSeconds().toString().padStart(2, "0");
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};

const form = ref({
  title: "",
  content: "",
  author_name: currentUser, // 使用当前用户名作为初始值
  category_id: null,
});

const handleSubmit = () => {
  const currentDate = new Date();

  form.value.created_at = formatDate(currentDate);
  form.value.updated_at = formatDate(currentDate);
  form.value.published_at = formatDate(currentDate);

  console.log(form.value);
  addPassageApi({
    title: form.value.title,
    content: form.value.content,
    author: form.value.author_name,
    category_id: form.value.category_id,
    created_at: form.value.created_at,
    updated_at: form.value.updated_at,
    published_at: form.value.published_at,
  }).then((res) => {
    console.log(res);
  });

  message.success("文章发布成功");
};

// 获取showCategoryApi()接口返回的数据
showCategoryApi().then((res) => {
  categories.value = res.data.map((item) => ({
    id: item.id,
    name: item.name,
  }));
  console.log(categories.value);
});

</script>

<style scoped>
.a-form-item {
  margin-bottom: 24px;
}
</style>

后端基本的接口

const express = require("express");
const router = express.Router();

const db = require("../utils/db");

// 文章接口

// 获取全部文章
router.post("/api/articleadd", (req, res) => {
  let sql = `select * from articles`;
  db.query(sql, (err, result) => {
    if (err) {
      res.json({
        status: 500,
        msg: "服务器内部错误",
      });
    } else {
      res.json({
        code: 200,
        msg: "获取成功",
        data: result,
      });
    }
  });
});

// 添加文章
router.post("/api/article", (req, res) => {
  const {
    title,
    content,
    author,
    category_id,
    created_at,
    updated_at,
    published_at,
  } = req.body;
  console.log(req.body);
  // 将文章信息保存到数据库
  const sql =
    "INSERT INTO articles (title, content, author, category_id, created_at, updated_at, published_at) VALUES (?, ?, ?, ?, ?, ?, ?)";
  const values = [
    title,
    content,
    author,
    category_id,
    created_at,
    updated_at,
    published_at,
  ];
  db.query(sql, values, (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "保存文章信息失败" });
    } else {
      res.json({ message: "保存文章信息成功" });
    }
  });
});

// export const getArticleById = (params) =>request.post("/api/articleById",params);
router.post("/api/articleById", (req, res) => {
  const { id } = req.body;
  console.log(req.body);
  const sql = "SELECT * FROM articles WHERE id = ?";
  db.query(sql, [id], (err, result) => {
    if (err) {
      console.error(err);
      res.send({ code: 500, msg: "获取文章信息失败" });
    } else {
      res.send({
        code: 200,
        msg: "获取成功",
        data: result,
      });
    }
  });
});

// export const getCategoryById = (params) =>request.post("/api/categoryById",params);

router.post("/api/categoryById", (req, res) => {
  const { id } = req.body;
  const sql = "SELECT * FROM categories WHERE id = ?";
  db.query(sql, [id], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "获取分类信息失败" });
    } else {
      res.json(result);
    }
  });
});

// export const searchApi = (params) =>reque st.post("/api/search",params);
router.post("/api/search", (req, res) => {
  const { searchValue } = req.body;
  let keyword = searchValue;
  const sql = `SELECT * FROM articles WHERE title LIKE '%${keyword}%'`;
  db.query(sql, (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "搜索失败" });
    } else {
      res.send({
        code: 200,
        msg: "获取成功",
        data: result,
      });
    }
  });
});

// export const getTagBytag = (params) =>request.post("/api/tagById",params);
router.post("/api/tagBytag", (req, res) => {
  const { tag } = req.body;
  const name = tag;
  const sql = "INSERT INTO tags (name) VALUES (?)"; // Modify the SQL statement to insert the name
  db.query(sql, [name], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "插入标签信息失败" }); // Update the error message for insertion failure
    } else {
      res.json(result);
    }
  });
});

// export const showTagApi = () => request.post("/api/tagadd");
router.post("/api/tagadd", (req, res) => {
  const sql = "SELECT * FROM tags";
  db.query(sql, (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "获取标签信息失败" });
    } else {
      res.json(result);
    }
  });
});

// export const addCommentApi = (params) => request.post("/api/comment", params);
router.post("/api/comment", (req, res) => {
  const { article_id, user_id, content, created_at, updated_at } = req.body;
  console.log(req.body);
  const sql =
    "INSERT INTO comments (article_id,user_id, content, created_at, updated_at) VALUES (?, ?, ?, DEFAULT, DEFAULT)";
  const values = [article_id, user_id, content, created_at, updated_at];
  db.query(sql, values, (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "保存评论信息失败" });
    } else {
      res.json({ message: "保存评论信息成功" });
    }
  });
});

// 删除文章
// export const deletePassageApi = (params) => request.post("/api/articledelete", params);
router.post("/api/articledelete", (req, res) => {
  const { id } = req.body;
  const sql = "UPDATE articles SET is_deleted = 1 WHERE id = ?";
  db.query(sql, [id], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "修改文章状态失败" });
    } else {
      res.send({
        code: 200,
        msg: "删除成功",
        data: result,
      });
    }
  });
});

// 恢复文章
// export const recoverPassageApi = (params) => request.post("/api/articlerecover", params);
router.post("/api/articlerecover", (req, res) => {
  const { id } = req.body;
  const sql = "UPDATE articles SET is_deleted = 0 WHERE id = ?";
  db.query(sql, [id], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "修改文章状态失败" });
    } else {
      res.send({
        code: 200,
        msg: "恢复成功",
        data: result,
      });
    }
  });
});

// export const getCommentApi = (params) => request.post("/api/getComment", params);
// 根据文章id获取评论
router.post("/api/getComment", (req, res) => {
  const { article_id } = req.body;
  const sql = "SELECT * FROM comments WHERE article_id = ?";
  db.query(sql, [article_id], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "获取评论信息失败" });
    } else {
      res.json(result);
    }
  });
});

// export const getAllCommentApi = () => request.post("/api/getAllComment");
// 获取全部评论
router.post("/api/getAllComment", (req, res) => {
  const sql = "SELECT * FROM comments";
  db.query(sql, (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "获取评论信息失败" });
    } else {
      res.send({
        code: 200,
        msg: "获取成功",
        data: result,
      });
    }
  });
});

// export const checkCommentApi = (params) => request.post("/api/checkComment", params);
// 审核评论
router.post("/api/checkComment", (req, res) => {
  const { id, approved } = req.body;
  console.log(req.body);
  const sql = "UPDATE comments SET approved = ? WHERE id = ?";
  db.query(sql, [approved, id], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "审核评论失败" });
    } else {
      res.json({ message: "审核评论成功" });
    }
  });
});

// export const addCategoryApi = (params) => request.post("/api/category", params);
router.post("/api/category", (req, res) => {
  const { name } = req.body;
  console.log(req.body);
  const sql = "INSERT INTO categories (name) VALUES (?)";
  db.query(sql, [name], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "添加分类失败" });
    } else {
      res.send({
        code: 200,
        msg: "添加成功",
        data: result,
      });
    }
  });
});

// export const showCategoryApi = () => request.post("/api/categoryadd");
router.post("/api/categoryadd", (req, res) => {
  const sql = "SELECT * FROM categories";
  db.query(sql, (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "获取分类信息失败" });
    } else {
      res.send({
        code: 200,
        msg: "获取成功",
        data: result,
      });
    }
  });
});

// export const deleteCategoryApi = (params) => request.post("/api/categorydelete", params);
router.post("/api/categorydelete", (req, res) => {
  const { id } = req.body;
  console.log(req.body);
  const sql = "DELETE FROM categories WHERE id = ?";
  db.query(sql, [id], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "删除分类失败" });
    } else {
      res.json({ message: "删除分类成功" });
    }
  });
});
 
// export const addLikeApi = (params) => request.post("/api/like", params);
router.post("/api/like", (req, res) => {
  const { article_id, likes_count } = req.body;
  console.log(req.body);
  const sql =
    "INSERT INTO articles_like (article_id, likes_count) VALUES (?, ?)";
  const values = [article_id, likes_count];
  db.query(sql, values, (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "保存点赞信息失败" });
    } else {
      // 获取点赞信息
      res.send({
        code: 200,
        msg: "保存成功",
        data: result,
      });
    }
  });
});

// export const getLikeApi = (params) => request.post("/api/getLike", params);
router.post("/api/getLike", (req, res) => {
  const { article_id } = req.body;
  const sql = "SELECT * FROM articles_like WHERE article_id = ?";
  db.query(sql, [article_id], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "获取点赞信息失败" });
    } else {
      res.send({
        code: 200,
        msg: "获取成功",
        data: result,
      });
    }
  });
});

// export const addCountApi = (params) => request.post("/api/count", params);
router.post("/api/count", (req, res) => {
  // 根据articles表中的article_id字段,插入到views_count字段
  const { id, views_count } = req.body;
  console.log(req.body);
  const sql = "UPDATE articles SET views_count = ? WHERE id = ?";
  db.query(sql, [views_count, id], (err, result) => {
    if (err) {
      console.error(err);
      res.status(500).json({ message: "保存浏览量信息失败" });
    } else {
      res.json({ message: "保存浏览量信息成功" });
    }
  });
});

module.exports = router;

你可能感兴趣的:(express,vue.js,前端,node.js)