pc

简介

此pc端基于nuxt3open in new window

前序准备

同管理后台,详见文档:前端

目录结构

├──📂 .nuxt                            # 开发模式下的产物
├──📂 .output                          # 打包构建的产物
├──📂 api                              # 所有请求
├──📂 assets                           # 静态资源(会经过构建工具构建)
├──📂 components                       # 全局公用组件
├──📂 composables                      # 全局可组合物(即hooks)
├──📂 constants                        # 静态数据
├──📂 enums                            # 全局枚举
├──📂 layouts                          # 基础布局  
├──📂 middleware                       # 中间件
├──📂 nuxt                             # nuxt.config.ts辅助函数
├──📂 pages                            # 所有页面
├──📂 plugins                          # 插件安装
├──📂 public                           # 服务器根目录
├──📂 scripts                          # js脚本
├──📂 stores                           # 全局状态管理
├──📂 typings                          # ts声明文件
├──📂 utils                            # 全局公用方法
├── .env.xxx                           # 环境变量配置
├── .eslintrc.cjs                      # eslint 配置项
├── app.vue                            # 根组件
├── global.d.ts                        # 全局ts声明文件
├── nuxt.config.ts                     # nuxt配置文件
├── package.json                       # package.json
├── tailwind.config.js                 # tailwindcss 配置项
├── tsconfig.json                      # ts 配置项

快速上手

  • 打开项目终端:使用vscode打开pc目录,在vscode左上角菜单中点击终端>新建终端

  • 复制env文件

    1. 复制.env.example文件,将复制的文件名修改为.env
    2. 复制.env.development.example,将复制的文件名修改为.env.development
    3. 复制.env.production.example,将复制的文件名修改为.env.production
  • 打开.env.development文件,修改NUXT_API_URL变量的值为项目安装部署的服务端地址

// env.development
# 请求域名
NUXT_API_URL=https://likeadmin.yixiangonline.com
  • 安装依赖(仅需要安装一次)
    在终端中运行命令

    npm install
    
  • 编译运行 在终端中运行命令

    npm run dev
    

项目上线

打包支持seo模式非seo模式(类似于vue的单页面应用),默认为非seo模式,修改.env文件可以修改模式

    # 是否开启ssr,填些任意值开启,为空则关闭
    NUXT_SSR=1

打包前修改接口请求域名,打开.env.production,修改NUXT_API_URL变量的值为项目安装部署的服务端地址

// env.production
# 请求域名
NUXT_API_URL=

注意

如果是非seo模式则不需要修改,将NUXT_API_URL留空即可,这样请求接口时会自动读取当前的域名做为接口请求的域名

seo模式

  • 修改路由基础路径,默认基础路径为/pc/,修改为/,打开.env文件修改

    // env
    # 基础路径
    NUXT_BASE_URL=/pc/
    
  • 在终端中运行命令

    npm run build
    
  • 将打包好后,会自动将打包产物复制到server/public/pc下面, 只需要提交代码到服务器即可

  • 服务器部署

  1. 部署之前,如果服务器没有安装node,需要打开宝塔【软件商店】,搜索“node”,安装【Node.js版本管理器 1.6】。
  2. 打开【网站】-【node项目】-【添加node项目】,设置好项目目录、域名、项目端口(默认端口为3000)等参数,然后添加即可。

  3. 进入node项目设置,【服务状态】,手动启动项目。

提示

需要修改端口,或者其他部署,请参考文档open in new window

非seo模式

  • 修改路由基础路径,默认基础路径为/pc/,如果不是请修改为/pc/,打开.env文件修改
    // env
    # 基础路径
    NUXT_BASE_URL=/pc/
    
  • 在终端中运行命令
    npm run build
    
  • 将打包好后,会自动将打包产物复制到server/public/pc下面,只需要提交代码到服务器即可

环境变量

公共环境

pc/.env

# 版本号
NUXT_VERSION=1.0

# 接口默认前缀  
NUXT_API_PREFIX=/api

# 客户端类型
NUXT_CLIENT=4

# 基础路径
NUXT_BASE_URL=/

# 是否开启ssr,填些任意值开启,为空则关闭
NUXT_SSR=1

# 端口号
NITRO_PORT=1000

开发环境

pc/.env.production

# 请求域名
NUXT_API_URL=

生产环境

pc/.env.development

