|
|
@@ -6,8 +6,8 @@
|
|
|
<div v-else-if="error" class="error-message">{{ error }}</div>
|
|
|
<!-- 正常展示内容 -->
|
|
|
<div v-else class="content-wrapper">
|
|
|
- <h1 class="title">{{ softwareIntro.title }}</h1>
|
|
|
- <div v-for="(paragraph, index) in softwareIntro.introParagraphs" :key="index" class="paragraph">
|
|
|
+ <h1 class="title">{{ currentTitle }}</h1>
|
|
|
+ <div v-for="(paragraph, index) in currentIntroParagraphs" :key="index" class="paragraph">
|
|
|
<p v-html="paragraph"></p>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -15,8 +15,11 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, onMounted } from 'vue';
|
|
|
-import { api5000 } from '@/utils/request'; // 导入封装的api5000
|
|
|
+import { ref, onMounted, onUnmounted, computed } from 'vue';
|
|
|
+import { api5000 } from '@/utils/request';
|
|
|
+import { useI18n } from 'vue-i18n';
|
|
|
+
|
|
|
+const { locale } = useI18n();
|
|
|
|
|
|
// 定义 targetId 为 prop
|
|
|
const props = defineProps({
|
|
|
@@ -26,36 +29,94 @@ const props = defineProps({
|
|
|
}
|
|
|
});
|
|
|
|
|
|
-// 存储介绍内容
|
|
|
+// 存储介绍内容(支持中英文)
|
|
|
const softwareIntro = ref({
|
|
|
title: '',
|
|
|
- introParagraphs: []
|
|
|
+ title_en: '',
|
|
|
+ intro: '',
|
|
|
+ intro_en: ''
|
|
|
+});
|
|
|
+
|
|
|
+// 当前语言状态(与全局同步)
|
|
|
+const language = ref(locale.value || localStorage.getItem('language') || 'zh');
|
|
|
+
|
|
|
+// 当前显示的标题
|
|
|
+const currentTitle = computed(() => {
|
|
|
+ return language.value === 'zh' ? softwareIntro.value.title : softwareIntro.value.title_en;
|
|
|
+});
|
|
|
+
|
|
|
+// 当前显示的段落内容
|
|
|
+const currentIntroParagraphs = computed(() => {
|
|
|
+ const intro = language.value === 'zh' ? softwareIntro.value.intro : softwareIntro.value.intro_en;
|
|
|
+ return intro
|
|
|
+ .replace(/<p>/g, '')
|
|
|
+ .replace(/<\/p>/g, '\r\n')
|
|
|
+ .replace(/<br>/g, '')
|
|
|
+ .split('\r\n')
|
|
|
+ .filter((p: string) => p.trim() !== '');
|
|
|
});
|
|
|
+
|
|
|
// 加载状态
|
|
|
const isLoading = ref(true);
|
|
|
// 错误信息
|
|
|
const error = ref('');
|
|
|
|
|
|
-// 判断是否为标题段落
|
|
|
-
|
|
|
-// 处理段落,将图片路径转换为 标签
|
|
|
-
|
|
|
-onMounted(async () => {
|
|
|
+// 获取数据
|
|
|
+const fetchSoftwareIntro = async () => {
|
|
|
try {
|
|
|
- // 使用 api5000 调用接口
|
|
|
const response = await api5000.get(`/admin/software-intro/${props.targetId}`);
|
|
|
- const { title, intro } = response.data;
|
|
|
- // 保留 \r\n 换行符
|
|
|
- const processedIntro = intro.replace(/<p>/g, '').replace(/<\/p>/g, '\r\n').replace(/<br>/g, '');
|
|
|
- softwareIntro.value.introParagraphs = processedIntro.split('\r\n').filter((paragraph: string) => paragraph.trim()!== '');
|
|
|
- softwareIntro.value.title = title;
|
|
|
+ const { title, title_en, intro, intro_en } = response.data;
|
|
|
+
|
|
|
+ // 设置多语言内容
|
|
|
+ softwareIntro.value.title = title || '';
|
|
|
+ softwareIntro.value.title_en = title_en || '';
|
|
|
+ softwareIntro.value.intro = intro || '';
|
|
|
+ softwareIntro.value.intro_en = intro_en || '';
|
|
|
} catch (err: any) {
|
|
|
error.value = err.message || '请求数据时发生错误';
|
|
|
} finally {
|
|
|
isLoading.value = false;
|
|
|
}
|
|
|
+};
|
|
|
+
|
|
|
+// 监听全局语言变化事件
|
|
|
+const handleLanguageChange = (event: Event) => {
|
|
|
+ const newLang = (event as CustomEvent<{ lang: string }>).detail.lang;
|
|
|
+ language.value = newLang;
|
|
|
+ // 重新获取数据以刷新内容
|
|
|
+ fetchSoftwareIntro();
|
|
|
+};
|
|
|
+
|
|
|
+// 页面挂载后初始化
|
|
|
+onMounted(async () => {
|
|
|
+ await fetchSoftwareIntro();
|
|
|
+
|
|
|
+ // 添加全局事件监听器
|
|
|
+ window.addEventListener('languageChanged', handleLanguageChange);
|
|
|
+});
|
|
|
+
|
|
|
+// 卸载时移除监听器
|
|
|
+onUnmounted(() => {
|
|
|
+ window.removeEventListener('languageChanged', handleLanguageChange);
|
|
|
+});
|
|
|
+
|
|
|
+// 封装设置视频样式的函数(保持原逻辑)
|
|
|
+const setVideoStyle = (video: HTMLVideoElement) => {
|
|
|
+ const containerWidth = (document.querySelector('.software-intro-container') as HTMLElement).offsetWidth;
|
|
|
+ const maxWidth = containerWidth * 0.8;
|
|
|
+ if (video.videoWidth > maxWidth) {
|
|
|
+ video.style.width = `${maxWidth}px`;
|
|
|
+ video.style.height = 'auto';
|
|
|
+ } else {
|
|
|
+ video.style.width = 'auto';
|
|
|
+ video.style.height = 'auto';
|
|
|
+ }
|
|
|
+ video.style.maxWidth = '80%';
|
|
|
+ video.style.objectFit = 'contain';
|
|
|
+};
|
|
|
|
|
|
- // 页面加载完成后,监听视频播放事件
|
|
|
+// 页面加载完成后,监听视频播放事件
|
|
|
+onMounted(() => {
|
|
|
const container = document.querySelector('.software-intro-container');
|
|
|
if (container) {
|
|
|
container.addEventListener('play', (event) => {
|
|
|
@@ -65,7 +126,6 @@ onMounted(async () => {
|
|
|
}
|
|
|
}, true);
|
|
|
|
|
|
- // 监听窗口大小变化事件,确保视频在窗口大小改变时也能适应
|
|
|
window.addEventListener('resize', () => {
|
|
|
const videos = container.querySelectorAll('video');
|
|
|
videos.forEach((video) => {
|
|
|
@@ -76,35 +136,20 @@ onMounted(async () => {
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
-
|
|
|
-// 封装设置视频样式的函数
|
|
|
-const setVideoStyle = (video: HTMLVideoElement) => {
|
|
|
- const containerWidth = (document.querySelector('.software-intro-container') as HTMLElement).offsetWidth;
|
|
|
- const maxWidth = containerWidth * 0.8; // 最大宽度为容器宽度的 80%
|
|
|
- if (video.videoWidth > maxWidth) {
|
|
|
- video.style.width = `${maxWidth}px`;
|
|
|
- video.style.height = 'auto';
|
|
|
- } else {
|
|
|
- video.style.width = 'auto';
|
|
|
- video.style.height = 'auto';
|
|
|
- }
|
|
|
- video.style.maxWidth = '80%';
|
|
|
- video.style.objectFit = 'contain';
|
|
|
-};
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
.software-intro-container {
|
|
|
width: 95%;
|
|
|
- margin: 0 auto;
|
|
|
+ margin: 0 auto;
|
|
|
padding: 20px;
|
|
|
- background-color: #fff;
|
|
|
- border-radius: 8px; /* 圆角 */
|
|
|
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影 */
|
|
|
- height: 80vh; /* 设置容器高度为视口高度的 80% */
|
|
|
- overflow-y: auto; /* 当内容超出容器高度时,显示垂直滚动条 */
|
|
|
- scrollbar-width: none; /* Firefox */
|
|
|
- -ms-overflow-style: none; /* Internet Explorer 10+ */
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
|
+ height: 80vh;
|
|
|
+ overflow-y: auto;
|
|
|
+ scrollbar-width: none;
|
|
|
+ -ms-overflow-style: none;
|
|
|
}
|
|
|
|
|
|
.loading-message {
|
|
|
@@ -117,7 +162,7 @@ const setVideoStyle = (video: HTMLVideoElement) => {
|
|
|
.error-message {
|
|
|
text-align: center;
|
|
|
font-size: 18px;
|
|
|
- color: #ff0000; /* 红色错误信息 */
|
|
|
+ color: #ff0000;
|
|
|
padding: 20px;
|
|
|
}
|
|
|
|
|
|
@@ -125,7 +170,7 @@ const setVideoStyle = (video: HTMLVideoElement) => {
|
|
|
font-size: 36px;
|
|
|
text-align: center;
|
|
|
margin-bottom: 20px;
|
|
|
- color: #333; /* 深灰色标题 */
|
|
|
+ color: #333;
|
|
|
}
|
|
|
|
|
|
.paragraph {
|
|
|
@@ -134,19 +179,18 @@ const setVideoStyle = (video: HTMLVideoElement) => {
|
|
|
|
|
|
p {
|
|
|
font-size: 16px;
|
|
|
- line-height: 1.8; /* 增大行高 */
|
|
|
- color: #666; /* 灰色文字 */
|
|
|
+ line-height: 1.8;
|
|
|
+ color: #666;
|
|
|
}
|
|
|
|
|
|
.intro-image {
|
|
|
max-width: 100%;
|
|
|
height: auto;
|
|
|
- border-radius: 4px; /* 图片圆角 */
|
|
|
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 图片阴影 */
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
margin-bottom: 10px;
|
|
|
}
|
|
|
|
|
|
-/* 控制视频尺寸 */
|
|
|
video {
|
|
|
width: 80%;
|
|
|
max-width: 80%;
|
|
|
@@ -154,11 +198,10 @@ video {
|
|
|
object-fit: contain;
|
|
|
}
|
|
|
|
|
|
-/* 响应式设计 */
|
|
|
@media (max-width: 768px) {
|
|
|
.software-intro-container {
|
|
|
padding: 15px;
|
|
|
- height: 90vh; /* 在小屏幕上,调整容器高度为视口高度的 90% */
|
|
|
+ height: 90vh;
|
|
|
}
|
|
|
|
|
|
.title {
|