Browse Source

first commit

master
韦创卫 2 years ago
commit
af0a0ceb9c
  1. 24
      .gitignore
  2. 2
      .npmrc
  3. 63
      README.md
  4. 21
      api/article.ts
  5. 66
      api/request.ts
  6. 23
      api/site.ts
  7. 22
      api/video.ts
  8. 4
      app.config.ts
  9. 54
      app.vue
  10. BIN
      assets/LGOO.png
  11. BIN
      assets/aboutindex.png
  12. BIN
      assets/bg-zuixinzixun.png
  13. 7
      assets/css/animate.min.css
  14. BIN
      assets/image/footer-bg.png
  15. BIN
      assets/image/in.png
  16. BIN
      assets/image/logo.png
  17. BIN
      assets/image/mail.png
  18. BIN
      assets/image/md-remove.png
  19. BIN
      assets/image/phone.png
  20. BIN
      assets/image/phone2.png
  21. BIN
      assets/image/service-bg.png
  22. BIN
      assets/image/weixin.png
  23. BIN
      assets/image/zixun-bg.jpg
  24. BIN
      assets/image/zixun-bg.png
  25. 124
      assets/particles.js
  26. 30
      components/PreviewVideo.vue
  27. 41
      composables/states.ts
  28. 72
      i18n.config.ts
  29. 231
      layouts/components/Footer.vue
  30. 137
      layouts/components/Header.vue
  31. 16
      layouts/default.vue
  32. 63
      nuxt.config.ts
  33. 23115
      package-lock.json
  34. 31
      package.json
  35. 47
      pages/about.vue
  36. 126
      pages/african-video.vue
  37. 689
      pages/index.vue
  38. 68
      pages/news-detail/[id].vue
  39. 102
      pages/news.vue
  40. 68
      pages/product-detail/[id].vue
  41. 140
      pages/product.vue
  42. 225
      pages/search.vue
  43. 68
      pages/service-detail/[id].vue
  44. 140
      pages/service.vue
  45. 70
      pages/video-detail/[id].vue
  46. 6
      plugins/particles.ts
  47. 35
      plugins/plugins.ts
  48. 18
      plugins/wow.ts
  49. BIN
      public/favicon.ico
  50. 3
      server/tsconfig.json
  51. 4
      tsconfig.json
  52. 7575
      yarn.lock

24
.gitignore

@ -0,0 +1,24 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist
# Node dependencies
node_modules
# Logs
logs
*.log
# Misc
.DS_Store
.fleet
.idea
# Local env files
.env
.env.*
!.env.example

2
.npmrc

@ -0,0 +1,2 @@
shamefully-hoist=true
strict-peer-dependencies=false

63
README.md

@ -0,0 +1,63 @@
# Nuxt 3 Minimal Starter
Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
## Setup
Make sure to install the dependencies:
```bash
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
```
## Development Server
Start the development server on `http://localhost:3000`:
```bash
# npm
npm run dev
# pnpm
pnpm run dev
# yarn
yarn dev
```
## Production
Build the application for production:
```bash
# npm
npm run build
# pnpm
pnpm run build
# yarn
yarn build
```
Locally preview production build:
```bash
# npm
npm run preview
# pnpm
pnpm run preview
# yarn
yarn preview
```
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

21
api/article.ts

@ -0,0 +1,21 @@
import http from './request'
export const getArticleList = (params: any) => {
return new Promise((resolve,reject)=>{
http.get('/cms/article/page',params).then((res)=> {
resolve(res)
}).catch((err)=>{
reject(err.message)
})
})
}
export const getArticle = (params: any) => {
return new Promise((resolve,reject)=>{
http.get('/cms/article/get',params).then((res)=> {
resolve(res)
}).catch((err)=>{
reject(err.message)
})
})
}

66
api/request.ts

@ -0,0 +1,66 @@
const appConfig = {
// BASE_URL: 'http://127.0.0.1:48080/app-api',
BASE_URL: 'http://119.23.220.80:16801/app-api',
TENANT_ID: 151
}
let clientId: any
const fetch = async (url: string, options: any) => {
if (!url) {
console.warn('url is must be string!')
return
}
const $config = useRuntimeConfig()
const reqUrl = url.indexOf('http') > -1 ? url : appConfig.BASE_URL + url
if (!options.headers) {
options.credentials = 'include' // 跨域携带cookie
options.headers = {
'tenant-id': appConfig.TENANT_ID
}
}
return new Promise((resolve, reject) => {
console.log(reqUrl)
useFetch(reqUrl, { ...options }).then(({ data, error }) => {
if (error && error.value) {
reject(error.value)
return
}
const res: any = data.value
if (res && res.code === 0) {
// return res 正确应该返回
resolve(res.data)
} else if (res && (res.msg || res.errMsg || res.message)) {
console.error(res.msg)
if (res.code === 401) { // 会话过期跳登录
setTimeout(()=>{
navigateTo('/login')
}, 1000)
return
}
reject(res.message)
}
}).catch(err => {
reject(err)
})
})
}
export default new class Http {
get(url: string, params: any) {
return fetch(url, { method: 'GET', params })
}
post(url: string, body: any) {
return fetch(url, { method: 'POST', body })
}
reqData(url: string, body: any) {
return fetch(url, { method: 'POST', body, headers: {} })
}
}

23
api/site.ts

@ -0,0 +1,23 @@
import http from './request'
export const getSiteInfo = () => {
return new Promise((resolve,reject)=>{
http.get('/cms/site-info/get',{}).then((res)=> {
resolve(res)
}).catch((err)=>{
reject(err.message)
})
})
}
export const getBanner = (params: any) => {
return new Promise((resolve,reject)=>{
http.get('/cms/banner/list',params).then((res)=> {
resolve(res)
}).catch((err)=>{
reject(err.message)
})
})
}

22
api/video.ts

@ -0,0 +1,22 @@
import http from './request'
export const getVideoList = (params: any) => {
return new Promise((resolve,reject)=>{
http.get('/cms/video/page',params).then((res)=> {
resolve(res)
}).catch((err)=>{
reject(err.message)
})
})
}
export const getVideo = (params: any) => {
return new Promise((resolve,reject)=>{
http.get('/cms/video/get',params).then((res)=> {
resolve(res)
}).catch((err)=>{
reject(err.message)
})
})
}

4
app.config.ts

@ -0,0 +1,4 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineAppConfig({
BASE_URL: 'http://127.0.0.1:48080/app-api'
})

54
app.vue

@ -0,0 +1,54 @@
<template>
<div class="">
<NuxtLayout name="default">
<NuxtLoadingIndicator color="red" />
<NuxtPage />
</NuxtLayout>
</div>
</template>
<script setup lang="ts">
import {getSiteInfo} from "~/api/site";
const siteInfo = useSiteInfo()
useHead({
title: '金梦网'
})
const themeOverrides = {
common: {
primaryColor: "#FC8952",
primaryColorHover: "#FC8952",
primaryColorPressed: "#FC8952",
primaryColorSuppl: "#FC8952",
},
Button: {
textColor: "#FC8952",
border: "1px solid #FF763B",
}
};
getSiteInfo().then((res: any) => {
const data = res
siteInfo.value = data
}).catch(err=>{
console.log(err)
})
</script>
<style>
body{
background-color: rgba(249, 249, 249, 1);
}
.w-1200 {
width: 1200px;
margin-left: auto;
margin-right: auto;
}
.w-1440{
width: 1440px;
margin: 0 auto;
}
.header-height{ height: 80px}
.nav {
border-bottom: 1px solid rgba(137, 107, 52, 0.15);
}
</style>

BIN
assets/LGOO.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
assets/aboutindex.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

BIN
assets/bg-zuixinzixun.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

7
assets/css/animate.min.css

File diff suppressed because one or more lines are too long

BIN
assets/image/footer-bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

BIN
assets/image/in.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
assets/image/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
assets/image/mail.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/image/md-remove.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

BIN
assets/image/phone.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
assets/image/phone2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
assets/image/service-bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 KiB

BIN
assets/image/weixin.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
assets/image/zixun-bg.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

BIN
assets/image/zixun-bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 KiB

124
assets/particles.js