# 请求域名
NUXT_API_URL=

路由

页面

页面相关请看文档open in new window

如何拦截一个需要登录才能访问的页面

// pages/xxxvue
<script lang="ts" setup>
    //...
    definePageMeta({
        auth: true
    })
    //...
</script>

接口请求

接口请求基于ohmyfetch库进行二次封装,并重写了nuxt$fetch函数,位于pc/utils/http,并且将创建的实例注入到了全局,在任何一个地方只需要使用$request即可发起请求

├──📂 http
│  ├── request.ts   # 封装的请求实例
│  ├── index.ts     # 接口返回统一处理及默认配置

一般只需要修改index.ts文件,其他文件无需修改
index.ts文件说明:

默认配置

const defaultOptions: FetchOptions = {
    // 基础接口地址
    baseURL: getApiUrl(),
    //请求头
    headers: {
        version: getVersion()
    },
    // 接口重试次数
    retry: 2,
    // 请求拦截
    async onRequest({ options }) {
        const { withToken } = options.requestOptions
        const headers = options.headers || {}
        // 添加token
        if (withToken) {
            const token = userStore.token
            headers['token'] = token
        }
        options.headers = headers
    },
    //自定义的参数
    requestOptions: {
        //请求前缀
        apiPrefix: getApiPrefix(),
        // 需要对返回数据进行处理
        isTransformResponse: true,
        // 是否返回默认的响应
        isReturnDefaultResponse: false,
        // 是否携带token
        withToken: true,
        // 是否将params视为data参数,仅限post请求
        isParamsToData: true,
        // 请求拦截器
        requestInterceptorsHook(options) {
            console.log(options)
            const { apiPrefix, isParamsToData } = options.requestOptions
            // 拼接请求前缀
            if (apiPrefix) {
                options.url = `${apiPrefix}${options.url}`
            }
            const params = options.params || {}
            // POST请求下如果无data,则将params视为data
            if (
                isParamsToData &&
                !Reflect.has(options, 'body') &&
                options.method?.toUpperCase() === RequestMethodsEnum.POST
            ) {
                options.body = params
                options.params = {}
            }
            return options
        },
        // 响应拦截器
        async responseInterceptorsHook(response, options) {
            const { isTransformResponse, isReturnDefaultResponse } =
                options.requestOptions
            //返回默认响应,当需要获取响应头及其他数据时可使用
            if (isReturnDefaultResponse) {
                return response
            }
            // 是否需要对数据进行处理
            if (!isTransformResponse) {
                return response._data
            }
            const { code, data, show, msg } = response._data
            switch (code) {
                case RequestCodeEnum.SUCCESS:
                    if (show) {
                        msg && feedback.msgSuccess(msg)
                    }
                    return data
                case RequestCodeEnum.FAIL:
                    if (show) {
                        msg && feedback.msgError(msg)
                    }
                    return Promise.reject(data)
                case RequestCodeEnum.LOGIN_FAILURE:
                    userStore.logout()
                    setPopupType(PopupTypeEnum.LOGIN)
                    toggleShowPopup(true)
                    return Promise.reject(data)
                default:
                    return data
            }
        },
        responseInterceptorsCatchHook(err) {
            return err
        }
    }
}

如何在单个接口中单独使用这些配置

// 配置
export function xxxx(data) {
    return $request.post({ 
        url: 'xxx',
        header: {
            'Content-type': ContentTypeEnum.FORM_DATA
        },
        data
    }, {
        // 忽略重复请求
        ignoreCancelToken: true,
        // 开启请求超时重新发起请求请求机制
        isOpenRetry: false,
         // 需要对返回数据进行处理
        isTransformResponse: false,
    })
}

在页面中使用且服务端渲染请求数据

推荐使用useAsyncData搭配api函数,下面为首页的接口请求示例

//api/shop.ts
export function getIndex() {
    return $request.get({ url: '/pc/index' })
}
//pages/index.vue
<script lang="ts" setup>
    //...
    import { getIndex } from '@/api/shop'
    const { data: pageData } = await useAsyncData(() => getIndex(), {
        default: () => ({
            all: [],
            hot: [],
            new: [],
            page: {}
        })
    })
    //...
</script>

如果直接调用getIndex()获取数据则会先获取到页面再调用接口数据

上次更新:
贡献者: Jason