Browse Source

新增状态:useForm等,页面样式融入config配置

master
科技小王子 8 months ago
parent
commit
2923695780
  1. 2
      api/cms/design/model/index.ts
  2. 19
      components/AppFooter.vue
  3. 16
      components/AppHeader.vue
  4. 3
      components/Breadcrumb.vue
  5. 11
      composables/configState.ts
  6. 2
      nuxt.config.ts
  7. 78
      pages/[custom]/index.vue
  8. 80
      pages/page/[id].vue
  9. 11
      pages/product/740a123.html.vue
  10. 8
      types/global.d.ts

2
api/cms/design/model/index.ts

@ -18,6 +18,8 @@ export interface Design {
width?: string; width?: string;
// 高 // 高
height?: string; height?: string;
// 页面样式
styles?: string;
// 附件 // 附件
images?: string; images?: string;
// 用户ID // 用户ID

19
components/AppFooter.vue

@ -1,17 +1,15 @@
<template> <template>
<footer class="overflow-hidden"> <footer class="overflow-hidden">
<div class="sm:h-[100px] h-[50px]"></div> <div class="sm:h-[100px] h-[50px]"></div>
<div class="text-center bg-white text-red-7 py-10" style="display: none">
本网站为小象CMS演示站提供的电视剧和电影资源均系收集于各大视频网站<br />
若本站收录的节目无意侵犯了贵司版权,请给我们留言,我们会及时逐步删除和规避程序自动搜索采集到的不提供分享的版权影视<br />
本站仅供测试和学习交流请大家支持正版
<div class=" bg-white my-3 w-3/4 m-auto" v-if="config.copyrightForDemoData">
<el-alert :title="config.copyrightForDemoData" center show-icon type="warning" />
</div> </div>
<div class="w-full flex flex-col sm:bg-black justify-between"> <div class="w-full flex flex-col sm:bg-black justify-between">
<!-- PC版 --> <!-- PC版 -->
<div class="sub-menu w-full md:w-3/4 m-auto flex justify-between py-10 text-center p-2 hidden-sm-and-down"> <div class="sub-menu w-full md:w-3/4 m-auto flex justify-between py-10 text-center p-2 hidden-sm-and-down">
<!-- 底部菜单 --> <!-- 底部菜单 -->
<div class="left flex flex-col sm:flex-row sm:flex-wrap justify-between gap-3xl sm:w-8/12 flex-wrap w-full">
<div class="left flex flex-col sm:flex-row sm:flex-wrap justify-between gap-3xl sm:w-9/12 flex-wrap w-full">
<template v-for="item in subMenu"> <template v-for="item in subMenu">
<div class="sub-menu-item text-left"> <div class="sub-menu-item text-left">
<div class="pb-4"> <div class="pb-4">
@ -29,10 +27,10 @@
</div> </div>
<!-- 关注我们 --> <!-- 关注我们 -->
<div class="right w-3/12 pr-3 text-right flex justify-end">
<div class="right w-3/12 pr-3 text-right flex justify-end" v-if="config.wxQrcode">
<div class="qrcode flex flex-col items-center"> <div class="qrcode flex flex-col items-center">
<el-image src="https://oss.wsdns.cn/20240327/f1175cc5aae741d3af05484747270bd5.jpeg" class="w-[100px]" />
<text class="text-gray-400 py-2">扫一扫关注</text>
<el-image :src="config.wxQrcode" class="w-[100px]" />
<text class="text-gray-400 py-2">{{ config.wxQrcodeText }}</text>
</div> </div>
</div> </div>
</div> </div>
@ -61,12 +59,13 @@
<span>Copyright © {{ new Date().getFullYear() }} {{ config?.copyright }}</span> <span>Copyright © {{ new Date().getFullYear() }} {{ config?.copyright }}</span>
<a class="text-gray-400 hover:text-gray-400" href="https://beian.miit.gov.cn/" target="_blank"> 备案号{{ config?.icpNo }}</a> <a class="text-gray-400 hover:text-gray-400" href="https://beian.miit.gov.cn/" target="_blank"> 备案号{{ config?.icpNo }}</a>
</div> </div>
<div class="tools flex gap-xl items-center">
<div class="tools flex gap-xl items-center opacity-80 hover:opacity-90">
<!-- <a href="https://github.com" class="sm:flex hidden items-center" target="_blank"><img src="@/assets/svg/github-mark-white.svg" alt="github" width="20" class="text-gray-400" /></a>--> <!-- <a href="https://github.com" class="sm:flex hidden items-center" target="_blank"><img src="@/assets/svg/github-mark-white.svg" alt="github" width="20" class="text-gray-400" /></a>-->
<!-- <a href="https://github.com" class="sm:hidden flex items-center" target="_blank"><img src="@/assets/svg/github-mark.svg" alt="github" width="20" class="text-gray-400" /></a>--> <!-- <a href="https://github.com" class="sm:hidden flex items-center" target="_blank"><img src="@/assets/svg/github-mark.svg" alt="github" width="20" class="text-gray-400" /></a>-->
<el-tooltip :content="`管理后台`" v-if="config.showAdminIcon">
<a :href="`https://${website.tenantId}.websoft.top`" target="_blank"><img src="@/assets/svg/websoft-mark-white.svg" alt="github" width="28" class="text-gray-400" /></a> <a :href="`https://${website.tenantId}.websoft.top`" target="_blank"><img src="@/assets/svg/websoft-mark-white.svg" alt="github" width="28" class="text-gray-400" /></a>
</el-tooltip>
</div> </div>
</div> </div>
</div> </div>
</footer> </footer>

16
components/AppHeader.vue

@ -25,12 +25,12 @@
text-color="#fff" text-color="#fff"
active-text-color="#ffd04b" active-text-color="#ffd04b"
:collapse="true" :collapse="true"
:ellipsis="false"
:ellipsis="true"
style="border-bottom: none" style="border-bottom: none"
@select="handleSelect" @select="handleSelect"
> >
<template v-for="(item, index) in navigations"> <template v-for="(item, index) in navigations">
<el-menu-item :index="item.path" v-if="index < visibleNumber">
<el-menu-item :index="item.path" v-if="index < (config.elMenuMaxNumber || 6)">
<el-sub-menu v-if="item?.children && item.children.length > 0" :index="`${item.path}`"> <el-sub-menu v-if="item?.children && item.children.length > 0" :index="`${item.path}`">
<template #title> <template #title>
<text class="text-[17px]">{{ item.title }}</text> <text class="text-[17px]">{{ item.title }}</text>
@ -42,10 +42,10 @@
</template> </template>
<!-- 顶部菜单超出数量折叠 --> <!-- 顶部菜单超出数量折叠 -->
<el-sub-menu index="more" v-if="navigations && navigations.length > visibleNumber">
<el-sub-menu index="more" v-if="navigations && navigations.length > (config.elMenuMaxNumber || 6)">
<template #title>更多菜单</template> <template #title>更多菜单</template>
<template v-for="(item, index) in navigations"> <template v-for="(item, index) in navigations">
<el-menu-item :index="item.path" :key="index" v-if="index >= visibleNumber">
<el-menu-item :index="item.path" :key="index" v-if="index >= (config.elMenuMaxNumber || 6)">
{{ item.title }}</el-menu-item {{ item.title }}</el-menu-item
> >
</template> </template>
@ -54,7 +54,7 @@
</nav> </nav>
</div> </div>
<div class="header__right items-center"> <div class="header__right items-center">
<div class="sm:flex hidden">
<div class="sm:flex hidden" v-if="config.showSearchTools">
<el-input <el-input
class="w-20 mr-4" class="w-20 mr-4"
placeholder="站内搜索" placeholder="站内搜索"
@ -76,8 +76,8 @@
</el-dropdown> </el-dropdown>
</template> </template>
<template v-else> <template v-else>
<el-button circle :icon="ElIconSearch" @click="navigateTo('/search')"></el-button>
<el-button circle :icon="ElIconUserFilled" @click="goLogin"></el-button>
<el-button v-if="config.showSearchIcon" circle :icon="ElIconSearch" @click="navigateTo('/search')"></el-button>
<el-button v-if="config.showLoginButton" circle :icon="ElIconUserFilled" @click="goLogin"></el-button>
</template> </template>
</ClientOnly> </ClientOnly>
</div> </div>
@ -99,7 +99,7 @@
const affix = useProductAffix(); const affix = useProductAffix();
// //
const visibleNumber = ref<number>(10);
const visibleNumber = ref<number>(6);
// index // index
const currentIndex = ref<string>('2'); const currentIndex = ref<string>('2');

3
components/Breadcrumb.vue

@ -3,8 +3,7 @@
<el-breadcrumb :separator-icon="ArrowRight"> <el-breadcrumb :separator-icon="ArrowRight">
<el-breadcrumb-item :to="{ path: '/' }"><el-icon class="cursor-pointer"><ElIconHouse /></el-icon></el-breadcrumb-item> <el-breadcrumb-item :to="{ path: '/' }"><el-icon class="cursor-pointer"><ElIconHouse /></el-icon></el-breadcrumb-item>
<el-breadcrumb-item v-if="data?.parentName" :to="{ path: data.parentPath }">{{ data.parentName }}</el-breadcrumb-item> <el-breadcrumb-item v-if="data?.parentName" :to="{ path: data.parentPath }">{{ data.parentName }}</el-breadcrumb-item>
<el-breadcrumb-item v-if="data?.categoryName" :to="{ path: data.categoryPath }">{{ data.categoryName }}</el-breadcrumb-item>
<el-breadcrumb-item v-if="title">{{ title }}</el-breadcrumb-item>
<el-breadcrumb-item v-if="data?.categoryName">{{ title ? title : data.categoryName }}</el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</div> </div>
</template> </template>

11
composables/configState.ts

@ -3,29 +3,40 @@ import type { Config } from '~/types/global';
import type {Website} from "~/api/cms/website/model"; import type {Website} from "~/api/cms/website/model";
import type {Navigation} from "~/api/cms/navigation/model"; import type {Navigation} from "~/api/cms/navigation/model";
// 网站信息
export const useWebsite = () => export const useWebsite = () =>
useState<Website>('website', () => { useState<Website>('website', () => {
return {}; return {};
}); });
// 参数配置
export const useConfigInfo = () => export const useConfigInfo = () =>
useState<Config>('config', () => { useState<Config>('config', () => {
return {}; return {};
}); });
// 主导航
export const useMenu = () => export const useMenu = () =>
useState<Navigation[]>('menu', () => { useState<Navigation[]>('menu', () => {
return []; return [];
}); });
// 副导航
export const useSubMenu = () => export const useSubMenu = () =>
useState<Navigation[]>('subMenu', () => { useState<Navigation[]>('subMenu', () => {
return []; return [];
}); });
// 页面元素
export const useForm = () => useState<Navigation>('form', () => {
return {};
});
// 固钉
export const useProductAffix = () => export const useProductAffix = () =>
useState<boolean>('affixTop', () => { useState<boolean>('affixTop', () => {
return false; return false;
}); });
// 登录凭证
export const useToken = () => useState('token', () => 'token xxx'); export const useToken = () => useState('token', () => 'token xxx');

2
nuxt.config.ts

@ -1,6 +1,4 @@
// https://nuxt.com/docs/api/configuration/nuxt-config // https://nuxt.com/docs/api/configuration/nuxt-config
import {domain} from "~/config";
export default defineNuxtConfig({ export default defineNuxtConfig({
compatibilityDate: '2024-04-03', compatibilityDate: '2024-04-03',
devtools: {enabled: false}, devtools: {enabled: false},

78
pages/[custom]/index.vue

@ -1,69 +1,97 @@
<template> <template>
<!-- Banner --> <!-- Banner -->
<Banner :data="form" /> <Banner :data="form" />
{{ form }}
<!-- 容器 --> <!-- 容器 -->
<div class="container md:w-3/4 m-auto" v-if="form"> <div class="container md:w-3/4 m-auto" v-if="form">
<div class="flex flex-col"> <div class="flex flex-col">
<Breadcrumb :data="form" /> <Breadcrumb :data="form" />
<div class="page-main w-full bg-white rounded-lg">
<div class="p-4 leading-7" v-html="form.design.content">
<div :class="form.design?.styles" class="page-main w-full bg-white rounded-lg">
<div class="p-4 leading-7" v-html="form.design?.content">
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div v-if="!form"> <div v-if="!form">
<el-empty description="404 页面不存在"></el-empty> <el-empty description="404 页面不存在"></el-empty>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type {Design} from "~/api/cms/design/model";
import type {ApiResult} from "~/api"; import type {ApiResult} from "~/api";
import {useServerRequest} from "~/composables/useServerRequest"; import {useServerRequest} from "~/composables/useServerRequest";
import {useConfigInfo, useToken} from "~/composables/configState";
import {useConfigInfo, useForm, useToken, useWebsite} from "~/composables/configState";
import Breadcrumb from "~/components/Breadcrumb.vue"; import Breadcrumb from "~/components/Breadcrumb.vue";
import type {BreadcrumbItem} from "~/types/global"; import type {BreadcrumbItem} from "~/types/global";
import type {Navigation} from "~/api/cms/navigation/model"; import type {Navigation} from "~/api/cms/navigation/model";
//
const route = useRoute(); const route = useRoute();
const { params } = route;
const { custom: path } = params;
//
const website = useWebsite();
const config = useConfigInfo(); const config = useConfigInfo();
const token = useToken(); const token = useToken();
//
const form = ref<Navigation | any>();
const form = useForm();
const breadcrumb = ref<BreadcrumbItem>(); const breadcrumb = ref<BreadcrumbItem>();
// //
const { data: nav } = await useServerRequest<ApiResult<Navigation>>('/cms/navigation/getNavigationByPath',{
query: {
path: '/' + path
const reload = async () => {
//
if(!form.value.navigationId && !form.value.path){
return ;
} }
})
if (nav.value?.data) {
// seo
// spm()
if(form.value.navigationId){
console.log('11111')
const { data: nav } = await useServerRequest<ApiResult<Navigation>>('/cms/navigation/' + form.value.navigationId)
if (nav.value?.data) {
form.value = nav.value.data form.value = nav.value.data
}
}
// spm
if(!form.value.navigationId){
console.log('2222')
const { data: nav } = await useServerRequest<ApiResult<Navigation>>('/cms/navigation/getNavigationByPath',{query: {path: form.value.path}})
if(nav.value?.data){
form.value = nav.value?.data;
}
}
// seo
useHead({ useHead({
title: `${form.value.title} - 网宿软件`,
meta: [{ name: form.value.design.keywords, content: form.value.design.description }],
title: `${form.value.title} - ${website.value.websiteName}`,
meta: [{ name: form.value.design?.keywords, content: form.value.design?.description }],
bodyAttrs: { bodyAttrs: {
class: "page-container", class: "page-container",
}, },
script: [ script: [
{ {
children: "console.log('Hello World')",
children: `console.log(${JSON.stringify(form.value)})`,
}, },
], ],
}); });
// //
breadcrumb.value = form.value.breadcrumb
breadcrumb.value = form.value
} }
</script>
<style scoped lang="scss">
watch(
() => route.query.spm,
(spm) => {
// TODO ()spmID
if(spm){
const spmValue = String(spm).split('.')
if(spmValue[5]){
form.value.navigationId = Number(spmValue[5])
}
return reload();
}
// TODO paramsID
const { custom } = route.params
form.value.path = `/${custom}`;
</style>
reload();
},
{ immediate: true }
);
</script>

80
pages/page/[id].vue

@ -0,0 +1,80 @@
<template>
<!-- Banner -->
<Banner :data="form" />
<!-- 容器 -->
<div class="container md:w-3/4 m-auto" v-if="form">
<div class="flex flex-col">
<Breadcrumb :data="form" />
<div :class="form.design?.styles" class="page-main w-full bg-white rounded-lg">
<div class="p-4 leading-7" v-html="form.design?.content">
</div>
</div>
</div>
</div>
<div v-if="!form">
<el-empty description="404 页面不存在"></el-empty>
</div>
</template>
<script setup lang="ts">
import type {ApiResult} from "~/api";
import {useServerRequest} from "~/composables/useServerRequest";
import {useConfigInfo, useForm, useToken} from "~/composables/configState";
import Breadcrumb from "~/components/Breadcrumb.vue";
import type {BreadcrumbItem} from "~/types/global";
import type {Navigation} from "~/api/cms/navigation/model";
//
const route = useRoute();
const config = useConfigInfo();
const token = useToken();
const form = useForm();
const breadcrumb = ref<BreadcrumbItem>();
//
const reload = async () => {
const { data: nav } = await useServerRequest<ApiResult<Navigation>>('/cms/navigation/' + form.value.navigationId)
if (nav.value?.data) {
form.value = nav.value.data
// seo
useHead({
title: `${form.value.title} - ${config.value.siteName}`,
meta: [{ name: form.value.design?.keywords, content: form.value.design?.description }],
bodyAttrs: {
class: "page-container",
},
script: [
{
children: "console.log('Hello World====')",
},
],
});
//
breadcrumb.value = form.value
}
}
watch(
() => route.query.spm,
(spm) => {
console.log(spm,'spm>>')
// TODO spmID
const spmValue = String(spm).split('.')
if(spmValue[5]){
form.value.navigationId = Number(spmValue[5])
}
// TODO ()paramsID
console.log(route.params.id,'sdfsd');
// const str = String(custom).replaceAll(".html", "");
// const split = str.split('-');
// if(split[1]){
// console.log('paramsID=' + split[1])
// form.value.navigationId = Number(split[1])
// }
reload();
},
{ immediate: true }
);
</script>

11
pages/product/740a123.html.vue

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
<div class="h-[500px] w-[500px] m-auto text-3xl text-center justify-center bg-amber mt-[100px] items-center">a740a123740a123740a123740a123</div>
</template>
<style scoped lang="scss">
</style>

8
types/global.d.ts

@ -9,6 +9,14 @@ export interface Config {
siteLogo?: string; siteLogo?: string;
subpageBanner?: string; subpageBanner?: string;
bottomBg?: string; bottomBg?: string;
elMenuMaxNumber?: number;
showSearchTools?: string;
showSearchIcon?: string;
showLoginButton?: string;
showAdminIcon?: string;
wxQrcode?: string;
wxQrcodeText?: string;
copyrightForDemoData?: string;
} }
export interface BreadcrumbItem { export interface BreadcrumbItem {

Loading…
Cancel
Save