@ -0,0 +1,124 @@
export const particlesJson = {
background: {
// color: "#eef3f7",
image: '~/assets/images/zixun-bg.png'
},
fullScreen: {
zIndex: -1,
enable: false
},
particles: {
number: {
value: 200,
density: {
enable: !0,
value_area: 800
}
},
color: {
value: "#EAF0F6"
},
shape: {
type: "circle",
stroke: {
width: 0,
color: "#ff0000"
},
polygon: {
nb_sides: 5
},
image: {
src: "",
width: 100,
height: 100
}
},
opacity: {
value: 1,
random: !1,
anim: {
enable: !1,
speed: 2,
opacity_min: 0,
sync: !1
}
},
size: {
value: 3,
random: !1,
anim: {
enable: !1,
speed: 20,
size_min: 0,
sync: !1
}
},
line_linked: {
enable: !0,
distance: 100,
color: "#EAF0F6",
opacity: 1,
width: 1
},
move: {
enable: !0,
speed: 2,
direction: "none",
random: !1,
straight: !1,
out_mode: "out",
bounce: !1,
attract: {
enable: !1,
rotateX: 3e3,
rotateY: 3e3
}
},
array: []
},
interactivity: {
detect_on: "canvas",
events: {
onhover: {
enable: !0,
mode: "grab"
},
onclick: {
enable: !0,
mode: "push"
},
resize: !0
},
modes: {
grab: {
distance: 100,
line_linked: {
opacity: 1
}
},
bubble: {
distance: 200,
size: 80,
duration: .4
},
repulse: {
distance: 200,
duration: .4
},
push: {
particles_nb: 4
},
remove: {
particles_nb: 2
}
},
mouse: {}
},
retina_detect: !1,
fn: {
interact: {},
modes: {},
vendors: {}
},
tmp: {}
}

30
components/PreviewVideo.vue

@ -0,0 +1,30 @@
<template>
<video ref="video" :id="id" :src="src" @mouseleave="mouseleave" @mouseover="mouseover"></video>
</template>
<script setup lang="ts">
const props = defineProps({
id: {
type: String,
required: true
},
src: {
type: String,
required: true
},
})
const mouseover = () => {
}
const mouseleave = () => {
}
</script>
<style scoped>
</style>

41
composables/states.ts

@ -0,0 +1,41 @@
interface SiteInfo{
siteName: string;
siteNameEn: string;
siteDesc: string;
siteDescEn: string;
logo: string;
wechatImage?: string;
wecomImage?: string;
wxmpImage?: string;
wechat?: string;
wxgzhImage?: string;
linkedin?: string;
linkedinImage?: string;
whatsapp?: string;
whatsappImage?: string;
email?: string;
emailImage?: string;
address?: string;
addressEn?: string;
pov?: string;
}
export const useSiteInfo = () => {
const siteInfo = useState<SiteInfo>('siteInfo', () => {
return {
siteName: '',
siteNameEn: '',
siteDesc: '',
siteDescEn: '',
logo: '',
}
})
return siteInfo;
}
export const useLang = () => useState<string>('lang', () => 'zh')

72
i18n.config.ts

@ -0,0 +1,72 @@
export default defineI18nConfig(() => ({
legacy: false,
locale: 'zh',
warnHtmlMessage: false,
messages: {
zh: {
language: 'English',
homePage: '首页',
aboutUs: '关于金梦网',
news: '最新资讯',
africanVideo: '走进非洲视频',
serviceAndProduct: '服务与产品',
service: '服务',
product: '产品',
link: '跳转链接',
readMord: '查看更多',
viewsCount: '浏览次数',
email: '邮箱',
wechat: '微信',
LinkedIn: 'LinkedIn',
WhatsAPp: 'WhatsAPp',
detail: '查看',
search: '搜索',
searchResult: '搜索结果',
wxOfficialAccounts: '公众号',
weCom: '企业微信',
wxMP: '微信小程序',
address: '地址',
icp: '备案号',
contactUs: '联系我们',
source: '来源',
article: '文章',
video: '视频',
noArticle: '未找到相关文章',
noVideo: '未找到相关视频',
},
en: {
language: '中文',
homePage: 'Home',
aboutUs: 'About',
news: 'News',
africanVideo: 'African Video',
serviceAndProduct: 'Service&Product',
service: 'Service',
product: 'Product',
readMord: 'More',
viewsCount: 'views',
email: 'Email',
wechat: 'Wechat',
LinkedIn: 'LinkedIn',
WhatsAPp: 'WhatsAPp',
detail: 'Detail',
search: 'Search',
searchResult: 'Search Result',
wxOfficialAccounts: 'Official Accounts',
weCom: 'WeCom',
wxMP: 'Mini Program',
address: 'Address',
icp: 'ICP',
contactUs: 'Contact Us',
source: 'Source',
article: 'Article',
video: 'Video',
noArticle: 'No related articles found',
noVideo: 'No related videos found',
}
}
}))

231
layouts/components/Footer.vue

@ -0,0 +1,231 @@
<template>
<div class="footer-box">
<div class="footer w-1200">
<div class="flex justify-between items-center footer-item1">
<div class="flex items-center">
<img class="w-[45px]" src="~/assets/image/logo.png"/>
<p class="logo-name">{{ locale == 'zh' ? siteInfo.siteName : siteInfo.siteNameEn }}</p>
</div>
<div class="tr">
<!-- 邮箱 -->
<NPopover :z-index="100"
arrow-style="background: linear-gradient(180deg, rgba(137,107,52,1) 1%,rgba(250,235,201,1) 100%);"
:raw="true" trigger="hover" placement="bottom">
<template #trigger>
<div class="ml-6">
<div class="flex items-center cursor-pointer">
<img class="w-[24px]" src="~/assets/image/mail.png"/>
<p class="ml-[10px]">{{ $t('email') }}</p>
</div>
</div>
</template>
<template #default>
<div class="lxfs flex flex-col justify-center items-center">
<p>{{ siteInfo.email }}</p>
<template v-if="siteInfo.emailImage">
<img :src="siteInfo.emailImage" class="cover-fill w-[100px] h-[100px] code mt-2"/>
<p class="py-1"></p>
</template>
</div>
</template>
</NPopover>
<!-- WhatsApp -->
<NPopover :z-index="100"
arrow-style="background: linear-gradient(180deg, rgba(137,107,52,1) 1%,rgba(250,235,201,1) 100%);"
:raw="true" trigger="hover" placement="bottom">
<template #trigger>
<div class="ml-6">
<div class="flex items-center cursor-pointer">
<img class="w-[24px]" src="~/assets/image/phone2.png"/>
<p class="ml-[10px]">{{ $t('WhatsApp') }}</p>
</div>
</div>
</template>
<template #default>
<div class="lxfs flex flex-col justify-center items-center">
<p>{{ siteInfo.whatsapp }}</p>
<img v-if="siteInfo.whatsappImage" :src="siteInfo.whatsappImage"
class="cover-fill w-[100px] h-[100px] code mt-2 /">
<p v-if="siteInfo.whatsappImage" class="py-1"></p>
</div>
</template>
</NPopover>
<!-- LinkedIn-->
<NPopover :z-index="100"
arrow-style="background: linear-gradient(180deg, rgba(137,107,52,1) 1%,rgba(250,235,201,1) 100%);"
:raw="true" trigger="hover" placement="bottom">
<template #trigger>
<div class="ml-6">
<div class="flex items-center cursor-pointer">
<img class="w-[24px]" src="~/assets/image/in.png"/>
<p class="ml-[10px]">{{ $t('LinkedIn') }}</p>
</div>
</div>
</template>
<template #default>
<div class="lxfs flex flex-col justify-center items-center">
<p>{{ siteInfo.linkedin }}</p>
<img v-if="siteInfo.linkedinImage" :src="siteInfo.linkedinImage"
class="cover-fill w-[100px] h-[100px] code mt-2 /">
<p v-if="siteInfo.linkedinImage" class="py-1"></p>
</div>
</template>
</NPopover>
<!-- 微信 -->
<NPopover :z-index="100"
arrow-style="background: linear-gradient(180deg, rgba(137,107,52,1) 1%,rgba(250,235,201,1) 100%);"
:raw="true" trigger="hover" placement="bottom">
<template #trigger>
<div class="ml-6">
<div class="flex items-center cursor-pointer">
<img class="w-[24px]" src="~/assets/image/weixin.png"/>
<p class="ml-[10px]">{{ $t('wechat') }}</p>
</div>
</div>
</template>
<template #default>
<div class="lxfs flex flex-col justify-center items-center">
<p>{{ siteInfo.wechat }}</p>
<img v-if="siteInfo.wechatImage" :src="siteInfo.wechatImage"
class="cover-fill w-[100px] h-[100px] code mt-2 /">
<p v-if="siteInfo.wechatImage" class="py-1"></p>
</div>
</template>
</NPopover>
</div>
</div>
<div class="footer-item2 flex justify-between items-center">
<div class="flex">
<div class=" wow animate__fadeInUp mr-[50px]">
<p style="color: #FFFFFF;font-size: 17px">{{ $t('link') }}</p>
<NuxtLink class="mt-[13px]" :to="localePath('/about')"
style="color: rgba(255,255,255,.6);font-size: 14px ;display: block">{{ $t('aboutUs') }}
</NuxtLink>
<NuxtLink class="mt-[7px]" :to="localePath('/service')"
style="color: rgba(255,255,255,.6);font-size: 14px; display: block">{{ $t('service') }}
</NuxtLink>
<NuxtLink class="mt-[7px]" :to="localePath('/product')"
style="color: rgba(255,255,255,.6);font-size: 14px; display: block">{{ $t('product') }}
</NuxtLink>
<NuxtLink class="mt-[7px]" :to="localePath('/african-video')"
style="color: rgba(255,255,255,.6);font-size: 14px ;display: block">{{ $t('africanVideo') }}
</NuxtLink>
<NuxtLink class="mt-[7px]" :to="localePath('/news')"
style="color: rgba(255,255,255,.6);font-size: 14px; display: block">{{ $t('news') }}
</NuxtLink>
</div>
<div class="wow animate__fadeInUp mr-[50px]">
<div>
<p style="color: #FFFFFF ;font-size: 17px;margin-bottom: 12px;text-align: center;">
{{ $t('wxOfficialAccounts') }}</p>
<img :src="siteInfo.wxgzhImage" class="cover-fill w-[100px] h-[100px] code">
</div>
</div>
<div class="wow animate__fadeInUp mr-[50px]">
<div>
<p style="color: #FFFFFF ;font-size: 17px;margin-bottom: 12px;text-align: center;">{{ $t('wxMP') }}</p>
<img :src="siteInfo.wxmpImage" class="cover-fill w-[100px] h-[100px] code">
</div>
</div>
<div class="wow animate__fadeInUp mr-[50px]">
<div>
<p style="color: #FFFFFF ;font-size: 17px;margin-bottom: 12px;text-align: center;">{{ $t('weCom') }}</p>
<img :src="siteInfo.wecomImage" class="cover-fill w-[100px] h-[100px] code">
</div>
</div>
</div>
<div>
<p class="flex items-center wow animate__backInRight" style="flex-direction: row-reverse;">
<span style="color: #896B34;font-size: 35px;font-weight: bold;">{{ siteInfo.phone }}</span>
<img class="w-[30px] mr-[8px] h-[30px]" src="~/assets/image/phone.png"/>
</p>
<!-- <p style="font-size: 14px;color: rgba(255,255,255,.4);margin-top: 20px" class="text-right">{{siteInfo.siteDesc}}</p>-->
<p style="font-size: 14px;color: rgba(255,255,255,.6)" class="text-right">
{{ $t('address') }}{{ locale == 'zh' ? siteInfo.address : siteInfo.addressEn }}</p>
</div>
</div>
<div class="flex justify-between">
<p class="" style="font-size: 14px;color: rgba(255,255,255,.4);margin-top: 20px;">
{{ locale == 'zh' ? siteInfo.companyName : siteInfo.companyNameEn }} {{ $t('icp') }}:
{{ locale == 'zh' ? siteInfo.pov : siteInfo.pov }}</p>
<p class="" style="font-size: 14px;color: rgba(255,255,255,.4);margin-top: 20px;">{{ $t('contactUs') }}</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {NPopover} from 'naive-ui'
const {locale} = useI18n()
const siteInfo = useSiteInfo()
const localePath = useLocalePath()
</script>
<style scoped>
.footer-box {
//background: #363636; background-image: url("~/assets/image/footer-bg.png"); background-size: contain;
}
.footer {
height: 480px;
}
.footer-place {
height: 400px;
}
.logo-name {
font-size: 20px;
color: rgba(255, 255, 255, .87);
margin-left: 15px;
}
.tr {
display: flex;
flex-direction: row-reverse;
color: rgba(255, 255, 255, .87);
font-size: 18px;
}
.footer-item1 {
border-bottom: 1px solid rgba(255, 255, 255, .1);
height: 120px;
}
.footer-item2 {
border-bottom: 1px solid rgba(255, 255, 255, .1);
height: 210px;
}
.footer-item2 img {
object-fit: cover;
}
.code {
border-radius: 8px;
}
.lxfs {
background: linear-gradient(180deg, rgba(137, 107, 52, 1) 1%, rgba(250, 235, 201, 1) 100%);
padding: 5px 10px;
border-radius: 4px;
color: #303030;
font-size: 16px;
}
</style>

