├── .eslintrc
├── .npmrc
├── types
├── IResult.ts
└── IUser.ts
├── public
├── 介绍.jpeg
├── 前端工程化.png
├── 大纲.jpeg
├── avatar.png
├── favicon.ico
├── qrcode.jpg
├── Docker部署.png
├── Node与服务器端.jpg
├── React全栈进阶.png
├── Vue3组件库实战.png
├── Vue源码全家桶.jpeg
├── webpack优化.jpeg
├── column-nuxt.png
└── course-nuxt.png
├── .vercel
└── output
│ ├── static
│ ├── favicon.ico
│ └── _nuxt
│ │ ├── app.config.e684eb09.js
│ │ ├── detail.37523c12.js
│ │ ├── index.d321cf39.js
│ │ ├── error-component.3b96486c.js
│ │ ├── error-500.5a01185b.js
│ │ ├── error-500.aa16ed4d.css
│ │ ├── error-404.7326de30.js
│ │ ├── error-404.23f2309d.css
│ │ └── nuxt-link.dd8747fa.js
│ ├── functions
│ └── __nitro.func
│ │ ├── index.mjs.map
│ │ ├── .vc-config.json
│ │ ├── chunks
│ │ ├── rollup
│ │ │ ├── _virtual_head-static.mjs.map
│ │ │ └── _virtual_head-static.mjs
│ │ ├── app
│ │ │ ├── _nuxt
│ │ │ │ ├── error-404-styles.a5c3f351.mjs.map
│ │ │ │ ├── error-500-styles.6b5b5ff2.mjs.map
│ │ │ │ ├── detail-94799639.mjs.map
│ │ │ │ ├── island-renderer-d2364c4c.mjs.map
│ │ │ │ ├── index-5689abd7.mjs.map
│ │ │ │ ├── detail-94799639.mjs
│ │ │ │ ├── error-500-d1baf535.mjs.map
│ │ │ │ ├── island-renderer-d2364c4c.mjs
│ │ │ │ ├── index-5689abd7.mjs
│ │ │ │ ├── app.config-a3bb0fb9.mjs
│ │ │ │ ├── app.config-a3bb0fb9.mjs.map
│ │ │ │ ├── error-500-styles.6b5b5ff2.mjs
│ │ │ │ ├── error-component-9ecfbe97.mjs
│ │ │ │ ├── error-404-59cb290a.mjs.map
│ │ │ │ ├── error-component-9ecfbe97.mjs.map
│ │ │ │ ├── error-500-d1baf535.mjs
│ │ │ │ ├── error-404-styles.a5c3f351.mjs
│ │ │ │ ├── error-404-59cb290a.mjs
│ │ │ │ ├── nuxt-link-58ca22a8.mjs.map
│ │ │ │ └── nuxt-link-58ca22a8.mjs
│ │ │ ├── styles.mjs.map
│ │ │ ├── styles.mjs
│ │ │ ├── client.manifest.mjs.map
│ │ │ └── client.manifest.mjs
│ │ ├── error-500.mjs.map
│ │ ├── error-500.mjs
│ │ ├── handlers
│ │ │ ├── renderer.mjs
│ │ │ └── renderer.mjs.map
│ │ └── nitro
│ │ │ └── vercel.mjs.map
│ │ ├── index.mjs
│ │ └── package.json
│ ├── nitro.json
│ └── config.json
├── .gitignore
├── store
├── counter.ts
└── user.ts
├── server
├── database
│ ├── client.ts
│ ├── migrations
│ │ ├── migration_lock.toml
│ │ ├── 20230509035903_init
│ │ │ └── migration.sql
│ │ ├── 20230509025205_init
│ │ │ └── migration.sql
│ │ └── 20230404135755_init
│ │ │ └── migration.sql
│ ├── repositories
│ │ ├── userRepository.ts
│ │ ├── columnRepository.ts
│ │ ├── courseRepository.ts
│ │ └── orderRepository.ts
│ ├── service
│ │ └── token.ts
│ ├── test.ts
│ ├── schema.prisma
│ └── seed.ts
└── api
│ ├── ordercomplete.post.ts
│ ├── order
│ └── [id].ts
│ ├── indexdata.ts
│ ├── purchased-course.ts
│ ├── column.ts
│ ├── course.ts
│ ├── column
│ └── [id].ts
│ ├── course
│ └── [id].ts
│ ├── order.post.ts
│ ├── userinfo.post.ts
│ ├── userinfo.get.ts
│ ├── login.post.ts
│ ├── register.post.ts
│ └── changePwd.post.ts
├── .env.template
├── pages
├── hello.vue
├── usercenter
│ ├── buy.vue
│ └── info.vue
├── index.vue
├── usercenter.vue
├── order-confirm.vue
├── list
│ └── [type].vue
├── order-pay.vue
├── login.vue
├── register.vue
└── [type]
│ └── detail
│ └── [id].vue
├── .vscode
└── settings.json
├── deploy.sh
├── composables
├── descrete.ts
├── auth.ts
└── request.ts
├── layouts
├── blank.vue
└── default.vue
├── tsconfig.json
├── Dockerfile
├── middleware
└── auth.ts
├── app.vue
├── test
└── index.spec.ts
├── error.vue
├── components
├── LoadingCourseSkeleton.vue
├── MyFooter.vue
├── Menu.vue
├── Catalogue.vue
├── ProdList.vue
├── Loading.vue
├── Tabs.vue
├── Counter.vue
├── Prod.vue
└── MyHeader.vue
├── .github
└── workflows
│ └── publish.yml
├── nuxt.config.ts
├── package.json
├── docker-compose.yml
└── README.md
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@antfu"
3 | }
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | shamefully-hoist=true
2 | strict-peer-dependencies=false
3 |
--------------------------------------------------------------------------------
/types/IResult.ts:
--------------------------------------------------------------------------------
1 | export interface IResult { ok: boolean; data: any }
2 |
--------------------------------------------------------------------------------
/public/介绍.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/介绍.jpeg
--------------------------------------------------------------------------------
/public/前端工程化.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/前端工程化.png
--------------------------------------------------------------------------------
/public/大纲.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/大纲.jpeg
--------------------------------------------------------------------------------
/public/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/avatar.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/qrcode.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/qrcode.jpg
--------------------------------------------------------------------------------
/public/Docker部署.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/Docker部署.png
--------------------------------------------------------------------------------
/public/Node与服务器端.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/Node与服务器端.jpg
--------------------------------------------------------------------------------
/public/React全栈进阶.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/React全栈进阶.png
--------------------------------------------------------------------------------
/public/Vue3组件库实战.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/Vue3组件库实战.png
--------------------------------------------------------------------------------
/public/Vue源码全家桶.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/Vue源码全家桶.jpeg
--------------------------------------------------------------------------------
/public/webpack优化.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/webpack优化.jpeg
--------------------------------------------------------------------------------
/public/column-nuxt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/column-nuxt.png
--------------------------------------------------------------------------------
/public/course-nuxt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/public/course-nuxt.png
--------------------------------------------------------------------------------
/types/IUser.ts:
--------------------------------------------------------------------------------
1 | export interface IUser {
2 | id?: number
3 | email: string
4 | name?: string
5 | }
6 |
--------------------------------------------------------------------------------
/.vercel/output/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/57code/nuxt-app/HEAD/.vercel/output/static/favicon.ico
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.log*
3 | .nuxt
4 | .nitro
5 | .cache
6 | .output
7 | .env
8 | dist
9 | .DS_Store
10 |
--------------------------------------------------------------------------------
/store/counter.ts:
--------------------------------------------------------------------------------
1 | export const useCounter = defineStore('count', {
2 | state: () => ({
3 | count: 1,
4 | }),
5 | })
6 |
--------------------------------------------------------------------------------
/store/user.ts:
--------------------------------------------------------------------------------
1 | export const useUser = defineStore('user', {
2 | state: () => ({
3 | userInfo: null,
4 | }),
5 | })
6 |
--------------------------------------------------------------------------------
/server/database/client.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from '@prisma/client'
2 |
3 | const prisma = new PrismaClient()
4 | export default prisma
5 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/index.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.mjs","sources":[],"sourcesContent":null,"names":[],"mappings":";;;;;;;;;;;;"}
--------------------------------------------------------------------------------
/.env.template:
--------------------------------------------------------------------------------
1 | DATABASE_URL="mysql://root:rootpassword@localhost:3306/ycxt"
2 | NUXT_BASE_URL=https://jsonplaceholder.typicode.com
3 | JSON_SECRET=thisisjsonsecret
--------------------------------------------------------------------------------
/pages/hello.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
--------------------------------------------------------------------------------
/.vercel/output/nitro.json:
--------------------------------------------------------------------------------
1 | {
2 | "date": "2023-02-24T01:03:34.451Z",
3 | "preset": "vercel",
4 | "commands": {
5 | "preview": "",
6 | "deploy": ""
7 | }
8 | }
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/app.config.e684eb09.js:
--------------------------------------------------------------------------------
1 | import{k as u,A as s}from"./entry.139a88d9.js";function a(e,n){return u()._useHead(e,n)}const o={};s(o);export{a as u};
2 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "prettier.enable": false,
3 | "editor.formatOnSave": false,
4 | "editor.codeActionsOnSave": {
5 | "source.fixAll.eslint": true
6 | }
7 | }
--------------------------------------------------------------------------------
/server/database/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (i.e. Git)
3 | provider = "mysql"
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/.vc-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "runtime": "nodejs16.x",
3 | "handler": "index.mjs",
4 | "launcherType": "Nodejs",
5 | "shouldAddHelpers": false
6 | }
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/rollup/_virtual_head-static.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"_virtual_head-static.mjs","sources":[],"sourcesContent":null,"names":[],"mappings":";;;;"}
--------------------------------------------------------------------------------
/server/database/migrations/20230509035903_init/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE `Column` ADD COLUMN `oPrice` DECIMAL(65, 30) NULL,
3 | ADD COLUMN `price` DECIMAL(65, 30) NULL;
4 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | echo Deploy Project
2 | # docker-compose up -d --force-recreate --build
3 |
4 | # 获取最新版代码
5 | git pull
6 |
7 | # 强制重新编译容器
8 | docker-compose down
9 | docker-compose up -d --force-recreate --build
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/detail.37523c12.js:
--------------------------------------------------------------------------------
1 | import{a as e,o as t,b as a}from"./entry.139a88d9.js";const c={};function n(o,r){return t(),a("h1",null,"Detail Page")}const l=e(c,[["render",n]]);export{l as default};
2 |
--------------------------------------------------------------------------------
/server/database/migrations/20230509025205_init/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE `Column` ADD COLUMN `url` VARCHAR(191) NULL;
3 |
4 | -- AlterTable
5 | ALTER TABLE `Course` ADD COLUMN `url` VARCHAR(191) NULL;
6 |
--------------------------------------------------------------------------------
/composables/descrete.ts:
--------------------------------------------------------------------------------
1 | import { createDiscreteApi } from 'naive-ui'
2 |
3 | export const { message, notification, dialog, loadingBar } = createDiscreteApi(
4 | ['message', 'dialog', 'notification', 'loadingBar'],
5 | )
6 |
--------------------------------------------------------------------------------
/layouts/blank.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // https://nuxt.com/docs/guide/concepts/typescript
3 | "extends": "./.nuxt/tsconfig.json",
4 | "compilerOptions": {
5 | "noImplicitAny": false
6 | },
7 | "ts-node": {
8 | "compilerOptions": {
9 | "module":"CommonJS"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | #Dockerfile
2 | #制定node镜像的版本
3 | FROM node:18-alpine
4 | #移动当前目录下面的文件到app目录下
5 | ADD . /app/
6 | #进入到app目录下面,类似cd
7 | WORKDIR /app
8 | #安装依赖
9 | RUN npm config set registry https://registry.npm.taobao.org/ && \
10 | npm i
11 | #对外暴露的端口
12 | EXPOSE 3000
13 | #程序启动脚本
14 | CMD ["npm", "start"]
--------------------------------------------------------------------------------
/middleware/auth.ts:
--------------------------------------------------------------------------------
1 | export default defineNuxtRouteMiddleware((to, from) => {
2 | const token = useCookie('token')
3 | const route = useRoute()
4 |
5 | // 未登录重定向到登录页
6 | if (!token.value) {
7 | if (process.client)
8 | message.error('请先登录')
9 |
10 | return navigateTo(`/login?from=${route.fullPath}`)
11 | }
12 | })
13 |
--------------------------------------------------------------------------------
/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/index.d321cf39.js:
--------------------------------------------------------------------------------
1 | import{_ as t}from"./nuxt-link.dd8747fa.js";import{a,o,b as n,e as c,w as s,F as _,f as r,h as d}from"./entry.139a88d9.js";const l={},i=r("h1",null,"Index Page",-1);function f(m,x){const e=t;return o(),n(_,null,[i,c(e,{to:"/detail"},{default:s(()=>[d("Detail Page")]),_:1})],64)}const h=a(l,[["render",f]]);export{h as default};
2 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/rollup/_virtual_head-static.mjs:
--------------------------------------------------------------------------------
1 | const _virtual__headStatic = {"headTags":"\n","bodyTags":"","bodyTagsOpen":"","htmlAttrs":"","bodyAttrs":""};
2 |
3 | export { _virtual__headStatic as default };
4 | //# sourceMappingURL=_virtual_head-static.mjs.map
5 |
--------------------------------------------------------------------------------
/composables/auth.ts:
--------------------------------------------------------------------------------
1 | export function logout() {
2 | // 清除状态
3 | const store = useUser()
4 | store.userInfo = null
5 |
6 | // 清cookie
7 | const token = useCookie('token')
8 | if (token.value)
9 | token.value = null
10 |
11 | message.success('退出登录成功')
12 |
13 | // 回到首页
14 | const route = useRoute()
15 | if (route.path !== '/')
16 | navigateTo('/')
17 | }
18 |
--------------------------------------------------------------------------------
/test/index.spec.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, test } from 'vitest'
2 | import { $fetch, setup } from '@nuxt/test-utils'
3 |
4 | describe('My test', async () => {
5 | await setup({
6 | // test context options
7 | })
8 |
9 | test('index page should be work', async () => {
10 | const html = await $fetch('/')
11 | expect(html).toMatch('
Index Page
')
12 | })
13 | })
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-404-styles.a5c3f351.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"error-404-styles.a5c3f351.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/error-404-styles-1.mjs-6ef6e240.js","/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/error-404-styles.a5c3f351.mjs"],"sourcesContent":null,"names":["style_0"],"mappings":"AAAA,MAAM,wDAA2D,GAAA,ukHAAA;;ACCjE,gCAAe,CAACA,wDAAO;;;;"}
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-500-styles.6b5b5ff2.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"error-500-styles.6b5b5ff2.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/error-500-styles-1.mjs-0a86f27a.js","/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/error-500-styles.6b5b5ff2.mjs"],"sourcesContent":null,"names":["style_0"],"mappings":"AAAA,MAAM,wDAA2D,GAAA,s6DAAA;;ACCjE,gCAAe,CAACA,wDAAO;;;;"}
--------------------------------------------------------------------------------
/server/api/ordercomplete.post.ts:
--------------------------------------------------------------------------------
1 | import { updateOrder } from '../database/repositories/orderRepository'
2 |
3 | export default defineEventHandler(async (e) => {
4 | const body = await readBody(e)
5 |
6 | try {
7 | await updateOrder(Number(body.id), { status: body.status })
8 | return { ok: true }
9 | }
10 | catch (error) {
11 | return sendError(e, createError('订单状态更新失败'))
12 | }
13 | })
14 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/styles.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"styles.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/styles.mjs"],"sourcesContent":null,"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,GAAE;AAChD,eAAe;AACf,EAAE,8DAA8D,EAAE,MAAM,OAAO,uCAAuC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;AAC5I,EAAE,8DAA8D,EAAE,MAAM,OAAO,uCAAuC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC;AAC5I;;;;"}
--------------------------------------------------------------------------------
/error.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 回到首页
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/components/LoadingCourseSkeleton.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/server/api/order/[id].ts:
--------------------------------------------------------------------------------
1 | import { getOrderById } from '~/server/database/repositories/orderRepository'
2 |
3 | export default defineEventHandler(async (e) => {
4 | // 获取订单id
5 | const id = e.context.params?.id ? parseInt(e.context.params.id) : undefined
6 | if (!id) {
7 | return sendError(e, createError({
8 | statusCode: 400,
9 | statusMessage: '缺少订单id',
10 | }))
11 | }
12 | const order = await getOrderById(id)
13 | return { ok: true, data: order }
14 | })
15 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/styles.mjs:
--------------------------------------------------------------------------------
1 | const interopDefault = r => r.default || r || [];
2 | const styles = {
3 | "node_modules/@nuxt/ui-templates/dist/templates/error-404.vue": () => import('./_nuxt/error-404-styles.a5c3f351.mjs').then(interopDefault),
4 | "node_modules/@nuxt/ui-templates/dist/templates/error-500.vue": () => import('./_nuxt/error-500-styles.6b5b5ff2.mjs').then(interopDefault)
5 | };
6 |
7 | export { styles as default };
8 | //# sourceMappingURL=styles.mjs.map
9 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/index.mjs:
--------------------------------------------------------------------------------
1 | globalThis._importMeta_={url:import.meta.url,env:process.env};import 'node-fetch-native/polyfill';
2 | import 'h3';
3 | import 'ufo';
4 | export { v as default } from './chunks/nitro/vercel.mjs';
5 | import 'ofetch';
6 | import 'destr';
7 | import 'unenv/runtime/fetch/index';
8 | import 'hookable';
9 | import 'scule';
10 | import 'ohash';
11 | import 'unstorage';
12 | import 'defu';
13 | import 'radix3';
14 | //# sourceMappingURL=index.mjs.map
15 |
--------------------------------------------------------------------------------
/components/MyFooter.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 | Copyright© 2023 by YCXT
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/server/api/indexdata.ts:
--------------------------------------------------------------------------------
1 | import { getNewColumns } from '../database/repositories/columnRepository'
2 | import { getNewCourses } from '../database/repositories/courseRepository'
3 |
4 | export default defineEventHandler(async (e) => {
5 | try {
6 | const columns = await getNewColumns()
7 | const courses = await getNewCourses()
8 |
9 | return { ok: true, data: { columns, courses } }
10 | }
11 | catch (error) {
12 | return sendError(e, createError('获取数据失败'))
13 | }
14 | })
15 |
--------------------------------------------------------------------------------
/components/Menu.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/layouts/default.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/server/api/purchased-course.ts:
--------------------------------------------------------------------------------
1 | import { isNuxtError } from 'nuxt/app'
2 | import { getCoursesByUser } from '../database/repositories/orderRepository'
3 | import { getTokenInfo } from '../database/service/token'
4 | export default defineEventHandler(async (e) => {
5 | try {
6 | const token = getTokenInfo(e)
7 |
8 | if (isNuxtError(token))
9 | return token
10 |
11 | const courses = await getCoursesByUser(token.id)
12 |
13 | return { ok: true, data: courses }
14 | }
15 | catch (error) {
16 | return sendError(e, createError('获取数据失败'))
17 | }
18 | })
19 |
--------------------------------------------------------------------------------
/server/api/column.ts:
--------------------------------------------------------------------------------
1 | import { getColumns } from '../database/repositories/columnRepository'
2 |
3 | export default defineEventHandler(async (e) => {
4 | try {
5 | // 获取分页信息
6 | const query = getQuery(e)
7 | const page = query.page ? parseInt(query.page as string) : 0
8 | const size = query.size ? parseInt(query.size as string) : 8
9 | // 分页获取课程列表和总条数
10 | const { columns, total } = await getColumns({ page, size })
11 |
12 | return { ok: true, data: { list: columns, total } }
13 | }
14 | catch (error) {
15 | return sendError(e, createError('获取数据失败'))
16 | }
17 | })
18 |
--------------------------------------------------------------------------------
/server/api/course.ts:
--------------------------------------------------------------------------------
1 | import { getCourses } from '../database/repositories/courseRepository'
2 |
3 | export default defineEventHandler(async (e) => {
4 | try {
5 | // 获取分页信息
6 | const query = getQuery(e)
7 | const page = query.page ? parseInt(query.page as string) : 0
8 | const size = query.size ? parseInt(query.size as string) : 8
9 | // 分页获取课程列表和总条数
10 | const { courses, total } = await getCourses({ page, size })
11 |
12 | return { ok: true, data: { list: courses, total } }
13 | }
14 | catch (error) {
15 | return sendError(e, createError('获取数据失败'))
16 | }
17 | })
18 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish Nuxt To HuaweiYun
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | jobs:
7 | PullSource:
8 | runs-on: ubuntu-latest
9 | name: "PullSource"
10 | steps:
11 | - name: Pull source
12 | uses: appleboy/ssh-action@v0.1.6
13 | with:
14 | host: "123.249.115.108"
15 | username: root
16 | key: ${{ secrets.ACCESS_TOKEN }}
17 | script: |
18 | cd /root/source/nuxt-app
19 | git checkout .
20 | docker-compose down
21 | docker-compose up -d --force-recreate --build
22 |
--------------------------------------------------------------------------------
/.vercel/output/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "overrides": {},
4 | "routes": [
5 | {
6 | "headers": {
7 | "cache-control": "public, max-age=2592000, immutable"
8 | },
9 | "src": "/_nuxt/.*"
10 | },
11 | {
12 | "src": "/_nuxt(.*)",
13 | "headers": {
14 | "cache-control": "public,max-age=31536000,immutable"
15 | },
16 | "continue": true
17 | },
18 | {
19 | "handle": "filesystem"
20 | },
21 | {
22 | "src": "/__nuxt_error",
23 | "dest": "/__nitro"
24 | },
25 | {
26 | "src": "/(.*)",
27 | "dest": "/__nitro"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/components/Catalogue.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 | -
17 |
18 | 第{{ index + 1 }}节
19 |
20 | {{ item.title }}
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/server/database/repositories/userRepository.ts:
--------------------------------------------------------------------------------
1 | import type { User } from '@prisma/client'
2 | import prisma from '~/server/database/client'
3 |
4 | export async function getUserByUsername(username: string): Promise {
5 | const result = await prisma.user.findUnique({
6 | where: {
7 | username,
8 | },
9 | })
10 | return result
11 | }
12 |
13 | export async function createUser(data: User) {
14 | const user = await prisma.user.create({ data })
15 | return user
16 | }
17 |
18 | export async function updateUser(id, data: Partial) {
19 | const user = await prisma.user.update({
20 | where: {
21 | id,
22 | },
23 | data,
24 | })
25 | return user
26 | }
27 |
--------------------------------------------------------------------------------
/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | export default defineNuxtConfig({
2 | imports: {
3 | dirs: ['store'],
4 | },
5 | modules: [
6 | '@unocss/nuxt',
7 | '@huntersofbook/naive-ui-nuxt',
8 | [
9 | '@pinia/nuxt',
10 | {
11 | autoImports: [
12 | // 自动引入 `defineStore(), storeToRefs()`
13 | 'defineStore',
14 | 'storeToRefs',
15 | ],
16 | },
17 | ],
18 | ],
19 | unocss: {
20 | uno: true, // enabled `@unocss/preset-uno`
21 | icons: true, // enabled `@unocss/preset-icons`
22 | attributify: true, // enabled `@unocss/preset-attributify`,
23 | // core options
24 | shortcuts: [],
25 | rules: [],
26 | safelist: [],
27 | },
28 | })
29 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/detail-94799639.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"detail-94799639.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/detail-94799639.js"],"sourcesContent":null,"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAcA,MAAM,YAAY,EAAC,CAAA;AACnB,SAAS,cAAe,CAAA,IAAA,EAAM,KAAO,EAAA,OAAA,EAAS,MAAQ,EAAA;AACpD,EAAM,KAAA,CAAA,CAAA,GAAA,EAAM,cAAe,CAAA,MAAM,CAAoB,CAAA,iBAAA,CAAA,CAAA,CAAA;AACvD,CAAA;AACA,MAAM,aAAa,SAAU,CAAA,KAAA,CAAA;AAC7B,SAAU,CAAA,KAAA,GAAQ,CAAC,KAAA,EAAO,GAAQ,KAAA;AAChC,EAAA,MAAM,aAAa,aAAc,EAAA,CAAA;AACjC,EAAC,CAAA,UAAA,CAAW,YAAY,UAAW,CAAA,OAAA,uBAA8B,GAAI,EAAA,CAAA,EAAI,IAAI,kBAAkB,CAAA,CAAA;AAC/F,EAAA,OAAO,UAAa,GAAA,UAAA,CAAW,KAAO,EAAA,GAAG,CAAI,GAAA,KAAA,CAAA,CAAA;AAC/C,CAAA,CAAA;AACM,MAAA,MAAA,+BAAqC,SAAW,EAAA,CAAC,CAAC,WAAa,EAAA,cAAc,CAAC,CAAC;;;;"}
--------------------------------------------------------------------------------
/server/api/column/[id].ts:
--------------------------------------------------------------------------------
1 | import { getColumnById, getColumns } from '~/server/database/repositories/columnRepository'
2 |
3 | export default defineEventHandler(async (e) => {
4 | const id = e.context.params?.id ? parseInt(e.context.params.id) : undefined
5 | if (!id)
6 | return sendError(e, createError({ statusCode: 400, statusMessage: '参数错误' }))
7 | try {
8 | const column = await getColumnById(id)
9 | if (!column)
10 | return sendError(e, createError({ statusCode: 404, statusMessage: '没有对应专栏' }))
11 |
12 | const { columns: recommend } = await getColumns({ page: 1, size: 2 })
13 |
14 | return { ok: true, data: { item: column, recommend } }
15 | }
16 | catch (error) {
17 | return sendError(e, createError({ statusCode: 500, statusMessage: '服务器错误' }))
18 | }
19 | })
20 |
--------------------------------------------------------------------------------
/server/api/course/[id].ts:
--------------------------------------------------------------------------------
1 | import { getCourseById, getCourses } from '~/server/database/repositories/courseRepository'
2 |
3 | export default defineEventHandler(async (e) => {
4 | const id = e.context.params?.id ? parseInt(e.context.params.id) : undefined
5 | if (!id)
6 | return sendError(e, createError({ statusCode: 400, statusMessage: '参数错误' }))
7 | try {
8 | const course = await getCourseById(id)
9 | if (!course)
10 | return sendError(e, createError({ statusCode: 404, statusMessage: '没有对应课程' }))
11 |
12 | const { courses: recommend } = await getCourses({ page: 1, size: 2 })
13 |
14 | return { ok: true, data: { item: course, recommend } }
15 | }
16 | catch (error) {
17 | return sendError(e, createError({ statusCode: 500, statusMessage: '服务器错误' }))
18 | }
19 | })
20 |
--------------------------------------------------------------------------------
/server/database/service/token.ts:
--------------------------------------------------------------------------------
1 | import jwt from 'jsonwebtoken'
2 |
3 | export function getTokenInfo(e) {
4 | let info
5 |
6 | const token = getCookie(e, 'token')
7 |
8 | // 令牌不存在
9 | if (!token) {
10 | return createError({
11 | statusCode: 401,
12 | statusMessage: 'token不存在!',
13 | })
14 | }
15 |
16 | try {
17 | // 解析token
18 | info = jwt.verify(token, process.env.JSON_SECRET!)
19 | const currentTime = Date.now() / 1000
20 |
21 | if (info.exp < currentTime) {
22 | return createError({
23 | statusCode: 401,
24 | statusMessage: 'token过期!',
25 | })
26 | }
27 |
28 | return info
29 | }
30 | catch (error) {
31 | return createError({
32 | statusCode: 401,
33 | statusMessage: 'token不合法!',
34 | })
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/components/ProdList.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 | {{ title }}
22 |
23 | 查看更多
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/server/api/order.post.ts:
--------------------------------------------------------------------------------
1 | import type { Order } from '@prisma/client'
2 | import { OrderStatus } from '@prisma/client'
3 | import { isNuxtError } from 'nuxt/app'
4 | import { getTokenInfo } from '../database/service/token'
5 | import { createOrder } from '../database/repositories/orderRepository'
6 |
7 | export default defineEventHandler(async (e) => {
8 | // 课程id
9 | const { courseId } = await readBody(e)
10 |
11 | // 用户id
12 | const result = getTokenInfo(e)
13 | if (isNuxtError(result))
14 | return sendError(e, result)
15 |
16 | // 构建订单实体
17 | const order = {
18 | courseId: Number(courseId),
19 | userId: result.id,
20 | createdAt: new Date(),
21 | status: OrderStatus.WAIT_CONFIRM,
22 | } as Order
23 |
24 | const o = await createOrder(order)
25 |
26 | return { ok: true, data: { orderId: o.id } }
27 | })
28 |
--------------------------------------------------------------------------------
/server/database/repositories/columnRepository.ts:
--------------------------------------------------------------------------------
1 | import type { Column } from '@prisma/client'
2 | import prisma from '~/server/database/client'
3 |
4 | export async function getNewColumns(): Promise {
5 | const result = await prisma.column.findMany({
6 | orderBy: { id: 'desc' },
7 | take: 4,
8 | })
9 | return result
10 | }
11 |
12 | export async function getColumns({ page, size }): Promise<{ columns: Column[] | null; total: number }> {
13 | const [columns, total] = await Promise.all([
14 | prisma.column.findMany({
15 | orderBy: { id: 'desc' },
16 | skip: page * size,
17 | take: size,
18 | }),
19 | prisma.column.count(),
20 | ])
21 | return { columns, total }
22 | }
23 |
24 | export async function getColumnById(id: number): Promise {
25 | const result = await prisma.column.findFirst({
26 | where: {
27 | id,
28 | },
29 | })
30 | return result
31 | }
32 |
--------------------------------------------------------------------------------
/components/Loading.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/components/Tabs.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
27 | {{ item.label }}
28 |
29 |
30 |
31 |
32 |
38 |
--------------------------------------------------------------------------------
/server/database/repositories/courseRepository.ts:
--------------------------------------------------------------------------------
1 | import type { Course } from '@prisma/client'
2 | import prisma from '~/server/database/client'
3 |
4 | export async function getNewCourses(): Promise {
5 | const result = await prisma.course.findMany({
6 | orderBy: { id: 'desc' },
7 | take: 4,
8 | })
9 | return result
10 | }
11 |
12 | export async function getCourses({ page, size }): Promise<{ courses: Course[] | null; total: number }> {
13 | const [courses, total] = await Promise.all([
14 | prisma.course.findMany({
15 | orderBy: { id: 'desc' },
16 | skip: page * size,
17 | take: size,
18 | }),
19 | prisma.course.count(),
20 | ])
21 | return { courses, total }
22 | }
23 |
24 | export async function getCourseById(id: number): Promise {
25 | const result = await prisma.course.findFirst({
26 | where: {
27 | id,
28 | },
29 | include: { Catalogue: true },
30 | })
31 | return result
32 | }
33 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/error-500.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"error-500.mjs","sources":["/Users/57code/nuxt-app/node_modules/@nuxt/ui-templates/dist/templates/error-500.mjs"],"sourcesContent":null,"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,cAAc,CAAC,aAAa,CAAC,uCAAuC,EAAC;AACvJ,MAAM,OAAO,GAAG,SAAS,EAAE,QAAQ,EAAE,EAAE;AACvC,IAAI,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC;AAClB,GAAG,IAAI,oCAAoC;AAC3C,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,UAAU,EAAE,KAAK,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC;AACpD,KAAK;AACL,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,aAAa,EAAE,KAAK,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC;AACvD,KAAK;AACL,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,OAAO,EAAE,KAAK,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC;AACjD,i1GAAi1G;AACj1G,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,UAAU,EAAE,KAAK,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC;AACpD,kFAAkF;AAClF,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC;AACrD,0BAA0B,CAAC;AAC3B,OAAO,GAAG;AACV,EAAC;AACD,MAAM,SAAS,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,SAAS,EAAE,GAAG,QAAQ,EAAE,EAAE,EAAC;AACxE,MAAC,QAAQ,GAAG;;;;"}
--------------------------------------------------------------------------------
/components/Counter.vue:
--------------------------------------------------------------------------------
1 |
41 |
42 |
43 |
44 | {{ transform(timeout) }}
45 |
46 |
47 |
--------------------------------------------------------------------------------
/server/database/test.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from '@prisma/client'
2 |
3 | const prisma = new PrismaClient()
4 |
5 | async function main() {
6 | // 插入一条数据
7 | // await prisma.user.create({
8 | // data: {
9 | // name: '村长',
10 | // email: 'yt0379@qq.com',
11 | // posts: {
12 | // create: {
13 | // title: '10分钟速通下一代ORM解决方案:Prisma',
14 | // },
15 | // },
16 | // },
17 | // })
18 |
19 | const post = await prisma.post.update({
20 | where: { id: 1 },
21 | data: { published: true },
22 | })
23 |
24 | // eslint-disable-next-line no-console
25 | console.log(post)
26 |
27 | // 查询所有用户
28 | const allUsers = await prisma.user.findMany({
29 | include: {
30 | posts: true,
31 | },
32 | })
33 |
34 | // console.log(allUsers)
35 | // eslint-disable-next-line no-console
36 | console.dir(allUsers, { depth: null })
37 | }
38 |
39 | main()
40 | .then(async () => {
41 | await prisma.$disconnect()
42 | })
43 | .catch(async (e) => {
44 | console.error(e)
45 | await prisma.$disconnect()
46 | process.exit(1)
47 | })
48 |
--------------------------------------------------------------------------------
/pages/usercenter/buy.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 | loading...
11 |
12 |
13 |
19 |
20 |
![]()
24 |
25 |
26 |
27 | {{ item.title }}
28 |
29 |
30 |
31 |
32 | 继续学习
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/server/api/userinfo.post.ts:
--------------------------------------------------------------------------------
1 | import { isNuxtError } from 'nuxt/app'
2 | import { updateUser } from '../database/repositories/userRepository'
3 | import { getTokenInfo } from '../database/service/token'
4 |
5 | export default defineEventHandler(async (e) => {
6 | // 验证权限
7 | const token = getTokenInfo(e)
8 |
9 | if (isNuxtError(token)) {
10 | return sendError(e, createError({
11 | statusCode: 401,
12 | statusMessage: 'token不合法!',
13 | }))
14 | }
15 |
16 | try {
17 | // 获取更新数据
18 | const body = await readBody(e)
19 |
20 | if (!body || body.username || body.password) {
21 | let statusMessage
22 | if (!body)
23 | statusMessage = '参数不存在'
24 | else if (body.username)
25 | statusMessage = '用户名不能修改'
26 | else
27 | statusMessage = '请使用修改密码接口'
28 | return sendError(e, createError({
29 | statusCode: 400,
30 | statusMessage,
31 | }))
32 | }
33 |
34 | const user = await updateUser(token.id, body)
35 | return { ok: true, data: user }
36 | }
37 | catch (error) {
38 | console.error(error)
39 | return sendError(e, createError('更新用户信息失败!'))
40 | }
41 | })
42 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/island-renderer-d2364c4c.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"island-renderer-d2364c4c.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/island-renderer-d2364c4c.js"],"sourcesContent":null,"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAcA,MAAM,qBAAqB,EAAC,CAAA;AAC5B,MAAM,gBAAA,0BAA0C,MAAO,CAAA;AAAA,EACrD,SAAW,EAAA,IAAA;AAAA,EACX,OAAS,EAAA,kBAAA;AACX,CAAC,CAAA,CAAA;AACD,MAAM,iCAAiD,eAAA,CAAA;AAAA,EACrD,KAAO,EAAA;AAAA,IACL,OAAS,EAAA;AAAA,MACP,IAAM,EAAA,MAAA;AAAA,MACN,QAAU,EAAA,IAAA;AAAA,KACZ;AAAA,GACF;AAAA,EACA,MAAM,MAAM,KAAO,EAAA;AACjB,IAAI,IAAA,EAAA,CAAA;AACJ,IAAA,MAAM,SAAY,GAAA,gBAAA,CAAiB,KAAM,CAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AACrD,IAAA,IAAI,CAAC,SAAW,EAAA;AACd,MAAA,MAAM,WAAY,CAAA;AAAA,QAChB,UAAY,EAAA,GAAA;AAAA,QACZ,aAAe,EAAA,CAAA,4BAAA,EAA+B,IAAK,CAAA,SAAA,CAAU,SAAS,CAAA,CAAA,CAAA;AAAA,OACvE,CAAA,CAAA;AAAA,KACH;AACA,IAAI,IAAA,OAAO,cAAc,QAAU,EAAA;AACjC,MAAA,OAAA,CAAQ,KAAK,SAAU,CAAA,aAAA,KAAkB,OAAO,KAAS,CAAA,GAAA,EAAA,CAAG,KAAK,SAAS,CAAA,CAAA,CAAA;AAAA,KAC5E;AACA,IAAA,OAAO,MAAM;AAAA,MACX,WAAY,CAAA,QAAA,EAAU,EAAE,EAAA,EAAI,eAAiB,EAAA,CAAC,CAAE,CAAA,SAAA,IAAa,MAAQ,EAAA,KAAA,CAAM,OAAQ,CAAA,KAAK,CAAC,CAAC,CAAA;AAAA,KAC5F,CAAA;AAAA,GACF;AACF,CAAC;;;;"}
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/error-component.3b96486c.js:
--------------------------------------------------------------------------------
1 | import{o as l,c as m,n as E,g as f,u as s,d as n,_ as o}from"./entry.139a88d9.js";const g={__name:"nuxt-error-page",props:{error:Object},setup(c){const{error:t}=c;(t.stack||"").split(`
2 | `).splice(1).map(e=>({text:e.replace("webpack:/","").replace(".vue",".js").trim(),internal:e.includes("node_modules")&&!e.includes(".cache")||e.includes("internal")||e.includes("new Promise")})).map(e=>`${e.text}`).join(`
3 | `);const r=Number(t.statusCode||500),a=r===404,u=t.statusMessage??(a?"Page Not Found":"Internal Server Error"),i=t.message||t.toString(),p=void 0,_=a?n(()=>o(()=>import("./error-404.7326de30.js"),["./error-404.7326de30.js","./nuxt-link.dd8747fa.js","./entry.139a88d9.js","./app.config.e684eb09.js","./error-404.23f2309d.css"],import.meta.url).then(e=>e.default||e)):n(()=>o(()=>import("./error-500.5a01185b.js"),["./error-500.5a01185b.js","./entry.139a88d9.js","./app.config.e684eb09.js","./error-500.aa16ed4d.css"],import.meta.url).then(e=>e.default||e));return(e,d)=>(l(),m(s(_),E(f({statusCode:s(r),statusMessage:s(u),description:s(i),stack:s(p)})),null,16))}},x=g;export{x as default};
4 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/index-5689abd7.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index-5689abd7.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/index-5689abd7.js"],"sourcesContent":null,"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAeA,MAAM,YAAY,EAAC,CAAA;AACnB,SAAS,cAAe,CAAA,IAAA,EAAM,KAAO,EAAA,OAAA,EAAS,MAAQ,EAAA;AACpD,EAAA,MAAM,mBAAsB,GAAA,kBAAA,CAAA;AAC5B,EAAA,KAAA,CAAM,CAA6B,2BAAA,CAAA,CAAA,CAAA;AACnC,EAAA,KAAA,CAAM,kBAAmB,CAAA,mBAAA,EAAqB,EAAE,EAAA,EAAI,WAAa,EAAA;AAAA,IAC/D,SAAS,OAAQ,CAAA,CAAC,CAAG,EAAA,MAAA,EAAQ,UAAU,QAAa,KAAA;AAClD,MAAA,IAAI,MAAQ,EAAA;AACV,QAAA,MAAA,CAAO,CAAa,WAAA,CAAA,CAAA,CAAA;AAAA,OACf,MAAA;AACL,QAAO,OAAA;AAAA,UACL,gBAAgB,aAAa,CAAA;AAAA,SAC/B,CAAA;AAAA,OACF;AAAA,KACD,CAAA;AAAA,IACD,CAAG,EAAA,CAAA;AAAA,GACL,EAAG,OAAO,CAAC,CAAA,CAAA;AACX,EAAA,KAAA,CAAM,CAAU,QAAA,CAAA,CAAA,CAAA;AAClB,CAAA;AACA,MAAM,aAAa,SAAU,CAAA,KAAA,CAAA;AAC7B,SAAU,CAAA,KAAA,GAAQ,CAAC,KAAA,EAAO,GAAQ,KAAA;AAChC,EAAA,MAAM,aAAa,aAAc,EAAA,CAAA;AACjC,EAAC,CAAA,UAAA,CAAW,YAAY,UAAW,CAAA,OAAA,uBAA8B,GAAI,EAAA,CAAA,EAAI,IAAI,iBAAiB,CAAA,CAAA;AAC9F,EAAA,OAAO,UAAa,GAAA,UAAA,CAAW,KAAO,EAAA,GAAG,CAAI,GAAA,KAAA,CAAA,CAAA;AAC/C,CAAA,CAAA;AACM,MAAA,KAAA,+BAAoC,SAAW,EAAA,CAAC,CAAC,WAAa,EAAA,cAAc,CAAC,CAAC;;;;"}
--------------------------------------------------------------------------------
/server/api/userinfo.get.ts:
--------------------------------------------------------------------------------
1 | import jwt from 'jsonwebtoken'
2 | import { getUserByUsername } from '../database/repositories/userRepository'
3 |
4 | export default defineEventHandler(async (e) => {
5 | // 获取令牌
6 | const token = getCookie(e, 'token')
7 |
8 | // 令牌不存在
9 | if (!token)
10 | return { ok: false }
11 |
12 | let info
13 | try {
14 | // 解析token
15 | info = jwt.verify(token, process.env.JSON_SECRET!)
16 | const currentTime = Date.now() / 1000
17 |
18 | if (info.exp < currentTime) {
19 | return sendError(e, createError({
20 | statusCode: 401,
21 | statusMessage: 'token过期!',
22 | }))
23 | }
24 | }
25 | catch (error) {
26 | return sendError(e, createError({
27 | statusCode: 401,
28 | statusMessage: 'token不合法!',
29 | }))
30 | }
31 |
32 | try {
33 | const user = await getUserByUsername(info.username)
34 |
35 | // 用户不存在
36 | if (!user) {
37 | return sendError(e, createError({
38 | statusCode: 401,
39 | statusMessage: '用户不存在!',
40 | }))
41 | }
42 | return { ok: true, data: user }
43 | }
44 | catch (error) {
45 | console.error(error)
46 | return sendError(e, createError('获取用户信息失败!'))
47 | }
48 | })
49 |
--------------------------------------------------------------------------------
/server/api/login.post.ts:
--------------------------------------------------------------------------------
1 | import bcrypt from 'bcryptjs'
2 | import jwt from 'jsonwebtoken'
3 | import type { User } from '@prisma/client'
4 | import { getUserByUsername } from '../database/repositories/userRepository'
5 |
6 | export default defineEventHandler(async (e) => {
7 | const { username, password } = await readBody(e)
8 |
9 | // 校验...
10 |
11 | try {
12 | // 获取用户
13 | const user = await getUserByUsername(username)
14 |
15 | if (!user) {
16 | return sendError(e, createError({
17 | statusCode: 401,
18 | statusMessage: '用户错误!',
19 | }))
20 | }
21 |
22 | // 校验密码
23 | const result = await bcrypt.compare(password, user.password)
24 |
25 | if (!result) {
26 | return sendError(e, createError({
27 | statusCode: 401,
28 | statusMessage: '密码错误!',
29 | }))
30 | }
31 |
32 | // 写入cookie
33 | const secret = process.env.JSON_SECRET as string
34 | const token = jwt.sign({ username: user.username, id: user.id }, secret, { expiresIn: '24h' })
35 | setCookie(e, 'token', token, { maxAge: 24 * 3600 })
36 |
37 | return { ok: true, data: user }
38 | }
39 | catch (error) {
40 | console.error(error)
41 | return sendError(e, createError('登录失败!'))
42 | }
43 | })
44 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/detail-94799639.mjs:
--------------------------------------------------------------------------------
1 | import { ssrRenderAttrs } from 'vue/server-renderer';
2 | import { useSSRContext } from 'vue';
3 | import { _ as _export_sfc } from '../server.mjs';
4 | import 'ofetch';
5 | import 'hookable';
6 | import 'unctx';
7 | import '@unhead/vue';
8 | import '@unhead/dom';
9 | import '@unhead/ssr';
10 | import 'vue-router';
11 | import 'h3';
12 | import 'ufo';
13 | import 'defu';
14 | import '../../nitro/vercel.mjs';
15 | import 'node-fetch-native/polyfill';
16 | import 'destr';
17 | import 'unenv/runtime/fetch/index';
18 | import 'scule';
19 | import 'ohash';
20 | import 'unstorage';
21 | import 'radix3';
22 |
23 | const _sfc_main = {};
24 | function _sfc_ssrRender(_ctx, _push, _parent, _attrs) {
25 | _push(`Detail Page
`);
26 | }
27 | const _sfc_setup = _sfc_main.setup;
28 | _sfc_main.setup = (props, ctx) => {
29 | const ssrContext = useSSRContext();
30 | (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/detail.vue");
31 | return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
32 | };
33 | const detail = /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender]]);
34 |
35 | export { detail as default };
36 | //# sourceMappingURL=detail-94799639.mjs.map
37 |
--------------------------------------------------------------------------------
/server/api/register.post.ts:
--------------------------------------------------------------------------------
1 | import bcrypt from 'bcryptjs'
2 | import jwt from 'jsonwebtoken'
3 | import type { User } from '@prisma/client'
4 | import { createUser, getUserByUsername } from '../database/repositories/userRepository'
5 |
6 | export default defineEventHandler(async (e) => {
7 | try {
8 | // 用户传递的参数
9 | const data = await readBody(e)
10 | const { username, password } = data
11 | // 校验...
12 |
13 | // 获取用户,存在同名用户
14 | const user = await getUserByUsername(username)
15 |
16 | if (user) {
17 | return sendError(e, createError({
18 | statusCode: 400,
19 | statusMessage: '用户名已存在!',
20 | }))
21 | }
22 |
23 | // 加密
24 | const salt = await bcrypt.genSalt(10)
25 | const hash = await bcrypt.hash(password, salt)
26 | data.password = hash
27 |
28 | // 入库
29 | const result = await createUser(data)
30 |
31 | // 生成token,写入cookie
32 | const secret = process.env.JSON_SECRET as string
33 | const token = jwt.sign({ username: result.username, id: result.id }, secret, { expiresIn: '24h' })
34 | setCookie(e, 'token', token, { maxAge: 24 * 3600 })
35 |
36 | return { ok: true, data: result }
37 | }
38 | catch (error) {
39 | console.error(error)
40 | return sendError(e, createError('注册失败!'))
41 | }
42 | })
43 |
--------------------------------------------------------------------------------
/pages/index.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
23 |
28 | {{ item.label }}
29 |
30 |
31 |
32 |
36 |
41 |
42 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "prisma": {
4 | "seed": "ts-node server/database/seed.ts"
5 | },
6 | "scripts": {
7 | "start": "nuxt start",
8 | "build": "nuxt build",
9 | "dev": "nuxt dev",
10 | "generate": "nuxt generate",
11 | "preview": "nuxt preview",
12 | "postinstall": "nuxt prepare",
13 | "lint": "eslint .",
14 | "lint:fix": "eslint . --fix",
15 | "test:unit": "vitest",
16 | "migrate": "npx prisma migrate dev --name init --schema server/database/schema.prisma",
17 | "seed": "npx prisma db seed",
18 | "clear":"npx prisma migrate reset --schema server/database/schema.prisma"
19 |
20 | },
21 | "devDependencies": {
22 | "@antfu/eslint-config": "^0.36.0",
23 | "@huntersofbook/naive-ui-nuxt": "^0.7.1",
24 | "@iconify-json/vscode-icons": "^1.1.22",
25 | "@nuxt/test-utils": "^3.2.3",
26 | "@unocss/nuxt": "^0.50.4",
27 | "eslint": "^8.36.0",
28 | "nuxt": "^3.3.3",
29 | "prisma": "^4.11.0",
30 | "ts-node": "^10.9.1",
31 | "typescript": "^4.9.5",
32 | "vitest": "^0.29.2"
33 | },
34 | "dependencies": {
35 | "@pinia/nuxt": "^0.4.7",
36 | "@prisma/client": "^4.11.0",
37 | "@types/bcryptjs": "^2.4.2",
38 | "@types/jsonwebtoken": "^9.0.1",
39 | "bcryptjs": "^2.4.3",
40 | "jsonwebtoken": "^9.0.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/pages/usercenter.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | -
35 | {{ item.title }}
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
54 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nitro-output",
3 | "version": "0.0.0",
4 | "private": true,
5 | "bundledDependencies": {
6 | "source-map-support": "0.5.21",
7 | "vue": "3.2.47",
8 | "node-fetch-native": "1.0.2",
9 | "h3": "1.5.0",
10 | "ofetch": "1.0.1",
11 | "ufo": "1.1.0",
12 | "destr": "1.2.2",
13 | "radix3": "1.0.0",
14 | "hookable": "5.4.2",
15 | "defu": "6.1.2",
16 | "unstorage": "1.1.5",
17 | "scule": "1.0.0",
18 | "ohash": "1.0.0",
19 | "vue-bundle-renderer": "1.0.2",
20 | "unctx": "2.1.2",
21 | "vue-router": "4.1.6",
22 | "unenv": "1.2.0",
23 | "@unhead/dom": "1.0.22",
24 | "@unhead/vue": "1.0.22",
25 | "@unhead/ssr": "1.0.22",
26 | "cookie-es": "0.5.0",
27 | "uncrypto": "0.1.2",
28 | "iron-webcrypto": "0.5.0",
29 | "@unhead/shared": "1.0.22",
30 | "unhead": "1.0.22",
31 | "@vue/server-renderer": "3.2.47",
32 | "source-map": "0.6.1",
33 | "buffer-from": "1.1.2",
34 | "@vue/devtools-api": "6.5.0",
35 | "@vue/compiler-dom": "3.2.47",
36 | "@vue/runtime-dom": "3.2.47",
37 | "@vue/shared": "3.2.47",
38 | "@vue/compiler-ssr": "3.2.47",
39 | "@vue/compiler-core": "3.2.47",
40 | "@vue/runtime-core": "3.2.47",
41 | "@vue/reactivity": "3.2.47",
42 | "estree-walker": "2.0.2",
43 | "@babel/parser": "7.21.0"
44 | }
45 | }
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 | services:
3 | mysql_db_container:
4 | image: mysql:latest
5 | command: --default-authentication-plugin=mysql_native_password
6 | environment:
7 | MYSQL_ROOT_PASSWORD: rootpassword # root账号密码
8 | ports:
9 | - 3306:3306
10 | volumes:
11 | - mysql_db_data_container:/var/lib/mysql
12 | healthcheck:
13 | test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
14 | interval: 30s
15 | timeout: 10s
16 | retries: 5
17 | adminer_container:
18 | image: adminer:latest
19 | environment:
20 | ADMINER_DEFAULT_SERVER: mysql_db_container
21 | ports:
22 | - 8080:8080
23 | nuxt_app_container:
24 | container_name: nuxt_app
25 | restart: always
26 | #构建容器
27 | build:
28 | context: .
29 | # 自动输入Y防止造成编译卡死
30 | args:
31 | - "-y"
32 | ports:
33 | - "3004:3000"
34 | environment:
35 | DATABASE_URL: mysql://root:rootpassword@mysql_db_container:3306/ycxt
36 | NUXT_BASE_URL: https://jsonplaceholder.typicode.com
37 | JSON_SECRET: thisisjsonsecret
38 | #command: >
39 | # /bin/sh -c 'npm run migrate && npm run build && npm start'
40 | command: >
41 | /bin/sh -c 'npm run clear && npm run migrate && npm run build && npm start'
42 | depends_on:
43 | mysql_db_container:
44 | condition: service_healthy
45 | volumes:
46 | mysql_db_data_container:
47 |
--------------------------------------------------------------------------------
/server/api/changePwd.post.ts:
--------------------------------------------------------------------------------
1 | import { isNuxtError } from 'nuxt/app'
2 | import bcrypt from 'bcryptjs'
3 | import { getUserByUsername, updateUser } from '../database/repositories/userRepository'
4 | import { getTokenInfo } from '../database/service/token'
5 |
6 | export default defineEventHandler(async (e) => {
7 | const token = getTokenInfo(e)
8 |
9 | if (isNuxtError(token)) {
10 | return sendError(e, createError({
11 | statusCode: 401,
12 | statusMessage: '请先登录!',
13 | }))
14 | }
15 |
16 | try {
17 | // 获取更新数据
18 | const body = await readBody(e)
19 |
20 | if (!body || !body.oldPwd || !body.newPwd) {
21 | return sendError(e, createError({
22 | statusCode: 400,
23 | statusMessage: '参数错误',
24 | }))
25 | }
26 |
27 | // 验证原密码
28 | const user = await getUserByUsername(token.username)
29 |
30 | // 校验密码
31 | const result = await bcrypt.compare(body.oldPwd, user!.password)
32 |
33 | if (!result) {
34 | return sendError(e, createError({
35 | statusCode: 400,
36 | statusMessage: '原密码错误!',
37 | }))
38 | }
39 |
40 | // 加密
41 | const salt = await bcrypt.genSalt(10)
42 | const hash = await bcrypt.hash(body.newPwd, salt)
43 |
44 | await updateUser(token.id, { password: hash })
45 | return { ok: true }
46 | }
47 | catch (error) {
48 | console.error(error)
49 | return sendError(e, createError('更新密码失败!'))
50 | }
51 | })
52 |
--------------------------------------------------------------------------------
/components/Prod.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
29 |
30 |
34 |
35 |
36 |
37 | {{ data.title }}
38 |
39 |
40 |
41 |
42 |
43 | 🌱 {{ data.price }}
44 |
45 |
46 | {{ data.oPrice }}
47 |
48 |
49 |
50 |
🌱 免费
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nuxt 3.0 全栈开发
2 |
3 | 本项目是掘金小册《[Nuxt 3.0全栈开发](https://s.juejin.cn/ds/Sp2b7DR/)》配套代码。
4 |
5 | ## 小册介绍
6 | 
7 |
8 | ## 小册内容
9 | 这门课程共分五个模块:
10 |
11 | 
12 |
13 | - 模块一,将从渲染模式等基础概念出发,先扭转一些同学的固有思维,补充缺失知识;
14 | - 模块二,结合个人博客案例,深入学习 Nuxt3 核心特性;
15 | - 模块三,解决项目工程化问题,从扩展性、复用性等角度深入了解模块等框架进阶知识;
16 | - 模块四,将为项目实战做准备,给大家讲解全栈知识,包括数据库设计、接口设计和开发,大家会接触并掌握 Apifox、Prisma 等前端比较时髦的新工具;
17 | - 模块五,项目实战,我会带大家开发一个知识分享社区主题的全栈项目,包括了从接口开发,到前端开发,再到优化、部署和持续集成的全流程实战。
18 | 相信学习完本小册,会让你深入掌握 Nuxt3 框架的同时,还能全方位提升自己的知识深度和架构水平。
19 |
20 | ## 你会学到什么?
21 | 本课程同时具备如下优势:
22 |
23 | - 案例驱动教学,核心知识点讲解将会用个人博客案例贯穿,学习基础知识同时掌握实战应用方法;
24 | - 全视频项目演示,每节内容均有配套代码,实战项目从设计到代码实现都有细致视频演示,同时搭配文字稿,满足各种学习需求;
25 | - TS 全栈开发,前后端完全使用 TypeScript 开发,补充后端知识的同时,也是一次 TS 学习实践;
26 | - 工程化实践,Nuxt 项目工程化搭建,多种扩展方法应用实践,自动生成数据库表数据,从开发到自动化部署全流程实战
27 | - 前沿技术栈,Nuxt3 + TS + Vite + Vue3 + NaiveUI + TailwindCSS + Nitro + Node.js + Prisma,给你现代化的开发流程和体验;
28 |
29 | ## 你将获得:
30 |
31 | - 搞清 SSR、SSG、SPA、hybrid 等渲染模式差异和选择;
32 | - 掌握 Nuxt3 核心用法和项目开发技巧;
33 | - 能够在 Nuxt 全栈开发中熟练运用 TypeScript;
34 | - 能完成 Nuxt 项目构建、开发和自动化部署等工程化任务;
35 | - 学会设计和实现接口,学会数据库设计和开发。
36 |
37 | ## 适宜人群
38 |
39 | - 欠缺前端项目经验,想要学习如何快速、高效构建真实完整前端实战项目;
40 | - 没有全栈开发经验,想要对前后端知识加深理解和实战的小伙伴;
41 | - 对前端框架理解不够深入,想要通过项目的实战加以巩固提升;
42 | - 对 TS 掌握不够熟练,希望通过实际开发强化水平的小伙伴们;
43 | - 对于 SSR/SSG 等架构感兴趣,苦于学习资料少、理解门槛较高;
44 | - 对项目性能优化、SEO 等缺乏实践经验的小伙伴
45 |
46 | ## 学习本课程需要哪些基础?
47 |
48 | - Vue 基本语法;
49 | - TypeScript 基础语法;
50 | - Node.js 基础语法。
--------------------------------------------------------------------------------
/pages/order-confirm.vue:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 | 产品信息
21 |
22 |
26 |
27 |
28 | {{ course.title }}
29 |
30 |
31 | {{ course.desc }}
32 |
33 |
34 |
35 |
36 |
37 | 请在 30 分钟内完成支付
38 |
39 |
40 |
41 | 总计:
42 |
43 | 🌱 {{ course.price }}
44 |
45 |
46 | 确认订单
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/server/database/repositories/orderRepository.ts:
--------------------------------------------------------------------------------
1 | import type { Order } from '@prisma/client'
2 | import prisma from '~/server/database/client'
3 |
4 | export async function createOrder(data: Order) {
5 | const order = await prisma.order.create({ data })
6 | return order
7 | }
8 |
9 | export async function getOrderById(id: number) {
10 | const result = await prisma.order.findUnique({
11 | where: {
12 | id,
13 | },
14 | include: {
15 | course: {
16 | select: {
17 | id: true,
18 | title: true,
19 | cover: true,
20 | price: true,
21 | desc: true,
22 | },
23 | },
24 | },
25 | })
26 | return result
27 | }
28 |
29 | export async function updateOrder(id: number, data: Partial) {
30 | const result = await prisma.order.update({
31 | where: {
32 | id,
33 | },
34 | data,
35 | })
36 | return result
37 | }
38 |
39 | export async function getCoursesByUser(userId: number) {
40 | const orders = await prisma.order.findMany({
41 | where: {
42 | userId,
43 | },
44 | include: {
45 | course: {
46 | select: {
47 | id: true,
48 | title: true,
49 | cover: true,
50 | },
51 | },
52 | },
53 | })
54 |
55 | const courses = orders.flatMap(order => order.course)
56 | const uniqueCourses = courses.filter((course, index, arr) => arr.findIndex(c => c.id === course.id) === index)
57 | return uniqueCourses
58 | }
59 |
--------------------------------------------------------------------------------
/pages/list/[type].vue:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 首页
31 |
32 |
33 |
34 | {{ title }}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-500-d1baf535.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"error-500-d1baf535.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/error-500-d1baf535.js"],"sourcesContent":null,"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiBA,MAAM,SAAY,GAAA;AAAA,EAChB,MAAQ,EAAA,WAAA;AAAA,EACR,iBAAmB,EAAA,IAAA;AAAA,EACnB,KAAO,EAAA;AAAA,IACL,OAAS,EAAA;AAAA,MACP,IAAM,EAAA,MAAA;AAAA,MACN,OAAS,EAAA,MAAA;AAAA,KACX;AAAA,IACA,OAAS,EAAA;AAAA,MACP,IAAM,EAAA,MAAA;AAAA,MACN,OAAS,EAAA,EAAA;AAAA,KACX;AAAA,IACA,UAAY,EAAA;AAAA,MACV,IAAM,EAAA,MAAA;AAAA,MACN,OAAS,EAAA,GAAA;AAAA,KACX;AAAA,IACA,aAAe,EAAA;AAAA,MACb,IAAM,EAAA,MAAA;AAAA,MACN,OAAS,EAAA,cAAA;AAAA,KACX;AAAA,IACA,WAAa,EAAA;AAAA,MACX,IAAM,EAAA,MAAA;AAAA,MACN,OAAS,EAAA,uCAAA;AAAA,KACX;AAAA,GACF;AAAA,EACA,MAAM,OAAS,EAAA;AACb,IAAA,MAAM,KAAQ,GAAA,OAAA,CAAA;AACd,IAAQ,OAAA,CAAA;AAAA,MACN,OAAO,CAAG,EAAA,KAAA,CAAM,UAAgB,CAAA,GAAA,EAAA,KAAA,CAAM,mBAAmB,KAAM,CAAA,OAAA,CAAA,CAAA;AAAA,MAC/D,QAAQ,EAAC;AAAA,MACT,KAAO,EAAA;AAAA,QACL;AAAA,UACE,QAAU,EAAA,CAAA,uuBAAA,CAAA;AAAA,SACZ;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AACD,IAAA,OAAO,CAAC,IAAA,EAAM,KAAO,EAAA,OAAA,EAAS,MAAW,KAAA;AACvC,MAAA,KAAA,CAAM,OAAO,cAAe,CAAA,UAAA,CAAW,EAAE,KAAA,EAAO,kIAAoI,EAAA,MAAM,CAAC,CAAA,CAAA,6NAAA,EAAiO,eAAe,OAAQ,CAAA,UAAU,oGAAoG,cAAe,CAAA,OAAA,CAAQ,WAAW,CAAmB,CAAA,gBAAA,CAAA,CAAA,CAAA;AAAA,KACxlB,CAAA;AAAA,GACF;AACF,CAAA,CAAA;AACA,MAAM,aAAa,SAAU,CAAA,KAAA,CAAA;AAC7B,SAAU,CAAA,KAAA,GAAQ,CAAC,KAAA,EAAO,GAAQ,KAAA;AAChC,EAAA,MAAM,aAAa,aAAc,EAAA,CAAA;AACjC,EAAC,CAAA,UAAA,CAAW,YAAY,UAAW,CAAA,OAAA,uBAA8B,GAAI,EAAA,CAAA,EAAI,IAAI,8DAA8D,CAAA,CAAA;AAC3I,EAAA,OAAO,UAAa,GAAA,UAAA,CAAW,KAAO,EAAA,GAAG,CAAI,GAAA,KAAA,CAAA,CAAA;AAC/C,CAAA,CAAA;AACM,MAAA,QAAA,+BAAuC,SAAW,EAAA,CAAC,CAAC,WAAa,EAAA,iBAAiB,CAAC,CAAC;;;;"}
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/island-renderer-d2364c4c.mjs:
--------------------------------------------------------------------------------
1 | import { defineComponent, createBlock, Teleport, h } from 'vue';
2 | import { c as createError } from '../server.mjs';
3 | import 'ofetch';
4 | import 'hookable';
5 | import 'unctx';
6 | import '@unhead/vue';
7 | import '@unhead/dom';
8 | import '@unhead/ssr';
9 | import 'vue-router';
10 | import 'h3';
11 | import 'ufo';
12 | import 'vue/server-renderer';
13 | import 'defu';
14 | import '../../nitro/vercel.mjs';
15 | import 'node-fetch-native/polyfill';
16 | import 'destr';
17 | import 'unenv/runtime/fetch/index';
18 | import 'scule';
19 | import 'ohash';
20 | import 'unstorage';
21 | import 'radix3';
22 |
23 | const components_islands = {};
24 | const islandComponents = /* @__PURE__ */ Object.freeze({
25 | __proto__: null,
26 | default: components_islands
27 | });
28 | const islandRenderer = /* @__PURE__ */ defineComponent({
29 | props: {
30 | context: {
31 | type: Object,
32 | required: true
33 | }
34 | },
35 | async setup(props) {
36 | var _a;
37 | const component = islandComponents[props.context.name];
38 | if (!component) {
39 | throw createError({
40 | statusCode: 404,
41 | statusMessage: `Island component not found: ${JSON.stringify(component)}`
42 | });
43 | }
44 | if (typeof component === "object") {
45 | await ((_a = component.__asyncLoader) == null ? void 0 : _a.call(component));
46 | }
47 | return () => [
48 | createBlock(Teleport, { to: "nuxt-island" }, [h(component || "span", props.context.props)])
49 | ];
50 | }
51 | });
52 |
53 | export { islandRenderer as default };
54 | //# sourceMappingURL=island-renderer-d2364c4c.mjs.map
55 |
--------------------------------------------------------------------------------
/pages/order-pay.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
30 |
31 |
32 | 确认支付
33 |
34 |
35 |
36 | 距离过期还有
37 |
38 |
39 | 订单已过期,请重新订阅课程
40 |
41 |
42 | 总额:
43 |
44 | 🌱 {{ course?.price }}
45 |
46 |
47 |
48 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/index-5689abd7.mjs:
--------------------------------------------------------------------------------
1 | import { _ as __nuxt_component_0 } from './nuxt-link-58ca22a8.mjs';
2 | import { withCtx, createTextVNode, useSSRContext } from 'vue';
3 | import { ssrRenderComponent } from 'vue/server-renderer';
4 | import { _ as _export_sfc } from '../server.mjs';
5 | import 'ufo';
6 | import 'ofetch';
7 | import 'hookable';
8 | import 'unctx';
9 | import '@unhead/vue';
10 | import '@unhead/dom';
11 | import '@unhead/ssr';
12 | import 'vue-router';
13 | import 'h3';
14 | import 'defu';
15 | import '../../nitro/vercel.mjs';
16 | import 'node-fetch-native/polyfill';
17 | import 'destr';
18 | import 'unenv/runtime/fetch/index';
19 | import 'scule';
20 | import 'ohash';
21 | import 'unstorage';
22 | import 'radix3';
23 |
24 | const _sfc_main = {};
25 | function _sfc_ssrRender(_ctx, _push, _parent, _attrs) {
26 | const _component_NuxtLink = __nuxt_component_0;
27 | _push(`Index Page
`);
28 | _push(ssrRenderComponent(_component_NuxtLink, { to: "/detail" }, {
29 | default: withCtx((_, _push2, _parent2, _scopeId) => {
30 | if (_push2) {
31 | _push2(`Detail Page`);
32 | } else {
33 | return [
34 | createTextVNode("Detail Page")
35 | ];
36 | }
37 | }),
38 | _: 1
39 | }, _parent));
40 | _push(``);
41 | }
42 | const _sfc_setup = _sfc_main.setup;
43 | _sfc_main.setup = (props, ctx) => {
44 | const ssrContext = useSSRContext();
45 | (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/index.vue");
46 | return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
47 | };
48 | const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["ssrRender", _sfc_ssrRender]]);
49 |
50 | export { index as default };
51 | //# sourceMappingURL=index-5689abd7.mjs.map
52 |
--------------------------------------------------------------------------------
/pages/usercenter/info.vue:
--------------------------------------------------------------------------------
1 |
2 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
55 | {{ item.value }}
56 |
57 |
58 |
59 |
60 |
61 |
62 | 提交修改
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/composables/request.ts:
--------------------------------------------------------------------------------
1 | import { merge } from 'lodash'
2 |
3 | type FetchType = typeof $fetch
4 | type ReqType = Parameters[0]
5 | type FetchOptions = Parameters[1]
6 |
7 | export function httpRequest(
8 | method: any,
9 | url: ReqType,
10 | bodyOrParams?: any,
11 | opts?: FetchOptions,
12 | ) {
13 | const token = useCookie('token')
14 | const router = useRouter()
15 | const route = useRoute()
16 |
17 | const defaultOpts = {
18 | method,
19 | // baseURL: '/api',
20 | headers: { token: token.value } as any,
21 | onRequestError() {
22 | message.error('请求出错,请重试!')
23 | },
24 | onResponseError({ response }) {
25 | switch (response.status) {
26 | case 400:
27 | message.error('参数错误')
28 | break
29 | case 401:
30 | message.error('没有访问权限')
31 | router.push(`/login?callback=${route.path}`)
32 | break
33 | case 403:
34 | message.error('服务器拒绝访问')
35 | break
36 | case 404:
37 | message.error('请求地址错误')
38 | break
39 | case 500:
40 | message.error('服务器故障')
41 | break
42 | default:
43 | message.error('网络连接故障')
44 | break
45 | }
46 | },
47 | } as FetchOptions
48 | if (defaultOpts) {
49 | if (method === 'post')
50 | defaultOpts.body = bodyOrParams
51 | else
52 | defaultOpts.params = bodyOrParams
53 | }
54 | return $fetch(url, merge(defaultOpts, opts))
55 | }
56 |
57 | export function httpPost(
58 | request: ReqType,
59 | body?: any,
60 | opts?: FetchOptions,
61 | ) {
62 | return httpRequest('post', request, body, opts)
63 | }
64 |
65 | export function httpGet(
66 | request: ReqType,
67 | opts?: FetchOptions,
68 | ) {
69 | return httpRequest('get', request, null, opts)
70 | }
71 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/app.config-a3bb0fb9.mjs:
--------------------------------------------------------------------------------
1 | import { a as useNuxtApp } from '../server.mjs';
2 |
3 | function useHead(input, options) {
4 | return useNuxtApp()._useHead(input, options);
5 | }
6 | function isObject(value) {
7 | return value !== null && typeof value === "object";
8 | }
9 | function _defu(baseObject, defaults, namespace = ".", merger) {
10 | if (!isObject(defaults)) {
11 | return _defu(baseObject, {}, namespace, merger);
12 | }
13 | const object = Object.assign({}, defaults);
14 | for (const key in baseObject) {
15 | if (key === "__proto__" || key === "constructor") {
16 | continue;
17 | }
18 | const value = baseObject[key];
19 | if (value === null || value === void 0) {
20 | continue;
21 | }
22 | if (merger && merger(object, key, value, namespace)) {
23 | continue;
24 | }
25 | if (Array.isArray(value) && Array.isArray(object[key])) {
26 | object[key] = [...value, ...object[key]];
27 | } else if (isObject(value) && isObject(object[key])) {
28 | object[key] = _defu(
29 | value,
30 | object[key],
31 | (namespace ? `${namespace}.` : "") + key.toString(),
32 | merger
33 | );
34 | } else {
35 | object[key] = value;
36 | }
37 | }
38 | return object;
39 | }
40 | function createDefu(merger) {
41 | return (...arguments_) => (
42 | // eslint-disable-next-line unicorn/no-array-reduce
43 | arguments_.reduce((p, c) => _defu(p, c, "", merger), {})
44 | );
45 | }
46 | const defuFn = createDefu((object, key, currentValue) => {
47 | if (typeof object[key] !== "undefined" && typeof currentValue === "function") {
48 | object[key] = currentValue(object[key]);
49 | return true;
50 | }
51 | });
52 | const inlineConfig = {};
53 | defuFn(inlineConfig);
54 |
55 | export { useHead as u };
56 | //# sourceMappingURL=app.config-a3bb0fb9.mjs.map
57 |
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/error-500.5a01185b.js:
--------------------------------------------------------------------------------
1 | import{a as i,o as a,b as r,f as e,t as s,p as n,i as l}from"./entry.139a88d9.js";import{u as d}from"./app.config.e684eb09.js";const c=t=>(n("data-v-32388612"),t=t(),l(),t),p={class:"font-sans antialiased bg-white dark:bg-black text-black dark:text-white grid min-h-screen place-content-center overflow-hidden"},h=c(()=>e("div",{class:"fixed -bottom-1/2 left-0 right-0 h-1/2 spotlight"},null,-1)),f={class:"max-w-520px text-center"},m=["textContent"],g=["textContent"],x={__name:"error-500",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},statusCode:{type:Number,default:500},statusMessage:{type:String,default:"Server error"},description:{type:String,default:"This page is temporarily unavailable."}},setup(t){const o=t;return d({title:`${o.statusCode} - ${o.statusMessage} | ${o.appName}`,script:[],style:[{children:'*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{margin:0;font-family:inherit;line-height:inherit}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}h1,p{margin:0}h1{font-size:inherit;font-weight:inherit}'}]}),(u,b)=>(a(),r("div",p,[h,e("div",f,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:s(t.statusCode)},null,8,m),e("p",{class:"text-xl px-8 sm:px-0 sm:text-4xl font-light mb-16 leading-tight",textContent:s(t.description)},null,8,g)])]))}},y=i(x,[["__scopeId","data-v-32388612"]]);export{y as default};
2 |
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/error-500.aa16ed4d.css:
--------------------------------------------------------------------------------
1 | .spotlight[data-v-32388612]{background:linear-gradient(45deg,#00dc82,#36e4da 50%,#0047e1);filter:blur(20vh)}.bg-white[data-v-32388612]{--tw-bg-opacity:1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.grid[data-v-32388612]{display:grid}.place-content-center[data-v-32388612]{place-content:center}.font-sans[data-v-32388612]{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-medium[data-v-32388612]{font-weight:500}.font-light[data-v-32388612]{font-weight:300}.h-1\/2[data-v-32388612]{height:50%}.text-8xl[data-v-32388612]{font-size:6rem;line-height:1}.text-xl[data-v-32388612]{font-size:1.25rem;line-height:1.75rem}.leading-tight[data-v-32388612]{line-height:1.25}.mb-8[data-v-32388612]{margin-bottom:2rem}.mb-16[data-v-32388612]{margin-bottom:4rem}.max-w-520px[data-v-32388612]{max-width:520px}.min-h-screen[data-v-32388612]{min-height:100vh}.overflow-hidden[data-v-32388612]{overflow:hidden}.px-8[data-v-32388612]{padding-left:2rem;padding-right:2rem}.fixed[data-v-32388612]{position:fixed}.left-0[data-v-32388612]{left:0}.right-0[data-v-32388612]{right:0}.-bottom-1\/2[data-v-32388612]{bottom:-50%}.text-center[data-v-32388612]{text-align:center}.text-black[data-v-32388612]{--tw-text-opacity:1;color:rgba(0,0,0,var(--tw-text-opacity))}.antialiased[data-v-32388612]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (min-width:640px){.sm\:text-4xl[data-v-32388612]{font-size:2.25rem;line-height:2.5rem}.sm\:text-10xl[data-v-32388612]{font-size:10rem;line-height:1}.sm\:px-0[data-v-32388612]{padding-left:0;padding-right:0}}@media (prefers-color-scheme:dark){.dark\:bg-black[data-v-32388612]{--tw-bg-opacity:1;background-color:rgba(0,0,0,var(--tw-bg-opacity))}.dark\:text-white[data-v-32388612]{--tw-text-opacity:1;color:rgba(255,255,255,var(--tw-text-opacity))}}
2 |
--------------------------------------------------------------------------------
/server/database/schema.prisma:
--------------------------------------------------------------------------------
1 | datasource db {
2 | provider = "mysql"
3 | url = env("DATABASE_URL")
4 | }
5 |
6 | generator client {
7 | provider = "prisma-client-js"
8 | }
9 |
10 | // 专栏
11 | model Column {
12 | id Int @id @default(autoincrement())
13 | title String
14 | cover String
15 | desc String?
16 | content String? @db.Text
17 | url String?
18 | price Decimal?
19 | oPrice Decimal?
20 | }
21 |
22 | model Course {
23 | id Int @id @default(autoincrement())
24 | title String
25 | cover String
26 | price Decimal
27 | oPrice Decimal
28 | desc String?
29 | detail String? @db.Text
30 | users UsersOnCourses[]
31 | orders Order[]
32 | Catalogue Catalogue[]
33 | url String?
34 | }
35 |
36 | // 章节
37 | model Catalogue {
38 | id Int @id @default(autoincrement())
39 | title String
40 | source String
41 | course Course @relation(fields: [courseId], references: [id])
42 | courseId Int
43 | }
44 |
45 | model User {
46 | id Int @id @default(autoincrement())
47 | username String @unique
48 | password String
49 | nickname String?
50 | avatar String?
51 | sex String?
52 | courses UsersOnCourses[]
53 | orders Order[]
54 | }
55 |
56 | model UsersOnCourses {
57 | user User @relation(fields: [userId], references: [id])
58 | userId Int
59 | course Course @relation(fields: [courseId], references: [id])
60 | courseId Int
61 |
62 | @@id([userId, courseId])
63 | }
64 |
65 | model Order {
66 | id Int @id @default(autoincrement())
67 | course Course @relation(fields: [courseId], references: [id])
68 | courseId Int
69 | user User @relation(fields: [userId], references: [id])
70 | userId Int
71 | createdAt DateTime
72 | status OrderStatus
73 | }
74 |
75 | enum OrderStatus {
76 | WAIT_CONFIRM
77 | WAIT_PAY
78 | COMPLETED
79 | }
80 |
--------------------------------------------------------------------------------
/components/MyHeader.vue:
--------------------------------------------------------------------------------
1 |
38 |
39 |
40 |
41 |
42 |
43 | 羊村学堂
44 |
45 |
46 |
47 |
55 |
56 |
57 |
58 |
59 |
60 | 登录
61 |
62 |
63 |
64 |
65 |
68 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/pages/login.vue:
--------------------------------------------------------------------------------
1 |
55 |
56 |
57 |
58 | 返回羊村
59 |
60 |
61 | 还未入村?
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | 登录
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/app.config-a3bb0fb9.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"app.config-a3bb0fb9.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/app.config-a3bb0fb9.js"],"sourcesContent":null,"names":[],"mappings":";;AACA,SAAS,OAAA,CAAQ,OAAO,OAAS,EAAA;AAC/B,EAAA,OAAO,UAAW,EAAA,CAAE,QAAS,CAAA,KAAA,EAAO,OAAO,CAAA,CAAA;AAC7C,CAAA;AACA,SAAS,SAAS,KAAO,EAAA;AACvB,EAAO,OAAA,KAAA,KAAU,IAAQ,IAAA,OAAO,KAAU,KAAA,QAAA,CAAA;AAC5C,CAAA;AACA,SAAS,KAAM,CAAA,UAAA,EAAY,QAAU,EAAA,SAAA,GAAY,KAAK,MAAQ,EAAA;AAC5D,EAAI,IAAA,CAAC,QAAS,CAAA,QAAQ,CAAG,EAAA;AACvB,IAAA,OAAO,KAAM,CAAA,UAAA,EAAY,EAAC,EAAG,WAAW,MAAM,CAAA,CAAA;AAAA,GAChD;AACA,EAAA,MAAM,MAAS,GAAA,MAAA,CAAO,MAAO,CAAA,IAAI,QAAQ,CAAA,CAAA;AACzC,EAAA,KAAA,MAAW,OAAO,UAAY,EAAA;AAC5B,IAAI,IAAA,GAAA,KAAQ,WAAe,IAAA,GAAA,KAAQ,aAAe,EAAA;AAChD,MAAA,SAAA;AAAA,KACF;AACA,IAAM,MAAA,KAAA,GAAQ,WAAW,GAAG,CAAA,CAAA;AAC5B,IAAI,IAAA,KAAA,KAAU,IAAQ,IAAA,KAAA,KAAU,KAAQ,CAAA,EAAA;AACtC,MAAA,SAAA;AAAA,KACF;AACA,IAAA,IAAI,UAAU,MAAO,CAAA,MAAA,EAAQ,GAAK,EAAA,KAAA,EAAO,SAAS,CAAG,EAAA;AACnD,MAAA,SAAA;AAAA,KACF;AACA,IAAI,IAAA,KAAA,CAAM,QAAQ,KAAK,CAAA,IAAK,MAAM,OAAQ,CAAA,MAAA,CAAO,GAAG,CAAC,CAAG,EAAA;AACtD,MAAO,MAAA,CAAA,GAAG,IAAI,CAAC,GAAG,OAAO,GAAG,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,KACzC,MAAA,IAAW,SAAS,KAAK,CAAA,IAAK,SAAS,MAAO,CAAA,GAAG,CAAC,CAAG,EAAA;AACnD,MAAA,MAAA,CAAO,GAAG,CAAI,GAAA,KAAA;AAAA,QACZ,KAAA;AAAA,QACA,OAAO,GAAG,CAAA;AAAA,QAAA,CACT,SAAY,GAAA,CAAA,EAAG,SAAe,CAAA,CAAA,CAAA,GAAA,EAAA,IAAM,IAAI,QAAS,EAAA;AAAA,QAClD,MAAA;AAAA,OACF,CAAA;AAAA,KACK,MAAA;AACL,MAAA,MAAA,CAAO,GAAG,CAAI,GAAA,KAAA,CAAA;AAAA,KAChB;AAAA,GACF;AACA,EAAO,OAAA,MAAA,CAAA;AACT,CAAA;AACA,SAAS,WAAW,MAAQ,EAAA;AAC1B,EAAA,OAAO,CAAI,GAAA,UAAA;AAAA;AAAA,IAET,UAAW,CAAA,MAAA,CAAO,CAAC,CAAA,EAAG,CAAM,KAAA,KAAA,CAAM,CAAG,EAAA,CAAA,EAAG,EAAI,EAAA,MAAM,CAAG,EAAA,EAAE,CAAA;AAAA,GAAA,CAAA;AAE3D,CAAA;AACA,MAAM,MAAS,GAAA,UAAA,CAAW,CAAC,MAAA,EAAQ,KAAK,YAAiB,KAAA;AACvD,EAAA,IAAI,OAAO,MAAO,CAAA,GAAG,MAAM,WAAe,IAAA,OAAO,iBAAiB,UAAY,EAAA;AAC5E,IAAA,MAAA,CAAO,GAAG,CAAA,GAAI,YAAa,CAAA,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AACtC,IAAO,OAAA,IAAA,CAAA;AAAA,GACT;AACF,CAAC,CAAA,CAAA;AACD,MAAM,eAAe,EAAC,CAAA;AACtB,MAAA,CAAO,YAAY,CAAA;;;;"}
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-500-styles.6b5b5ff2.mjs:
--------------------------------------------------------------------------------
1 | const error500_vue_vue_type_style_index_0_scoped_32388612_lang = ".spotlight[data-v-32388612]{background:linear-gradient(45deg,#00dc82,#36e4da 50%,#0047e1);filter:blur(20vh)}.bg-white[data-v-32388612]{--tw-bg-opacity:1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.grid[data-v-32388612]{display:grid}.place-content-center[data-v-32388612]{place-content:center}.font-sans[data-v-32388612]{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-medium[data-v-32388612]{font-weight:500}.font-light[data-v-32388612]{font-weight:300}.h-1\\/2[data-v-32388612]{height:50%}.text-8xl[data-v-32388612]{font-size:6rem;line-height:1}.text-xl[data-v-32388612]{font-size:1.25rem;line-height:1.75rem}.leading-tight[data-v-32388612]{line-height:1.25}.mb-8[data-v-32388612]{margin-bottom:2rem}.mb-16[data-v-32388612]{margin-bottom:4rem}.max-w-520px[data-v-32388612]{max-width:520px}.min-h-screen[data-v-32388612]{min-height:100vh}.overflow-hidden[data-v-32388612]{overflow:hidden}.px-8[data-v-32388612]{padding-left:2rem;padding-right:2rem}.fixed[data-v-32388612]{position:fixed}.left-0[data-v-32388612]{left:0}.right-0[data-v-32388612]{right:0}.-bottom-1\\/2[data-v-32388612]{bottom:-50%}.text-center[data-v-32388612]{text-align:center}.text-black[data-v-32388612]{--tw-text-opacity:1;color:rgba(0,0,0,var(--tw-text-opacity))}.antialiased[data-v-32388612]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (min-width:640px){.sm\\:text-4xl[data-v-32388612]{font-size:2.25rem;line-height:2.5rem}.sm\\:text-10xl[data-v-32388612]{font-size:10rem;line-height:1}.sm\\:px-0[data-v-32388612]{padding-left:0;padding-right:0}}@media (prefers-color-scheme:dark){.dark\\:bg-black[data-v-32388612]{--tw-bg-opacity:1;background-color:rgba(0,0,0,var(--tw-bg-opacity))}.dark\\:text-white[data-v-32388612]{--tw-text-opacity:1;color:rgba(255,255,255,var(--tw-text-opacity))}}";
2 |
3 | const error500Styles_6b5b5ff2 = [error500_vue_vue_type_style_index_0_scoped_32388612_lang];
4 |
5 | export { error500Styles_6b5b5ff2 as default };
6 | //# sourceMappingURL=error-500-styles.6b5b5ff2.mjs.map
7 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-component-9ecfbe97.mjs:
--------------------------------------------------------------------------------
1 | import { useSSRContext, unref, mergeProps, defineAsyncComponent } from 'vue';
2 | import { ssrRenderComponent } from 'vue/server-renderer';
3 |
4 | const _sfc_main = {
5 | __name: "nuxt-error-page",
6 | __ssrInlineRender: true,
7 | props: {
8 | error: Object
9 | },
10 | setup(__props) {
11 | var _a;
12 | const { error } = __props;
13 | (error.stack || "").split("\n").splice(1).map((line) => {
14 | const text = line.replace("webpack:/", "").replace(".vue", ".js").trim();
15 | return {
16 | text,
17 | internal: line.includes("node_modules") && !line.includes(".cache") || line.includes("internal") || line.includes("new Promise")
18 | };
19 | }).map((i) => `${i.text}`).join("\n");
20 | const statusCode = Number(error.statusCode || 500);
21 | const is404 = statusCode === 404;
22 | const statusMessage = (_a = error.statusMessage) != null ? _a : is404 ? "Page Not Found" : "Internal Server Error";
23 | const description = error.message || error.toString();
24 | const stack = void 0;
25 | const _Error404 = /* @__PURE__ */ defineAsyncComponent(() => import('./error-404-59cb290a.mjs').then((r) => r.default || r));
26 | const _Error = /* @__PURE__ */ defineAsyncComponent(() => import('./error-500-d1baf535.mjs').then((r) => r.default || r));
27 | const ErrorTemplate = is404 ? _Error404 : _Error;
28 | return (_ctx, _push, _parent, _attrs) => {
29 | _push(ssrRenderComponent(unref(ErrorTemplate), mergeProps({ statusCode: unref(statusCode), statusMessage: unref(statusMessage), description: unref(description), stack: unref(stack) }, _attrs), null, _parent));
30 | };
31 | }
32 | };
33 | const _sfc_setup = _sfc_main.setup;
34 | _sfc_main.setup = (props, ctx) => {
35 | const ssrContext = useSSRContext();
36 | (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("node_modules/nuxt/dist/app/components/nuxt-error-page.vue");
37 | return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
38 | };
39 | const _sfc_main$1 = _sfc_main;
40 |
41 | export { _sfc_main$1 as default };
42 | //# sourceMappingURL=error-component-9ecfbe97.mjs.map
43 |
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/error-404.7326de30.js:
--------------------------------------------------------------------------------
1 | import{_ as a}from"./nuxt-link.dd8747fa.js";import{a as n,o as r,b as d,f as e,t as s,e as l,w as c,h as p,p as m,i as f}from"./entry.139a88d9.js";import{u as h}from"./app.config.e684eb09.js";const x=t=>(m("data-v-30d2164e"),t=t(),f(),t),u={class:"font-sans antialiased bg-white dark:bg-black text-black dark:text-white grid min-h-screen place-content-center overflow-hidden"},g=x(()=>e("div",{class:"fixed left-0 right-0 spotlight z-10"},null,-1)),_={class:"max-w-520px text-center z-20"},b=["textContent"],w=["textContent"],y={class:"w-full flex items-center justify-center"},S={__name:"error-404",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},statusCode:{type:Number,default:404},statusMessage:{type:String,default:"Not Found"},description:{type:String,default:"Sorry, the page you are looking for could not be found."},backHome:{type:String,default:"Go back home"}},setup(t){const o=t;return h({title:`${o.statusCode} - ${o.statusMessage} | ${o.appName}`,script:[],style:[{children:'*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}a{color:inherit;text-decoration:inherit}body{margin:0;font-family:inherit;line-height:inherit}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}h1,p{margin:0}h1{font-size:inherit;font-weight:inherit}'}]}),(k,v)=>{const i=a;return r(),d("div",u,[g,e("div",_,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:s(t.statusCode)},null,8,b),e("p",{class:"text-xl px-8 sm:px-0 sm:text-4xl font-light mb-16 leading-tight",textContent:s(t.description)},null,8,w),e("div",y,[l(i,{to:"/",class:"gradient-border text-md sm:text-xl py-2 px-4 sm:py-3 sm:px-6 cursor-pointer"},{default:c(()=>[p(s(t.backHome),1)]),_:1})])])])}}},I=n(S,[["__scopeId","data-v-30d2164e"]]);export{I as default};
2 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-404-59cb290a.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"error-404-59cb290a.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/error-404-59cb290a.js"],"sourcesContent":null,"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-component-9ecfbe97.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"error-component-9ecfbe97.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/error-component-9ecfbe97.js"],"sourcesContent":null,"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/client.manifest.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"client.manifest.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/client.manifest.mjs"],"sourcesContent":null,"names":[],"mappings":"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"}
--------------------------------------------------------------------------------
/pages/register.vue:
--------------------------------------------------------------------------------
1 |
67 |
68 |
69 | 加入羊群
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | 登录
84 |
85 |
86 |
87 | 注册即同意
88 |
89 | 《服务协议》
90 |
91 | 和
92 |
93 | 《隐私政策》
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/server/database/migrations/20230404135755_init/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE `Column` (
3 | `id` INTEGER NOT NULL AUTO_INCREMENT,
4 | `title` VARCHAR(191) NOT NULL,
5 | `cover` VARCHAR(191) NOT NULL,
6 | `desc` VARCHAR(191) NULL,
7 | `content` TEXT NULL,
8 |
9 | PRIMARY KEY (`id`)
10 | ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
11 |
12 | -- CreateTable
13 | CREATE TABLE `Course` (
14 | `id` INTEGER NOT NULL AUTO_INCREMENT,
15 | `title` VARCHAR(191) NOT NULL,
16 | `cover` VARCHAR(191) NOT NULL,
17 | `price` DECIMAL(65, 30) NOT NULL,
18 | `oPrice` DECIMAL(65, 30) NOT NULL,
19 | `desc` VARCHAR(191) NULL,
20 | `detail` TEXT NULL,
21 |
22 | PRIMARY KEY (`id`)
23 | ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
24 |
25 | -- CreateTable
26 | CREATE TABLE `Catalogue` (
27 | `id` INTEGER NOT NULL AUTO_INCREMENT,
28 | `title` VARCHAR(191) NOT NULL,
29 | `source` VARCHAR(191) NOT NULL,
30 | `courseId` INTEGER NOT NULL,
31 |
32 | PRIMARY KEY (`id`)
33 | ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
34 |
35 | -- CreateTable
36 | CREATE TABLE `User` (
37 | `id` INTEGER NOT NULL AUTO_INCREMENT,
38 | `username` VARCHAR(191) NOT NULL,
39 | `password` VARCHAR(191) NOT NULL,
40 | `nickname` VARCHAR(191) NULL,
41 | `avatar` VARCHAR(191) NULL,
42 | `sex` VARCHAR(191) NULL,
43 |
44 | UNIQUE INDEX `User_username_key`(`username`),
45 | PRIMARY KEY (`id`)
46 | ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
47 |
48 | -- CreateTable
49 | CREATE TABLE `UsersOnCourses` (
50 | `userId` INTEGER NOT NULL,
51 | `courseId` INTEGER NOT NULL,
52 |
53 | PRIMARY KEY (`userId`, `courseId`)
54 | ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
55 |
56 | -- CreateTable
57 | CREATE TABLE `Order` (
58 | `id` INTEGER NOT NULL AUTO_INCREMENT,
59 | `courseId` INTEGER NOT NULL,
60 | `userId` INTEGER NOT NULL,
61 | `createdAt` DATETIME(3) NOT NULL,
62 | `status` ENUM('WAIT_CONFIRM', 'WAIT_PAY', 'COMPLETED') NOT NULL,
63 |
64 | PRIMARY KEY (`id`)
65 | ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
66 |
67 | -- AddForeignKey
68 | ALTER TABLE `Catalogue` ADD CONSTRAINT `Catalogue_courseId_fkey` FOREIGN KEY (`courseId`) REFERENCES `Course`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
69 |
70 | -- AddForeignKey
71 | ALTER TABLE `UsersOnCourses` ADD CONSTRAINT `UsersOnCourses_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
72 |
73 | -- AddForeignKey
74 | ALTER TABLE `UsersOnCourses` ADD CONSTRAINT `UsersOnCourses_courseId_fkey` FOREIGN KEY (`courseId`) REFERENCES `Course`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
75 |
76 | -- AddForeignKey
77 | ALTER TABLE `Order` ADD CONSTRAINT `Order_courseId_fkey` FOREIGN KEY (`courseId`) REFERENCES `Course`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
78 |
79 | -- AddForeignKey
80 | ALTER TABLE `Order` ADD CONSTRAINT `Order_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
81 |
--------------------------------------------------------------------------------
/pages/[type]/detail/[id].vue:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
50 | {{ data?.data.item.title }}
51 |
52 |
53 | {{ data?.data.item.desc }}
54 |
55 |
56 |
57 | 🌱 {{ data?.data.item.price }}
58 |
59 |
60 | {{ data?.data.item.oPrice }}
61 |
62 |
63 |
64 |
65 |
66 |
67 | 快到碗里来
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
88 |
89 |
90 |
91 |
92 |
精品推荐
93 |
94 |
97 |
98 |
99 |
100 |
101 |
102 |
107 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-500-d1baf535.mjs:
--------------------------------------------------------------------------------
1 | import { _ as _export_sfc } from '../server.mjs';
2 | import { mergeProps, useSSRContext } from 'vue';
3 | import { u as useHead } from './app.config-a3bb0fb9.mjs';
4 | import { ssrRenderAttrs, ssrInterpolate } from 'vue/server-renderer';
5 | import 'ofetch';
6 | import 'hookable';
7 | import 'unctx';
8 | import '@unhead/vue';
9 | import '@unhead/dom';
10 | import '@unhead/ssr';
11 | import 'vue-router';
12 | import 'h3';
13 | import 'ufo';
14 | import 'defu';
15 | import '../../nitro/vercel.mjs';
16 | import 'node-fetch-native/polyfill';
17 | import 'destr';
18 | import 'unenv/runtime/fetch/index';
19 | import 'scule';
20 | import 'ohash';
21 | import 'unstorage';
22 | import 'radix3';
23 |
24 | const _sfc_main = {
25 | __name: "error-500",
26 | __ssrInlineRender: true,
27 | props: {
28 | appName: {
29 | type: String,
30 | default: "Nuxt"
31 | },
32 | version: {
33 | type: String,
34 | default: ""
35 | },
36 | statusCode: {
37 | type: Number,
38 | default: 500
39 | },
40 | statusMessage: {
41 | type: String,
42 | default: "Server error"
43 | },
44 | description: {
45 | type: String,
46 | default: "This page is temporarily unavailable."
47 | }
48 | },
49 | setup(__props) {
50 | const props = __props;
51 | useHead({
52 | title: `${props.statusCode} - ${props.statusMessage} | ${props.appName}`,
53 | script: [],
54 | style: [
55 | {
56 | children: `*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{margin:0;font-family:inherit;line-height:inherit}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}h1,p{margin:0}h1{font-size:inherit;font-weight:inherit}`
57 | }
58 | ]
59 | });
60 | return (_ctx, _push, _parent, _attrs) => {
61 | _push(`${ssrInterpolate(__props.statusCode)}
${ssrInterpolate(__props.description)}
`);
62 | };
63 | }
64 | };
65 | const _sfc_setup = _sfc_main.setup;
66 | _sfc_main.setup = (props, ctx) => {
67 | const ssrContext = useSSRContext();
68 | (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("node_modules/@nuxt/ui-templates/dist/templates/error-500.vue");
69 | return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
70 | };
71 | const error500 = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-32388612"]]);
72 |
73 | export { error500 as default };
74 | //# sourceMappingURL=error-500-d1baf535.mjs.map
75 |
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/error-404.23f2309d.css:
--------------------------------------------------------------------------------
1 | .spotlight[data-v-30d2164e]{background:linear-gradient(45deg,#00dc82,#36e4da 50%,#0047e1);bottom:-30vh;filter:blur(20vh);height:40vh}.gradient-border[data-v-30d2164e]{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:.5rem;position:relative}@media (prefers-color-scheme:light){.gradient-border[data-v-30d2164e]{background-color:#ffffff4d}.gradient-border[data-v-30d2164e]:before{background:linear-gradient(90deg,#e2e2e2,#e2e2e2 25%,#00dc82 50%,#36e4da 75%,#0047e1)}}@media (prefers-color-scheme:dark){.gradient-border[data-v-30d2164e]{background-color:#1414144d}.gradient-border[data-v-30d2164e]:before{background:linear-gradient(90deg,#303030,#303030 25%,#00dc82 50%,#36e4da 75%,#0047e1)}}.gradient-border[data-v-30d2164e]:before{background-size:400% auto;border-radius:.5rem;bottom:0;content:"";left:0;-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;opacity:.5;padding:2px;position:absolute;right:0;top:0;transition:background-position .3s ease-in-out,opacity .2s ease-in-out;width:100%}.gradient-border[data-v-30d2164e]:hover:before{background-position:-50% 0;opacity:1}.bg-white[data-v-30d2164e]{--tw-bg-opacity:1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.cursor-pointer[data-v-30d2164e]{cursor:pointer}.flex[data-v-30d2164e]{display:flex}.grid[data-v-30d2164e]{display:grid}.place-content-center[data-v-30d2164e]{place-content:center}.items-center[data-v-30d2164e]{align-items:center}.justify-center[data-v-30d2164e]{justify-content:center}.font-sans[data-v-30d2164e]{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-medium[data-v-30d2164e]{font-weight:500}.font-light[data-v-30d2164e]{font-weight:300}.text-8xl[data-v-30d2164e]{font-size:6rem;line-height:1}.text-xl[data-v-30d2164e]{font-size:1.25rem;line-height:1.75rem}.leading-tight[data-v-30d2164e]{line-height:1.25}.mb-8[data-v-30d2164e]{margin-bottom:2rem}.mb-16[data-v-30d2164e]{margin-bottom:4rem}.max-w-520px[data-v-30d2164e]{max-width:520px}.min-h-screen[data-v-30d2164e]{min-height:100vh}.overflow-hidden[data-v-30d2164e]{overflow:hidden}.px-8[data-v-30d2164e]{padding-left:2rem;padding-right:2rem}.py-2[data-v-30d2164e]{padding-bottom:.5rem;padding-top:.5rem}.px-4[data-v-30d2164e]{padding-left:1rem;padding-right:1rem}.fixed[data-v-30d2164e]{position:fixed}.left-0[data-v-30d2164e]{left:0}.right-0[data-v-30d2164e]{right:0}.text-center[data-v-30d2164e]{text-align:center}.text-black[data-v-30d2164e]{--tw-text-opacity:1;color:rgba(0,0,0,var(--tw-text-opacity))}.antialiased[data-v-30d2164e]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.w-full[data-v-30d2164e]{width:100%}.z-10[data-v-30d2164e]{z-index:10}.z-20[data-v-30d2164e]{z-index:20}@media (min-width:640px){.sm\:text-4xl[data-v-30d2164e]{font-size:2.25rem;line-height:2.5rem}.sm\:text-xl[data-v-30d2164e]{font-size:1.25rem;line-height:1.75rem}.sm\:text-10xl[data-v-30d2164e]{font-size:10rem;line-height:1}.sm\:px-0[data-v-30d2164e]{padding-left:0;padding-right:0}.sm\:py-3[data-v-30d2164e]{padding-bottom:.75rem;padding-top:.75rem}.sm\:px-6[data-v-30d2164e]{padding-left:1.5rem;padding-right:1.5rem}}@media (prefers-color-scheme:dark){.dark\:bg-black[data-v-30d2164e]{--tw-bg-opacity:1;background-color:rgba(0,0,0,var(--tw-bg-opacity))}.dark\:text-white[data-v-30d2164e]{--tw-text-opacity:1;color:rgba(255,255,255,var(--tw-text-opacity))}}
2 |
--------------------------------------------------------------------------------
/.vercel/output/static/_nuxt/nuxt-link.dd8747fa.js:
--------------------------------------------------------------------------------
1 | import{j as C,k as p,l as q,m as y,q as k,r as b,s as P,v as A,x,y as R,z as T}from"./entry.139a88d9.js";async function _(t,a=C()){if(a._routePreloaded||(a._routePreloaded=new Set),a._routePreloaded.has(t))return;const e=a._preloadPromises=a._preloadPromises||[];if(e.length>4)return Promise.all(e).then(()=>_(t,a));a._routePreloaded.add(t);const r=a.resolve(t).matched.map(o=>{var n;return(n=o.components)==null?void 0:n.default}).filter(o=>typeof o=="function");for(const o of r){const n=Promise.resolve(o()).catch(()=>{}).finally(()=>e.splice(e.indexOf(n)));e.push(n)}await Promise.all(e)}const g=globalThis.requestIdleCallback||(t=>{const a=Date.now(),e={didTimeout:!1,timeRemaining:()=>Math.max(0,50-(Date.now()-a))};return setTimeout(()=>{t(e)},1)}),N=globalThis.cancelIdleCallback||(t=>{clearTimeout(t)}),S=t=>{const a=p();a.isHydrating?a.hooks.hookOnce("app:suspense:resolve",()=>{g(t)}):g(t)},w=(...t)=>t.find(a=>a!==void 0),B="noopener noreferrer";function E(t){const a=t.componentName||"NuxtLink";return q({name:a,props:{to:{type:[String,Object],default:void 0,required:!1},href:{type:[String,Object],default:void 0,required:!1},target:{type:String,default:void 0,required:!1},rel:{type:String,default:void 0,required:!1},noRel:{type:Boolean,default:void 0,required:!1},prefetch:{type:Boolean,default:void 0,required:!1},noPrefetch:{type:Boolean,default:void 0,required:!1},activeClass:{type:String,default:void 0,required:!1},exactActiveClass:{type:String,default:void 0,required:!1},prefetchedClass:{type:String,default:void 0,required:!1},replace:{type:Boolean,default:void 0,required:!1},ariaCurrentValue:{type:String,default:void 0,required:!1},external:{type:Boolean,default:void 0,required:!1},custom:{type:Boolean,default:void 0,required:!1}},setup(e,{slots:r}){const o=C(),n=y(()=>e.to||e.href||""),c=y(()=>e.external||e.target&&e.target!=="_self"?!0:typeof n.value=="object"?!1:n.value===""||k(n.value,!0)),v=b(!1),s=b(null);if(e.prefetch!==!1&&e.noPrefetch!==!0&&typeof n.value=="string"&&e.target!=="_blank"&&!L()){const f=p();let u,l=null;P(()=>{const m=I();S(()=>{u=g(()=>{var d;(d=s==null?void 0:s.value)!=null&&d.tagName&&(l=m.observe(s.value,async()=>{l==null||l(),l=null,await Promise.all([f.hooks.callHook("link:prefetch",n.value).catch(()=>{}),!c.value&&_(n.value,o).catch(()=>{})]),v.value=!0}))})})}),A(()=>{u&&N(u),l==null||l(),l=null})}return()=>{var m,d;if(!c.value)return x(R("RouterLink"),{ref:h=>{s.value=h==null?void 0:h.$el},to:n.value,...v.value&&!e.custom?{class:e.prefetchedClass||t.prefetchedClass}:{},activeClass:e.activeClass||t.activeClass,exactActiveClass:e.exactActiveClass||t.exactActiveClass,replace:e.replace,ariaCurrentValue:e.ariaCurrentValue,custom:e.custom},r.default);const i=typeof n.value=="object"?((m=o.resolve(n.value))==null?void 0:m.href)??null:n.value||null,f=e.target||null,u=e.noRel?null:w(e.rel,t.externalRelAttribute,i?B:"")||null,l=()=>T(i,{replace:e.replace});return e.custom?r.default?r.default({href:i,navigate:l,route:o.resolve(i),rel:u,target:f,isExternal:c.value,isActive:!1,isExactActive:!1}):null:x("a",{ref:s,href:i,rel:u,target:f},(d=r.default)==null?void 0:d.call(r))}}})}const j=E({componentName:"NuxtLink"});function I(){const t=p();if(t._observer)return t._observer;let a=null;const e=new Map,r=(n,c)=>(a||(a=new IntersectionObserver(v=>{for(const s of v){const i=e.get(s.target);(s.isIntersecting||s.intersectionRatio>0)&&i&&i()}})),e.set(n,c),a.observe(n),()=>{e.delete(n),a.unobserve(n),e.size===0&&(a.disconnect(),a=null)});return t._observer={observe:r}}function L(){const t=navigator.connection;return!!(t&&(t.saveData||/2g/.test(t.effectiveType)))}export{j as _};
2 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/client.manifest.mjs:
--------------------------------------------------------------------------------
1 | const client_manifest = {
2 | "_app.config.e684eb09.js": {
3 | "resourceType": "script",
4 | "module": true,
5 | "file": "app.config.e684eb09.js",
6 | "imports": [
7 | "node_modules/nuxt/dist/app/entry.mjs"
8 | ]
9 | },
10 | "_nuxt-link.dd8747fa.js": {
11 | "resourceType": "script",
12 | "module": true,
13 | "file": "nuxt-link.dd8747fa.js",
14 | "imports": [
15 | "node_modules/nuxt/dist/app/entry.mjs"
16 | ]
17 | },
18 | "node_modules/@nuxt/ui-templates/dist/templates/error-404.css": {
19 | "resourceType": "style",
20 | "file": "error-404.23f2309d.css",
21 | "src": "node_modules/@nuxt/ui-templates/dist/templates/error-404.css"
22 | },
23 | "node_modules/@nuxt/ui-templates/dist/templates/error-404.vue": {
24 | "resourceType": "script",
25 | "module": true,
26 | "css": [],
27 | "file": "error-404.7326de30.js",
28 | "imports": [
29 | "_nuxt-link.dd8747fa.js",
30 | "node_modules/nuxt/dist/app/entry.mjs",
31 | "_app.config.e684eb09.js"
32 | ],
33 | "isDynamicEntry": true,
34 | "src": "node_modules/@nuxt/ui-templates/dist/templates/error-404.vue"
35 | },
36 | "error-404.23f2309d.css": {
37 | "file": "error-404.23f2309d.css",
38 | "resourceType": "style"
39 | },
40 | "node_modules/@nuxt/ui-templates/dist/templates/error-500.css": {
41 | "resourceType": "style",
42 | "file": "error-500.aa16ed4d.css",
43 | "src": "node_modules/@nuxt/ui-templates/dist/templates/error-500.css"
44 | },
45 | "node_modules/@nuxt/ui-templates/dist/templates/error-500.vue": {
46 | "resourceType": "script",
47 | "module": true,
48 | "css": [],
49 | "file": "error-500.5a01185b.js",
50 | "imports": [
51 | "node_modules/nuxt/dist/app/entry.mjs",
52 | "_app.config.e684eb09.js"
53 | ],
54 | "isDynamicEntry": true,
55 | "src": "node_modules/@nuxt/ui-templates/dist/templates/error-500.vue"
56 | },
57 | "error-500.aa16ed4d.css": {
58 | "file": "error-500.aa16ed4d.css",
59 | "resourceType": "style"
60 | },
61 | "node_modules/nuxt/dist/app/entry.mjs": {
62 | "resourceType": "script",
63 | "module": true,
64 | "dynamicImports": [
65 | "virtual:nuxt:/Users/57code/nuxt-app/.nuxt/error-component.mjs"
66 | ],
67 | "file": "entry.139a88d9.js",
68 | "isEntry": true,
69 | "src": "node_modules/nuxt/dist/app/entry.mjs"
70 | },
71 | "pages/detail.vue": {
72 | "resourceType": "script",
73 | "module": true,
74 | "file": "detail.37523c12.js",
75 | "imports": [
76 | "node_modules/nuxt/dist/app/entry.mjs"
77 | ],
78 | "isDynamicEntry": true,
79 | "src": "pages/detail.vue"
80 | },
81 | "pages/index.vue": {
82 | "resourceType": "script",
83 | "module": true,
84 | "file": "index.d321cf39.js",
85 | "imports": [
86 | "_nuxt-link.dd8747fa.js",
87 | "node_modules/nuxt/dist/app/entry.mjs"
88 | ],
89 | "isDynamicEntry": true,
90 | "src": "pages/index.vue"
91 | },
92 | "virtual:nuxt:/Users/57code/nuxt-app/.nuxt/error-component.mjs": {
93 | "resourceType": "script",
94 | "module": true,
95 | "dynamicImports": [
96 | "node_modules/@nuxt/ui-templates/dist/templates/error-404.vue",
97 | "node_modules/@nuxt/ui-templates/dist/templates/error-500.vue"
98 | ],
99 | "file": "error-component.3b96486c.js",
100 | "imports": [
101 | "node_modules/nuxt/dist/app/entry.mjs"
102 | ],
103 | "isDynamicEntry": true,
104 | "src": "virtual:nuxt:/Users/57code/nuxt-app/.nuxt/error-component.mjs"
105 | }
106 | };
107 |
108 | export { client_manifest as default };
109 | //# sourceMappingURL=client.manifest.mjs.map
110 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-404-styles.a5c3f351.mjs:
--------------------------------------------------------------------------------
1 | const error404_vue_vue_type_style_index_0_scoped_30d2164e_lang = '.spotlight[data-v-30d2164e]{background:linear-gradient(45deg,#00dc82,#36e4da 50%,#0047e1);bottom:-30vh;filter:blur(20vh);height:40vh}.gradient-border[data-v-30d2164e]{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:.5rem;position:relative}@media (prefers-color-scheme:light){.gradient-border[data-v-30d2164e]{background-color:hsla(0,0%,100%,.3)}.gradient-border[data-v-30d2164e]:before{background:linear-gradient(90deg,#e2e2e2,#e2e2e2 25%,#00dc82 50%,#36e4da 75%,#0047e1)}}@media (prefers-color-scheme:dark){.gradient-border[data-v-30d2164e]{background-color:hsla(0,0%,8%,.3)}.gradient-border[data-v-30d2164e]:before{background:linear-gradient(90deg,#303030,#303030 25%,#00dc82 50%,#36e4da 75%,#0047e1)}}.gradient-border[data-v-30d2164e]:before{background-size:400% auto;border-radius:.5rem;bottom:0;content:"";left:0;-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;opacity:.5;padding:2px;position:absolute;right:0;top:0;transition:background-position .3s ease-in-out,opacity .2s ease-in-out;width:100%}.gradient-border[data-v-30d2164e]:hover:before{background-position:-50% 0;opacity:1}.bg-white[data-v-30d2164e]{--tw-bg-opacity:1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.cursor-pointer[data-v-30d2164e]{cursor:pointer}.flex[data-v-30d2164e]{display:flex}.grid[data-v-30d2164e]{display:grid}.place-content-center[data-v-30d2164e]{place-content:center}.items-center[data-v-30d2164e]{align-items:center}.justify-center[data-v-30d2164e]{justify-content:center}.font-sans[data-v-30d2164e]{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.font-medium[data-v-30d2164e]{font-weight:500}.font-light[data-v-30d2164e]{font-weight:300}.text-8xl[data-v-30d2164e]{font-size:6rem;line-height:1}.text-xl[data-v-30d2164e]{font-size:1.25rem;line-height:1.75rem}.leading-tight[data-v-30d2164e]{line-height:1.25}.mb-8[data-v-30d2164e]{margin-bottom:2rem}.mb-16[data-v-30d2164e]{margin-bottom:4rem}.max-w-520px[data-v-30d2164e]{max-width:520px}.min-h-screen[data-v-30d2164e]{min-height:100vh}.overflow-hidden[data-v-30d2164e]{overflow:hidden}.px-8[data-v-30d2164e]{padding-left:2rem;padding-right:2rem}.py-2[data-v-30d2164e]{padding-bottom:.5rem;padding-top:.5rem}.px-4[data-v-30d2164e]{padding-left:1rem;padding-right:1rem}.fixed[data-v-30d2164e]{position:fixed}.left-0[data-v-30d2164e]{left:0}.right-0[data-v-30d2164e]{right:0}.text-center[data-v-30d2164e]{text-align:center}.text-black[data-v-30d2164e]{--tw-text-opacity:1;color:rgba(0,0,0,var(--tw-text-opacity))}.antialiased[data-v-30d2164e]{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.w-full[data-v-30d2164e]{width:100%}.z-10[data-v-30d2164e]{z-index:10}.z-20[data-v-30d2164e]{z-index:20}@media (min-width:640px){.sm\\:text-4xl[data-v-30d2164e]{font-size:2.25rem;line-height:2.5rem}.sm\\:text-xl[data-v-30d2164e]{font-size:1.25rem;line-height:1.75rem}.sm\\:text-10xl[data-v-30d2164e]{font-size:10rem;line-height:1}.sm\\:px-0[data-v-30d2164e]{padding-left:0;padding-right:0}.sm\\:py-3[data-v-30d2164e]{padding-bottom:.75rem;padding-top:.75rem}.sm\\:px-6[data-v-30d2164e]{padding-left:1.5rem;padding-right:1.5rem}}@media (prefers-color-scheme:dark){.dark\\:bg-black[data-v-30d2164e]{--tw-bg-opacity:1;background-color:rgba(0,0,0,var(--tw-bg-opacity))}.dark\\:text-white[data-v-30d2164e]{--tw-text-opacity:1;color:rgba(255,255,255,var(--tw-text-opacity))}}';
2 |
3 | const error404Styles_a5c3f351 = [error404_vue_vue_type_style_index_0_scoped_30d2164e_lang];
4 |
5 | export { error404Styles_a5c3f351 as default };
6 | //# sourceMappingURL=error-404-styles.a5c3f351.mjs.map
7 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/error-500.mjs:
--------------------------------------------------------------------------------
1 | const _messages = {"appName":"Nuxt","version":"","statusCode":500,"statusMessage":"Server error","description":"This page is temporarily unavailable."};
2 | const _render = function({ messages }) {
3 | var __t, __p = '';
4 | __p += '' +
5 | ((__t = ( messages.statusCode )) == null ? '' : __t) +
6 | ' - ' +
7 | ((__t = ( messages.statusMessage )) == null ? '' : __t) +
8 | ' | ' +
9 | ((__t = ( messages.appName )) == null ? '' : __t) +
10 | '' +
11 | ((__t = ( messages.statusCode )) == null ? '' : __t) +
12 | '
' +
13 | ((__t = ( messages.description )) == null ? '' : __t) +
14 | '
';
15 | return __p
16 | };
17 | const _template = (messages) => _render({ messages: { ..._messages, ...messages } });
18 | const template = _template;
19 |
20 | export { template };
21 | //# sourceMappingURL=error-500.mjs.map
22 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/error-404-59cb290a.mjs:
--------------------------------------------------------------------------------
1 | import { _ as __nuxt_component_0 } from './nuxt-link-58ca22a8.mjs';
2 | import { _ as _export_sfc } from '../server.mjs';
3 | import { mergeProps, withCtx, createTextVNode, toDisplayString, useSSRContext } from 'vue';
4 | import { u as useHead } from './app.config-a3bb0fb9.mjs';
5 | import { ssrRenderAttrs, ssrInterpolate, ssrRenderComponent } from 'vue/server-renderer';
6 | import 'ufo';
7 | import 'ofetch';
8 | import 'hookable';
9 | import 'unctx';
10 | import '@unhead/vue';
11 | import '@unhead/dom';
12 | import '@unhead/ssr';
13 | import 'vue-router';
14 | import 'h3';
15 | import 'defu';
16 | import '../../nitro/vercel.mjs';
17 | import 'node-fetch-native/polyfill';
18 | import 'destr';
19 | import 'unenv/runtime/fetch/index';
20 | import 'scule';
21 | import 'ohash';
22 | import 'unstorage';
23 | import 'radix3';
24 |
25 | const _sfc_main = {
26 | __name: "error-404",
27 | __ssrInlineRender: true,
28 | props: {
29 | appName: {
30 | type: String,
31 | default: "Nuxt"
32 | },
33 | version: {
34 | type: String,
35 | default: ""
36 | },
37 | statusCode: {
38 | type: Number,
39 | default: 404
40 | },
41 | statusMessage: {
42 | type: String,
43 | default: "Not Found"
44 | },
45 | description: {
46 | type: String,
47 | default: "Sorry, the page you are looking for could not be found."
48 | },
49 | backHome: {
50 | type: String,
51 | default: "Go back home"
52 | }
53 | },
54 | setup(__props) {
55 | const props = __props;
56 | useHead({
57 | title: `${props.statusCode} - ${props.statusMessage} | ${props.appName}`,
58 | script: [],
59 | style: [
60 | {
61 | children: `*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}a{color:inherit;text-decoration:inherit}body{margin:0;font-family:inherit;line-height:inherit}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}h1,p{margin:0}h1{font-size:inherit;font-weight:inherit}`
62 | }
63 | ]
64 | });
65 | return (_ctx, _push, _parent, _attrs) => {
66 | const _component_NuxtLink = __nuxt_component_0;
67 | _push(`${ssrInterpolate(__props.statusCode)}
${ssrInterpolate(__props.description)}
`);
68 | _push(ssrRenderComponent(_component_NuxtLink, {
69 | to: "/",
70 | class: "gradient-border text-md sm:text-xl py-2 px-4 sm:py-3 sm:px-6 cursor-pointer"
71 | }, {
72 | default: withCtx((_, _push2, _parent2, _scopeId) => {
73 | if (_push2) {
74 | _push2(`${ssrInterpolate(__props.backHome)}`);
75 | } else {
76 | return [
77 | createTextVNode(toDisplayString(__props.backHome), 1)
78 | ];
79 | }
80 | }),
81 | _: 1
82 | }, _parent));
83 | _push(`
`);
84 | };
85 | }
86 | };
87 | const _sfc_setup = _sfc_main.setup;
88 | _sfc_main.setup = (props, ctx) => {
89 | const ssrContext = useSSRContext();
90 | (ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("node_modules/@nuxt/ui-templates/dist/templates/error-404.vue");
91 | return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
92 | };
93 | const error404 = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-30d2164e"]]);
94 |
95 | export { error404 as default };
96 | //# sourceMappingURL=error-404-59cb290a.mjs.map
97 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/nuxt-link-58ca22a8.mjs.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"nuxt-link-58ca22a8.mjs","sources":["/Users/57code/nuxt-app/.nuxt/dist/server/_nuxt/nuxt-link-58ca22a8.js"],"sourcesContent":null,"names":["_a"],"mappings":"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"}
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/app/_nuxt/nuxt-link-58ca22a8.mjs:
--------------------------------------------------------------------------------
1 | import { defineComponent, computed, ref, h, resolveComponent } from 'vue';
2 | import { hasProtocol } from 'ufo';
3 | import { u as useRouter, n as navigateTo } from '../server.mjs';
4 |
5 | const firstNonUndefined = (...args) => args.find((arg) => arg !== void 0);
6 | const DEFAULT_EXTERNAL_REL_ATTRIBUTE = "noopener noreferrer";
7 | function defineNuxtLink(options) {
8 | const componentName = options.componentName || "NuxtLink";
9 | return /* @__PURE__ */ defineComponent({
10 | name: componentName,
11 | props: {
12 | // Routing
13 | to: {
14 | type: [String, Object],
15 | default: void 0,
16 | required: false
17 | },
18 | href: {
19 | type: [String, Object],
20 | default: void 0,
21 | required: false
22 | },
23 | // Attributes
24 | target: {
25 | type: String,
26 | default: void 0,
27 | required: false
28 | },
29 | rel: {
30 | type: String,
31 | default: void 0,
32 | required: false
33 | },
34 | noRel: {
35 | type: Boolean,
36 | default: void 0,
37 | required: false
38 | },
39 | // Prefetching
40 | prefetch: {
41 | type: Boolean,
42 | default: void 0,
43 | required: false
44 | },
45 | noPrefetch: {
46 | type: Boolean,
47 | default: void 0,
48 | required: false
49 | },
50 | // Styling
51 | activeClass: {
52 | type: String,
53 | default: void 0,
54 | required: false
55 | },
56 | exactActiveClass: {
57 | type: String,
58 | default: void 0,
59 | required: false
60 | },
61 | prefetchedClass: {
62 | type: String,
63 | default: void 0,
64 | required: false
65 | },
66 | // Vue Router's `` additional props
67 | replace: {
68 | type: Boolean,
69 | default: void 0,
70 | required: false
71 | },
72 | ariaCurrentValue: {
73 | type: String,
74 | default: void 0,
75 | required: false
76 | },
77 | // Edge cases handling
78 | external: {
79 | type: Boolean,
80 | default: void 0,
81 | required: false
82 | },
83 | // Slot API
84 | custom: {
85 | type: Boolean,
86 | default: void 0,
87 | required: false
88 | }
89 | },
90 | setup(props, { slots }) {
91 | const router = useRouter();
92 | const to = computed(() => {
93 | return props.to || props.href || "";
94 | });
95 | const isExternal = computed(() => {
96 | if (props.external) {
97 | return true;
98 | }
99 | if (props.target && props.target !== "_self") {
100 | return true;
101 | }
102 | if (typeof to.value === "object") {
103 | return false;
104 | }
105 | return to.value === "" || hasProtocol(to.value, true);
106 | });
107 | const prefetched = ref(false);
108 | const el = void 0;
109 | return () => {
110 | var _a2;
111 | var _a, _b;
112 | if (!isExternal.value) {
113 | return h(
114 | resolveComponent("RouterLink"),
115 | {
116 | ref: void 0,
117 | to: to.value,
118 | ...prefetched.value && !props.custom ? { class: props.prefetchedClass || options.prefetchedClass } : {},
119 | activeClass: props.activeClass || options.activeClass,
120 | exactActiveClass: props.exactActiveClass || options.exactActiveClass,
121 | replace: props.replace,
122 | ariaCurrentValue: props.ariaCurrentValue,
123 | custom: props.custom
124 | },
125 | slots.default
126 | );
127 | }
128 | const href = typeof to.value === "object" ? (_a2 = (_a = router.resolve(to.value)) == null ? void 0 : _a.href) != null ? _a2 : null : to.value || null;
129 | const target = props.target || null;
130 | const rel = props.noRel ? null : firstNonUndefined(props.rel, options.externalRelAttribute, href ? DEFAULT_EXTERNAL_REL_ATTRIBUTE : "") || null;
131 | const navigate = () => navigateTo(href, { replace: props.replace });
132 | if (props.custom) {
133 | if (!slots.default) {
134 | return null;
135 | }
136 | return slots.default({
137 | href,
138 | navigate,
139 | route: router.resolve(href),
140 | rel,
141 | target,
142 | isExternal: isExternal.value,
143 | isActive: false,
144 | isExactActive: false
145 | });
146 | }
147 | return h("a", { ref: el, href, rel, target }, (_b = slots.default) == null ? void 0 : _b.call(slots));
148 | };
149 | }
150 | });
151 | }
152 | const __nuxt_component_0 = /* @__PURE__ */ defineNuxtLink({ componentName: "NuxtLink" });
153 |
154 | export { __nuxt_component_0 as _ };
155 | //# sourceMappingURL=nuxt-link-58ca22a8.mjs.map
156 |
--------------------------------------------------------------------------------
/server/database/seed.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from '@prisma/client'
2 | const prisma = new PrismaClient()
3 | async function main() {
4 | await prisma.column.create({
5 | data: {
6 | title: 'Docker部署与持续集成',
7 | cover: 'Docker部署.png',
8 | url: 'https://duz.xet.tech/s/2zl8EZ',
9 | desc: '',
10 | content: '',
11 | oPrice: 299,
12 | price: 199,
13 | },
14 | })
15 | await prisma.column.create({
16 | data: {
17 | title: 'Node服务器端',
18 | cover: 'Node与服务器端.jpg',
19 | url: 'https://appwhrkrsz84443.pc.xiaoe-tech.com/p/t_pc/goods_pc_detail/goods_detail/p_62b177bae4b09baaaaef38b9?product_id=p_62b177bae4b09baaaaef38b9',
20 | desc: '',
21 | content: '',
22 | oPrice: 699,
23 | price: 599,
24 | },
25 | })
26 |
27 | await prisma.column.create({
28 | data: {
29 | title: '前端工程化',
30 | cover: '前端工程化.png',
31 | url: 'https://appwhrkrsz84443.pc.xiaoe-tech.com/p/t_pc/goods_pc_detail/goods_detail/p_62b17adae4b07bd2d7b0af40?product_id=p_62b17adae4b07bd2d7b0af40',
32 | desc: '',
33 | content: '',
34 | oPrice: 699,
35 | price: 599,
36 | },
37 | })
38 |
39 | await prisma.column.create({
40 | data: {
41 | title: 'Webpack优化实战',
42 | cover: 'webpack优化.jpeg',
43 | url: 'https://appwhrkrsz84443.pc.xiaoe-tech.com/p/t_pc/goods_pc_detail/goods_detail/p_63252784e4b0a51fef1bb2dc?product_id=p_63252784e4b0a51fef1bb2dc',
44 | desc: '',
45 | content: '',
46 | oPrice: 399,
47 | price: 299,
48 | },
49 | })
50 |
51 | // await prisma.column.create({
52 | // data: {
53 | // title: '上层框架最佳选择: Nuxt',
54 | // cover: 'column-nuxt.png',
55 | // desc: '上层框架最佳选择:Nuxt 是一个基于 Vue 的上层全栈通用框架,它提供了大量优秀特性提升开发效率和体验,因此是 Vue 栈上层框架的最佳选择之一。',
56 | // content: `开箱即用的开发环境
57 | // 开发者对一款现代框架的一个重要要求就是开箱即用。在这方面 Nuxt 提供了如下能力:
58 |
59 | // 整合 Vue3 作为视图引擎;
60 | // 整合 Webpack5 和 Vite 作为打包工具;
61 | // 提供最新 ES 语法,零配置 TS 支持;
62 | // 内置 vue-router,基于文件的路由;
63 | // 内置 SSR 友好的全局状态管理模块;
64 | // 内置数据访问模块 useFetch 等等。
65 | // 良好的开发体验
66 | // 良好的开发体验主要来源于效率工具和避免重复劳动,这方面我们看一下 Nuxt 提供的能力:
67 |
68 | // 基于文件的路由支持;
69 | // 组件、依赖库、工具集的自动导入;
70 | // 内置的数据获取模块和新的编程范式;
71 | // 零配置的 TS 支持;
72 | // 插件、模块、中间件等多种复用机制。
73 | // 服务端能力
74 | // Nuxt 内置了 Nitro 服务端引擎,能够同时提供 SSR 和 API 路由支持,这也就是说,除了能够提供服务端渲染能力,我们还能编写服务端接口,这使我们拥有了全栈开发能力。另外 API 兼容 node、connect、express,未来也可以把应用发布到 Node.js、Serverless 等服务器运行环境。
75 |
76 | // 不同场景解决方案
77 | // 为了满足开发者多种场景开发需求,Nuxt 提供了 5 种渲染模式:
78 |
79 | // 服务端渲染 SSR;
80 | // 客户端渲染 SPA;
81 | // 全静态内容生成 SSG;
82 | // 混合渲染模式 Hybrid;
83 | // 边缘渲染 Edge-render。
84 | // 在后面章节中,我们也将给大家详细介绍这几种模式的异同和选择。`,
85 | // },
86 | // })
87 |
88 | await prisma.course.create({
89 | data: {
90 | title: 'React全栈实战',
91 | cover: 'React全栈进阶.png',
92 | oPrice: 899,
93 | price: 799,
94 | url: 'https://appwhrkrsz84443.pc.xiaoe-tech.com/p/t_pc/goods_pc_detail/goods_detail/p_6402a238e4b07b0558395e96',
95 | },
96 | })
97 |
98 | await prisma.course.create({
99 | data: {
100 | title: 'Vue3组件库实战',
101 | cover: 'Vue3组件库实战.png',
102 | desc: '这门课我会全面讲解 Nuxt3 核心知识,然后在后端开发方面做一个知识扩展,最后带大家完成一个完整的实战项目。',
103 | oPrice: 699,
104 | price: 599,
105 | url: 'https://appwhrkrsz84443.pc.xiaoe-tech.com/p/t_pc/goods_pc_detail/goods_detail/p_62a44620e4b01c509abcbcda?product_id=p_62a44620e4b01c509abcbcda',
106 | },
107 | })
108 | await prisma.course.create({
109 | data: {
110 | title: 'Vue源码全家桶',
111 | cover: 'Vue源码全家桶.jpeg',
112 | desc: '这门课我会全面讲解 Nuxt3 核心知识,然后在后端开发方面做一个知识扩展,最后带大家完成一个完整的实战项目。',
113 | oPrice: 699,
114 | price: 599,
115 | url: 'https://appwhrkrsz84443.pc.xiaoe-tech.com/p/t_pc/goods_pc_detail/goods_detail/p_62b4e11be4b0a51feef6bb4f?product_id=p_62b4e11be4b0a51feef6bb4f',
116 | },
117 | })
118 |
119 | await prisma.course.create({
120 | data: {
121 | title: 'Nuxt全栈开发',
122 | cover: 'course-nuxt.png',
123 | desc: '这门课我会全面讲解 Nuxt3 核心知识,然后在后端开发方面做一个知识扩展,最后带大家完成一个完整的实战项目。',
124 | oPrice: 129,
125 | price: 99,
126 | detail: `这门课程共分五个模块:
127 | 模块一,将从渲染模式等基础概念出发,先扭转一些同学的固有思维,补充缺失知识;
128 | 模块二,结合个人博客案例,深入学习 Nuxt3 核心特性;
129 | 模块三,解决项目工程化问题,从扩展性、复用性等角度深入了解模块等框架进阶知识;
130 | 模块四,将为项目实战做准备,给大家讲解全栈知识,包括数据库设计、接口设计和开发,大家会接触并掌握 Apifox、Prisma 等前端比较时髦的新工具;
131 | 模块五,项目实战,我会带大家开发一个知识分享社区主题的全栈项目,包括了从接口开发,到前端开发,再到优化、部署和持续集成的全流程实战。
132 | 相信学习完本小册,会让你深入掌握 Nuxt3 的同时,还能全方位提升自己的知识深度和架构水平。`,
133 | Catalogue: {
134 | createMany: {
135 | data: [
136 | { title: '01开篇:课程介绍和安排', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
137 | { title: '02上层框架最佳选择', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
138 | { title: '03五种渲染模式', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
139 | { title: '04快速创建首个nuxt项目', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
140 | { title: '05文件路由和布局', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
141 | { title: '06使用静态资源', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
142 | { title: '07自动导入特性', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
143 | { title: '08API路由', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
144 | { title: '09数据获取', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
145 | { title: '10状态管理', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
146 | { title: '11错误处理', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
147 | { title: '12常用配置和优化', source: 'https://juejin.cn/video/7202149403342143520/section/7202885295820242947' },
148 | ],
149 | },
150 | },
151 | },
152 | })
153 | }
154 | main()
155 | .then(async () => {
156 | await prisma.$disconnect()
157 | })
158 | .catch(async (e) => {
159 | console.error(e)
160 | await prisma.$disconnect()
161 | process.exit(1)
162 | })
163 |
--------------------------------------------------------------------------------
/.vercel/output/functions/__nitro.func/chunks/handlers/renderer.mjs:
--------------------------------------------------------------------------------
1 | import { createRenderer } from 'vue-bundle-renderer/runtime';
2 | import { eventHandler, getQuery, createError } from 'h3';
3 | import { renderToString } from 'vue/server-renderer';
4 | import { u as useNitroApp, a as useRuntimeConfig, g as getRouteRules } from '../nitro/vercel.mjs';
5 | import { joinURL } from 'ufo';
6 | import 'node-fetch-native/polyfill';
7 | import 'ofetch';
8 | import 'destr';
9 | import 'unenv/runtime/fetch/index';
10 | import 'hookable';
11 | import 'scule';
12 | import 'ohash';
13 | import 'unstorage';
14 | import 'defu';
15 | import 'radix3';
16 |
17 | function defineRenderHandler(handler) {
18 | return eventHandler(async (event) => {
19 | if (event.node.req.url.endsWith("/favicon.ico")) {
20 | event.node.res.setHeader("Content-Type", "image/x-icon");
21 | event.node.res.end(
22 | "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
23 | );
24 | return;
25 | }
26 | const response = await handler(event);
27 | if (!response) {
28 | if (!event.node.res.writableEnded) {
29 | event.node.res.statusCode = event.node.res.statusCode === 200 ? 500 : event.node.res.statusCode;
30 | event.node.res.end(
31 | "No response returned from render handler: " + event.node.req.url
32 | );
33 | }
34 | return;
35 | }
36 | const nitroApp = useNitroApp();
37 | await nitroApp.hooks.callHook("render:response", response, { event });
38 | if (!event.node.res.headersSent && response.headers) {
39 | for (const header in response.headers) {
40 | event.node.res.setHeader(header, response.headers[header]);
41 | }
42 | if (response.statusCode) {
43 | event.node.res.statusCode = response.statusCode;
44 | }
45 | if (response.statusMessage) {
46 | event.node.res.statusMessage = response.statusMessage;
47 | }
48 | }
49 | return typeof response.body === "string" ? response.body : JSON.stringify(response.body);
50 | });
51 | }
52 |
53 | const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
54 | const unsafeChars = /[<>\b\f\n\r\t\0\u2028\u2029]/g;
55 | const reserved = /^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/;
56 | const escaped = {
57 | "<": "\\u003C",
58 | ">": "\\u003E",
59 | "/": "\\u002F",
60 | "\\": "\\\\",
61 | "\b": "\\b",
62 | "\f": "\\f",
63 | "\n": "\\n",
64 | "\r": "\\r",
65 | " ": "\\t",
66 | "\0": "\\0",
67 | "\u2028": "\\u2028",
68 | "\u2029": "\\u2029"
69 | };
70 | const objectProtoOwnPropertyNames = Object.getOwnPropertyNames(Object.prototype).sort().join("\0");
71 | function devalue(value) {
72 | const counts = new Map();
73 | let logNum = 0;
74 | function log(message) {
75 | if (logNum < 100) {
76 | console.warn(message);
77 | logNum += 1;
78 | }
79 | }
80 | function walk(thing) {
81 | if (typeof thing === "function") {
82 | log(`Cannot stringify a function ${thing.name}`);
83 | return;
84 | }
85 | if (counts.has(thing)) {
86 | counts.set(thing, counts.get(thing) + 1);
87 | return;
88 | }
89 | counts.set(thing, 1);
90 | if (!isPrimitive(thing)) {
91 | const type = getType(thing);
92 | switch (type) {
93 | case "Number":
94 | case "String":
95 | case "Boolean":
96 | case "Date":
97 | case "RegExp":
98 | return;
99 | case "Array":
100 | thing.forEach(walk);
101 | break;
102 | case "Set":
103 | case "Map":
104 | Array.from(thing).forEach(walk);
105 | break;
106 | default:
107 | const proto = Object.getPrototypeOf(thing);
108 | if (proto !== Object.prototype && proto !== null && Object.getOwnPropertyNames(proto).sort().join("\0") !== objectProtoOwnPropertyNames) {
109 | if (typeof thing.toJSON !== "function") {
110 | log(`Cannot stringify arbitrary non-POJOs ${thing.constructor.name}`);
111 | }
112 | } else if (Object.getOwnPropertySymbols(thing).length > 0) {
113 | log(`Cannot stringify POJOs with symbolic keys ${Object.getOwnPropertySymbols(thing).map((symbol) => symbol.toString())}`);
114 | } else {
115 | Object.keys(thing).forEach((key) => walk(thing[key]));
116 | }
117 | }
118 | }
119 | }
120 | walk(value);
121 | const names = new Map();
122 | Array.from(counts).filter((entry) => entry[1] > 1).sort((a, b) => b[1] - a[1]).forEach((entry, i) => {
123 | names.set(entry[0], getName(i));
124 | });
125 | function stringify(thing) {
126 | if (names.has(thing)) {
127 | return names.get(thing);
128 | }
129 | if (isPrimitive(thing)) {
130 | return stringifyPrimitive(thing);
131 | }
132 | const type = getType(thing);
133 | switch (type) {
134 | case "Number":
135 | case "String":
136 | case "Boolean":
137 | return `Object(${stringify(thing.valueOf())})`;
138 | case "RegExp":
139 | return thing.toString();
140 | case "Date":
141 | return `new Date(${thing.getTime()})`;
142 | case "Array":
143 | const members = thing.map((v, i) => i in thing ? stringify(v) : "");
144 | const tail = thing.length === 0 || thing.length - 1 in thing ? "" : ",";
145 | return `[${members.join(",")}${tail}]`;
146 | case "Set":
147 | case "Map":
148 | return `new ${type}([${Array.from(thing).map(stringify).join(",")}])`;
149 | default:
150 | if (thing.toJSON) {
151 | let json = thing.toJSON();
152 | if (getType(json) === "String") {
153 | try {
154 | json = JSON.parse(json);
155 | } catch (e) {
156 | }
157 | }
158 | return stringify(json);
159 | }
160 | if (Object.getPrototypeOf(thing) === null) {
161 | if (Object.keys(thing).length === 0) {
162 | return "Object.create(null)";
163 | }
164 | return `Object.create(null,{${Object.keys(thing).map((key) => `${safeKey(key)}:{writable:true,enumerable:true,value:${stringify(thing[key])}}`).join(",")}})`;
165 | }
166 | return `{${Object.keys(thing).map((key) => `${safeKey(key)}:${stringify(thing[key])}`).join(",")}}`;
167 | }
168 | }
169 | const str = stringify(value);
170 | if (names.size) {
171 | const params = [];
172 | const statements = [];
173 | const values = [];
174 | names.forEach((name, thing) => {
175 | params.push(name);
176 | if (isPrimitive(thing)) {
177 | values.push(stringifyPrimitive(thing));
178 | return;
179 | }
180 | const type = getType(thing);
181 | switch (type) {
182 | case "Number":
183 | case "String":
184 | case "Boolean":
185 | values.push(`Object(${stringify(thing.valueOf())})`);
186 | break;
187 | case "RegExp":
188 | values.push(thing.toString());
189 | break;
190 | case "Date":
191 | values.push(`new Date(${thing.getTime()})`);
192 | break;
193 | case "Array":
194 | values.push(`Array(${thing.length})`);
195 | thing.forEach((v, i) => {
196 | statements.push(`${name}[${i}]=${stringify(v)}`);
197 | });
198 | break;
199 | case "Set":
200 | values.push("new Set");
201 | statements.push(`${name}.${Array.from(thing).map((v) => `add(${stringify(v)})`).join(".")}`);
202 | break;
203 | case "Map":
204 | values.push("new Map");
205 | statements.push(`${name}.${Array.from(thing).map(([k, v]) => `set(${stringify(k)}, ${stringify(v)})`).join(".")}`);
206 | break;
207 | default:
208 | values.push(Object.getPrototypeOf(thing) === null ? "Object.create(null)" : "{}");
209 | Object.keys(thing).forEach((key) => {
210 | statements.push(`${name}${safeProp(key)}=${stringify(thing[key])}`);
211 | });
212 | }
213 | });
214 | statements.push(`return ${str}`);
215 | return `(function(${params.join(",")}){${statements.join(";")}}(${values.join(",")}))`;
216 | } else {
217 | return str;
218 | }
219 | }
220 | function getName(num) {
221 | let name = "";
222 | do {
223 | name = chars[num % chars.length] + name;
224 | num = ~~(num / chars.length) - 1;
225 | } while (num >= 0);
226 | return reserved.test(name) ? `${name}0` : name;
227 | }
228 | function isPrimitive(thing) {
229 | return Object(thing) !== thing;
230 | }
231 | function stringifyPrimitive(thing) {
232 | if (typeof thing === "string") {
233 | return stringifyString(thing);
234 | }
235 | if (thing === void 0) {
236 | return "void 0";
237 | }
238 | if (thing === 0 && 1 / thing < 0) {
239 | return "-0";
240 | }
241 | const str = String(thing);
242 | if (typeof thing === "number") {
243 | return str.replace(/^(-)?0\./, "$1.");
244 | }
245 | return str;
246 | }
247 | function getType(thing) {
248 | return Object.prototype.toString.call(thing).slice(8, -1);
249 | }
250 | function escapeUnsafeChar(c) {
251 | return escaped[c] || c;
252 | }
253 | function escapeUnsafeChars(str) {
254 | return str.replace(unsafeChars, escapeUnsafeChar);
255 | }
256 | function safeKey(key) {
257 | return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : escapeUnsafeChars(JSON.stringify(key));
258 | }
259 | function safeProp(key) {
260 | return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? `.${key}` : `[${escapeUnsafeChars(JSON.stringify(key))}]`;
261 | }
262 | function stringifyString(str) {
263 | let result = '"';
264 | for (let i = 0; i < str.length; i += 1) {
265 | const char = str.charAt(i);
266 | const code = char.charCodeAt(0);
267 | if (char === '"') {
268 | result += '\\"';
269 | } else if (char in escaped) {
270 | result += escaped[char];
271 | } else if (code >= 55296 && code <= 57343) {
272 | const next = str.charCodeAt(i + 1);
273 | if (code <= 56319 && (next >= 56320 && next <= 57343)) {
274 | result += char + str[++i];
275 | } else {
276 | result += `\\u${code.toString(16).toUpperCase()}`;
277 | }
278 | } else {
279 | result += char;
280 | }
281 | }
282 | result += '"';
283 | return result;
284 | }
285 |
286 | const appRootId = "__nuxt";
287 |
288 | const appRootTag = "div";
289 |
290 | function buildAssetsURL(...path) {
291 | return joinURL(publicAssetsURL(), useRuntimeConfig().app.buildAssetsDir, ...path);
292 | }
293 | function publicAssetsURL(...path) {
294 | const publicBase = useRuntimeConfig().app.cdnURL || useRuntimeConfig().app.baseURL;
295 | return path.length ? joinURL(publicBase, ...path) : publicBase;
296 | }
297 |
298 | globalThis.__buildAssetsURL = buildAssetsURL;
299 | globalThis.__publicAssetsURL = publicAssetsURL;
300 | const getClientManifest = () => import('../app/client.manifest.mjs').then((r) => r.default || r).then((r) => typeof r === "function" ? r() : r);
301 | const getStaticRenderedHead = () => import('../rollup/_virtual_head-static.mjs').then((r) => r.default || r);
302 | const getServerEntry = () => import('../app/server.mjs').then((r) => r.default || r);
303 | const getSSRStyles = lazyCachedFunction(() => import('../app/styles.mjs').then((r) => r.default || r));
304 | const getSSRRenderer = lazyCachedFunction(async () => {
305 | const manifest = await getClientManifest();
306 | if (!manifest) {
307 | throw new Error("client.manifest is not available");
308 | }
309 | const createSSRApp = await getServerEntry();
310 | if (!createSSRApp) {
311 | throw new Error("Server bundle is not available");
312 | }
313 | const options = {
314 | manifest,
315 | renderToString: renderToString$1,
316 | buildAssetsURL
317 | };
318 | const renderer = createRenderer(createSSRApp, options);
319 | async function renderToString$1(input, context) {
320 | const html = await renderToString(input, context);
321 | return `<${appRootTag} id="${appRootId}">${html}${appRootTag}>`;
322 | }
323 | return renderer;
324 | });
325 | const getSPARenderer = lazyCachedFunction(async () => {
326 | const manifest = await getClientManifest();
327 | const options = {
328 | manifest,
329 | renderToString: () => `<${appRootTag} id="${appRootId}">${appRootTag}>`,
330 | buildAssetsURL
331 | };
332 | const renderer = createRenderer(() => () => {
333 | }, options);
334 | const result = await renderer.renderToString({});
335 | const renderToString = (ssrContext) => {
336 | const config = useRuntimeConfig();
337 | ssrContext.payload = {
338 | serverRendered: false,
339 | config: {
340 | public: config.public,
341 | app: config.app
342 | },
343 | data: {},
344 | state: {}
345 | };
346 | ssrContext.renderMeta = ssrContext.renderMeta ?? getStaticRenderedHead;
347 | return Promise.resolve(result);
348 | };
349 | return {
350 | rendererContext: renderer.rendererContext,
351 | renderToString
352 | };
353 | });
354 | const PAYLOAD_URL_RE = /\/_payload(\.[a-zA-Z0-9]+)?.js(\?.*)?$/;
355 | const renderer = defineRenderHandler(async (event) => {
356 | const nitroApp = useNitroApp();
357 | const ssrError = event.node.req.url?.startsWith("/__nuxt_error") ? getQuery(event) : null;
358 | if (ssrError && ssrError.statusCode) {
359 | ssrError.statusCode = parseInt(ssrError.statusCode);
360 | }
361 | if (ssrError && event.node.req.socket.readyState !== "readOnly") {
362 | throw createError("Cannot directly render error page!");
363 | }
364 | const islandContext = void 0;
365 | let url = ssrError?.url || islandContext?.url || event.node.req.url;
366 | const isRenderingPayload = PAYLOAD_URL_RE.test(url);
367 | if (isRenderingPayload) {
368 | url = url.substring(0, url.lastIndexOf("/")) || "/";
369 | event.node.req.url = url;
370 | }
371 | const routeOptions = getRouteRules(event);
372 | const ssrContext = {
373 | url,
374 | event,
375 | runtimeConfig: useRuntimeConfig(),
376 | noSSR: !!event.node.req.headers["x-nuxt-no-ssr"] || routeOptions.ssr === false || (false),
377 | error: !!ssrError,
378 | nuxt: void 0,
379 | /* NuxtApp */
380 | payload: ssrError ? { error: ssrError } : {},
381 | islandContext
382 | };
383 | const renderer = ssrContext.noSSR ? await getSPARenderer() : await getSSRRenderer();
384 | const _rendered = await renderer.renderToString(ssrContext).catch((error) => {
385 | throw !ssrError && ssrContext.payload?.error || error;
386 | });
387 | await ssrContext.nuxt?.hooks.callHook("app:rendered", { ssrContext });
388 | if (ssrContext.payload?.error && !ssrError) {
389 | throw ssrContext.payload.error;
390 | }
391 | if (isRenderingPayload) {
392 | const response2 = renderPayloadResponse(ssrContext);
393 | return response2;
394 | }
395 | const renderedMeta = await ssrContext.renderMeta?.() ?? {};
396 | const inlinedStyles = await renderInlineStyles(ssrContext.modules ?? ssrContext._registeredComponents ?? []) ;
397 | const htmlContext = {
398 | island: Boolean(islandContext),
399 | htmlAttrs: normalizeChunks([renderedMeta.htmlAttrs]),
400 | head: normalizeChunks([
401 | renderedMeta.headTags,
402 | null,
403 | _rendered.renderResourceHints(),
404 | _rendered.renderStyles(),
405 | inlinedStyles,
406 | ssrContext.styles
407 | ]),
408 | bodyAttrs: normalizeChunks([renderedMeta.bodyAttrs]),
409 | bodyPrepend: normalizeChunks([
410 | renderedMeta.bodyScriptsPrepend,
411 | ssrContext.teleports?.body
412 | ]),
413 | body: [_rendered.html],
414 | bodyAppend: normalizeChunks([
415 | `