写接口
This commit is contained in:
parent
5c9b297760
commit
54c35687c9
@ -1,10 +1,43 @@
|
|||||||
/* 淡入淡出动画 */
|
.indexFade-enter-active,
|
||||||
.fade-enter-active,
|
.indexFade-leave-active {
|
||||||
.fade-leave-active {
|
|
||||||
transition: opacity 0.3s ease;
|
transition: opacity 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter-from,
|
.indexFade-enter-from,
|
||||||
.fade-leave-to {
|
.indexFade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
/* 淡入淡出动画 */
|
||||||
|
|
||||||
|
.slide-enter-active,
|
||||||
|
.slide-leave-active {
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
}
|
||||||
|
.slide-enter-from,
|
||||||
|
.slide-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(100%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-left-enter-active,
|
||||||
|
.slide-left-leave-active,
|
||||||
|
.slide-right-enter-active,
|
||||||
|
.slide-right-leave-active {
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.slide-left-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(50px, 0);
|
||||||
|
}
|
||||||
|
.slide-left-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50px, 0);
|
||||||
|
}
|
||||||
|
.slide-right-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50px, 0);
|
||||||
|
}
|
||||||
|
.slide-right-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(50px, 0);
|
||||||
|
}
|
111
docs/06-Nuxt生命周期.md
Normal file
111
docs/06-Nuxt生命周期.md
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# Nuxt HTTP 请求生命周期
|
||||||
|
|
||||||
|
当一个 HTTP 请求发送到 Nuxt 应用时,它会经过一系列步骤,下面是完整的请求生命周期:
|
||||||
|
|
||||||
|
## 服务器端处理
|
||||||
|
|
||||||
|
### 1. Nitro 服务器初始化(仅一次)
|
||||||
|
|
||||||
|
- Nitro 服务器启动并初始化 `/server/plugins` 目录下的插件
|
||||||
|
- 这些插件只在服务器启动时执行一次
|
||||||
|
- 在无服务器环境中,每个请求都会启动服务器,但插件不会被等待执行完成
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-1-setup-nitro-server-and-nitro-plugins-once)
|
||||||
|
|
||||||
|
### 2. Nitro 服务器中间件
|
||||||
|
|
||||||
|
- 对于每个请求,执行 `server/middleware/` 下的中间件
|
||||||
|
- 这些中间件可用于身份验证、日志记录或请求转换
|
||||||
|
- 如果中间件返回值,请求将终止并将返回值作为响应
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-2-nitro-server-middleware)
|
||||||
|
|
||||||
|
### 3. 请求路由分发
|
||||||
|
|
||||||
|
根据请求路径,Nitro 将请求分发到不同的处理程序:
|
||||||
|
|
||||||
|
- 如果请求路径匹配 `/api/*`,则路由到 API 处理程序(`server/api/` 目录)
|
||||||
|
- 如果请求路径匹配 `server/routes/` 中定义的路由,则路由到相应的处理程序
|
||||||
|
- 如果是页面请求,则继续 Nuxt 应用的初始化
|
||||||
|
|
||||||
|
[服务器目录结构](https://nuxt.com/docs/guide/directory-structure/server)
|
||||||
|
|
||||||
|
### 4. API 处理(如果是 API 请求)
|
||||||
|
|
||||||
|
- 如果请求匹配 `server/api/` 目录中的路由,相应的处理程序将被执行
|
||||||
|
- 处理程序可以直接返回 JSON 数据、Promise 或使用 `event.node.res.end()` 发送响应
|
||||||
|
- API 处理完成后,请求结束,不会继续到 Vue 应用
|
||||||
|
|
||||||
|
[服务器 API](https://nuxt.com/docs/guide/directory-structure/server)
|
||||||
|
|
||||||
|
### 5. Nuxt 应用初始化(如果是页面请求)
|
||||||
|
|
||||||
|
- 创建 Vue 和 Nuxt 实例
|
||||||
|
- 执行 Nuxt 服务器插件,包括内置插件和 `plugins/` 目录中的自定义插件
|
||||||
|
- 调用 `app:created` 钩子
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-3-initialize-nuxt-and-execute-nuxt-app-plugins)
|
||||||
|
|
||||||
|
### 6. 路由验证
|
||||||
|
|
||||||
|
- 如果在 `definePageMeta` 中定义了 `validate` 方法,则调用该方法验证动态路由参数
|
||||||
|
- 如果验证失败,可能会终止请求或重定向
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-4-route-validation)
|
||||||
|
|
||||||
|
### 7. 执行 Nuxt 应用中间件
|
||||||
|
|
||||||
|
- 执行全局路由中间件、命名路由中间件和匿名路由中间件
|
||||||
|
- 中间件可以执行重定向,这会导致浏览器收到 `Location:` 头并发起新请求
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-5-execute-nuxt-app-middleware)
|
||||||
|
|
||||||
|
### 8. 页面和组件设置
|
||||||
|
|
||||||
|
- 初始化页面和组件
|
||||||
|
- 使用 `useFetch` 和 `useAsyncData` 获取所需数据
|
||||||
|
- 服务器端不执行 Vue 生命周期钩子如 `onBeforeMount`、`onMounted` 等
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-6-setup-page-and-components)
|
||||||
|
|
||||||
|
### 9. 渲染和生成 HTML 输出
|
||||||
|
|
||||||
|
- 将组件与 `unhead` 设置结合生成完整的 HTML 文档
|
||||||
|
- 调用 `app:rendered` 钩子
|
||||||
|
- 调用 `render:html` 钩子,允许操作生成的 HTML
|
||||||
|
- 将 HTML 和相关数据发送回客户端
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-7-render-and-generate-html-output)
|
||||||
|
|
||||||
|
## 客户端处理
|
||||||
|
|
||||||
|
### 1. 执行 Nuxt 应用中间件
|
||||||
|
|
||||||
|
- 中间件在服务器端和客户端都会运行
|
||||||
|
- 可以使用 `import.meta.client` 和 `import.meta.server` 区分环境
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-3-execute-nuxt-app-middleware)
|
||||||
|
|
||||||
|
### 2. 挂载 Vue 应用和水合
|
||||||
|
|
||||||
|
- 调用 `app:beforeMount` 钩子
|
||||||
|
- 调用 `app.mount('#__nuxt')` 将 Vue 应用挂载到 DOM
|
||||||
|
- Vue 执行水合步骤,使客户端应用程序具有交互性
|
||||||
|
- 调用 `app:mounted` 钩子
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-4-mount-vue-application-and-hydration)
|
||||||
|
|
||||||
|
### 3. Vue 生命周期
|
||||||
|
|
||||||
|
- 浏览器执行完整的 Vue 生命周期
|
||||||
|
- 包括 `onBeforeMount`、`onMounted` 等钩子
|
||||||
|
|
||||||
|
[Nuxt 生命周期](https://nuxt.com/docs/guide/concepts/nuxt-lifecycle#step-5-vue-lifecycle)
|
||||||
|
|
||||||
|
## 重要说明
|
||||||
|
|
||||||
|
- 服务器端重定向会导致浏览器收到 `Location:` 头并发起新请求,所有应用状态将重置
|
||||||
|
- 中间件在服务器端渲染和客户端水合期间都会执行,可能导致代码执行两次
|
||||||
|
- 对于 API 请求,建议使用 `useAsyncData`、`useFetch` 等 SSR 友好的组合式函数,确保服务器端获取的数据在水合期间被重用
|
||||||
|
|
||||||
|
[通用渲染](https://nuxt.com/docs/guide/concepts/rendering#universal-rendering)
|
@ -1,10 +1,10 @@
|
|||||||
import { mysqlTable, index, primaryKey, unique, varchar, int, tinyint, datetime } from "drizzle-orm/mysql-core"
|
import { mysqlTable, index, primaryKey, unique, varchar, int, tinyint, datetime } from "drizzle-orm/mysql-core"
|
||||||
import { sql } from "drizzle-orm"
|
import { sql } from "drizzle-orm"
|
||||||
import { bigintString } from './customType.js';
|
import { bigintString } from '~/drizzle/customType';
|
||||||
const bigint = bigintString;
|
const bigint = bigintString;
|
||||||
export const blogMenu = mysqlTable("blog_menu", {
|
export const blogMenu = mysqlTable("blog_menu", {
|
||||||
id: bigint({ mode: "number" }).notNull(),
|
id: bigint({ mode: "number" }).notNull(),
|
||||||
pid: bigint({ mode: "number" }).notNull(),
|
pid: bigint({ mode: "number" }).default('0').notNull(),
|
||||||
name: varchar({ length: 255 }).notNull(),
|
name: varchar({ length: 255 }).notNull(),
|
||||||
desc: varchar({ length: 255 }),
|
desc: varchar({ length: 255 }),
|
||||||
icon: varchar({ length: 255 }).default("").notNull(),
|
icon: varchar({ length: 255 }).default("").notNull(),
|
||||||
|
@ -5,11 +5,9 @@
|
|||||||
<div class="homeLayout">
|
<div class="homeLayout">
|
||||||
<HomeHeader class="homeHeader"/>
|
<HomeHeader class="homeHeader"/>
|
||||||
<div class="homeMain">
|
<div class="homeMain">
|
||||||
<div class="homeMainLeft" name="left"></div>
|
|
||||||
<main class="homeMainContent">
|
<main class="homeMainContent">
|
||||||
<slot class="homeMainContent"/>
|
<slot name="default" class="homeMainContent"/>
|
||||||
</main>
|
</main>
|
||||||
<div class="homeMainRight" name="right"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -38,7 +36,7 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > div.homeMainLeft {
|
& > .homeMainLeft {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +46,7 @@
|
|||||||
background-color: var(--bg-color-be);
|
background-color: var(--bg-color-be);
|
||||||
}
|
}
|
||||||
|
|
||||||
& > div.homeMainRight {
|
& > .homeMainRight {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
18
modules/my-imports.ts
Normal file
18
modules/my-imports.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { defineNuxtModule, addImportsSources } from '@nuxt/kit'
|
||||||
|
|
||||||
|
export default defineNuxtModule({
|
||||||
|
meta: {
|
||||||
|
name: 'my-imports'
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
addImportsSources({
|
||||||
|
from: 'consola',
|
||||||
|
imports: [
|
||||||
|
// 列出您需要从consola导入的函数
|
||||||
|
'createConsola',
|
||||||
|
'consola'
|
||||||
|
// 其他需要的函数...
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
@ -13,6 +13,9 @@ export default defineNuxtConfig({
|
|||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
port: 3000,
|
port: 3000,
|
||||||
},
|
},
|
||||||
|
features: {
|
||||||
|
devLogs: 'silent' // 这是默认值,确保它没有被设置为 true,日志区分server和client, false为不在client打印
|
||||||
|
},
|
||||||
css: [
|
css: [
|
||||||
'~/assets/css/style.css',
|
'~/assets/css/style.css',
|
||||||
'~/assets/css/font.css',
|
'~/assets/css/font.css',
|
||||||
@ -40,12 +43,12 @@ export default defineNuxtConfig({
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
layoutTransition:{
|
layoutTransition:{
|
||||||
name: 'fade',
|
name: 'indexFade',
|
||||||
mode: 'out-in',
|
mode: 'out-in',
|
||||||
type: 'transition', // 明确指定动画类型
|
type: 'transition', // 明确指定动画类型
|
||||||
duration: {
|
duration: {
|
||||||
enter: 200,
|
enter: 300,
|
||||||
leave: 500
|
leave: 300
|
||||||
},
|
},
|
||||||
appear: true
|
appear: true
|
||||||
},
|
},
|
||||||
@ -92,6 +95,11 @@ export default defineNuxtConfig({
|
|||||||
'/docs/json'
|
'/docs/json'
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
defaultToken: {
|
||||||
|
username: process.env.USERNAME || 'expressgy',
|
||||||
|
nickname: process.env.PASSWORD || 'Nie',
|
||||||
|
userId: '1'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: 'home',
|
||||||
|
pageTransition: {
|
||||||
|
name: 'slide',
|
||||||
|
mode: 'out-in',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
const {data} = useFetch('/api/blog/blogMenu')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>Blog</div>
|
<div>内容SS{{data}}</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -1,6 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: 'home',
|
||||||
|
pageTransition: {
|
||||||
|
name: 'slide',
|
||||||
|
mode: 'out-in',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: 'home',
|
||||||
|
pageTransition: {
|
||||||
|
name: 'slide',
|
||||||
|
mode: 'out-in',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: 'home',
|
||||||
|
pageTransition: {
|
||||||
|
name: 'slide',
|
||||||
|
mode: 'out-in',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,27 +1,42 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import consola from "consola";
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: 'home',
|
||||||
|
pageTransition: {
|
||||||
|
name: 'slide',
|
||||||
|
mode: 'out-in',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
const {data} = await useFetch('/api/hello')
|
const {data} = await useFetch('/api/hello')
|
||||||
consola.info(toValue(data))
|
consola.info(toValue(data))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="homeIndex">
|
<div class="homeIndex">
|
||||||
<div>redisData: {{data}}</div>
|
<div>redisData: {{ data }}</div>
|
||||||
<div class="f1">汇文明朝体 ""“”| 星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890</div>
|
<div class="f1">汇文明朝体 ""“”|
|
||||||
<div class="f2">落霞孤鹜 ""“”| 星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890</div>
|
星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
|
||||||
<div class="f3">nice ""“”| 星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890</div>
|
</div>
|
||||||
<div class="f4">TechnicLite ""“”| 星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890</div>
|
<div class="f2">落霞孤鹜 ""“”|
|
||||||
<div class="f5">星撰</div>
|
星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
|
||||||
<div class="f6">6sans-serif ""“”| 星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890</div>
|
</div>
|
||||||
<div class="f7">default ""“”| 星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890</div>
|
<div class="f3">nice ""“”|
|
||||||
</div>
|
星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
|
||||||
|
</div>
|
||||||
|
<div class="f4">TechnicLite ""“”|
|
||||||
|
星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
|
||||||
|
</div>
|
||||||
|
<div class="f5">星撰</div>
|
||||||
|
<div class="f6">6sans-serif ""“”|
|
||||||
|
星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
|
||||||
|
</div>
|
||||||
|
<div class="f7">default ""“”|
|
||||||
|
星撰你好啊,你叫什么名字,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.homeIndex{
|
.homeIndex {
|
||||||
/* 定义英文字体 */
|
/* 定义英文字体 */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'MyEnglishFont';
|
font-family: 'MyEnglishFont';
|
||||||
@ -35,19 +50,24 @@ consola.info(toValue(data))
|
|||||||
src: local('LXGW WenKai');
|
src: local('LXGW WenKai');
|
||||||
unicode-range: U+201c, U+201d; /* 中文范围 */
|
unicode-range: U+201c, U+201d; /* 中文范围 */
|
||||||
}
|
}
|
||||||
div.f1{
|
|
||||||
|
div.f1 {
|
||||||
font-family: AA !important;
|
font-family: AA !important;
|
||||||
}
|
}
|
||||||
div.f2{
|
|
||||||
|
div.f2 {
|
||||||
font-family: 'LXGW WenKai';
|
font-family: 'LXGW WenKai';
|
||||||
}
|
}
|
||||||
div.f3{
|
|
||||||
|
div.f3 {
|
||||||
font-family: 'nice';
|
font-family: 'nice';
|
||||||
}
|
}
|
||||||
div.f4{
|
|
||||||
|
div.f4 {
|
||||||
font-family: 'TechnicLite';
|
font-family: 'TechnicLite';
|
||||||
}
|
}
|
||||||
div.f5{
|
|
||||||
|
div.f5 {
|
||||||
font-family: 'KingHwa_OldSong' !important;
|
font-family: 'KingHwa_OldSong' !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
pages/home/tools/index.vue
Normal file
17
pages/home/tools/index.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
definePageMeta({
|
||||||
|
layout: 'home',
|
||||||
|
pageTransition: {
|
||||||
|
name: 'slide',
|
||||||
|
mode: 'out-in',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>tools</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -8,9 +8,10 @@ const leaveTime = ref(false)
|
|||||||
// 离开前路由拦截
|
// 离开前路由拦截
|
||||||
onBeforeRouteLeave((to, from, next) => {
|
onBeforeRouteLeave((to, from, next) => {
|
||||||
leaveTime.value = true
|
leaveTime.value = true
|
||||||
|
consola.error('leave')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
next(true)
|
next(true)
|
||||||
}, 1300)
|
}, 1000)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export default defineEventHandler(event => {
|
export default defineEventHandler(event => {
|
||||||
return 'Hello blog/blogMenu.[blogId].delete' + event.context.params.blogId;
|
return 'Hello blog/blogMenu.[blogId].delete' + event.context.params?.blogId;
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export default defineEventHandler(event => {
|
export default defineEventHandler(event => {
|
||||||
return 'Hello blog/blogMenu.[blogId].patch' + event.context.params.blogId;
|
return 'Hello blog/blogMenu.[blogId].patch' + event.context.params?.blogId;
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export default defineEventHandler(event => {
|
export default defineEventHandler(event => {
|
||||||
return 'Hello blog/blogMenu.[blogId].update' + event.context.params.blogId;
|
return 'Hello blog/blogMenu.[blogId].update' + event.context.params?.blogId;
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
export default defineEventHandler(event => {
|
import {BlogMenuDB} from "~/server/services/blog/blogMenu";
|
||||||
return 'Hello blog/blogMenu.get'
|
import consola from "consola";
|
||||||
|
|
||||||
|
export default defineEventHandler(async event => {
|
||||||
|
// 获取登录信息
|
||||||
|
const headerAuth = event.context.auth
|
||||||
|
// 初始化DB
|
||||||
|
const blogMenuDB = new BlogMenuDB(event)
|
||||||
|
const resd = await blogMenuDB.getBlogMenu(headerAuth)
|
||||||
|
consola.info(resd)
|
||||||
|
return resd
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
export default defineEventHandler(event => {
|
export default defineEventHandler(async event => {
|
||||||
|
const requAuth = event.context.auth
|
||||||
|
const body = await readBody(event)
|
||||||
|
if(!requAuth.isTrue) {
|
||||||
|
// 判断为正常登录
|
||||||
|
throw createError({
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
return 'Hello blog/blogMenu.post'
|
return 'Hello blog/blogMenu.post'
|
||||||
})
|
})
|
||||||
|
@ -3,7 +3,6 @@ import consola from "consola";
|
|||||||
export default defineEventHandler(async event => {
|
export default defineEventHandler(async event => {
|
||||||
// console.log(await event.context.redis.get('SI HI'))
|
// console.log(await event.context.redis.get('SI HI'))
|
||||||
consola.info('API')
|
consola.info('API')
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
||||||
consola.info('API TimeOut')
|
consola.info('API TimeOut')
|
||||||
const result = await event.context.redis.get('SI HI');
|
const result = await event.context.redis.get('SI HI');
|
||||||
return {
|
return {
|
||||||
|
@ -2,10 +2,12 @@ import consola from "consola";
|
|||||||
export default defineEventHandler(event => {
|
export default defineEventHandler(event => {
|
||||||
// 跳过无需验证的路由
|
// 跳过无需验证的路由
|
||||||
if (event.path?.startsWith('/api/auth')) return
|
if (event.path?.startsWith('/api/auth')) return
|
||||||
|
const {defaultToken} = useRuntimeConfig()
|
||||||
|
|
||||||
const token = getHeader(event, 'Authorization')?.split('Bearer ')[1];
|
const token = getHeader(event, 'Authorization')?.split('Bearer ')[1];
|
||||||
const t = generateAccessToken({
|
const t = generateAccessToken({
|
||||||
name: event.path,
|
...defaultToken,
|
||||||
|
isTrue: false
|
||||||
})
|
})
|
||||||
consola.info(`Token ${t}`);
|
consola.info(`Token ${t}`);
|
||||||
|
|
||||||
|
@ -44,7 +44,8 @@ export default defineNitroPlugin(async nitroApp => {
|
|||||||
const db = drizzle(pool,{
|
const db = drizzle(pool,{
|
||||||
logger: {
|
logger: {
|
||||||
logQuery: (query, params) => {
|
logQuery: (query, params) => {
|
||||||
consola.debug(`SQL: ${query} - Params: ${JSON.stringify(params)}`); // 打印日志,包括查询和参数
|
console.log(`SQL: ${query} - Params: ${JSON.stringify(params, (_, v) =>
|
||||||
|
typeof v === 'bigint' ? v.toString() : v)}`); // 打印日志,包括查询和参数
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
40
server/services/blog/blogMenu.ts
Normal file
40
server/services/blog/blogMenu.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import type {EventHandlerRequest, H3Event} from "h3";
|
||||||
|
import type {MySql2Database, MySqlRawQueryResult} from "drizzle-orm/mysql2";
|
||||||
|
import type {RedisClient} from "ioredis/built/connectors/SentinelConnector/types";
|
||||||
|
import type {Pool} from "mysql2/promise";
|
||||||
|
import type {HeaderAuth} from "~/types/nuxt.config";
|
||||||
|
import {blogMenu} from "~/drizzle/schema";
|
||||||
|
import {and, asc, desc, eq} from "drizzle-orm";
|
||||||
|
|
||||||
|
type InsertBlogMenu = typeof blogMenu.$inferInsert;
|
||||||
|
|
||||||
|
export class BlogMenuDB {
|
||||||
|
private readonly db:MySql2Database<Record<string, never>>& { $client: Pool }
|
||||||
|
private readonly redis: RedisClient
|
||||||
|
constructor(event: H3Event<EventHandlerRequest>) {
|
||||||
|
this.db = event.context.mysql
|
||||||
|
this.redis = event.context.redis
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入目录
|
||||||
|
async insertBlogMenu(insertBlogMenu: InsertBlogMenu, headerAuth: HeaderAuth): Promise<MySqlRawQueryResult> {
|
||||||
|
const result = await this.db.insert(blogMenu).values({
|
||||||
|
...insertBlogMenu,
|
||||||
|
createdBy: headerAuth.userId,
|
||||||
|
})
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询目录
|
||||||
|
async getBlogMenu(headerAuth: HeaderAuth){
|
||||||
|
// 指定用户的
|
||||||
|
// 判断未删除的
|
||||||
|
// 如果是登陆的,可以查看未公开的,如果不是,只能查看公开的
|
||||||
|
return this.db
|
||||||
|
.select()
|
||||||
|
.from(blogMenu)
|
||||||
|
.where(
|
||||||
|
and(eq(blogMenu.createdBy, headerAuth.userId), eq(blogMenu.deleted, 0), headerAuth.isTrue ? undefined : eq(blogMenu.public, 1))
|
||||||
|
).orderBy(asc(blogMenu.sort), desc(blogMenu.createdAt));
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import * as schema from "../../drizzle/schema";
|
import * as schema from "~/drizzle/schema";
|
||||||
export function entity() {
|
export function entity() {
|
||||||
return schema
|
return schema
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
import type {StringValue} from "ms";
|
import type {StringValue} from "ms";
|
||||||
const {sign, verify} = jwt
|
const {sign, verify} = jwt
|
||||||
console.log(jwt)
|
|
||||||
// export function jwt() {}
|
|
||||||
|
|
||||||
|
|
||||||
export const generateAccessToken = (payload: object) => {
|
export const generateAccessToken = (payload: object) => {
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
{
|
{
|
||||||
// https://nuxt.com/docs/guide/concepts/typescript
|
// https://nuxt.com/docs/guide/concepts/typescript
|
||||||
"extends": "./.nuxt/tsconfig.json"
|
"extends": "./.nuxt/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"paths": {
|
||||||
|
// "~/*": ["./*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
7
types/nuxt.config.d.ts
vendored
7
types/nuxt.config.d.ts
vendored
@ -9,3 +9,10 @@
|
|||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
export type HeaderAuth = {
|
||||||
|
username: string;
|
||||||
|
nickname: string;
|
||||||
|
userId: string;
|
||||||
|
isTrue: boolean;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user