137
layouts/components/Header.vue

@ -0,0 +1,137 @@
<template>
<header class="header w-full">
<div class="container header-height flex items-center">
<NuxtLink :to="localePath('/')" class="logo-box flex items-center">
<img class="logo" :src="siteInfo.logo"/>
</NuxtLink>
<div class="flex-1 flex">
<NuxtLink :class="{active: activeKey.startsWith('index') }" class="nav-item items-center flex px-4 hover:text-yellow" :to="localePath('/')">
{{ $t('homePage') }}
</NuxtLink>
<NuxtLink :class="{active: activeKey.startsWith('news')}" class="nav-item items-center flex px-4" :to="localePath('/news')">
{{ $t('news') }}
</NuxtLink>
<NuxtLink :class="{active: activeKey.startsWith('african-video')}" class="nav-item items-center flex px-4" :to="localePath('/african-video')" >
{{ $t('africanVideo') }}
</NuxtLink>
<NPopover trigger="hover" placement="bottom">
<template #trigger>
<span :style="{color: (activeKey.startsWith('service') || activeKey.startsWith('product')? '#896B34':'')}" class="nav-item items-center flex px-4 cursor-pointer">
{{$t('serviceAndProduct')}}
</span>
</template>
<div class="p-2">
<NuxtLink :class="{active: activeKey.startsWith('service')}" class="nav-item items-center flex py-2" :to="localePath('/service')">
{{ $t('service') }}
</NuxtLink>
<NuxtLink :class="{active: activeKey.startsWith('product')}" class="nav-item items-center flex py-2" :to="localePath('/product')">
{{ $t('product') }}
</NuxtLink>
</div>
</NPopover>
<NuxtLink :class="{active: activeKey.startsWith('about')}" class="nav-item items-center flex px-4" :to="localePath('/about')">
{{ $t('aboutUs') }}
</NuxtLink>
</div>
<NSpace class="items-center">
<NInput @keydown="searchFunc" :placeholder="$t('search')" size="medium" v-model:value="keyword">
<template #prefix>
<n-icon :component="SearchOutline" color="#E5E5E5" />
</template>
</NInput>
<NButton size="medium" text type="default" @click="switchLanguage" tertiary>{{ $t('language') }}</NButton>
</NSpace>
</div>
</header>
</template>
<script setup lang="ts">
import {MenuOption, NIcon, NInput, NButton, NSpace,NDropdown,NPopover} from "naive-ui";
import {NuxtLink} from "#components";
import {SearchOutline} from "@vicons/ionicons5";
//
const siteInfo = useSiteInfo()
//
const activeKey = ref<String>('index')
const route = useRoute()
activeKey.value = route.name?route.name.toString(): ''
watch(
() => route.name,
(name) => {
console.log(name)
activeKey.value = name?name.toString(): ''
}
)
const serviceAndProduct = ref<any[]>([
{
label: '布朗酒店,伦敦',
key: "brown's hotel, london"
},
])
//
const { locale, locales, setLocale } = useI18n()
const localePath = useLocalePath()
const switchLanguage = () => {
locale.value = locale.value == 'zh' ? 'en' : 'zh'
useCookie('lang').value = locale.value
}
//
const keyword = ref<String>('')
const searchFunc = (e: any) => {
if(e.key === 'Enter'){
const path = localePath({
path: '/search',
query: {
word: keyword.value
}
})
navigateTo(path)
}
}
</script>
<style scoped>
.header {
position: fixed;
top: 0;
z-index: 999;
background: rgba(255,255,255, .7);
color: #333333;
}
.logo-box{
max-width: 300px;
height: 60px;
overflow: hidden;
display: flex;
align-content: center;
}
.logo{
width: 100%;
height: 100%;
object-fit: contain;
}
.container {
width: 1200px;
margin: 0 auto;
}
.nav-item {
font-size: 18px;
position: relative;
}
.nav-item:hover {
color: #896B34;
}
.nav-item.active {
color: #896B34;
}
</style>

16
layouts/default.vue

@ -0,0 +1,16 @@
<template>
<div>
<Header></Header>
<slot/>
<Footer></Footer>
</div>
</template>
<script lang="ts" setup>
import Header from "~/layouts/components/Header.vue";
import Footer from "~/layouts/components/Footer.vue";
import {NSpin} from "naive-ui";
</script>
<style scoped>
</style>

63
nuxt.config.ts

