新版本官网优化完成

This commit is contained in:
2025-02-12 16:37:07 +08:00
parent 43a2e17a80
commit 3efdbfc662
547 changed files with 23001 additions and 28169 deletions

131
pages/m/article/[id].vue Normal file
View File

@@ -0,0 +1,131 @@
<template>
<Banner :layout="layout" />
<!-- 主体部分 -->
<div class="p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ page.title }}
</h2>
</div>
<div class="content">
<!-- 文章模型 -->
<ul class="news_listn clearfix pt-2">
<template v-for="(item,index) in list" key="index">
<li class="clearfix">
<a :href="mDetail(item)" class=" fl mr-1">
<el-image :src="item.image" :fit="`scale-down`" class="w-[120px] h-[80px]" :alt="item.title" />
</a>
<div class="list">
<h3 class="text-lg"><a :href="mDetail(item)" :title="item.title" class="line-clamp-1 text-left">{{ item.title }}</a></h3>
<div v-html="item.comments" class="line-clamp-2"></div>
<!-- <div class="date">发布日期{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</div>-->
<!-- <div class="n-more" ><a :href="detail(item)" >查看更多>></a></div>-->
</div>
</li>
</template>
<div class="clearboth"></div>
</ul>
<Pagination :total="total" @done="search" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Banner from "@/components/Banner.vue";
import {useLayout, usePage} from "~/composables/configState";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
import dayjs from "dayjs";
import type { ComponentSize } from 'element-plus'
import {mDetail, paramsId} from "~/utils/common";
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
import {pageCmsArticle} from "~/api/cms/cmsArticle";
const route = useRoute();
// 页面信息
const list = ref<CmsArticle[]>([]);
const i18n = useI18n();
const category = ref<CmsNavigation[]>([]);
const total = ref(0);
// 获取状态
const page = usePage();
const layout = useLayout();
// 搜索表单
const where = reactive<CmsArticleParam>({
keywords: '',
page: 1,
limit: 20,
status: 0,
parentId: undefined,
categoryId: undefined,
lang: i18n.locale.value
});
// 加载页面数据
const reload = async () => {
getCmsNavigation(paramsId()).then(data => {
// 获取栏目信息
page.value = data
layout.value.banner = data.banner;
// 设置页面标题
useSeoMeta({
description: data.comments || data.title,
keywords: data.title,
titleTemplate: `${data?.title}` + ' - %s',
})
// 二级栏目分类
listCmsNavigation({
parentId: data.parentId == 0 ? data.navigationId : data.parentId
}).then(categoryData => {
category.value = categoryData;
// 加载文章列表
if(data.parentId == 0 && category.value.length > 0){
where.parentId = data.navigationId;
}else {
where.categoryId = data.navigationId;
}
pageCmsArticle(where).then(response => {
if(response){
total.value = response?.count;
list.value = response?.list;
}
})
})
}).catch(err => {
console.log(err,'加载失败...')
})
}
/**
* 搜索
* @param data
*/
const search = (data: CmsArticleParam) => {
where.page = data.page;
reload();
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>

129
pages/m/case/[id].vue Normal file
View File

@@ -0,0 +1,129 @@
<template>
<Banner :layout="layout" />
<!-- 主体部分 -->
<div class="p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ page.title }}
</h2>
</div>
<div class="content py-3">
<el-row :gutter="16">
<el-col :span="24" v-for="(item,index) in list" key="index">
<div class="cast-item">
<a :href="mDetail(item)" :title="item.title" class="img"><el-image :fit="`scale-down`" :src="item.image" :alt="item.title" /></a>
<div class="flex flex-col leading-7">
<a :href="mDetail(item)" class="text-[16px] font-bold" :title="item.title">{{ item.title }}</a>
<a :href="mDetail(item)" class="more"><span class="text-gray-400">{{ $t('case.detail') }}>></span></a>
</div>
</div>
</el-col>
</el-row>
<Pagination :total="total" @done="search" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Banner from "@/components/Banner.vue";
import {useLayout, usePage} from "~/composables/configState";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
import type { ComponentSize } from 'element-plus'
import {paramsId} from "~/utils/common";
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
import {pageCmsArticle} from "~/api/cms/cmsArticle";
import CmsArticleList from "~/components/CmsArticleList.vue";
const route = useRoute();
// 页面信息
const list = ref<CmsArticle[]>([]);
const i18n = useI18n();
const category = ref<CmsNavigation[]>([]);
const total = ref(0);
// 获取状态
const page = usePage();
const layout = useLayout();
// 搜索表单
const where = reactive<CmsArticleParam>({
keywords: '',
page: 1,
limit: 20,
status: 0,
parentId: undefined,
categoryId: undefined,
lang: i18n.locale.value
});
// 加载页面数据
const reload = async () => {
await getCmsNavigation(paramsId()).then(data => {
page.value = data;
// layout.value = data.design;
layout.value.banner = data.banner;
// seo
useSeoMeta({
description: data.comments || data.title,
keywords: data.title,
titleTemplate: `${data?.title}` + ' - %s',
})
// 二级栏目分类
listCmsNavigation({
parentId: data.parentId == 0 ? data.navigationId : data.parentId
}).then(navigation => {
category.value = navigation;
// 加载文章列表
if(data.parentId == 0 && category.value.length > 0){
where.parentId = page.value.navigationId;
}else {
where.categoryId = page.value.navigationId;
}
pageCmsArticle(where).then(response => {
if(response){
total.value = response.count;
list.value = response.list;
}
})
})
})
}
/**
* 搜索
* @param data
*/
const search = (data: CmsArticleParam) => {
where.page = data.page;
reload();
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>
<style scoped lang="less">
.case_listn li{
max-width: 200px;
}
.cast-item{
border: 1px solid #eeeeee;
padding: 10px;
margin-bottom: 10px;
}
</style>

View File

@@ -0,0 +1,67 @@
<template>
<!-- 移动端 -->
<div class="sm:hidden w-full bg-white mb-3 " v-if="ad">
<el-carousel indicator-position="none">
<el-carousel-item v-for="(item,index) in ad?.imageList" :key="index">
<el-image :src="item.url" />
</el-carousel-item>
</el-carousel>
</div>
</template>
<script setup lang="ts">
import type {CompanyParam} from "~/api/system/company/model";
import type {CmsAd} from "~/api/cms/cmsAd/model";
import {pageCmsAd} from "~/api/cms/cmsAd";
const props = withDefaults(
defineProps<{
config?: any;
list?: any[];
disabled?: boolean;
title?: string;
comments?: string;
}>(),
{
title: '卡片标题',
comments: '卡片描述'
}
);
const emit = defineEmits<{
(e: 'done'): void;
}>();
const ad = ref<CmsAd>();
// 搜索表单
const where = reactive<CompanyParam>({
keywords: ''
});
// 请求数据
const reload = async () => {
pageCmsAd({
type: 1,
lang: getLang()
}).then(res => {
if(res){
ad.value = res.list[0];
}
})
}
watch(
() => props.config,
() => {
reload();
},
{immediate: true}
);
</script>
<style>
.el-carousel__container{
height: 240px !important;
}
</style>

202
pages/m/detail/[id].vue Normal file
View File

@@ -0,0 +1,202 @@
<!-- 文章详情 -->
<template>
<Banner :layout="layout"/>
<!-- 主体部分 -->
<div class="p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ form.categoryName }}
</h2>
</div>
<div class="content">
<!-- 新闻详细 -->
<div class="news_detail">
<h1 class="title">{{ form.title }}</h1>
<div class="info_title clearfix">
<h3 class="text-center text-gray-400">
{{ $t('createTime') }}<span>{{ dayjs(form.createTime).format('YYYY-MM-DD') }}</span>
{{ $t('author') }}<span>{{ form.nickname }}</span>
{{ $t('click') }}<span>{{ form.actualViews }}</span>
</h3>
<div class="share">
<!-- Baidu Button BEGIN -->
<div class="bdsharebuttonbox">
<a href="#" class="bds_more" data-cmd="more"></a>
<a href="#" class="bds_qzone" data-cmd="qzone"></a>
<a href="#" class="bds_tsina" data-cmd="tsina"></a>
<a href="#" class="bds_tqq" data-cmd="tqq"></a>
<a href="#" class="bds_renren" data-cmd="renren"></a>
<a href="#" class="bds_weixin" data-cmd="weixin"></a>
</div>
</div>
</div>
<div class="content text-lg" v-html="form.content"></div>
<h3 class="tag">{{ $t('articleUrl') }}{{ locationUrl() }} </h3>
<Tags :data="form.tags" />
<NextArticle />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type {BreadcrumbItem} from "~/types/global";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import {locationUrl, paramsId} from "~/utils/common";
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
import useFormData from "~/utils/use-form-data";
import dayjs from "dayjs";
import Banner from "@/components/Banner.vue";
import type {Layout} from "~/api/layout/model";
import {getCmsArticle} from "~/api/cms/cmsArticle";
import {listCmsNavigation} from "~/api/cms/cmsNavigation";
import Tags from "~/components/Tags.vue";
// 引入状态管理
const route = useRoute();
const layout = ref<Layout>({});
const breadcrumb = ref<BreadcrumbItem>();
const showPassword = ref<boolean>();
const category = ref<CmsNavigation[]>([]);
// 配置信息
const {form, assignFields} = useFormData<CmsArticle>({
// 文章id
articleId: undefined,
// 文章模型
model: undefined,
// 文章标题
title: undefined,
// 分类类型
type: undefined,
// 展现方式
showType: undefined,
// 文章类型
categoryId: undefined,
// 文章分类
categoryName: undefined,
parentId: undefined,
// 封面图
image: undefined,
// 附件
files: undefined,
// 附件
fileList: [],
// 缩列图
thumbnail: undefined,
// 视频地址
video: undefined,
// 上传的文件类型
accept: undefined,
// 来源
source: undefined,
// 文章内容
content: undefined,
// 虚拟阅读量
virtualViews: undefined,
// 实际阅读量
actualViews: undefined,
// 访问权限
permission: undefined,
// 访问密码
password: undefined,
password2: undefined,
// 用户ID
userId: undefined,
// 用户昵称
nickname: undefined,
// 账号
username: undefined,
// 用户头像
// userAvatar: undefined,
author: undefined,
// 所属门店ID
shopId: undefined,
//
likes: undefined,
// 排序
sortNumber: undefined,
// 备注
comments: undefined,
// 状态
status: undefined,
// 创建时间
createTime: undefined,
// 更新时间
updateTime: undefined,
// 租户ID
tenantId: undefined,
// 租户名称
tenantName: undefined,
// 租户logo
logo: undefined,
// 详情页路径
detail: undefined
});
// 请求数据
const reload = async () => {
await getCmsArticle(paramsId()).then(data => {
assignFields(data)
layout.value.banner = data?.banner;
// 二级栏目分类
if (data.parentId) {
listCmsNavigation({parentId: data.parentId}).then(list => {
category.value = list;
})
}
if(form.permission === 1){
console.log('登录可见')
return;
}
if(form.permission === 2){
console.log('需要密码')
showPassword.value = true;
return;
}
})
// seo
useSeoMeta({
description: form?.comments,
keywords: form.title,
titleTemplate: `${form?.title}` + ' - %s',
})
// 面包屑
breadcrumb.value = form
}
watch(
() => route.path,
(path) => {
reload();
},
{immediate: true}
);
</script>
<style lang="scss">
.content {
padding-top: 15px;
overflow: hidden;
}
.content p{
}
.content img{
padding: 10px 0;
max-width: 100%;
height: auto;
}
.content video {
width: 100%;
height: auto;
}
</style>

183
pages/m/index.vue Normal file
View File

@@ -0,0 +1,183 @@
<template>
<!-- 首页banner -->
<Carousel ref="CarouselRef"/>
<div class="search">
<el-input v-model="keyword" :placeholder="$t('index.keyword')" :suffix-icon="Search" @change="onSearch"/>
</div>
<!-- 产品分类 -->
<div class="cp p-3" v-if="cpCategory">
<el-row :gutter="16">
<el-col :span="6" v-for="(item,index) in cpCategory" :key="index">
<div class="item flex flex-col justify-center mb-2" v-if="index < 8">
<a :href="navTo(item)" class="img" style="border-radius: 100%;">
<el-avatar fit="fill" :size="65" :src="`${item.icon}`" style="border: 1px solid #FFFFFF; box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);"/>
</a>
<div class="text-center py-1"><a :href="navTo(item)">{{ item.title }}</a></div>
</div>
</el-col>
</el-row>
</div>
<div class="clearboth"></div>
<div class="advs"><p><img :src="config?.MobileIndexInfoTopImage"
title="1729219778290291.jpg" alt="1.jpg"/></p>
<p><br/></p>
<p><br/></p></div>
<div class="clearboth"></div>
<div class="products">
<div class="products_title">
{{ $t('index.companyProfile') }}
</div>
<div class="contentss clearfix">
<div class="tps"><p><a :href="i18n.locale.value == 'en' ? `/en/m/page/1100.html` : `/m/page/1025.html`" target="_self"><img
:src="config.MobileIndexInfoImage" title="1729219913337024.jpg"
alt="2.jpg"/></a></p>
<p><br/></p></div>
<div class="nrs">
{{ config.MobileIndexInfo }}
</div>
</div>
</div>
<div class="products" v-if="caseCategory">
<div class="products_title">
{{ $t('index.parentNameCase') }}
</div>
<ul>
<li v-for="(item,index) in caseCategory" :key="index">
<a :href="navTo(item)" title="轨道交通建设项目" class="img">
<img :src="item.icon" alt="轨道交通建设项目"/>
<h3>{{ item.title }}</h3>
</a>
</li>
</ul>
</div>
<div class="tu"><p><img :src="config.MobileIndexInfoHZGYImage" title="活动房安装"
alt="活动房安装" border="0" vspace="0" style="white-space: normal;"/></p>
<p><br/></p></div>
<div class="hezuo">
<div class="products_title">
<a><span class="text-[#0c6fcd]" >{{ $t('index.partner') }}</span></a>
</div>
<div class="con"><p><a><img
:src="config.MobileIndexInfoLogoList" title="1587462469987062.jpg"
alt="手机合作.jpg"/></a></p></div>
</div>
<!-- 服务中国 走向海外 -->
<div v-html="config.MobileIndexCode" class="mservice"></div>
<div class="advs"><a :href="`${i18n.locale.value == 'en' ? '/en/m/video/1075.html' : '/m/video/1000.html'}`"><img :src="config.MobileIndexBottomBanner"
title="1553249693490374.jpg" alt="555.jpg" border="0" vspace="0"/></a></div>
<div class="news">
<div class="products_title">
{{ $t('index.news') }}
</div>
<ul>
<li v-for="(item,index) in hotNews" :key="index">
<a :href="mDetail(item)" :title="item.title">
{{ item.title }}
</a>
<div class="line-clamp-1 max-w-[320px]" v-html="item.comments"></div>
</li>
</ul>
</div>
<div class="clearboth"></div>
<div class="products">
<div class="products_title">
{{ $t('index.contact') }}
</div>
<div class="flex flex-col p-3 leading-8">
<span class="text-left">{{ $t('page.tel') }}{{ config.tel }}</span>
<span class="text-left">{{ $t('page.phone') }}{{ config.fax }}</span>
<span class="text-left">{{ $t('page.fax') }}{{ config.phone }}</span>
<span class="text-left">{{ $t('page.email') }}{{ config.email }}</span>
<span class="text-left">{{ $t('page.address') }}{{ config.address }}</span>
<span class="text-left">{{ $t('page.factory') }}{{ config.address2 }}</span>
<span class="text-left">{{ $t('page.domain') }}{{ config.pageLeftInfoUrl }}</span>
</div>
</div>
<div class="distraction">
</div>
</template>
<script setup lang="ts">
import Carousel from "~/pages/m/components/Carousel.vue";
import {useConfigInfo, useWebsite} from "~/composables/configState";
import {Search} from '@element-plus/icons-vue'
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
import {pageCmsArticle} from "~/api/cms/cmsArticle";
import {navTo} from "~/utils/common";
import {getSiteInfo} from "~/api/layout";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
const props = withDefaults(
defineProps<{
name?: any;
}>(),
{}
);
const config = useConfigInfo();
const website = useWebsite();
const keyword = ref();
const i18n = useI18n();
const hotNews = ref<CmsArticle[]>([]);
const topNavs = ref<any>([]);
const cpCategory = ref<CmsNavigation[]>([]);
const caseCategory = ref<any>([]);
const onSearch = () => {
window.location.href = `/m/search/${keyword.value}`;
}
// TODO 读取服务器缓存数据
await getSiteInfo({
lang: i18n.locale.value
}).then(data => {
website.value = data
topNavs.value = data.topNavs?.filter(d => d.title === '产品系列' || d.title === 'Product')
if(topNavs.value[0].children){
cpCategory.value = topNavs.value[0].children;
}
caseCategory.value = data.topNavs?.filter(d => d.title === '项目展示' || d.title === 'Case')[0].children
})
const reload = async () => {
// 新闻头条
pageCmsArticle({
limit: 4,
status: 0,
recommend: 1,
parentId: i18n.locale.value == 'en' ? 1077 : 1002,
lang: i18n.locale.value
}).then(res => {
if(res){
hotNews.value = res?.list;
}
})
}
reload();
</script>
<style scoped lang="less">
</style>

220
pages/m/item/[id].vue Normal file
View File

@@ -0,0 +1,220 @@
<script setup lang="ts">
import type {BreadcrumbItem} from "~/types/global";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import {locationUrl, navTo, paramsId} from "~/utils/common";
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
import useFormData from "~/utils/use-form-data";
import Banner from "@/components/Banner.vue";
import type {Layout} from "~/api/layout/model";
import {getCmsArticle} from "~/api/cms/cmsArticle";
import {listCmsNavigation} from "~/api/cms/cmsNavigation";
import Tags from "~/components/Tags.vue";
// 引入状态管理
const route = useRoute();
const layout = ref<Layout>({});
const breadcrumb = ref<BreadcrumbItem>();
const showPassword = ref<boolean>();
const category = ref<CmsNavigation[]>([]);
const fileList = ref<any>();
// 配置信息
const {form, assignFields} = useFormData<CmsArticle>({
// 文章id
articleId: undefined,
// 文章模型
model: undefined,
// 文章标题
title: undefined,
// 分类类型
type: undefined,
// 展现方式
showType: undefined,
// 文章类型
categoryId: undefined,
// 文章分类
categoryName: undefined,
parentId: undefined,
// 封面图
image: undefined,
// 附件
files: undefined,
// 缩列图
thumbnail: undefined,
// 视频地址
video: undefined,
// 上传的文件类型
accept: undefined,
// 来源
source: undefined,
// 文章内容
content: undefined,
// 虚拟阅读量
virtualViews: undefined,
// 实际阅读量
actualViews: undefined,
// 访问权限
permission: undefined,
// 访问密码
password: undefined,
password2: undefined,
// 用户ID
userId: undefined,
// 用户昵称
nickname: undefined,
// 账号
username: undefined,
// 用户头像
// userAvatar: undefined,
author: undefined,
// 所属门店ID
shopId: undefined,
//
likes: undefined,
// 排序
sortNumber: undefined,
// 备注
comments: undefined,
// 状态
status: undefined,
// 创建时间
createTime: undefined,
// 更新时间
updateTime: undefined,
tenantId: undefined,
// 租户名称
tenantName: undefined,
// 租户logo
logo: undefined,
// 详情页路径
detail: undefined
});
// 请求数据
const reload = async () => {
await getCmsArticle(paramsId()).then(data => {
assignFields(data)
layout.value.banner = data?.banner;
// 二级栏目分类
if (data.parentId) {
listCmsNavigation({parentId: data.parentId}).then(list => {
category.value = list;
})
}
if(form.permission === 1){
console.log('登录可见')
return;
}
if(form.permission === 2){
console.log('需要密码')
showPassword.value = true;
return;
}
})
// seo
useSeoMeta({
description: form.comments || form.title,
keywords: form.title,
titleTemplate: `${form?.title}` + ' - %s',
})
// 面包屑
breadcrumb.value = form
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>
<template>
<Banner :layout="layout"/>
<!-- 主体部分 -->
<div class="clearfix p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ form.categoryName || '分类名称' }}
</h2>
</div>
<div class="detail-container">
<!-- 产品详细 -->
<div class="product_detail" id="pd1">
<div class="allcontent clearfix">
<div style="float: left;">
<div class="img clearfix" id="play">
<el-carousel v-if="form.files" :interval="4000">
<el-carousel-item v-for="item in JSON.parse(form.files)" :key="item" style="display: flex; align-items: center; justify-content: center">
<el-image fit="cover" :src="item" />
</el-carousel-item>
</el-carousel>
</div>
</div>
<div class="list mb-10">
<ul class="list_p">
<h1 class="title">{{ form.title }}</h1>
<li><h2>{{ $t('categoryName') }}<a :href="navTo(form,`/product/${form.categoryId}`)"><strong>{{ form.categoryName }}</strong></a></h2></li>
<li class="text-left">{{ $t('createTime') }}<span>{{ form.createTime }}</span></li>
<li class="text-left">{{ $t('overview') }}</li>
<div class="bg-gray-100 p-2 w-[360px]">{{ form.comments }}</div>
<li class="inquiry"><a :href="navTo(form,`/m/order/${form.articleId}.html}`)">{{ $t('onlineInquiry') }}</a></li>
</ul>
</div>
</div>
<div class="clearboth"></div>
<div class="p_detail">
<ul id="product-tab" class="product-tab clearfix">
<li class="cur">{{ $t('show.detail') }}</li>
</ul>
<div class="content tab-content text-sm" v-html="form.content"></div>
</div>
<h3 class="tag">{{ $t('articleUrl') }}{{ locationUrl() }} </h3>
<Tags :data="form.tags" />
<NextArticle />
</div>
</div>
</div>
</div>
</template>
<style lang="scss">
.content {
padding-top: 15px;
overflow: hidden;
}
.content p{
text-indent: 0;
}
.content img{
padding: 5px 0;
max-width: 100%;
height: auto;
}
.content video {
width: 100%;
height: auto;
}
.product_detail{
padding: 5px 0 !important;
}
.product_detail .list{
margin-left: 0 !important;
}
.product_detail .img{
width: 90vw !important;
}
</style>

232
pages/m/order/[id].vue Normal file
View File

@@ -0,0 +1,232 @@
<template>
<!-- Banner -->
<Banner :layout="layout" />
<!-- 主体部分 -->
<div class="clearfix p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>{{ $t('order.title') }}</h2>
<Breadcrumb :data="page" :categoryName="page.categoryName" />
</div>
<div class="form-box p-5">
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="120"
label-position="left"
status-icon
>
<el-form-item :label="$t('order.title')" prop="title" class="hover:bg-gray-50 p-2">
<el-input v-model="form.title" :placeholder="$t('order.title')"/>
</el-form-item>
<el-form-item :label="$t('order.content')" prop="content" class="hover:bg-gray-50 p-2">
<el-input type="textarea" :rows="5" cols="80" v-model="form.content" :placeholder="$t('order.content')"/>
</el-form-item>
<el-form-item :label="$t('order.realName')" prop="realName" class="hover:bg-gray-50 p-2">
<el-input v-model="form.realName" :placeholder="$t('order.realName')"/>
</el-form-item>
<el-form-item :label="$t('order.phone')" prop="phone" class="hover:bg-gray-50 p-2">
<el-input v-model="form.phone" :maxlength="11" :placeholder="$t('order.phone')"/>
</el-form-item>
<el-form-item :label="$t('order.email')" prop="email" class="hover:bg-gray-50 p-2">
<el-input v-model="form.email" :placeholder="$t('order.email')"/>
</el-form-item>
<el-form-item :label="$t('order.address')" prop="address" class="hover:bg-gray-50 p-2">
<el-input v-model="form.address" :placeholder="$t('order.address')"/>
</el-form-item>
<el-form-item :label="$t('order.code')" prop="code" class="hover:bg-gray-50 p-2">
<el-space class="flex">
<el-input size="large" :placeholder="$t('order.imgCode')" maxlength="5" v-model="form.code" />
<el-image :alt="$t('order.imgCode')" v-if="captcha" :src="captcha" @click="changeCaptcha" />
</el-space>
</el-form-item>
<el-form-item>
<div class="submitForm ml-2">
<el-button type="primary" size="large" @click="submitForm(formRef)">
{{ $t('order.submit') }}
</el-button>
</div>
</el-form-item>
</el-form>
</div>
</div>
<el-dialog v-model="dialogVisible">
<div class="flex justify-center">
<el-image w-full :src="dialogImageUrl" alt="查看证件" />
</div>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import {useLayout, usePage} from "~/composables/configState";
import {paramsId} from "~/utils/common";
import {ArrowRight} from '@element-plus/icons-vue'
import type {FormInstance, FormRules} from 'element-plus'
import type {CmsOrder} from "~/api/cms/cmsOrder/model";
import useFormData from "~/utils/use-form-data";
import {addCmsOrder} from "~/api/cms/cmsOrder";
import {getCmsArticle} from "~/api/cms/cmsArticle";
import {getCaptcha} from "~/api/passport/login";
// 引入状态管理
const route = useRoute();
const layout = useLayout();
const page = usePage();
const dialogVisible = ref(false)
const formRef = ref<FormInstance>()
const dialogImageUrl = ref('')
// 验证码 base64 数据
const captcha = ref('');
const text = ref<string>('');
const {form, resetFields} = useFormData<CmsOrder>({
// 订单号
orderId: undefined,
// 模型名称
model: 'order',
// 订单标题
title: undefined,
// 订单编号
orderNo: undefined,
// 订单类型0商城 1询价 2留言
type: undefined,
// 关联项目ID配合订单类型使用
articleId: undefined,
// 真实姓名
realName: undefined,
// 手机号码
phone: undefined,
// 电子邮箱
email: undefined,
// 收货地址
address: undefined,
// 订单内容
content: undefined,
// 订单总额
totalPrice: '0.00',
// 实际付款
payPrice: '0.00',
// 报价询价
price: '0.00',
// 购买数量
totalNum: undefined,
// 二维码地址,保存订单号,支付成功后才生成
qrcode: undefined,
// 下单渠道0网站 1小程序 2其他
channel: undefined,
// 过期时间
expirationTime: undefined,
// 订单是否已结算(0未结算 1已结算)
isSettled: undefined,
// 用户id
userId: undefined,
// 备注
comments: undefined,
// 排序号
sortNumber: undefined,
// 是否删除, 0否, 1是
deleted: undefined,
// 租户id
tenantId: undefined,
// 创建时间
createTime: undefined,
// 图像验证码
code: '',
})
const rules = reactive<FormRules<CmsOrder>>({
title: [
{required: true, message: '请输入产品名称', trigger: 'blur'},
],
phone: [
{required: true, message: '请输入手机号码', trigger: 'blur'},
{pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur'},
],
realName: [
{required: true, message: '请输入联系人姓名', trigger: 'blur'},
],
content: [
{required: true, message: '请输入留言内容', trigger: 'blur'},
]
})
/* 获取图形验证码 */
const changeCaptcha = async () => {
getCaptcha().then(captchaData => {
captcha.value = captchaData.base64;
text.value = captchaData.text;
})
};
// 请求数据
const reload = async () => {
getCmsArticle(paramsId()).then(data => {
form.articleId = data.articleId;
layout.value.banner = data.banner;
form.content = ''
// seo
useSeoMeta({
description: form.comments || form.title,
keywords: form.title,
titleTemplate: `${form?.title}` + ' - %s',
})
changeCaptcha();
})
}
// 提交表单
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
if(form.code !== text.value){
await reload();
ElMessage.error('验证码不正确!');
return false;
}
await formEl.validate((valid) => {
if (valid) {
addCmsOrder(form).then(res => {
if (res.code == 0) {
ElMessage.success(res.message)
resetFields();
reload();
} else {
return ElMessage.error(res.message)
}
})
}
})
}
onMounted(() => {
// 在这里放置你想要在组件渲染完成后执行的代码
console.log('组件已挂载');
});
watch(
() => route.path,
() => {
reload();
},
{ immediate: true }
);
</script>
<style lang="scss">
.content {
padding-top: 15px;
overflow: hidden;
text-indent: 2em;
}
.content p{
line-height: 2em;
}
.content img{
padding: 10px;
max-width: 100%;
}
</style>

78
pages/m/page/[id].vue Normal file
View File

@@ -0,0 +1,78 @@
<template>
<!-- Banner -->
<Banner :layout="layout" />
<!-- 主体部分 -->
<div class="clearfix p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>{{ page.title }}</h2>
</div>
<div class="content text-lg" v-html="page.design?.content"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { useLayout, usePage} from "~/composables/configState";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import {paramsId} from "~/utils/common";
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
// 引入状态管理
const route = useRoute();
const layout = useLayout();
const page = usePage();
const category = ref<CmsNavigation[]>([]);
// 加载页面布局
const reload = async () => {
getCmsNavigation(paramsId()).then(data => {
page.value = data
layout.value.banner = data.banner;
// 二级栏目分类
if(data.parentId && data.parentId > 0){
listCmsNavigation({
parentId: data.parentId == 0 ? data.navigationId : data.parentId
}).then(list => {
category.value = list
})
}
// seo
useSeoMeta({
description: data.comments || data.title,
keywords: data.title,
titleTemplate: `${data?.title}` + ' - %s',
})
})
}
watch(
() => route.path,
() => {
reload();
},
{ immediate: true }
);
</script>
<style lang="scss">
.content {
padding-top: 15px;
padding-bottom: 30px;
overflow: hidden;
}
.content p{
}
.content img{
padding: 5px 0;
max-width: 100%;
height: auto;
}
.content video {
width: 100%;
height: auto;
}
</style>

122
pages/m/product/[id].vue Normal file
View File

@@ -0,0 +1,122 @@
<template>
<Banner :layout="layout" />
<!-- 主体部分 -->
<div class="clearfix p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ page.title }}
</h2>
</div>
<div class="content">
<!-- 产品列表 -->
<el-row :gutter="20">
<template v-for="(item,index) in list" key="index">
<el-col :span="24" class="my-3">
<div class="item p-2 border-1 border-gray-200 border-solid hover:border-blue-500">
<a :href="mDetail(item)" :title="item.title" class="img"><el-image :fit="`scale-down`" :src="item.image" :alt="item.title" /></a>
<h3>
<a :href="mDetail(item)" :title="item.title" class="text-lg font-bold">{{ item.title }}</a>
<span class="line-clamp-1 text-gray-400 text-sm font-normal">{{ item.comments }}</span>
</h3>
</div>
</el-col>
</template>
</el-row>
<Pagination :total="total" @done="search" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Banner from "@/components/Banner.vue";
import {useLayout, usePage} from "~/composables/configState";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
import {mDetail, paramsId} from "~/utils/common";
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
import {pageCmsArticle} from "~/api/cms/cmsArticle";
const route = useRoute();
// 页面信息
const list = ref<CmsArticle[]>([]);
const i18n = useI18n();
const category = ref<CmsNavigation[]>([]);
const total = ref(0);
// 获取状态
const page = usePage();
const layout = useLayout();
// 搜索表单
const where = reactive<CmsArticleParam>({
keywords: '',
page: 1,
limit: 20,
status: 0,
parentId: undefined,
categoryId: undefined,
lang: i18n.locale.value
});
const reload = async () => {
console.log(paramsId())
getCmsNavigation(paramsId()).then(data => {
// 获取栏目信息
page.value = data
layout.value.banner = data.banner;
// 设置页面标题
useSeoMeta({
description: data.comments || data.title,
keywords: data.title,
titleTemplate: `${data?.title}` + ' - %s',
})
// 二级栏目分类
listCmsNavigation({
parentId: data.parentId == 0 ? data.navigationId : data.parentId
}).then(categoryData => {
category.value = categoryData;
// 加载文章列表
if(data.parentId == 0 && category.value.length > 0){
where.parentId = data.navigationId;
}else {
where.categoryId = data.navigationId;
}
pageCmsArticle(where).then(response => {
if(response){
total.value = response?.count;
list.value = response?.list;
}
})
})
}).catch(err => {
console.log(err,'加载失败...')
})
}
/**
* 搜索
* @param data
*/
const search = (data: CmsArticleParam) => {
where.page = data.page;
reload();
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>

147
pages/m/search/[id].vue Normal file
View File

@@ -0,0 +1,147 @@
<template>
<Banner :layout="layout" />
<!-- 主体部分 -->
<div class="p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ $t('searchKeywords') }}{{ where.keywords }}
</h2>
</div>
<el-alert v-if="where.keywords" :title="`${$t('search.results')}${$t('search.find')} ${total} ${$t('search.nums')}`" type="warning" :closable="false" />
<div class="content">
<ul class="news_listn clearfix">
<template v-for="(item,index) in list" key="index">
<li class="clearfix">
<div class="">
<h3 class="text-lg"><a :href="mDetail(item)" :title="item.title" v-html="replaceKeywords(item.title)"></a></h3>
<div v-html="replaceKeywords(item.comments)" class="line-clamp-2 text-gray-400"></div>
<div class="date text-gray-400">{{ $t('createTime') }}{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</div>
</div>
</li>
</template>
<div class="clearboth"></div>
</ul>
<Pagination :total="total" @done="search" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Banner from "@/components/Banner.vue";
import {useConfigInfo, useLayout, usePage} from "~/composables/configState";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
import dayjs from "dayjs";
import {getPath} from "~/utils/common";
import {listCmsNavigation} from "~/api/cms/cmsNavigation";
import {pageCmsArticle} from "~/api/cms/cmsArticle";
import {listCmsModel} from "~/api/cms/cmsModel";
const route = useRoute();
// 页面信息
const runtimeConfig = useRuntimeConfig();
const list = ref<CmsArticle[]>([]);
const i18n = useI18n();
const category = ref<CmsNavigation[]>([]);
const total = ref(0);
// 获取状态
const page = usePage();
const layout = useLayout();
const config = useConfigInfo();
// 搜索表单
const where = reactive<CmsArticleParam>({
keywords: '',
page: 1,
limit: 10,
status: 0,
parentId: undefined,
categoryId: undefined,
lang: i18n.locale.value
});
const replaceKeywords = (text: any) => {
return text.replace(`${where.keywords}`,'<font color=#ff0000>' + where.keywords + '</font>');
}
// 加载页面数据
const reload = async () => {
listCmsModel({
model: getPath(2)
}).then(response => {
const data = response[0];
if(data){
// 获取栏目信息
page.value = data
layout.value.banner = data.banner;
// 设置页面标题
useSeoMeta({
description: data?.comments || `${route.params.id}`,
keywords: `${route.params.id}`,
titleTemplate: `【搜索结果】${route.params.id}` + ' - %s',
})
// 二级栏目分类
listCmsNavigation({
parentId: i18n.locale.value == 'en' ? 1073 : 998,
}).then(categoryData => {
category.value = categoryData;
// 加载文章列表
if(!getPath(1)){
return ElMessage.error('请输入搜索关键词!');
}
where.keywords = `${route.params.id}`;
pageCmsArticle(where).then(response => {
if(response){
total.value = response?.count;
list.value = response?.list;
}
})
})
}
}).catch(err => {
console.log(err,'加载失败...')
})
}
useHead({
title: `搜索结果 - ${config.value.siteName || runtimeConfig.public.siteName}`,
bodyAttrs: {
class: "page-container",
}
});
/**
* 搜索
* @param data
*/
const search = (data: CmsArticleParam) => {
where.page = data.page;
reload();
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>
<style scoped lang="less">
.sitemp h2{
width: 500px !important;
}
</style>

185
pages/m/show/[id].vue Normal file
View File

@@ -0,0 +1,185 @@
<!-- 文章详情 -->
<template>
<Banner :layout="layout"/>
<!-- 主体部分 -->
<div class="p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ form.categoryName || '分类名称' }}
</h2>
</div>
<div class="detail-container">
<!-- 产品详细 -->
<div class="product_detail" id="pd1">
<div class="allcontent clearfix">
<div class="text-center text-xl text-gray-800 py-2">{{ form.title }}</div>
<el-carousel v-if="form.files" :interval="4000">
<el-carousel-item v-for="item in form.files" :key="item" class="" style="display: flex; align-items: center; justify-content: center">
<el-image :src="item" />
</el-carousel-item>
</el-carousel>
</div>
<div class="clearboth"></div>
<div class="p_detail">
<ul id="product-tab" class="product-tab clearfix">
<li class="cur">{{ $t('show.detail') }}</li>
</ul>
<div class="content tab-content text-sm" v-html="form.content"></div>
</div>
<h3 class="tag">{{ $t('articleUrl') }}{{ locationUrl() }} </h3>
<Tags :data="form.tags" />
<NextArticle />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import {locationUrl, paramsId} from "~/utils/common";
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
import useFormData from "~/utils/use-form-data";
import Banner from "@/components/Banner.vue";
import type {Layout} from "~/api/layout/model";
import {getCmsArticle} from "~/api/cms/cmsArticle";
import {listCmsNavigation} from "~/api/cms/cmsNavigation";
import Tags from "~/components/Tags.vue";
// 引入状态管理
const route = useRoute();
const layout = ref<Layout>({});
const category = ref<CmsNavigation[]>([]);
// 配置信息
const {form, assignFields} = useFormData<CmsArticle>({
// 文章id
articleId: undefined,
// 文章模型
model: undefined,
// 文章标题
title: undefined,
// 分类类型
type: undefined,
// 展现方式
showType: undefined,
// 文章类型
categoryId: undefined,
// 文章分类
categoryName: undefined,
parentId: undefined,
// 封面图
image: undefined,
// 附件
files: undefined,
// 缩列图
thumbnail: undefined,
// 视频地址
video: undefined,
// 上传的文件类型
accept: undefined,
// 来源
source: undefined,
// 文章内容
content: undefined,
// 虚拟阅读量
virtualViews: undefined,
// 实际阅读量
actualViews: undefined,
// 访问权限
permission: undefined,
// 访问密码
password: undefined,
password2: undefined,
// 用户ID
userId: undefined,
// 用户昵称
nickname: undefined,
// 账号
username: undefined,
// 用户头像
// userAvatar: undefined,
author: undefined,
// 所属门店ID
shopId: undefined,
//
likes: undefined,
// 排序
sortNumber: undefined,
// 备注
comments: undefined,
// 状态
status: undefined,
// 创建时间
createTime: undefined,
// 更新时间
updateTime: undefined,
tenantId: undefined,
// 租户名称
tenantName: undefined,
// 租户logo
logo: undefined,
// 详情页路径
detail: undefined
});
// 请求数据
const reload = async () => {
await getCmsArticle(paramsId()).then(data => {
assignFields(data);
layout.value.banner = data?.banner;
if (data.files) {
form.files = JSON.parse(data.files);
}
// 二级栏目分类
listCmsNavigation({
parentId: data.parentId
}).then(list => {
category.value = list
})
// seo
useSeoMeta({
description: form.comments || form.title,
keywords: form.title,
titleTemplate: `${form?.title}` + ' - %s',
})
}).catch(err => {
console.log(err,'err')
})
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>
<style lang="scss">
.content {
padding-top: 15px;
overflow: hidden;
}
.content p{
}
.content img{
padding: 10px;
max-width: 100%;
height: auto;
}
.content video {
width: 100%;
height: auto;
}
</style>

135
pages/m/tags/[id].vue Normal file
View File

@@ -0,0 +1,135 @@
<template>
<Banner :layout="layout" />
<!-- 主体部分 -->
<div class="p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ $t('label') }}{{ where.tags }}
</h2>
</div>
<el-alert v-if="where.keywords" :title="`${$t('search.results')}${$t('search.find')} ${total} ${$t('search.nums')}`" type="warning" :closable="false" />
<div class="content">
<ul class="news_listn clearfix">
<template v-for="(item,index) in list" key="index">
<li class="clearfix">
<div class="">
<h3 class="text-lg"><a :href="mDetail(item)" :title="item.title" v-html="replaceKeywords(item.title)"></a></h3>
<div v-html="replaceKeywords(item.comments)" class="line-clamp-2 text-gray-400"></div>
<div class="date text-gray-400">{{ $t('createTime') }}{{ dayjs(item.createTime).format('YYYY-MM-DD') }}</div>
</div>
</li>
</template>
<div class="clearboth"></div>
</ul>
<Pagination :total="total" @done="search" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Banner from "@/components/Banner.vue";
import {useLayout, usePage} from "~/composables/configState";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
import dayjs from "dayjs";
import {getPath} from "~/utils/common";
import {listCmsNavigation} from "~/api/cms/cmsNavigation";
import {pageCmsArticle} from "~/api/cms/cmsArticle";
import {listCmsModel} from "~/api/cms/cmsModel";
const route = useRoute();
// 页面信息
const list = ref<CmsArticle[]>([]);
const i18n = useI18n();
const category = ref<CmsNavigation[]>([]);
const total = ref(0);
// 获取状态
const page = usePage();
const layout = useLayout();
// 搜索表单
const where = reactive<CmsArticleParam>({
tags: '',
page: 1,
limit: 10,
status: 0,
parentId: undefined,
categoryId: undefined,
lang: i18n.locale.value
});
const replaceKeywords = (text: any) => {
return text.replace(`${where.keywords}`,'<font color=#ff0000>' + where.keywords + '</font>');
}
// 加载页面数据
const reload = async () => {
listCmsModel({
model: getPath(2)
}).then(response => {
const data = response[0];
if(data){
// 获取栏目信息
page.value = data
layout.value.banner = data.banner
// 设置页面标题
useSeoMeta({
description: data?.comments || `${route.params.id}`,
keywords: `${route.params.id}`,
titleTemplate: `【搜索结果】${route.params.id}` + ' - %s',
})
// 二级栏目分类
listCmsNavigation({
parentId: i18n.locale.value == 'en' ? 1073 : 998,
}).then(categoryData => {
category.value = categoryData;
// 加载文章列表
if(!getPath(1)){
return ElMessage.error('请输入搜索关键词!');
}
where.tags = `${route.params.id}`;
pageCmsArticle(where).then(response => {
if(response){
total.value = response?.count;
list.value = response?.list;
}
})
})
}
}).catch(err => {
console.log(err,'加载失败...')
})
}
/**
* 搜索
* @param data
*/
const search = (data: CmsArticleParam) => {
where.page = data.page;
reload();
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>
<style scoped lang="less">
.sitemp h2{
width: 500px !important;
}
</style>

110
pages/m/video/[id].vue Normal file
View File

@@ -0,0 +1,110 @@
<template>
<Banner :layout="layout" />
<!-- 主体部分 -->
<div class="p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ page.title }}
</h2>
</div>
<div class="content">
<!-- 产品列表 -->
<MCmsProductList :data="list" />
<Pagination :total="total" @done="search" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Banner from "@/components/Banner.vue";
import {useLayout, usePage} from "~/composables/configState";
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import type {CmsArticle, CmsArticleParam} from "~/api/cms/cmsArticle/model";
import {paramsId} from "~/utils/common";
import {getCmsNavigation, listCmsNavigation} from "~/api/cms/cmsNavigation";
import {pageCmsArticle} from "~/api/cms/cmsArticle";
import MCmsProductList from "~/components/MCmsProductList.vue";
const route = useRoute();
// 页面信息
const list = ref<CmsArticle[]>([]);
const i18n = useI18n();
const category = ref<CmsNavigation[]>([]);
const total = ref(0);
// 获取状态
const page = usePage();
const layout = useLayout();
// 搜索表单
const where = reactive<CmsArticleParam>({
keywords: '',
page: 1,
limit: 20,
status: 0,
parentId: undefined,
categoryId: undefined,
lang: i18n.locale.value
});
const reload = async () => {
getCmsNavigation(paramsId()).then(data => {
// 获取栏目信息
page.value = data
layout.value.banner = data.banner;
// 设置页面标题
useSeoMeta({
description: data.comments || data.title,
keywords: data.title,
titleTemplate: `${data?.title}` + ' - %s',
})
// 二级栏目分类
listCmsNavigation({
parentId: data.parentId == 0 ? data.navigationId : data.parentId
}).then(categoryData => {
category.value = categoryData;
// 加载文章列表
if(data.parentId == 0 && category.value.length > 0){
where.parentId = data.navigationId;
}else {
where.categoryId = data.navigationId;
}
pageCmsArticle(where).then(response => {
if(response){
total.value = response?.count;
list.value = response?.list;
}
})
})
}).catch(err => {
console.log(err,'加载失败...')
})
}
/**
* 搜索
* @param data
*/
const search = (data: CmsArticleParam) => {
where.page = data.page;
reload();
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>

View File

@@ -0,0 +1,183 @@
<!-- 文章详情 -->
<template>
<Banner :layout="layout"/>
<!-- 主体部分 -->
<div class="p-5">
<div class="m-page">
<div class="sitemp h-[32px] flex justify-between">
<h2>
{{ form.categoryName || '分类名称' }}
</h2>
</div>
<div class="detail-container">
<!-- 产品详细 -->
<div class="product_detail" id="pd1">
<div class="allcontent clearfix">
<div class="text-center text-xl text-gray-800 py-5">{{ form.title }}</div>
<el-carousel v-if="form.files" :interval="4000" height="400px">
<el-carousel-item v-for="item in form.files" :key="item" style="display: flex; align-items: center; justify-content: center">
<el-image :src="item" />
</el-carousel-item>
</el-carousel>
</div>
<div class="clearboth"></div>
<div class="p_detail">
<ul id="product-tab" class="product-tab clearfix">
<li class="cur">{{ $t('show.detail') }}</li>
</ul>
<!-- 内容组件 -->
<MContent class="text-sm" :data="form.content" />
</div>
<h3 class="tag">{{ $t('articleUrl') }}{{ locationUrl() }} </h3>
<Tags :data="form.tags" />
<NextArticle />
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type {CmsNavigation} from "~/api/cms/cmsNavigation/model";
import {locationUrl, paramsId} from "~/utils/common";
import type {CmsArticle} from "~/api/cms/cmsArticle/model";
import useFormData from "~/utils/use-form-data";
import Banner from "@/components/Banner.vue";
import type {Layout} from "~/api/layout/model";
import {getCmsArticle} from "~/api/cms/cmsArticle";
import {listCmsNavigation} from "~/api/cms/cmsNavigation";
import Tags from "~/components/Tags.vue";
import MContent from "~/components/MContent.vue";
// 引入状态管理
const route = useRoute();
const i18n = useI18n();
const layout = ref<Layout>({});
const category = ref<CmsNavigation[]>([]);
const parentName = ref('项目展示');
// 配置信息
const {form, assignFields} = useFormData<CmsArticle>({
// 文章id
articleId: undefined,
// 文章模型
model: undefined,
// 文章标题
title: undefined,
// 分类类型
type: undefined,
tags: undefined,
// 展现方式
showType: undefined,
// 文章类型
categoryId: undefined,
// 文章分类
categoryName: undefined,
parentId: undefined,
// 封面图
image: undefined,
// 附件
files: undefined,
// 缩列图
thumbnail: undefined,
// 视频地址
video: undefined,
// 上传的文件类型
accept: undefined,
// 来源
source: undefined,
// 文章内容
content: undefined,
// 虚拟阅读量
virtualViews: undefined,
// 实际阅读量
actualViews: undefined,
// 访问权限
permission: undefined,
// 访问密码
password: undefined,
password2: undefined,
// 用户ID
userId: undefined,
// 用户昵称
nickname: undefined,
// 账号
username: undefined,
// 用户头像
// userAvatar: undefined,
author: undefined,
// 所属门店ID
shopId: undefined,
//
likes: undefined,
// 排序
sortNumber: undefined,
// 备注
comments: undefined,
// 状态
status: undefined,
// 创建时间
createTime: undefined,
// 更新时间
updateTime: undefined,
tenantId: undefined,
// 租户名称
tenantName: undefined,
// 租户logo
logo: undefined,
// 详情页路径
detail: undefined
});
// 请求数据
const reload = async () => {
await getCmsArticle(paramsId()).then(data => {
assignFields(data);
layout.value.banner = data?.banner;
if (data.files) {
form.files = JSON.parse(data.files);
}
// 二级栏目分类
listCmsNavigation({
parentId: data.parentId,
lang: i18n.locale.value
}).then(list => {
category.value = list
// 宣传视频
if(data.categoryName == '宣传视频'){
parentName.value = '宣传视频'
category.value = [];
}
})
// seo
useSeoMeta({
description: form.comments || form.title,
keywords: form.title,
titleTemplate: `${form?.title}` + ' - %s',
})
}).catch(err => {
console.log(err,'err')
})
}
watch(
() => route.path,
() => {
reload();
},
{immediate: true}
);
</script>
<style lang="scss">
</style>