作者 xiaoqiu

优化了环境配置,封装了请求函数

import { useGet } from "~/utils/request";
import type { queryParams } from "./types/app";
// 获取应用列表
export const getAppList = (params: queryParams) => {
return useGet('/dh/app/listFrontApp', params)
}
// 获取已分类的所有应用
export const getAllApp = () => {
return useGet('/dh/app/allFrontApp')
}
// 获取应用详情
export const getAppDetail = (appId: number) => {
return useGet(`/dh/app/${appId}`)
}
\ No newline at end of file
... ...
import { useGet } from "~/utils/request";
// 获取分类信息
export const getClassifyList = async () => {
const {data } = await useGet('/dh/type/typeTree')
return data
}
\ No newline at end of file
... ...
// 单个应用类型
export interface appType {
id: number,
title: string,
popupContent: string,
image: string,
description: string,
type: number,
isPopup: string,
isRecommend: string,
typeIds: number | number[]
types: Types[]
}
// 单个应用详情
export interface appDetail {
id: number
title: string
content: string
popupContent?: string
image: string
description: string
type?: number
isPopup?: string
link: string
isRecommend?: string
types: Types[]
}
export interface Types{
id: number,
label: string,
icon?: string,
alias?: string,
disabled?: boolean,
children: Array<Types>
}
// 查询应用参数类型
export interface queryParams {
pageNum: number
pageSize: number
typeIds?: number | number[]
typeAlias?: string
title?: string
isPopup?: string
isRecommend?: string
}
// 返回所有应用
export interface appListType {
alias: string
appVos: appType[]
disabled: boolean
icon: string
id: number
label: string
sort: number
children: Array<appListType>
}
\ No newline at end of file
... ...
export interface classifyType{
id: number,
label: string,
icon: string,
disabled: boolean,
children: Array<classifyType>
}
\ No newline at end of file
... ...
export interface webSiteType {
id: number
webname: string
webtitle: string
webkeywords: string
webdescription: string
rollingAnnouncements: string
bottomAnnouncement: string
}
\ No newline at end of file
... ...
// 获取网站信息
import { useGet } from "~/utils/request";
export const getWebSite = async () => {
const { data } = await useGet('/dh/config/get')
return data
}
\ No newline at end of file
... ...
... ... @@ -4,18 +4,16 @@
</NuxtLayout>
</template>
<script setup>
const webSite = useState("webSite", () => {});
const sortList = useState("sortTree", () => []);
const { data: webData } = await useFetch(
"http://aitoolht.crgx.net/dh/config/get"
);
const { data: treeData } = await useFetch(
"http://aitoolht.crgx.net/dh/type/typeTree"
);
webSite.value = webData.value.data;
sortList.value = treeData.value.data;
<script lang="ts" setup>
import { getWebSite } from "~/api/webSite";
import { getClassifyList } from "~/api/classify";
import type { webSiteType } from "~/api/types/webSite";
import type { classifyType } from "~/api/types/classify";
const webSite = useState<webSiteType>("webSite");
const sortList = useState<classifyType>("sortTree");
webSite.value = await getWebSite();
sortList.value = await getClassifyList();
useHead({
title: webSite.value.webname,
meta: [
... ...
... ... @@ -92,7 +92,7 @@
<div class="group p-3">
<div class="flex items-start space-x-4">
<img
:src="'http://aitoolht.crgx.net' + appItem.image"
:src="config.public.baseUrl + appItem.image"
:alt="appItem.title"
class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg"
/>
... ... @@ -117,7 +117,7 @@
<div class="group p-3">
<div class="flex items-start space-x-4">
<img
:src="'http://aitoolht.crgx.net' + appItem.image"
:src="config.public.baseUrl + appItem.image"
:alt="appItem.title"
class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg"
/>
... ... @@ -148,6 +148,7 @@ const props = defineProps<{
}>();
const childAlias = ref(props.childData.children[0].alias);
const config = useRuntimeConfig();
// 阻止默认行为
function onNuxtLink(event: any) {
event.preventDefault();
... ...
... ... @@ -53,7 +53,7 @@
<div class="group p-3">
<div class="flex items-start space-x-4">
<img
:src="'http://aitoolht.crgx.net' + item.image"
:src="config.public.baseUrl + item.image"
:alt="item.title"
class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg"
/>
... ... @@ -78,7 +78,7 @@
<div class="group p-3">
<div class="flex items-start space-x-4">
<img
:src="'http://aitoolht.crgx.net' + item.image"
:src="config.public.baseUrl + item.image"
:alt="item.title"
class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg"
/>
... ... @@ -106,7 +106,7 @@ import { Promotion } from "@element-plus/icons-vue";
defineProps<{
childData: any;
}>();
const config = useRuntimeConfig();
// 阻止默认行为
function onNuxtLink(event: any) {
event.preventDefault();
... ...
... ... @@ -59,7 +59,7 @@
<div class="group p-3">
<div class="flex items-start space-x-4">
<img
:src="'http://aitoolht.crgx.net' + item.image"
:src="config.public.baseUrl + item.image"
:alt="item.title"
class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg"
/>
... ... @@ -84,7 +84,7 @@
<div class="group p-3">
<div class="flex items-start space-x-4">
<img
:src="'http://aitoolht.crgx.net' + item.image"
:src="config.public.baseUrl + item.image"
:alt="item.title"
class="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg"
/>
... ... @@ -115,7 +115,7 @@ defineProps<{
navTitle: string;
navIcon: string;
}>();
const config = useRuntimeConfig();
// 阻止默认行为
function onNuxtLink(event: any) {
event.preventDefault();
... ...
module.exports = {
apps: [
{
name: 'linkNuxt3',
script: './.output/server/index.mjs',
port: 3666,
instances: 'max',
exec_mode: 'cluster',
autorestart: true,
args: 'start'
}
]
}
\ No newline at end of file
... ...
... ... @@ -2,7 +2,7 @@
export default defineNuxtConfig({
runtimeConfig: {
public: {
baseUrl: 'http://aitoolht.crgx.net',
baseUrl: process.env.NUXT_API_URL,
}
},
devtools: { enabled: true },
... ... @@ -14,6 +14,21 @@ export default defineNuxtConfig({
host: 'localhost',
port: 3666
},
nitro: {
devProxy: {
'/dev-api': {
target: 'http://192.168.2.188:35273/',
changeOrigin: true,
}
},
// 该配置用于服务端请求转发
routeRules: {
'/dev-api/**': {
proxy: 'http://192.168.2.188:35273/**'
}
}
},
css: [
'~/assets/iconfonts/iconfont.css',
],
... ...
... ... @@ -2,8 +2,8 @@
"name": "nuxt-app",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"build": "nuxt build --dotenv .env.production",
"dev": "nuxt dev --dotenv .env.development",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
... ...
... ... @@ -18,11 +18,14 @@
</template>
<script lang="ts" setup>
const sortList = useState("sortTree");
import type { appType } from "~/api/types/app";
import { getAppList } from "~/api/app";
import type { classifyType } from "~/api/types/classify";
const sortList = useState<classifyType>("sortTree");
const route = useRoute();
const router = useRouter();
const { name } = route.params;
const list = ref<any[]>([]);
const list = ref<appType[]>([]);
const total = ref<number>(0);
const params = ref<any>({
pageNum: 1,
... ... @@ -64,13 +67,8 @@ function onPageChange(pageNum: number) {
path: route.path + "/page/" + pageNum,
});
}
const { data } = await useFetch(
"http://aitoolht.crgx.net/dh/app/listFrontApp",
{
method: "get",
params: params.value,
}
);
list.value = data.value.rows;
total.value = data.value.total;
const res = await getAppList(params.value);
list.value = res.rows;
total.value = res.total;
</script>
... ...
... ... @@ -20,12 +20,14 @@
</template>
<script lang="ts" setup>
import { ref } from "vue";
const sortList = useState("sortTree");
import type { appType } from "~/api/types/app";
import { getAppList } from "~/api/app";
import type { classifyType } from "~/api/types/classify";
const sortList = useState<classifyType>("sortTree");
const route = useRoute();
const router = useRouter();
const { pageNum, name } = route.params;
const list = ref<any[]>([]);
const list = ref<appType[]>([]);
const total = ref<number>(0);
const params = ref<any>({
pageNum: Number(pageNum),
... ... @@ -74,13 +76,7 @@ function onPageChange(pageNum: number) {
}
}
const { data } = await useFetch(
"http://aitoolht.crgx.net/dh/app/listFrontApp",
{
method: "get",
params: params.value,
}
);
list.value = data.value.rows;
total.value = data.value.total;
const res = await getAppList(params.value);
list.value = res.rows;
total.value = res.total;
</script>
... ...
<script setup>
<script lang="ts" setup>
import { getAppDetail } from "~/api/app";
import type { appDetail, Types } from "~/api/types/app";
import type { webSiteType } from "~/api/types/webSite";
const route = useRoute();
const config = useRuntimeConfig();
const showAd = ref(true);
const appDetail = ref({
const DetailData = ref<appDetail>({
id: 0,
title: "",
content: "",
image: "",
description: "",
link: "",
types: [],
});
const webSite = useState("webSite");
const detailAd = ref({
width: 300,
height: 177,
frontAdVos: [],
});
function mergeDuplicates(data) {
const webSite = useState<webSiteType>("webSite");
function mergeDuplicates(data: Types[]) {
const map = new Map();
data.forEach((item) => {
... ... @@ -27,7 +30,7 @@ function mergeDuplicates(data) {
const existing = map.get(item.id);
// 避免重复的子项(基于子项id)
const existingChildIds = new Set(
existing.children.map((child) => child.id)
existing.children.map((child: any) => child.id)
);
item.children.forEach((child) => {
if (!existingChildIds.has(child.id)) {
... ... @@ -39,34 +42,26 @@ function mergeDuplicates(data) {
return Array.from(map.values());
}
const { data: detailData } = await useFetch(
`http://aitoolht.crgx.net/dh/app/${route.params.id}`
);
const { data: adData } = await useFetch(
"http://aitoolht.crgx.net/dh/ad/listFrontAd",
{
method: "get",
params: { pageSize: 10, pageNum: 1, code: "top" },
}
);
detailAd.value = adData.value.rows[0];
appDetail.value = detailData.value.data;
appDetail.value.types = mergeDuplicates(detailData.value.data.types);
// 获取详情数据
const detailRes = await getAppDetail(Number(route.params.id));
DetailData.value = detailRes.data;
DetailData.value.types = mergeDuplicates(detailRes.data.types);
useHead({
title: appDetail.value.popupContent
? `${appDetail.value.title} - ${appDetail.value.popupContent}`
: appDetail.value.title,
title: DetailData.value.popupContent
? `${DetailData.value.title} - ${DetailData.value.popupContent}`
: DetailData.value.title,
meta: [
{ name: "description", content: appDetail.value.description },
{ name: "description", content: DetailData.value.description },
{
name: "og:title",
content: `${appDetail.value.title}-${appDetail.value.popupContent}`,
content: `${DetailData.value.title}-${DetailData.value.popupContent}`,
},
{ name: "og:description", content: appDetail.value.description },
{ name: "og:description", content: DetailData.value.description },
{
name: "og:image",
content: config.public.baseUrl + appDetail.value.image,
content: config.public.baseUrl + DetailData.value.image,
},
{ name: "og:url", content: route.fullPath },
{ name: "og:site_name", content: webSite.value.webname },
... ... @@ -79,25 +74,25 @@ useHead({
<main class="flex-grow md:p-6 bg-white p-1">
<!-- Top Application Info Bar -->
<header
v-show="appDetail.types.length > 0"
v-show="DetailData.types.length > 0"
class="bg-white shadow-sm md:py-4 md:px-8 py-2 px-4 flex md:items-center md:justify-between flex-col md:flex-row"
>
<div class="flex items-center space-x-4">
<img
:src="config.public.baseUrl + appDetail.image"
:src="config.public.baseUrl + DetailData.image"
alt="App Icon"
class="w-16 h-16 object-contain"
/>
<div>
<h1 class="text-2xl font-bold text-[#5961f9]">
{{ appDetail.title }}
{{ DetailData.title }}
</h1>
<p class="text-sm text-gray-600 mt-1">
{{ appDetail.description }}
{{ DetailData.description }}
</p>
<div class="mt-2 flex items-center space-x-2">
<div
v-for="tag in appDetail.types"
v-for="tag in DetailData.types"
class="flex items-center space-x-2"
>
<template v-if="tag.children.length > 0">
... ... @@ -123,7 +118,7 @@ useHead({
</div>
<div class="flex md:space-x-3 md:mt-0 mt-4">
<a
:href="appDetail.link"
:href="DetailData.link"
target="_blank"
class="!rounded-button whitespace-nowrap px-4 py-2 bg-[#5961f9] max-[768px]:text-xs text-white hover:bg-blue-600 transition-colors"
>
... ... @@ -134,7 +129,7 @@ useHead({
<main class="relative w-full">
<!-- 悬浮广告弹窗 -->
<div
<!-- <div
class="md:absolute top-0 right-0 md:m-4 z-50 relative max-[768px]:m-auto"
v-show="showAd"
:style="{
... ... @@ -158,9 +153,9 @@ useHead({
X
</div>
</div>
</div>
</div> -->
<div class="md:max-w-5xl mx-auto md:p-8 p-2 w-full">
<div v-html="appDetail.content"></div>
<div v-html="DetailData.content"></div>
</div>
</main>
</main>
... ...
<script setup>
const recommendList = ref([]);
const appList = ref([]);
const { data: RecommendData } = await useFetch(
"http://aitoolht.crgx.net/dh/app/listFrontApp",
{
method: "get",
params: { pageSize: 10, pageNum: 1, isRecommend: "1" },
}
);
const { data: allData } = await useFetch(
"http://aitoolht.crgx.net/dh/app/allFrontApp"
);
recommendList.value = RecommendData.value.rows;
appList.value = allData.value.data;
<script lang="ts" setup>
import type { appListType, appType } from "~/api/types/app";
import { getAppList, getAllApp } from "~/api/app";
const recommendList = ref<appType[]>([]);
const appList = ref<appListType[]>([]);
// 获取推荐应用
const recommendRes = await getAppList({
pageSize: 10,
pageNum: 1,
isRecommend: "1",
});
recommendList.value = recommendRes.rows;
// 获取全部应用
const allRes = await getAllApp();
appList.value = allRes.data;
</script>
<template>
... ...
... ... @@ -14,11 +14,14 @@
</template>
<script lang="ts" setup>
import type { appType } from "~/api/types/app";
import { getAppList } from "~/api/app";
const route = useRoute();
const router = useRouter();
const { keyword } = route.query as { keyword: string };
const list = ref<any[]>([]);
const list = ref<appType[]>([]);
const total = ref<number>(0);
const params = ref<any>({
pageNum: 1,
... ... @@ -35,13 +38,7 @@ function onPageChange(pageNum: number) {
});
}
const { data } = await useFetch(
"http://aitoolht.crgx.net/dh/app/listFrontApp",
{
method: "get",
params: params.value,
}
);
list.value = data.value.rows;
total.value = data.value.total;
const res = await getAppList(params.value);
list.value = res.rows;
total.value = res.total;
</script>
... ...
... ... @@ -20,12 +20,13 @@
</template>
<script lang="ts" setup>
import { ref } from "vue";
import type { appType } from "~/api/types/app";
import { getAppList } from "~/api/app";
const route = useRoute();
const router = useRouter();
const { pageNum } = route.params;
const { keyword } = route.query as { keyword: string };
const list = ref<any[]>([]);
const list = ref<appType[]>([]);
const total = ref<number>(0);
const params = ref<any>({
pageNum: Number(pageNum),
... ... @@ -50,14 +51,7 @@ function onPageChange(pageNum: number) {
});
}
}
const { data } = await useFetch(
"http://aitoolht.crgx.net/dh/app/listFrontApp",
{
method: "get",
params: params.value,
}
);
list.value = data.value.rows;
total.value = data.value.total;
const res = await getAppList(params.value);
list.value = res.rows;
total.value = res.total;
</script>
... ...
import { ElLoading } from 'element-plus'
const useMyfetch = async (url: any, options?: any, headers?: any) => {
let loadingInstance
try {
loadingInstance = ElLoading.service()
const config = useRuntimeConfig() // 3.0正式版环境变量要从useRuntimeConfig里的public拿
const reqUrl = config.public.baseUrl + url // 你的接口地址
// 不设置key,始终拿到的都是第一个请求的值,参数一样则不会进行第二次请求
// 可以设置默认headers例如
const customHeaders = {
Authorization: useCookie('accessToken').value,
...headers
}
const { data, pending } = await useFetch(reqUrl, {
...options,
watch: false,
headers: customHeaders
})
const result = data.value as any
if (pending && loadingInstance) {
loadingInstance.close()
}
return result
} catch (err) {
return Promise.reject(err)
} finally {
if (loadingInstance) {
loadingInstance.close()
}
}
}
export const useGet = (url: string, params?: any, headers?: any) => {
return useMyfetch(url, { method: 'get', params }, headers)
}
export const usePost = (url: string, params?: any, headers?: any) => {
return useMyfetch(url, { method: 'post', body: params }, headers)
}
export const usePut = (url: string, params?: any, headers?: any) => {
return useMyfetch(url, { method: 'put', body: params }, headers)
}
... ...