@ -0,0 +1,63 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
theme: "",
devtools: {enabled: false},
css: ['animate.css/animate.css'],
build: {
transpile:
process.env.NODE_ENV === 'production'
? [
'naive-ui',
'vueuc',
'@css-render/vue3-ssr',
'@juggle/resize-observer'
]
: ['@juggle/resize-observer']
},
vite: {
optimizeDeps: {
include:
process.env.NODE_ENV === 'development'
? ['naive-ui', 'vueuc', 'date-fns-tz/esm/formatInTimeZone']
: []
}
},
modules: [
[
'@nuxtjs/i18n',
{
vueI18n: './i18n.config.ts',
defaultLocale: 'zh',
locales: ['zh', 'en']
}
],
[
'nuxt-lodash',
{
prefix: "_",
prefixSkip: ["string"],
upperAfterPrefix: false,
exclude: ["map"],
alias: [
["camelCase", "stringToCamelCase"], // => stringToCamelCase
["kebabCase", "stringToKebab"], // => stringToKebab
["isDate", "isLodashDate"], // => _isLodashDate
],
}
],
'@nuxtjs/tailwindcss',
'@hypernym/nuxt-anime',
'dayjs-nuxt'
],
plugins: [
{
src: '~/plugins/particles.ts'
},
{
src: '~/plugins/wow.ts',
mode: 'client'
}
],
})

23115
package-lock.json

File diff suppressed because it is too large

31
package.json

@ -0,0 +1,31 @@
{
"name": "nuxt-app",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"devDependencies": {
"@hypernym/nuxt-anime": "^2.1.0",
"@nuxt/devtools": "latest",
"@nuxtjs/i18n": "^8.0.0-rc.2",
"@types/node": "^18.17.3",
"@vicons/ionicons5": "^0.12.0",
"animate.css": "^4.1.1",
"dayjs-nuxt": "^1.1.2",
"naive-ui": "^2.34.4",
"vue-i18n": "9.3.0-beta.24",
"nuxt": "^3.6.5",
"wow.js": "^1.2.2"
},
"dependencies": {
"@css-render/vue3-ssr": "^0.15.12",
"@nuxtjs/tailwindcss": "^6.8.0",
"nuxt-lodash": "^2.5.0",
"tsparticles-slim": "^2.12.0",
"vue3-particles": "^2.12.0"
}
}

47
pages/about.vue

@ -0,0 +1,47 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<p>{{ locale == 'zh' ? aboutArticle.title : aboutArticle.titleEn }}</p>
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<div class="w-1200 py-8">
<div v-html="locale == 'zh' ? aboutArticle.content: aboutArticle.contentEn"></div>
</div>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem} from "naive-ui";
const {locale} = useI18n()
const localePath = useLocalePath()
import {getArticle,} from "~/api/article";
useHead({
title: `金梦网-关于金梦网`
})
//
const aboutArticle = ref<any>({
title: '',
titleEn: '',
content: '',
contentEn: '',
})
getArticle({
id: 30
}).then((res: any) => {
if (res) {
aboutArticle.value = res
}
})
</script>
<style scoped>
</style>

126
pages/african-video.vue

@ -0,0 +1,126 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
{{ $t('africanVideo') }}
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<!-- 视频列表-->
<div class="africen-list w-1200 mt-6 py-6">
<NuxtLink v-for="(item, index) in videoDataList" :to="localePath('/video-detail/' + item.id)" class="africen inline-block cursor-pointer ">
<div class="africen-img-box" @mouseleave="item.play = false" @mouseover="item.play = true" >
<video v-if="item.play" autoplay muted class="africen-img-cover" :src="item.videoUrl"/>
<video v-if="!item.picUrl" v-show="!item.play" muted class="africen-img" :src="item.videoUrl"/>
<img v-if="item.picUrl" v-show="!item.play" muted class="africen-img" :src="item.picUrl"/>
<div class="africen-video-desc">
<div class="view-num pl-2">
<p class="flex items-center"> <NIcon :component="VideocamOutline" size="25"></NIcon> <span class="ml-1">{{item.viewsCount}}</span></p>
</div>
</div>
</div>
<p class="africen-title py-2">{{locale =='zh'?item.title:item.titleEn}}</p>
<div class="africen-desc">
<div class="africen-time">{{dayjs(item.createTime).format('YYYY-MM-DD')}}</div>
</div>
</NuxtLink>
</div>
<!-- 分页-->
<div class="flex justify-center py-8">
<NPagination
:item-count="videoItemCount"
@update-page="videoPageChange"
/>
</div>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NIcon, NPagination} from "naive-ui";
import {getVideoList} from "~/api/video";
import {VideocamOutline} from "@vicons/ionicons5";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
//
const videoPageParams = {
pageNo: 1,
pageSize: 10
}
const videoItemCount = ref(0)
const videoDataList = ref<any[]>([])
const videoPageChange = (pageNo: number) => {
getVideoList(videoPageParams).then( (res: any) => {
videoDataList.value = res.list
videoItemCount.value = res.total
})
}
videoPageChange(1)
</script>
<style scoped>
.africen-list{
background-color: #FFFFFF;
}
.africen {
width: 280px;
margin: 0 10px 30px;
}
.africen-title{
height: 50px;
overflow: hidden;
text-overflow: ellipsis;
line-height: 20px;
}
.africen-img-box {
width: 100%;
height: 175px;
position: relative;
border-radius: 8px;
overflow: hidden;
}
.africen-img {
width: 100%;
height: 100%;
object-fit: cover;
z-index: 1;
}
.africen-img-cover{
width: 100%;
height: 100%;
object-fit: cover;
z-index: 2;
}
.africen-video-desc {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 25px;
line-height: 20px;
background-image: linear-gradient(to top, rgba(0, 0, 0, .5), transparent);
color: #FFFFFF;
z-index: 10;
}
.africen-time {
color: #9A9A9A;
}
</style>

689
pages/index.vue

