|
|
|
@ -24,15 +24,8 @@ |
|
|
|
<!-- 上方:课程页面列表(横向滑动) --> |
|
|
|
<div class="page-list-container"> |
|
|
|
<div class="page-list-scroll"> |
|
|
|
<draggable |
|
|
|
v-model="pageList" |
|
|
|
class="page-list" |
|
|
|
item-key="id" |
|
|
|
handle=".drag-handle" |
|
|
|
:animation="200" |
|
|
|
@start="onPageDragStart" |
|
|
|
@end="onPageDragEnd" |
|
|
|
> |
|
|
|
<draggable v-model="pageList" class="page-list" item-key="id" handle=".drag-handle" :animation="200" |
|
|
|
@start="onPageDragStart" @end="onPageDragEnd"> |
|
|
|
<template #item="{ element: page, index }"> |
|
|
|
<div :class="['page-item', { active: currentPageId === page.id }]" @click="selectPage(page)"> |
|
|
|
<!-- 拖拽手柄 --> |
|
|
|
@ -73,7 +66,7 @@ |
|
|
|
<a-form :model="currentPage" layout="vertical" class="page-form"> |
|
|
|
<!-- 内容编辑组件 --> |
|
|
|
<ContentEditor v-model:components="contentComponents" /> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 重点单词表格组件 --> |
|
|
|
<WordTable :course-page-id="currentPage.id" ref="wordTableRef" /> |
|
|
|
</a-form> |
|
|
|
@ -97,11 +90,7 @@ |
|
|
|
</a-form-item> |
|
|
|
<a-form-item label="页面类型" name="type"> |
|
|
|
<a-select v-model:value="currentPage.type" placeholder="选择类型"> |
|
|
|
<a-select-option |
|
|
|
v-for="option in pageTypeOptions" |
|
|
|
:key="option.value" |
|
|
|
:value="option.value" |
|
|
|
> |
|
|
|
<a-select-option v-for="option in pageTypeOptions" :key="option.value" :value="option.value"> |
|
|
|
{{ option.label }} |
|
|
|
</a-select-option> |
|
|
|
</a-select> |
|
|
|
@ -117,10 +106,7 @@ |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 右侧:手机预览区域 --> |
|
|
|
<MobilePreview |
|
|
|
:content-components="contentComponents" |
|
|
|
@refresh="refreshPreview" |
|
|
|
/> |
|
|
|
<MobilePreview :content-components="contentComponents" @refresh="refreshPreview" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
@ -241,7 +227,7 @@ async function loadPageList() { |
|
|
|
const result = await list(params); |
|
|
|
const records = result.records || []; |
|
|
|
pageList.value = records; |
|
|
|
|
|
|
|
|
|
|
|
// 如果没有页面,自动创建一个 |
|
|
|
if (pageList.value.length === 0) { |
|
|
|
await handleAddPage(); |
|
|
|
@ -256,7 +242,7 @@ async function loadPageList() { |
|
|
|
*/ |
|
|
|
function selectPage(page: any) { |
|
|
|
currentPageId.value = page.id; |
|
|
|
|
|
|
|
|
|
|
|
// 加载页面数据 |
|
|
|
loadPageData(page.id); |
|
|
|
} |
|
|
|
@ -268,12 +254,32 @@ async function loadPageData(id: string) { |
|
|
|
if (!id) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
const result = await getById({ id }); |
|
|
|
Object.assign(currentPage, result); |
|
|
|
|
|
|
|
// 保存原始内容用于比较 |
|
|
|
const originalContent = result.content; |
|
|
|
|
|
|
|
// 解析content字段为组件列表 |
|
|
|
parseContentToComponents(result.content); |
|
|
|
|
|
|
|
// 检查解析后的内容是否有变化(添加了style等默认值) |
|
|
|
const updatedContent = componentsToContent(); |
|
|
|
|
|
|
|
// 如果内容有变化,自动保存到数据库 |
|
|
|
if (originalContent !== updatedContent) { |
|
|
|
try { |
|
|
|
await edit({ |
|
|
|
id: currentPage.id, |
|
|
|
content: updatedContent |
|
|
|
}); |
|
|
|
console.log('自动保存了组件样式初始化数据'); |
|
|
|
} catch (error) { |
|
|
|
console.error('自动保存组件样式失败:', error); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
createMessage.error('加载页面数据失败'); |
|
|
|
} |
|
|
|
@ -289,19 +295,69 @@ function parseContentToComponents(content: string) { |
|
|
|
try { |
|
|
|
const parsed = JSON.parse(content); |
|
|
|
if (Array.isArray(parsed)) { |
|
|
|
// 确保每个文本组件都有language字段 |
|
|
|
// 确保每个组件都有必要的字段 |
|
|
|
contentComponents.value = parsed.map(component => { |
|
|
|
if (component.type === 'text' && !component.language) { |
|
|
|
return { ...component, language: 'zh' }; // 默认中文 |
|
|
|
const updatedComponent = { ...component }; |
|
|
|
|
|
|
|
if (component.type == 'text') { |
|
|
|
|
|
|
|
if (!updatedComponent.language) { |
|
|
|
updatedComponent.language = 'zh'; // 默认中文 |
|
|
|
} |
|
|
|
|
|
|
|
// 确保组件有style对象 |
|
|
|
if (!updatedComponent.style) { |
|
|
|
updatedComponent.style = {}; |
|
|
|
} |
|
|
|
|
|
|
|
// 确保style对象有字体大小,如果没有则初始化为40rpx |
|
|
|
if (!updatedComponent.style.fontSize) { |
|
|
|
updatedComponent.style.fontSize = '40rpx'; |
|
|
|
} else { |
|
|
|
// 检查并修正fontSize单位,清理异常单位 |
|
|
|
let fontSize = updatedComponent.style.fontSize; |
|
|
|
if (typeof fontSize === 'string') { |
|
|
|
// 清理异常的rpx单位(如:rrpx, rrrpx, 40rrrrrrpx等) |
|
|
|
fontSize = fontSize.replace(/r+px$/i, 'rpx'); |
|
|
|
|
|
|
|
// 提取数字部分,确保格式正确 |
|
|
|
const numMatch = fontSize.match(/(\d+)/); |
|
|
|
if (numMatch) { |
|
|
|
const num = numMatch[1]; |
|
|
|
// 统一设置为正确的rpx格式 |
|
|
|
updatedComponent.style.fontSize = `${num}rpx`; |
|
|
|
} else { |
|
|
|
// 如果无法提取数字,使用默认值 |
|
|
|
updatedComponent.style.fontSize = '40rpx'; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 确保style对象有字体颜色,如果没有则初始化为#333 |
|
|
|
if (!updatedComponent.style.color) { |
|
|
|
updatedComponent.style.color = '#333'; |
|
|
|
} |
|
|
|
|
|
|
|
// 确保style对象有字体样式,如果没有则初始化为宋体 |
|
|
|
if (!updatedComponent.style.fontFamily) { |
|
|
|
updatedComponent.style.fontFamily = 'SimSun'; |
|
|
|
} |
|
|
|
} |
|
|
|
return component; |
|
|
|
|
|
|
|
return updatedComponent; |
|
|
|
}); |
|
|
|
console.log('解析后的组件列表:', contentComponents.value); |
|
|
|
} else { |
|
|
|
// 如果是字符串,创建一个文本组件 |
|
|
|
contentComponents.value = [{ |
|
|
|
type: 'text', |
|
|
|
content: content, |
|
|
|
language: 'zh' // 默认中文 |
|
|
|
language: 'zh', // 默认中文 |
|
|
|
style: { |
|
|
|
fontSize: '40rpx', // 默认字体大小 |
|
|
|
color: '#333', // 默认字体颜色 |
|
|
|
fontFamily: '宋体' // 默认字体样式 |
|
|
|
} |
|
|
|
}]; |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
@ -309,7 +365,12 @@ function parseContentToComponents(content: string) { |
|
|
|
contentComponents.value = [{ |
|
|
|
type: 'text', |
|
|
|
content: content, |
|
|
|
language: 'zh' // 默认中文 |
|
|
|
language: 'zh', // 默认中文 |
|
|
|
style: { |
|
|
|
fontSize: '40rpx', // 默认字体大小 |
|
|
|
color: '#333', // 默认字体颜色 |
|
|
|
fontFamily: '宋体' // 默认字体样式 |
|
|
|
} |
|
|
|
}]; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -348,18 +409,18 @@ async function handleAddPage() { |
|
|
|
if (result.id) { |
|
|
|
// 设置新页面的ID |
|
|
|
newPage.id = result.id; |
|
|
|
|
|
|
|
|
|
|
|
// 将新页面添加到页面列表中 |
|
|
|
pageList.value.push(newPage); |
|
|
|
|
|
|
|
|
|
|
|
// 重新设置所有页面的排序值 |
|
|
|
updatePageSortOrder(); |
|
|
|
|
|
|
|
|
|
|
|
// 设置为当前编辑页面 |
|
|
|
Object.assign(currentPage, newPage); |
|
|
|
contentComponents.value = []; |
|
|
|
currentPageId.value = newPage.id; |
|
|
|
|
|
|
|
|
|
|
|
createMessage.success('新增页面成功'); |
|
|
|
} else { |
|
|
|
createMessage.error(result.message || '新增页面失败'); |
|
|
|
@ -472,7 +533,7 @@ async function savePageOrder() { |
|
|
|
return edit({ id: page.id, sort: page.sort }); |
|
|
|
} |
|
|
|
}).filter(Boolean); |
|
|
|
|
|
|
|
|
|
|
|
await Promise.all(updatePromises); |
|
|
|
} catch (error) { |
|
|
|
console.error('保存页面排序失败:', error); |
|
|
|
@ -506,10 +567,10 @@ async function handleSave() { |
|
|
|
const result = await edit(pageData); |
|
|
|
if (result) { |
|
|
|
// createMessage.success('保存成功'); |
|
|
|
|
|
|
|
|
|
|
|
// 重新加载页面列表以确保数据同步 |
|
|
|
await loadPageList(); |
|
|
|
|
|
|
|
|
|
|
|
// 保持当前页面选中状态 |
|
|
|
if (currentPageId.value) { |
|
|
|
const currentPageInList = pageList.value.find(p => p.id === currentPageId.value); |
|
|
|
|