@ -0,0 +1,689 @@
<template>
<div>
<!-- 轮播图-->
<NCarousel draggable autoplay class="carousel">
<img v-for="item in bannerList"
class="carousel-img w-full"
:src="item.picUrl"
/>
</NCarousel>
<!-- 关于我们-->
<div class="about-box ">
<ClientOnly>
<vue-particles id="particles" :particlesInit="particlesInit" :options="particlesJson"
:particlesLoaded="particlesLoaded"></vue-particles>
</ClientOnly>
<div class="about">
<div class="about-header flex justify-between items-center">
<p class="about-title">
<img class="about-title-left" src="~/assets/aboutindex.png"/>
{{ locale == 'zh' ? aboutArticle.title : aboutArticle.titleEn }}
</p>
<NuxtLink :to="localePath('/about')" class="about-more hover:opacity-75">{{ $t('readMord') }} &gt;&gt;
</NuxtLink>
</div>
<div class="about-body flex justify-between">
<div class="about-body-left wow animate__slideInLeft"
v-html="locale =='zh'?aboutArticle.content:aboutArticle.contentEn">
</div>
<div class="wow animate__slideInRight">
<div class="about-body-right">
<img :src="aboutArticle.picUrl"/>
</div>
</div>
</div>
</div>
</div>
<!-- 最新资讯 start -->
<div class="news ">
<div style="height: 38px"></div>
<div class="news-header w-1440">
<p class="news-header-title wow animate__bounceIn">-{{ $t('news') }}-</p>
<NuxtLink :to="localePath('/news')" class="news-more hover:opacity-75">{{ $t('readMord') }} &gt;&gt;</NuxtLink>
</div>
<div class="news-carousel-box wow animate__fadeInUp">
<NCarousel style="height: 350px" :default-index="1" centered-slides draggable :slides-per-view="3"
prev-slide-style="transform: translateX(-170%) translateZ(-200px);opacity: 1;"
next-slide-style="transform: translateX(70%) translateZ(-200px);opacity: 1;"
effect="card">
<NCarouselItem v-for="(item, index) in articleDataList" :key="item.id" class="news-carousel-item">
<NuxtLink :to="localePath('/news-detail/' + item.id)" class="news-item">
<img class="news-item-img" :src="item.picUrl"/>
<p class="news-item-title truncate">{{ locale == 'zh' ? item.title : item.titleEn }}</p>
</NuxtLink>
</NCarouselItem>
</NCarousel>
</div>
</div>
<!-- 最新资讯 end -->
<!-- 走近非洲 start -->
<div class="african">
<div style="height: 52px"></div>
<div class="news-header ">
<p style="color: #896B34" class="news-header-title wow animate__flip">-{{ $t('africanVideo') }}-</p>
</div>
<!-- 视频列表-->
<div class="w-1440 pt-6 wow animate__fadeInUp">
<NuxtLink v-for="(item, index) in videoDataList" :to="localePath('/video-detail/' + item.id)"
class="africen inline-block cursor-pointer">
<div class="africen-img-box" @mouseleave="item.play = false" @mouseover="item.play = true">
<video v-if="item.play" autoplay muted class="africen-img-cover" :src="item.videoUrl"/>
<video v-if="!item.picUrl" v-show="!item.play" muted class="africen-img" :src="item.videoUrl"/>
<img v-if="item.picUrl" v-show="!item.play" muted class="africen-img" :src="item.picUrl"/>
<div class="africen-video-desc">
<div class="view-num pl-2">
<p class="flex items-center">
<NIcon :component="VideocamOutline" size="25"></NIcon>
<span class="ml-1">{{ item.viewsCount }}</span>
</p>
</div>
</div>
</div>
<p class="africen-title py-2 truncate">{{ locale == 'zh' ? item.title : item.titleEn }}</p>
<div class="africen-desc">
<div class="africen-time">{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</div>
</div>
</NuxtLink>
</div>
<div class="flex justify-center">
<NuxtLink :to="localePath('/african-video')"
class="africen-more hover:opacity-75 flex items-center justify-center">
<img style="width: 28px;margin-right: 10px" src="~/assets/image/md-remove.png"/>
{{ $t('readMord') }}
</NuxtLink>
</div>
</div>
<!-- 走近非洲 end -->
<!-- 服务与产品 start -->
<div class="service-product">
<div class="w-1200 wow animate__fadeInLeftBig">
<div class="flex justify-between border-b">
<div class="tabs flex">
<div @click="activeKey = 'service'" :class="{active: activeKey === 'service'}" class="tab">{{
$t('service')
}}
</div>
<div @click="activeKey = 'product'" :class="{active: activeKey === 'product'}" class="tab">{{
$t('product')
}}
</div>
</div>
<div>
<NuxtLink :to="localePath('/product')" class="product-more">{{ $t('readMord') }}&gt;&gt;</NuxtLink>
</div>
</div>
<div class="tab-pane-box">
<div v-show="activeKey == 'service'" class="tab-pane">
<!-- :to="localePath({name: 'news-detail',params: {id: item.id}})"-->
<NuxtLink :class="{animate__headShake:item.hover,animate__animated: item.hover}"
@mouseleave="item.hover = false" @mouseover="item.hover = true"
v-for="(item, index) in serviceDataList"
:to="localePath('/news-detail/' + item.id)"
class="product flex justify-between py-8">
<div class="flex">
<img class="product-img" :src="item.picUrl"/>
<div class="ml-8">
<p class="product-title">{{ locale == 'zh' ? item.title : item.titleEn }}</p>
<p class="product-content">{{ locale == 'zh' ? item.content : item.contentEn }}</p>
<p class="product-desc"><span style="color: #906D2C;">{{ item.viewsCount }}</span>
{{ $t('viewsCount') }} <span class="pl-4">{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</span>
</p>
</div>
</div>
<p class="btn-detail">{{ $t('detail') }}</p>
</NuxtLink>
</div>
<div v-show="activeKey == 'product'" class="tab-pane">
<!-- :to="localePath({name: 'news-detail',params: {id: item.id}})"-->
<NuxtLink :class="{animate__headShake:item.hover,animate__animated: item.hover}"
@mouseleave="item.hover = false" @mouseover="item.hover = true"
v-for="(item, index) in productDataList"
:to="localePath('/news-detail/' + item.id)"
class="product flex justify-between py-8">
<div class="flex">
<img class="product-img" :src="item.picUrl"/>
<div class="ml-8">
<p class="product-title">{{ locale == 'zh' ? item.title : item.titleEn }}</p>
<p class="product-content">{{ locale == 'zh' ? item.content : item.contentEn }}</p>
<p class="product-desc"><span style="color: #906D2C;">{{ item.viewsCount }}</span>
{{ $t('viewsCount') }} <span class="pl-4">{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</span>
</p>
</div>
</div>
<p class="btn-detail">{{ $t('detail') }}</p>
</NuxtLink>
</div>
</div>
<!-- 分页-->
<!-- <div class="flex justify-center py-8">-->
<!-- <NPagination :item-count="productItemCount" simple/>-->
<!-- </div>-->
</div>
</div>
<!-- 服务与产品 end -->
<!-- 加载动画 -->
<div v-if="loadIng"
class="w-screen h-screen fixed bg-white top-0 left-0 right-0 bottom-0 flex items-center justify-center z-[999]">
<!-- <div class="">-->
<!-- </div>-->
<span class="loading">
<span class="loading-inner">
<img class="" src="~/assets/image/logo.png" />
</span>
</span>
</div>
</div>
</template>
<script setup lang="ts">
import {NCarousel, NPagination, NCarouselItem, NIcon, NSpin} from 'naive-ui'
import {getArticle, getArticleList} from '~/api/article'
const siteInfo = useSiteInfo()
const {locale} = useI18n()
const localePath = useLocalePath()
const dayjs = useDayjs()
import {VideocamOutline} from '@vicons/ionicons5'
//
useHead({
title: `金梦网`
})
const activeKey = ref<String>('service')
const loadIng = ref<Boolean>(true)
//
import {particlesJson} from '~/assets/particles'
import {loadSlim} from "tsparticles-slim"
import {Engine} from "tsparticles-engine";
import {getVideoList} from "~/api/video";
import {getBanner} from "~/api/site";
const particlesInit = async (engine: Engine) => {
//await loadFull(engine);
await loadSlim(engine);
};
const particlesLoaded = async (container: any) => {
console.log("Particles container loaded", container);
};
//
onMounted(() => {
loadIng.value = false
})
setTimeout(() => {
loadIng.value = false
}, 10000)
//
const bannerList = ref<any[]>([])
getBanner({
position: 1
}).then((res: any) => {
bannerList.value = res
})
//
const videoPageParams = {
pageNo: 1,
pageSize: 8
}
const videoItemCount = ref(0)
const videoDataList = ref<any[]>([])
const videoPageChange = (pageNo: number) => {
getVideoList(videoPageParams).then((res: any) => {
videoDataList.value = res.list
videoItemCount.value = res.total
})
}
videoPageChange(1)
//
const articleDataList = ref<any[]>([])
getArticleList({
pageNo: 1,
pageSize: 10,
categoryId: 28
}).then((res: any) => {
articleDataList.value = res.list
})
//
const productItemCount = ref(0)
const productDataList = ref<any[]>([{}])
const serviceDataList = ref<any[]>([{}])
getArticleList({
pageNo: 1,
pageSize: 3,
categoryId: 30
}).then((res: any) => {
if (process.client) {
res.list.forEach(item => {
// div
var tempDiv = document.createElement('div');
tempDiv.innerHTML = item.content;
var plainText = tempDiv.textContent;
item.content = plainText
tempDiv.innerHTML = item.contentEn;
plainText = tempDiv.textContent;
item.contentEn = plainText
})
}
productDataList.value = res.list
})
getArticleList({
pageNo: 1,
pageSize: 3,
categoryId: 31
}).then((res: any) => {
if (process.client) {
res.list.forEach(item => {
// div
var tempDiv = document.createElement('div');
tempDiv.innerHTML = item.content;
var plainText = tempDiv.textContent;
item.content = plainText
tempDiv.innerHTML = item.contentEn;
plainText = tempDiv.textContent;
item.contentEn = plainText
})
}
serviceDataList.value = res.list
})
//
const aboutArticle = ref<any>({})
getArticle({
id: 36
}).then((res: any) => {
if (res) {
aboutArticle.value = res
}
})
</script>
<style scoped>
.btn-detail {
width: 60px;
height: 24px;
line-height: 24px;
border-radius: 4px;
background: linear-gradient(180deg, rgba(229, 203, 152, 1) 0%, rgba(250, 235, 201, 1) 100%);
color: rgba(137, 107, 52, 1);
font-size: 12px;
text-align: center;
}
.product {
border-bottom: 1px solid rgba(137, 107, 52, 0.08);
}
.product-title {
font-size: 20px;
color: #333333;
width: 420px;
}
.product-content {
font-size: 16px;
color: #6C6C6C;
height: 40px;
line-height: 20px;
margin: 10px 0;
overflow: hidden;
text-overflow: ellipsis;
width: 420px;
}
.product-desc {
font-size: 12px;
color: #999999;
width: 420px;
}
.product-img {
width: 200px;
height: 120px;
object-fit: cover;
}
.product-more {
color: rgba(229, 203, 152, 1);
font-size: 14px;
height: 40px;
line-height: 40px;
}
.tabs {
}
.tab {
width: 130px;
height: 40px;
font-size: 18px;
text-align: center;
line-height: 40px;
cursor: pointer;
}
.tab.active {
background: linear-gradient(180deg, rgba(51, 51, 51, 1) 0%, rgba(51, 51, 51, 0.56) 100%);
color: rgba(229, 203, 152, 1);
}
.carousel {
height: 800px;
}
.about {
width: 1340px;
margin: 0 auto;
padding: 70px 0;
z-index: 20;
position: sticky;
}
.about-box {
position: relative;
background-image: url("~/assets/image/zixun-bg.jpg");
background-size: contain;
background-position: center;
//background-repeat: no-repeat; background-color: #FFFFFF;
}
#particles {
position: absolute;
width: 100%;
height: 100%;
}
.about-header {
}
.about-title {
font-size: 40px;
position: relative;
padding-left: 18px;
color: #101010;
}
.about-title-left {
width: 6px;
height: 40px;
position: absolute;
left: 0;
top: 0;
bottom: 0;
margin: auto;
}
.about-more {
width: 130px;
height: 40px;
line-height: 40px;
text-align: center;
color: #E5CB98;
background: linear-gradient(180deg, rgba(54, 54, 54, 1) 0%, rgba(132, 132, 132, 1) 99%);
cursor: pointer;
}
.about-body {
margin-top: 35px;
}
.about-body-left {
width: 730px;
font-size: 18px;
line-height: 40px;
}
.about-body-right {
height: auto;
position: relative;
width: 497px;
margin-right: 16px;
transition: all 0.6s;
}
.about-body-right:hover {
transform: scale(1.2);
}
.about-body-right::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
display: block;
background-color: rgba(51, 51, 51, 0.28);
top: 16px;
right: -16px;
z-index: -1;
}
.news {
width: 100%;
height: 610px;
background-image: url("~/assets/bg-zuixinzixun.png");
margin: 0 auto;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.news-header {
height: 58px;
position: relative;
}
.news-header-title {
color: #E5CB98;
font-size: 40px;
text-align: center;
line-height: 58px;
}
.news-more {
width: 130px;
height: 40px;
line-height: 40px;
text-align: center;
color: #E5CB98;
background: linear-gradient(180deg, rgba(229, 203, 152, 1) 0%, rgba(250, 235, 201, 1) 99%);
color: rgba(137, 107, 52, 1);
border-radius: 4px;
cursor: pointer;
position: absolute;
right: 50px;
top: 0;
bottom: 0;
margin: auto;
}
.news-carousel-box {
width: 1400px;
margin: 140px auto 0;
height: 300px;
}
.news-carousel-item {
display: block;
}
.news-item {
width: 430px;
height: 243px;
border-radius: 8px;
overflow: hidden;
position: relative;
display: block;
}
.news-item-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.news-item-title {
background-color: #ffffff;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 45px;
line-height: 45px;
font-size: 16px;
padding: 0 16px;
display: block;
}
.africen {
width: 320px;
margin: 0 20px 30px;
}
.africen-img-box {
width: 320px;
height: 175px;
position: relative;
border-radius: 8px;
overflow: hidden;
}
.africen-img {
width: 100%;
height: 100%;
object-fit: cover;
z-index: 1;
}
.africen-img-cover {
width: 100%;
height: 100%;
object-fit: cover;
z-index: 2;
}
.africen-video-desc {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 25px;
line-height: 20px;
background-image: linear-gradient(to top, rgba(0, 0, 0, .5), transparent);
color: #FFFFFF;
z-index: 10;
}
.africen-time {
color: #9A9A9A;
}
.africen-more {
width: 250px;
height: 50px;
line-height: 50px;
border-radius: 4px;
background: linear-gradient(180deg, rgba(51, 51, 51, 1) 0%, rgba(51, 51, 51, 0.56) 99%);
color: rgba(229, 203, 152, 1);
font-size: 16px;
text-align: center;
margin: 30px auto;
}
.tab-pane {
min-height: 100px;
}
.service-product {
background-image: url("~/assets/image/service-bg.png");
background-size: contain;
}
/* loading.css */
.loading {
display: inline-block;
width: 100px;
height: 100px;
position: relative;
border: 4px solid #896B34;
animation: loader 4s infinite ease;
}
.loading-inner {
vertical-align: top;
display: inline-block;
width: 100%;
background-color: #896B34;
animation: loader-inner 4s infinite ease-in;
}
@keyframes loader {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(180deg);
}
50% {
transform: rotate(180deg);
}
75% {
transform: rotate(360deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loader-inner {
0% {
height: 0%;
}
25% {
height: 0%;
}
50% {
height: 100%;
}
75% {
height: 100%;
}
100% {
height: 0%;
}
}
</style>

68
pages/news-detail/[id].vue

@ -0,0 +1,68 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/news')">{{ $t('news') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<p>{{ locale == 'zh' ? articleData.title : articleData.titleEn}}</p>
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<div class="w-1200 py-8">
<p class="title">{{ locale == 'zh' ? articleData.title : articleData.titleEn}}</p>
<NSpace class="article-footer">
<span class="">{{dayjs(articleData.createTime).format('YYYY-MM-DD')}}</span>
<span class="">{{$t('source')}}{{locale== 'zh'? articleData.source: articleData.sourceEn}}</span>
<span class="flex items-center"><NIcon :component="EyeOutline" size="20px"></NIcon>{{articleData.viewsCount}} {{$t('viewsCount')}}</span>
</NSpace>
<div v-html="locale == 'zh'?articleData.content: articleData.contentEn"></div>
</div>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NIcon, NSpace} from "naive-ui";
import {getArticle} from "~/api/article";
import {EyeOutline} from "@vicons/ionicons5";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
const router = useRoute()
const articleData = ref<any>({
title: '',
titleEn: '',
content: '',
contentEn: '',
viewsCount: 0,
source: '',
sourceEn: ''
})
getArticle({
id: router.params.id
}).then( (res: any) => {
articleData.value = res
})
</script>
<style scoped>
.title{
color: rgba(16, 16, 16, 1);
font-size: 36px;
font-weight: bold;
margin-bottom: 20px;
}
.article-footer{
color: #9A9A9A;
font-size: 14px;
margin-bottom: 40px;
}
</style>

102
pages/news.vue

@ -0,0 +1,102 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
{{ $t('news') }}
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<!-- 文章列表-->
<div class="w-1440">
<div class="w-1200">
<NuxtLink v-for="(item, index) in articleDataList" :to="localePath('/news-detail/' + item.id)" class="article flex justify-between">
<div class="flex flex-col justify-between">
<p class="article-title line-clamp-2">{{ locale== 'zh'?item.title:item.titleEn}}</p>
<NSpace class="article-footer">
<span class="">{{locale== 'zh'? item.source: item.sourceEn}}</span>
<span class="">{{item.viewsCount}} {{$t('viewsCount')}}</span>
<span class="">{{dayjs(item.createTime).format('YYYY-MM-DD')}}</span>
</NSpace>
</div>
<img :src="item.picUrl" class="article-img" />
</NuxtLink>
</div>
</div>
</div>
<!-- 分页-->
<div class="flex justify-center py-8">
<NPagination
:itemCount="itemCount"
:page-size="10"
@update-page="queryList"
/>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NSpace, NPagination, NThing} from 'naive-ui'
import {getArticleList} from "~/api/article";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
useHead({
title: `金梦网-最新资讯`
})
const pageParams = {
pageNo: 1,
pageSize: 10,
categoryId: 28
}
const itemCount = ref(0)
const articleDataList = ref<any[]>([])
const queryList = (pageNo: number) => {
pageParams.pageNo = pageNo
getArticleList(pageParams).then((res: any)=> {
articleDataList.value = res.list
itemCount.value = res.total
})
}
queryList(1)
</script>
<style scoped>
.data-list {
}
.article{
border-bottom: 1px solid rgba(137, 107, 52, 0.15);
padding: 38px 0 28px;
}
.article-img {
width: 260px;
height: 165px;
border-radius: 8px;
}
.article-title{
width: 859px;
height: 92px;
line-height: 45px;
color: rgba(51, 51, 51, 1);
font-size: 20px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
.article-footer {
font-size: 14px;
color: #9A9A9A;
}
.nav {
border-bottom: 1px solid rgba(137, 107, 52, 0.15);
}
</style>

68
pages/product-detail/[id].vue

@ -0,0 +1,68 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/product')">{{ $t('product') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<p>{{ locale == 'zh' ? articleData.title : articleData.titleEn}}</p>
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<div class="w-1200 py-8">
<p class="title">{{ locale == 'zh' ? articleData.title : articleData.titleEn}}</p>
<NSpace class="article-footer">
<span class="">{{dayjs(articleData.createTime).format('YYYY-MM-DD')}}</span>
<span class="">{{$t('source')}}{{locale== 'zh'? articleData.source: articleData.sourceEn}}</span>
<span class="flex items-center"><NIcon :component="EyeOutline" size="20px"></NIcon>{{articleData.viewsCount}} {{$t('viewsCount')}}</span>
</NSpace>
<div v-html="locale == 'zh'?articleData.content: articleData.contentEn"></div>
</div>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NIcon, NSpace} from "naive-ui";
import {getArticle} from "~/api/article";
import {EyeOutline} from "@vicons/ionicons5";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
const router = useRoute()
const articleData = ref<any>({
title: '',
titleEn: '',
content: '',
contentEn: '',
viewsCount: 0,
source: '',
sourceEn: ''
})
getArticle({
id: router.params.id
}).then( (res: any) => {
articleData.value = res
})
</script>
<style scoped>
.title{
color: rgba(16, 16, 16, 1);
font-size: 36px;
font-weight: bold;
margin-bottom: 20px;
}
.article-footer{
color: #9A9A9A;
font-size: 14px;
margin-bottom: 40px;
}
</style>

140
pages/product.vue

@ -0,0 +1,140 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
{{ $t('product') }}
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<!-- 文章列表-->
<div class="w-1440">
<div class="w-1200">
<NuxtLink v-for="item in articleDataList" :to="localePath('/product-detail/' + item.id)" class="product flex justify-between py-8">
<div class="flex">
<img class="product-img" :src="item.picUrl"/>
<div class="ml-8">
<p class="product-title">{{locale == 'zh'?item.title: item.titleEn}}</p>
<p class="product-content">{{locale == 'zh'?item.content: item.contentEn}}</p>
<p class="product-desc"><span style="color: #906D2C;">{{item.viewsCount}}</span> {{$t('viewsCount')}} <span class="pl-4">{{dayjs(item.createTime).format('YYYY-MM-DD')}}</span></p>
</div>
</div>
<p class="btn-detail">{{$t('detail')}}</p>
</NuxtLink>
</div>
</div>
</div>
<!-- 分页-->
<div class="flex justify-center py-8">
<NPagination
:item-count="itemCount"
@update-page="queryList"
/>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NSpace, NPagination, NThing} from 'naive-ui'
import {getArticleList} from "~/api/article";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
useHead({
title: `金梦网-产品`
})
const pageParams = {
pageNo: 1,
pageSize: 10,
categoryId: 30
}
const itemCount = ref(0)
const articleDataList = ref<any[]>([])
const queryList = (pageNo: number) => {
pageParams.pageNo = pageNo
getArticleList(pageParams).then((res: any)=> {
if(process.client) {
res.list.forEach(item => {
// div
var tempDiv = document.createElement('div');
tempDiv.innerHTML = item.content;
var plainText = tempDiv.textContent;
item.content = plainText
tempDiv.innerHTML = item.contentEn;
plainText = tempDiv.textContent;
item.contentEn = plainText
})
}
articleDataList.value = res.list
itemCount.value = res.total
})
}
queryList(1)
</script>
<style scoped>
.data-list {
}
.btn-detail {
width: 60px;
height: 24px;
line-height: 24px;
border-radius: 4px;
background: linear-gradient(180deg, rgba(229, 203, 152, 1) 0%, rgba(250, 235, 201, 1) 100%);
color: rgba(137, 107, 52, 1);
font-size: 12px;
text-align: center;
}
.product-title {
font-size: 20px;
color: #333333;
width: 420px;
}
.product-content {
font-size: 16px;
color: #6C6C6C;
height: 40px;
line-height: 20px;
margin: 10px 0;
overflow: hidden;
text-overflow: ellipsis;
width: 420px;
}
.product-desc {
font-size: 12px;
color: #999999;
width: 420px;
}
.product-img {
width: 200px;
height: 120px;
object-fit: cover;
}
.product-more {
color: rgba(229, 203, 152, 1);
font-size: 14px;
height: 40px;
line-height: 40px;
}
.nav {
border-bottom: 1px solid rgba(137, 107, 52, 0.15);
}
</style>

225
pages/search.vue

@ -0,0 +1,225 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
{{ $t('searchResult') }}
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<!-- 文章列表-->
<div class="w-1440">
<div class="w-1200">
<n-divider title-placement="left">
{{ $t('article') }}
</n-divider>
<NuxtLink v-for="(item, index) in articleDataList" :to="localePath('/news-detail/' + item.id)"
class="article flex justify-between">
<div class="flex flex-col justify-between">
<p class="article-title line-clamp-2">{{ locale == 'zh' ? item.title : item.titleEn }}</p>
<NSpace class="article-footer">
<span class="">{{ locale == 'zh' ? item.source : item.sourceEn }}</span>
<span class="">{{ item.viewsCount }} {{ $t('viewsCount') }}</span>
<span class="">{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</span>
</NSpace>
</div>
<img :src="item.picUrl" class="article-img"/>
</NuxtLink>
<!-- 分页-->
<div v-show="articleDataList.length >0" class="flex justify-center py-8">
<NPagination
:itemCount="articleCount"
:page-size="10"
@change="queryArticleList"
/>
</div>
<NEmpty :description="$t('noArticle')" v-if="articleDataList.length == 0"></NEmpty>
</div>
<div class="w-1200">
<n-divider title-placement="left">
{{ $t('video') }}
</n-divider>
<NuxtLink v-for="(item, index) in videoDataList" :to="localePath('/video-detail/' + item.id)"
class="africen inline-block cursor-pointer ">
<div class="africen-img-box" @mouseleave="item.play = false" @mouseover="item.play = true">
<video v-if="item.play" autoplay muted class="africen-img-cover" :src="item.videoUrl"/>
<video v-if="!item.picUrl" v-show="!item.play" muted class="africen-img" :src="item.videoUrl"/>
<img v-if="item.picUrl" v-show="!item.play" muted class="africen-img" :src="item.picUrl"/>
<div class="africen-video-desc">
<div class="view-num pl-2">
<p class="flex items-center">
<NIcon :component="VideocamOutline" size="25"></NIcon>
<span class="ml-1">{{ item.viewsCount }}</span></p>
</div>
</div>
</div>
<p class="africen-title py-2">{{ locale == 'zh' ? item.title : item.titleEn }}</p>
<div class="africen-desc">
<div class="africen-time">{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</div>
</div>
</NuxtLink>
<!-- 分页-->
<div v-show="videoDataList.length >0" class="flex justify-center py-8">
<NPagination
:itemCount="videoCount"
:page-size="10"
@change="queryVideoList"
/>
</div>
<NEmpty :description="$t('noVideo')" v-if="videoDataList.length == 0"></NEmpty>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NSpace, NPagination, NDivider, NIcon, NEmpty} from 'naive-ui'
import {getArticleList} from "~/api/article";
import {getVideoList} from "~/api/video";
import {VideocamOutline} from "@vicons/ionicons5";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
const router = useRoute()
useHead({
title: `金梦网-搜索`
})
const articlePageParams = {
pageNo: 1,
pageSize: 10,
keyWord: ''
}
const videoPageParams = {
pageNo: 1,
pageSize: 10,
keyWord: ''
}
articlePageParams.keyWord = router.query.word || ''
videoPageParams.keyWord = router.query.word || ''
watch(() => router.query, (newVal, oldValue) => {
articlePageParams.keyWord = newVal.word ? newVal.word.toString() : ''
videoPageParams.keyWord = newVal.word ? newVal.word.toString() : ''
queryArticleList(1)
queryVideoList(1)
})
const articleCount = ref(0)
const videoCount = ref(0)
const articleDataList = ref<any[]>([])
const videoDataList = ref<any[]>([])
const queryArticleList = (pageNo: number) => {
articlePageParams.pageNo = pageNo
getArticleList(articlePageParams).then((res: any) => {
articleDataList.value = res.list
articleCount.value = res.total
})
}
queryArticleList(1)
const queryVideoList = (pageNo: number) => {
videoPageParams.pageNo = pageNo
getVideoList(videoPageParams).then((res: any) => {
videoDataList.value = res.list
videoCount.value = res.total
})
}
queryVideoList(1)
</script>
<style scoped>
.data-list {
}
.article {
border-bottom: 1px solid rgba(137, 107, 52, 0.15);
padding: 38px 0 28px;
}
.article-img {
width: 260px;
height: 165px;
border-radius: 8px;
}
.article-title {
width: 859px;
height: 92px;
line-height: 45px;
color: rgba(51, 51, 51, 1);
font-size: 20px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
.article-footer {
font-size: 14px;
color: #9A9A9A;
}
.nav {
border-bottom: 1px solid rgba(137, 107, 52, 0.15);
}
.africen {
width: 280px;
margin: 0 10px 30px;
}
.africen-title {
height: 50px;
overflow: hidden;
text-overflow: ellipsis;
line-height: 20px;
}
.africen-img-box {
width: 100%;
height: 175px;
position: relative;
border-radius: 8px;
overflow: hidden;
}
.africen-img {
width: 100%;
height: 100%;
object-fit: cover;
z-index: 1;
}
.africen-img-cover {
width: 100%;
height: 100%;
object-fit: cover;
z-index: 2;
}
.africen-video-desc {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 25px;
line-height: 20px;
background-image: linear-gradient(to top, rgba(0, 0, 0, .5), transparent);
color: #FFFFFF;
z-index: 10;
}
</style>

68
pages/service-detail/[id].vue

@ -0,0 +1,68 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/service')">{{ $t('service') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<p>{{ locale == 'zh' ? articleData.title : articleData.titleEn}}</p>
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<div class="w-1200 py-8">
<p class="title">{{ locale == 'zh' ? articleData.title : articleData.titleEn}}</p>
<NSpace class="article-footer">
<span class="">{{dayjs(articleData.createTime).format('YYYY-MM-DD')}}</span>
<span class="">{{$t('source')}}{{locale== 'zh'? articleData.source: articleData.sourceEn}}</span>
<span class="flex items-center"><NIcon :component="EyeOutline" size="20px"></NIcon>{{articleData.viewsCount}} {{$t('viewsCount')}}</span>
</NSpace>
<div v-html="locale == 'zh'?articleData.content: articleData.contentEn"></div>
</div>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NIcon, NSpace} from "naive-ui";
import {getArticle} from "~/api/article";
import {EyeOutline} from "@vicons/ionicons5";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
const router = useRoute()
const articleData = ref<any>({
title: '',
titleEn: '',
content: '',
contentEn: '',
viewsCount: 0,
source: '',
sourceEn: ''
})
getArticle({
id: router.params.id
}).then( (res: any) => {
articleData.value = res
})
</script>
<style scoped>
.title{
color: rgba(16, 16, 16, 1);
font-size: 36px;
font-weight: bold;
margin-bottom: 20px;
}
.article-footer{
color: #9A9A9A;
font-size: 14px;
margin-bottom: 40px;
}
</style>

140
pages/service.vue

@ -0,0 +1,140 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
{{ $t('service') }}
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<!-- 文章列表-->
<div class="w-1440">
<div class="w-1200">
<NuxtLink v-for="item in articleDataList" :to="localePath('/service-detail/' + item.id)" class="product flex justify-between py-8">
<div class="flex">
<img class="product-img" :src="item.picUrl"/>
<div class="ml-8">
<p class="product-title">{{locale == 'zh'?item.title: item.titleEn}}</p>
<p class="product-content">{{locale == 'zh'?item.content: item.contentEn}}</p>
<p class="product-desc"><span style="color: #906D2C;">{{item.viewsCount}}</span> {{$t('viewsCount')}} <span class="pl-4">{{dayjs(item.createTime).format('YYYY-MM-DD')}}</span></p>
</div>
</div>
<p class="btn-detail">{{$t('detail')}}</p>
</NuxtLink>
</div>
</div>
</div>
<!-- 分页-->
<div class="flex justify-center py-8">
<NPagination
:item-count="itemCount"
@update-page="queryList"
/>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NSpace, NPagination, NThing} from 'naive-ui'
import {getArticleList} from "~/api/article";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
useHead({
title: `金梦网-服务`
})
const pageParams = {
pageNo: 1,
pageSize: 10,
categoryId: 31
}
const itemCount = ref(0)
const articleDataList = ref<any[]>([])
const queryList = (pageNo: number) => {
pageParams.pageNo = pageNo
getArticleList(pageParams).then((res: any)=> {
if(process.client) {
res.list.forEach(item => {
// div
var tempDiv = document.createElement('div');
tempDiv.innerHTML = item.content;
var plainText = tempDiv.textContent;
item.content = plainText
tempDiv.innerHTML = item.contentEn;
plainText = tempDiv.textContent;
item.contentEn = plainText
})
}
articleDataList.value = res.list
itemCount.value = res.total
})
}
queryList(1)
</script>
<style scoped>
.data-list {
}
.btn-detail {
width: 60px;
height: 24px;
line-height: 24px;
border-radius: 4px;
background: linear-gradient(180deg, rgba(229, 203, 152, 1) 0%, rgba(250, 235, 201, 1) 100%);
color: rgba(137, 107, 52, 1);
font-size: 12px;
text-align: center;
}
.product-title {
font-size: 20px;
color: #333333;
width: 420px;
}
.product-content {
font-size: 16px;
color: #6C6C6C;
height: 40px;
line-height: 20px;
margin: 10px 0;
overflow: hidden;
text-overflow: ellipsis;
width: 420px;
}
.product-desc {
font-size: 12px;
color: #999999;
width: 420px;
}
.product-img {
width: 200px;
height: 120px;
object-fit: cover;
}
.product-more {
color: rgba(229, 203, 152, 1);
font-size: 14px;
height: 40px;
line-height: 40px;
}
.nav {
border-bottom: 1px solid rgba(137, 107, 52, 0.15);
}
</style>

70
pages/video-detail/[id].vue

@ -0,0 +1,70 @@
<template>
<div>
<div class="header-height"></div>
<div class="w-1200 py-8 nav">
<NBreadcrumb>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/')">{{ $t('homePage') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<NuxtLink :to="localePath('/news')">{{ $t('africanVideo') }}</NuxtLink>
</NBreadcrumbItem>
<NBreadcrumbItem>
<p>{{ locale == 'zh' ? articleData.title : articleData.titleEn}}</p>
</NBreadcrumbItem>
</NBreadcrumb>
</div>
<div class="w-1200 py-8">
<p class="title">{{ locale == 'zh' ? articleData.title : articleData.titleEn}}</p>
<NSpace class="article-footer">
<span class="">{{dayjs(articleData.createTime).format('YYYY-MM-DD')}}</span>
<!-- <span class="">{{$t('source')}}{{locale== 'zh'? articleData.source: articleData.sourceEn}}</span>-->
<span class="flex items-center"><NIcon :component="EyeOutline" size="20px"></NIcon> {{articleData.viewsCount}} {{$t('viewsCount')}}</span>
</NSpace>
<video class="video" controls :src="articleData.videoUrl">
</video>
</div>
</div>
</template>
<script setup lang="ts">
import {NBreadcrumb, NBreadcrumbItem, NSpace,NIcon} from "naive-ui";
import {getVideo} from "~/api/video";
const dayjs = useDayjs()
const {locale} = useI18n()
const localePath = useLocalePath()
import {EyeOutline} from '@vicons/ionicons5'
const router = useRoute()
const articleData = ref<any>({
title: '',
titleEn: '',
content: '',
contentEn: '',
viewsCount: 0,
source: '',
sourceEn: ''
})
getVideo({
id: router.params.id
}).then( (res: any) => {
articleData.value = res
})
</script>
<style scoped>
.title{
color: rgba(16, 16, 16, 1);
font-size: 36px;
font-weight: bold;
margin-bottom: 20px;
}
.article-footer{
color: #9A9A9A;
font-size: 14px;
margin-bottom: 40px;
}
</style>

6
plugins/particles.ts

@ -0,0 +1,6 @@
import { defineNuxtPlugin } from '#app'
import particles from 'vue3-particles'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(particles);
})

35
plugins/plugins.ts

@ -0,0 +1,35 @@
import { setup } from '@css-render/vue3-ssr'
import { defineNuxtPlugin } from '#app'
export default defineNuxtPlugin((nuxtApp) => {
if (process.server) {
const { collect } = setup(nuxtApp.vueApp)
const originalRenderMeta = nuxtApp.ssrContext?.renderMeta
// @ts-ignore
nuxtApp.ssrContext = nuxtApp.ssrContext || {}
// @ts-ignore
nuxtApp.ssrContext.renderMeta = () => {
if (!originalRenderMeta) {
return {
headTags: collect()
}
}
const originalMeta = originalRenderMeta()
if ('then' in originalMeta) {
return originalMeta.then((resolvedOriginalMeta) => {
return {
...resolvedOriginalMeta,
headTags: resolvedOriginalMeta['headTags'] + collect()
}
})
} else {
return {
...originalMeta,
headTags: originalMeta['headTags'] + collect()
}
}
}
}
})

18
plugins/wow.ts

@ -0,0 +1,18 @@
import { defineNuxtPlugin } from '#app'
// @ts-ignore
import WOW from 'wow.js'
export default defineNuxtPlugin((nuxtApp) => {
new WOW({ //可以添加自定义内容
animateClass: 'animate__animated',
boxClass: 'wow',
offset: 0,
mobile: true,
live: false,
scrollContainer: null,
resetAnimation: true,
}).init()
})

BIN
public/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

3
server/tsconfig.json

@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}

4
tsconfig.json

@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}

7575
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save