V1.2.0需求完成测试版
This commit is contained in:
40
mining-pool/src/assets/styles/wangEditorv4.scss
Normal file
40
mining-pool/src/assets/styles/wangEditorv4.scss
Normal file
@@ -0,0 +1,40 @@
|
||||
.dynamic-content {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: #222;
|
||||
// 富文本样式
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
:deep(th), :deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #f3f4f6;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong), :deep(b) {
|
||||
font-weight: bold !important;
|
||||
color: inherit !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
:deep(em), :deep(i) {
|
||||
font-style: italic !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #661FFB !important;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,7 +297,7 @@ export default {
|
||||
// 使用 name 进行导航,避免重复的路由参数
|
||||
this.$router.push({
|
||||
path:url,
|
||||
params: {
|
||||
query: {
|
||||
lang: lang,
|
||||
coin: this.activeItemCoin.value,
|
||||
imgUrl: this.activeItemCoin.imgUrl
|
||||
|
||||
@@ -108,6 +108,47 @@ export const backendSystem_zh = {
|
||||
commonProblems:"常见问题",
|
||||
other:"其他",
|
||||
announcementCenter:"公告中心",
|
||||
search:"搜索",
|
||||
recommendContent:"推荐内容",
|
||||
recentActivities:"最近活动",
|
||||
viewMore:"查看更多活动公告",
|
||||
documentType:"文档类型",
|
||||
documentTitle:"文档标题",
|
||||
wangeditor:"wangeditor 富文本文档编辑器",
|
||||
insertAnchor:"插入锚点",
|
||||
previewDocument:"预览文档",
|
||||
saveDocument:"保存文档",
|
||||
publishDocument:"发布文档",
|
||||
reset:"重置",
|
||||
documentConfiguration:"文档配置",
|
||||
navigationTitle:"导航标题",
|
||||
pleaseInputDocumentTitle:"请输入文档标题",
|
||||
pleaseSelectDocumentType:"请选择文档类型",
|
||||
titleImageAddress:"标题图片地址",
|
||||
pleaseInputImageAddress:"请输入图片地址",
|
||||
articleAccessAddress:"文章访问地址",
|
||||
pleaseInputAccessAddress:"请输入访问地址",
|
||||
richTextEditor:"富文本编辑器",
|
||||
documentPreview:"文档预览",
|
||||
printPreview:"打印预览",
|
||||
close:"关闭",
|
||||
noContent:"暂无内容",
|
||||
modifyDocument:"修改文档",
|
||||
contentSaved:"内容已保存到本地,请尽快发布,关闭页面可能丢失内容",
|
||||
|
||||
pleaseInputAnchorName:"请输入锚点名称(不能重复)",
|
||||
anchorNameErrorMessage:"锚点名只能包含字母、数字、下划线和中划线",
|
||||
anchorInserted:"锚点已插入",
|
||||
confirm:"确定",
|
||||
pleaseSelectHeader:"请先选中一个标题(h1~h6)",
|
||||
pleaseInputAnchorID:"请输入锚点ID(不能重复)",
|
||||
titleAnchor:"标题锚点",
|
||||
anchorIDErrorMessage:"ID只能包含字母、数字、下划线和中划线",
|
||||
anchorIDAdded:"锚点ID已添加",
|
||||
contentReset:"内容已重置",
|
||||
selectCurrency:"选择币种",
|
||||
pleaseSelectCurrency2:"添加挖矿教程,请选择币种",
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +263,46 @@ export const backendSystem_en = {
|
||||
commonProblems:"Common Problems",
|
||||
other:"Other",
|
||||
announcementCenter:"Announcement Center",
|
||||
|
||||
search:"Search",
|
||||
recommendContent:"Recommend Content",
|
||||
recentActivities:"Recent Activities",
|
||||
viewMore:"View More Activity Announcements",
|
||||
documentType:"Document Type",
|
||||
documentTitle:"Document Title",
|
||||
wangeditor:"wangeditor Rich Text Editor",
|
||||
insertAnchor:"Insert Anchor",
|
||||
previewDocument:"Preview Document",
|
||||
saveDocument:"Save Document",
|
||||
publishDocument:"Publish Document",
|
||||
reset:"Reset",
|
||||
documentConfiguration:"Document Configuration",
|
||||
navigationTitle:"Navigation Title",
|
||||
pleaseInputDocumentTitle:"Please input document title",
|
||||
pleaseSelectDocumentType:"Please select document type",
|
||||
titleImageAddress:"Title Image Address",
|
||||
pleaseInputImageAddress:"Please input image address",
|
||||
articleAccessAddress:"Article Access Address",
|
||||
pleaseInputAccessAddress:"Please input access address",
|
||||
richTextEditor:"Rich Text Editor",
|
||||
documentPreview:"Document Preview",
|
||||
printPreview:"Print Preview",
|
||||
close:"Close",
|
||||
noContent:"No Content",
|
||||
modifyDocument:"Modify Document",
|
||||
contentSaved:"Content has been saved to local, please publish it as soon as possible, the content may be lost if the page is closed",
|
||||
|
||||
pleaseInputAnchorName:"Please input anchor name (cannot be repeated)",
|
||||
anchorNameErrorMessage:"Anchor name can only contain letters, numbers, underscores, and hyphens",
|
||||
anchorInserted:"Anchor inserted",
|
||||
confirm:"Confirm",
|
||||
pleaseSelectHeader:"Please select a title (h1~h6)",
|
||||
pleaseInputAnchorID:"Please input anchor ID (cannot be repeated)",
|
||||
titleAnchor:"Title Anchor",
|
||||
anchorIDErrorMessage:"ID can only contain letters, numbers, underscores, and hyphens",
|
||||
anchorIDAdded:"Anchor ID added",
|
||||
contentReset:"Content has been reset",
|
||||
selectCurrency:"Select Currency",
|
||||
pleaseSelectCurrency2:"Please select a currency when adding mining tutorials",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,8 +85,11 @@ export const home_zh = {
|
||||
noData:"暂无公告",
|
||||
viewAll:"查看所有",
|
||||
articles:"篇文章",
|
||||
|
||||
|
||||
allocationExplanation:"矿池分配及转账规则",
|
||||
loadingContent:"正在加载内容...",
|
||||
noContent:"暂无内容",
|
||||
unknownType:"未知类型",
|
||||
other:"其他",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +180,11 @@ export const home_en = {
|
||||
noData:"No data",
|
||||
viewAll:"View all",
|
||||
articles:" articles",
|
||||
allocationExplanation:"Pool allocation and transfer rules",
|
||||
loadingContent:"Loading content...",
|
||||
noContent:"No content",
|
||||
unknownType:"Unknown Type",
|
||||
other:"Other",
|
||||
|
||||
}
|
||||
}
|
||||
@@ -108,22 +108,7 @@ const childrenRoutes = [
|
||||
|
||||
}
|
||||
},
|
||||
{//编辑器测试markdown
|
||||
path: 'markdown',
|
||||
name: 'Markdown',
|
||||
component: () => import('../views/markdown.vue'),
|
||||
meta: {
|
||||
title: 'markdown编辑器测试',
|
||||
// description: i18n.t(`seo.helpCenter`),
|
||||
allAuthority: [`all`],
|
||||
// keywords: {
|
||||
// en: 'Help Center,Beginner Guide,Mining Data,Frequently Asked Questions,Announcement Center,Other',
|
||||
// zh: '帮助中心,新手入门,常见问题,公告中心'
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
{//广播页面
|
||||
path: 'broadcast',
|
||||
name: 'Broadcast',
|
||||
@@ -911,67 +896,7 @@ router.beforeEach((to, from, next) => {
|
||||
|
||||
|
||||
|
||||
// if (jurisdiction && jurisdiction.roleKey == `back_admin`) {
|
||||
// if (to.name == 'Login' || to.name == 'Register' || jurisdiction && jurisdiction.roleKey && to.meta.allAuthority.includes(jurisdiction.roleKey)) {
|
||||
// return next();
|
||||
// } else {
|
||||
// // 无权限
|
||||
// Message({
|
||||
// showClose: true,
|
||||
// message: `当前身份只能访问后台管理系统`,
|
||||
// type: 'error'
|
||||
// });
|
||||
// localStorage.setItem("activeIndex", `1`);
|
||||
// return next({ path: `/${lang}/broadcast` });
|
||||
|
||||
|
||||
// }
|
||||
// } else {
|
||||
// // 未登录
|
||||
// if (!token) {
|
||||
// console.log(`未登录`);
|
||||
// if (
|
||||
// to.meta.allAuthority &&
|
||||
// (
|
||||
// to.meta.allAuthority[0] === 'all' ||
|
||||
// (jurisdiction && jurisdiction.roleKey && to.meta.allAuthority.includes(jurisdiction.roleKey))
|
||||
// )
|
||||
// ) {
|
||||
// return next();
|
||||
// } else {
|
||||
|
||||
|
||||
// // 无权限
|
||||
// Message({
|
||||
// showClose: true,
|
||||
// message: i18n.t(`mining.jurisdiction`),
|
||||
// type: 'error'
|
||||
// });
|
||||
// return next({ path: `/${lang}/login` });
|
||||
// }
|
||||
|
||||
// } else {
|
||||
// if (to.name === 'Login' || to.name === 'Register') {
|
||||
// return next({ path: `/${lang}` });
|
||||
// } else if (to.meta.allAuthority &&
|
||||
// (
|
||||
// to.meta.allAuthority[0] === 'all' ||
|
||||
// (jurisdiction && jurisdiction.roleKey && to.meta.allAuthority.includes(jurisdiction.roleKey))
|
||||
// )
|
||||
// ) {
|
||||
// return next();
|
||||
// } else {
|
||||
// // 无权限
|
||||
// Message({
|
||||
// showClose: true,
|
||||
// message: i18n.t(`mining.jurisdiction`),
|
||||
// type: 'error'
|
||||
// });
|
||||
// return next({ path: `/${lang}/login` });
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// --------------------------
|
||||
// 未登录
|
||||
if (!token) {
|
||||
@@ -1000,9 +925,11 @@ if (!token) {
|
||||
|
||||
|
||||
if (jurisdiction && jurisdiction.roleKey == `back_admin`) {
|
||||
if (to.name == 'Login' || to.name == 'Register' || to.path == `/${lang}` || jurisdiction && jurisdiction.roleKey && to.meta.allAuthority.includes(jurisdiction.roleKey)) {
|
||||
if (to.name == 'Login' || to.name == 'Register' || jurisdiction && jurisdiction.roleKey && to.meta.allAuthority.includes(jurisdiction.roleKey)) {
|
||||
return next();
|
||||
} else {
|
||||
} else if(to.path == `/${lang}`) {
|
||||
return next({ path: `/${lang}/userManagement` });
|
||||
}else {
|
||||
// 无权限
|
||||
Message({
|
||||
showClose: true,
|
||||
@@ -1014,6 +941,7 @@ if (!token) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (to.name === 'Login' || to.name === 'Register') {
|
||||
|
||||
@@ -297,26 +297,28 @@ export default {
|
||||
// if (this.$route.name =="AccessMiningPool" ) {
|
||||
// this.$router.go(-1);
|
||||
// }
|
||||
|
||||
|
||||
this.fetchAllList(this.listParams)
|
||||
|
||||
if (this.$route.params.coin) {
|
||||
this.activeCoin = this.$route.params.coin
|
||||
console.log(this.$route, "this.$route.query.coin");
|
||||
|
||||
if (this.$route.query.coin) {
|
||||
this.activeCoin = this.$route.query.coin
|
||||
// this.currencyPath = this.$route.query.imgUrl
|
||||
this.imgUrl = this.$route.params.imgUrl
|
||||
this.currencyPath = this.$route.params.imgUrl
|
||||
this.params.coin = this.$route.params.coin
|
||||
this.imgUrl = this.$route.query.imgUrl
|
||||
this.currencyPath = this.$route.query.imgUrl
|
||||
this.params.coin = this.$route.query.coin
|
||||
this.$addStorageEvent(1, `activeCoin`, JSON.stringify(this.activeCoin))
|
||||
this.activeItem = this.currencyList.find(item => { return item.value == this.params.coin })
|
||||
const item = this.currencyList.find(item => { return item.value == this.params.coin })
|
||||
|
||||
if (item && item.path) {
|
||||
// this.clickJump(item)
|
||||
const mockEvent = {
|
||||
stopPropagation: () => {},
|
||||
currentTarget: document.getElementById('menu1')
|
||||
};
|
||||
this.changeMenuName(mockEvent, item)
|
||||
const item = this.navList.find(item => { return item.coin == this.params.coin })
|
||||
console.log(item, "item65656565",this.navList,this.$route.query.coin);
|
||||
|
||||
if (item && item.coin) {
|
||||
this.clickJump(item)
|
||||
// const mockEvent = {
|
||||
// stopPropagation: () => {},
|
||||
// currentTarget: document.getElementById('menu1')
|
||||
// };
|
||||
// this.changeMenuName(mockEvent, item)
|
||||
}
|
||||
|
||||
|
||||
@@ -358,25 +360,25 @@ export default {
|
||||
|
||||
}
|
||||
// 从本地存储获取activeItem
|
||||
const savedActiveItem = localStorage.getItem('activeItem');
|
||||
if (savedActiveItem) {
|
||||
try {
|
||||
this.activeItem = JSON.parse(savedActiveItem);
|
||||
} catch (error) {
|
||||
console.error('Parse activeItem failed:', error);
|
||||
// 使用默认值
|
||||
this.activeItem = this.currencyList[0];
|
||||
}
|
||||
} else {
|
||||
// 没有存储值时使用默认值
|
||||
this.activeItem = this.currencyList[0];
|
||||
}
|
||||
// const savedActiveItem = localStorage.getItem('activeItem');
|
||||
// if (savedActiveItem) {
|
||||
// try {
|
||||
// this.activeItem = JSON.parse(savedActiveItem);
|
||||
// } catch (error) {
|
||||
// console.error('Parse activeItem failed:', error);
|
||||
// // 使用默认值
|
||||
// this.activeItem = this.currencyList[0];
|
||||
// }
|
||||
// } else {
|
||||
// // 没有存储值时使用默认值
|
||||
// this.activeItem = this.currencyList[0];
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
this.fetchAllList(this.listParams)
|
||||
|
||||
|
||||
|
||||
},
|
||||
@@ -386,16 +388,28 @@ export default {
|
||||
const res = await documentsList(params)
|
||||
console.log(res,"res");
|
||||
|
||||
if (res.code === 200) {
|
||||
if (res && res.code === 200) {
|
||||
this.navList = res.rows
|
||||
|
||||
const item = this.navList.find(item => { return item.coin == this.params.coin })
|
||||
|
||||
if (this.$route.query.id) {
|
||||
|
||||
if (item && item.coin) {
|
||||
this.DetailsParams.id= item.id
|
||||
this.DetailsParams.coin = item.coin
|
||||
this.clickJump(item)
|
||||
|
||||
}else if (this.$route.query.id) {
|
||||
this.DetailsParams.id = this.$route.query.id
|
||||
|
||||
}else{
|
||||
this.DetailsParams.id = this.navList[0].id;
|
||||
this.DetailsParams.id = res.rows[0].id;
|
||||
}
|
||||
this.fetchProblemDetails(this.DetailsParams)
|
||||
|
||||
if (this.DetailsParams.id) {
|
||||
this.fetchProblemDetails(this.DetailsParams)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
@@ -465,6 +479,8 @@ export default {
|
||||
clickJump(item) {
|
||||
|
||||
this.DetailsParams.id = item.id
|
||||
this.DetailsParams.coin = item.coin
|
||||
this.activeCoin = item.coin
|
||||
this.fetchProblemDetails(this.DetailsParams)
|
||||
// if (!item.path) return; // 添加路径检查
|
||||
// this.activeCoin = item.value
|
||||
|
||||
@@ -50,10 +50,10 @@
|
||||
<section class="menu">
|
||||
|
||||
<ul>
|
||||
|
||||
{{ DetailsParams.coin }}
|
||||
<li
|
||||
|
||||
:class="{ active: DetailsParams.id == item.id }"
|
||||
:class="{ active: DetailsParams.coin == item.coin }"
|
||||
@click="clickJump(item)"
|
||||
v-for="item in navList"
|
||||
:key="item.id"
|
||||
@@ -61,6 +61,7 @@
|
||||
<img :src="item.titleUrl" alt="coin" />
|
||||
<span>
|
||||
{{ item.title }}
|
||||
{{ item.coin }}
|
||||
</span>
|
||||
</li>
|
||||
<!-- <li
|
||||
@@ -84,11 +85,11 @@
|
||||
|
||||
<section class="rightContent">
|
||||
<div v-if="tutorialLoading" class="loading-container">
|
||||
<span class="loading-text">正在加载内容...</span>
|
||||
<span class="loading-text">{{ $t('home.loadingContent') || '正在加载内容...' }}</span>
|
||||
</div>
|
||||
<div v-else-if="info && info.trim()" class="dynamic-content" v-html="info"></div>
|
||||
<div v-else class="no-content">
|
||||
<p>暂无内容</p>
|
||||
<p>{{ $t('home.noContent') || '暂无内容' }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -794,20 +795,25 @@ export default {
|
||||
.dynamic-content {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: #222;
|
||||
// 富文本样式
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(th), :deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #f3f4f6;
|
||||
background: #D2C3EA;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong), :deep(b) {
|
||||
@@ -820,13 +826,22 @@ export default {
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #007bff !important;
|
||||
color: #661FFB !important;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
}
|
||||
:deep(p) {
|
||||
text-align: justify !important;
|
||||
text-justify: inter-ideograph !important;
|
||||
text-indent: 2em !important;
|
||||
line-height: 2 !important;
|
||||
margin: 0.8em 0 !important;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
</section>
|
||||
<section class="rightContent">
|
||||
<div v-if="problemLoading" class="loading-container">
|
||||
<span class="loading-text">正在加载内容...</span>
|
||||
<span class="loading-text">{{ $t('home.loadingContent') || '正在加载内容...' }}</span>
|
||||
</div>
|
||||
<div v-else-if="info && info.trim()" class="dynamic-content" v-html="info"></div>
|
||||
<div v-else class="no-content">
|
||||
<p>暂无内容</p>
|
||||
<p>{{ $t('home.noContent') || '暂无内容' }}</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -7,8 +7,10 @@ export default {
|
||||
listParams: {
|
||||
lang: `${this.$i18n.locale}`,
|
||||
childType: 3,
|
||||
pageNum:1,
|
||||
pageSize:50
|
||||
},
|
||||
navContentParams: {
|
||||
DetailsParams: {
|
||||
lang: `${this.$i18n.locale}`,
|
||||
childType:3,//1服务条款、2费率、3API文档 childType
|
||||
},
|
||||
@@ -22,16 +24,30 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.getDocumentsList(this.listParams)
|
||||
this.fetchProblemDetails(this.navContentParams)
|
||||
|
||||
},
|
||||
methods: {
|
||||
async getDocumentsList(params) {
|
||||
try {
|
||||
const res = await documentsList(params)
|
||||
console.log(res,"res");
|
||||
if (res && res.code === 200) {
|
||||
this.navList = res.rows
|
||||
|
||||
this.navList = res.data
|
||||
console.log('文档列表:', res)
|
||||
if (this.$route.query.id) {
|
||||
this.DetailsParams.id = this.$route.query.id
|
||||
|
||||
}else{
|
||||
this.DetailsParams.id = res.rows[0].id;
|
||||
}
|
||||
if (this.DetailsParams.id) {
|
||||
this.fetchProblemDetails(this.DetailsParams)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取文档列表失败:', error)
|
||||
}
|
||||
@@ -158,6 +174,13 @@ export default {
|
||||
html += '</table>\n'
|
||||
return html
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
clickJump(item) {
|
||||
|
||||
this.DetailsParams.id = item.id
|
||||
this.fetchProblemDetails(this.DetailsParams)
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -937,9 +937,9 @@
|
||||
<section class="leftMenu">
|
||||
<ul>
|
||||
|
||||
<li>
|
||||
<li v-for="item in navList" :class="{navActive:String(item.id) === String(DetailsParams.id)}" :key="item.id" @click="clickJump(item)">
|
||||
<i class="iconfont icon-baogao file"></i
|
||||
>{{ $t(`apiFile.leftMenu`) }}
|
||||
>{{ item.title}}
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
@@ -948,11 +948,11 @@
|
||||
|
||||
<section class="rightContent">
|
||||
<div v-if="documentLoading" class="loading-container">
|
||||
<span class="loading-text">正在加载内容...</span>
|
||||
<span class="loading-text">{{ $t('home.loadingContent') || '正在加载内容...' }}</span>
|
||||
</div>
|
||||
<div v-else-if="info && info.trim()" class="dynamic-content" v-html="info"></div>
|
||||
<div v-else class="no-content">
|
||||
<p>暂无内容</p>
|
||||
<p>{{ $t('home.noContent') || '暂无内容' }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -2093,10 +2093,12 @@ a{
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
li {
|
||||
width: 100%;
|
||||
list-style: none;
|
||||
min-height: 40px;
|
||||
display: flex;
|
||||
@@ -2460,20 +2462,49 @@ a{
|
||||
.dynamic-content {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: #222;
|
||||
|
||||
// 富文本样式
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
:deep(ul) {
|
||||
background: #f4f4f4;
|
||||
padding: 10px;
|
||||
padding-left: 18px;
|
||||
|
||||
}
|
||||
:deep(li) {
|
||||
margin-top: 10px;
|
||||
|
||||
}
|
||||
:deep(code) {
|
||||
line-height: 1px !important;
|
||||
|
||||
|
||||
}
|
||||
:deep(span) {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
:deep(pre) {
|
||||
background: #f4f4f4;
|
||||
line-height: 1 !important;
|
||||
padding: 18px 8px;
|
||||
}
|
||||
|
||||
:deep(th), :deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #f3f4f6;
|
||||
background: #D2C3EA;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong), :deep(b) {
|
||||
@@ -2486,12 +2517,25 @@ a{
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #007bff !important;
|
||||
color: #661FFB !important;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(p) {
|
||||
text-align: justify !important;
|
||||
text-justify: inter-ideograph !important;
|
||||
|
||||
line-height: 2 !important;
|
||||
margin: 0.8em 0 !important;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* 加载动画 */
|
||||
@@ -2521,4 +2565,8 @@ a{
|
||||
padding: 25px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.navActive{
|
||||
background: #AC85E0 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -8,11 +8,11 @@
|
||||
</section>
|
||||
<section class="rightContent">
|
||||
<div v-if="problemLoading" class="loading-container">
|
||||
<span class="loading-text">正在加载内容...</span>
|
||||
<span class="loading-text">{{ $t('home.loadingContent') || '正在加载内容...' }}</span>
|
||||
</div>
|
||||
<div v-else-if="info && info.trim()" class="dynamic-content" v-html="info"></div>
|
||||
<div v-else class="no-content">
|
||||
<p>暂无内容</p>
|
||||
<p>{{ $t('home.noContent') || '暂无内容' }}</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -2,17 +2,17 @@ import { findDataInfo } from "../../../api/documentManagement"
|
||||
export default{
|
||||
data(){
|
||||
return{
|
||||
|
||||
typeArray:[],
|
||||
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
// this.fetchDataInfo()
|
||||
|
||||
|
||||
|
||||
if (this.$route.query.id) {
|
||||
this.fetchDataInfo({id:this.$route.query.id})
|
||||
}
|
||||
// if (this.$route.query.id) {
|
||||
// this.fetchDataInfo({id:this.$route.query.id})
|
||||
// }
|
||||
|
||||
},
|
||||
methods:{
|
||||
@@ -20,13 +20,49 @@ export default{
|
||||
const res = await findDataInfo(params)
|
||||
if (res && res.code === 200) {
|
||||
this.modifyData = res.data
|
||||
this.addParams.content = this.modifyData.content
|
||||
this.addParams = this.modifyData
|
||||
// 确保type字段为字符串类型,以便与TypeList中的value匹配
|
||||
this.addParams.type = String(this.addParams.type)
|
||||
|
||||
|
||||
|
||||
this.addParams.childType = String(this.addParams.childType)
|
||||
this.typeArray = [this.addParams.type]
|
||||
// 标记已从后台获取数据,避免被本地存储覆盖
|
||||
this.hasBackendData = true
|
||||
// 强制用接口数据刷新编辑器内容
|
||||
if (this.editor && this.addParams.content) {
|
||||
this.editor.txt.html(this.addParams.content)
|
||||
this.html = this.addParams.content
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 币种选择变更处理
|
||||
* @param {string} scope - 选择的币种
|
||||
*/
|
||||
changeScreen(scope) {
|
||||
let brand = scope
|
||||
for (let index in this.currencyList) {
|
||||
let aa = this.currencyList[index];
|
||||
let value = aa.value;
|
||||
if (brand === value) {
|
||||
this.$refs.screen.$el.children[0].children[0].setAttribute('style', "background:url(" + aa.imgUrl + ") no-repeat 10PX;background-size: 20PX 20PX;color:#333;padding-left: 33PX;");
|
||||
}
|
||||
}
|
||||
|
||||
// 保存用户选择的币种到localStorage
|
||||
localStorage.setItem('userManagement_selectedCurrency', scope);
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
handleClearScreen(){
|
||||
// 清除币种图片样式
|
||||
if (this.$refs.screen && this.$refs.screen.$el) {
|
||||
this.$refs.screen.$el.children[0].children[0].style.background = '';
|
||||
this.$refs.screen.$el.children[0].children[0].style.paddingLeft = '';
|
||||
}
|
||||
// 也可以清除 localStorage 里的币种选择
|
||||
localStorage.removeItem('userManagement_selectedCurrency');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,49 @@
|
||||
<template>
|
||||
<div class="editor-page" v-loading="addLoading">
|
||||
<div
|
||||
class="editor-page"
|
||||
v-loading="addLoading"
|
||||
:class="{ 'no-scroll': addLoading }"
|
||||
>
|
||||
<h2 style="margin-bottom: 20px">
|
||||
{{ $t("backendSystem.addDocument") || "新增文档" }}
|
||||
</h2>
|
||||
|
||||
<!-- 页面头部 -->
|
||||
|
||||
<div class="page-header">
|
||||
<div class="header-left">
|
||||
<div class="title-section">
|
||||
<i class="el-icon-edit-outline title-icon"></i>
|
||||
<h1 class="page-title">wangeditor 富文本文档编辑器</h1>
|
||||
<h1 class="page-title">
|
||||
{{
|
||||
$t("backendSystem.wangeditor") || "wangeditor 富文本文档编辑器"
|
||||
}}
|
||||
</h1>
|
||||
</div>
|
||||
<p class="page-description">
|
||||
使用富文本编辑器创建和管理文档,支持文本格式化、链接、列表等功能
|
||||
</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-link"
|
||||
@click="handleInsertAnchor"
|
||||
>
|
||||
{{ $t("backendSystem.insertAnchor") || "插入锚点" }}
|
||||
</el-button>
|
||||
<el-button type="info" icon="el-icon-view" @click="handlePreview">
|
||||
预览文档
|
||||
{{ $t("backendSystem.previewDocument") || "预览文档" }}
|
||||
</el-button>
|
||||
<el-button type="success" icon="el-icon-document" @click="handleSave">
|
||||
保存文档
|
||||
{{ $t("backendSystem.saveDocument") || "保存文档" }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
icon="el-icon-upload2"
|
||||
@click="handelAddDocument"
|
||||
>
|
||||
发布文档
|
||||
{{ $t("backendSystem.publishDocument") || "发布文档" }}
|
||||
</el-button>
|
||||
<el-button type="danger" icon="el-icon-delete" @click="handleReset">
|
||||
{{ $t("backendSystem.reset") || "重置" }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -32,49 +52,45 @@
|
||||
<div class="config-section">
|
||||
<div class="section-header">
|
||||
<i class="el-icon-setting"></i>
|
||||
<span>文档配置</span>
|
||||
<span>{{
|
||||
$t("backendSystem.documentConfiguration") || "文档配置"
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<div class="config-content">
|
||||
<div class="config-row">
|
||||
<div class="config-item">
|
||||
<label>导航标题</label>
|
||||
<label>{{
|
||||
$t("backendSystem.navigationTitle") || "导航标题"
|
||||
}}</label>
|
||||
<el-input
|
||||
v-model="addParams.title"
|
||||
placeholder="请输入文档标题"
|
||||
:placeholder="
|
||||
$t('backendSystem.pleaseInputDocumentTitle') || '请输入文档标题'
|
||||
"
|
||||
@input="handleAutoSave"
|
||||
size="medium"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<label class="required">文档类型</label>
|
||||
<label class="required">{{
|
||||
$t("backendSystem.documentType") || "文档类型"
|
||||
}}</label>
|
||||
<el-cascader
|
||||
:options="TypeList"
|
||||
v-model="typeArray"
|
||||
@change="handleAutoSaveType(typeArray)"
|
||||
clearable
|
||||
placeholder="请选择文档类型"
|
||||
:placeholder="
|
||||
$t('backendSystem.pleaseSelectDocumentType') || '请选择文档类型'
|
||||
"
|
||||
:props="{
|
||||
label: 'label',
|
||||
value: 'value',
|
||||
children: 'children',
|
||||
}"
|
||||
/>
|
||||
<!-- <el-select
|
||||
v-model="addParams.type"
|
||||
placeholder="请选择文档类型"
|
||||
@change="handleAutoSaveType(addParams.type)"
|
||||
size="medium"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in TypeList"
|
||||
:key="item.value"
|
||||
:label="$t(item.label)"
|
||||
:value="item.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -82,75 +98,102 @@
|
||||
<div class="config-content">
|
||||
<div class="config-row">
|
||||
<div class="config-item">
|
||||
<label>标题图片地址</label>
|
||||
<label>{{
|
||||
$t("backendSystem.titleImageAddress") || "标题图片地址"
|
||||
}}</label>
|
||||
<el-input
|
||||
v-model="addParams.titleUrl"
|
||||
placeholder="请输入图片地址"
|
||||
:placeholder="
|
||||
$t('backendSystem.pleaseInputImageAddress') || '请输入图片地址'
|
||||
"
|
||||
@input="handleAutoSave"
|
||||
size="medium"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<label>文章访问地址</label>
|
||||
<label>{{
|
||||
$t("backendSystem.articleAccessAddress") || "文章访问地址"
|
||||
}}</label>
|
||||
<el-input
|
||||
v-model="addParams.articleUrl"
|
||||
placeholder="请输入访问地址"
|
||||
:placeholder="
|
||||
$t('backendSystem.pleaseInputAccessAddress') || '请输入访问地址'
|
||||
"
|
||||
@input="handleAutoSave"
|
||||
size="medium"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="config-content">
|
||||
<div class="config-row">
|
||||
<div class="config-item">
|
||||
<label >{{
|
||||
$t("backendSystem.coin2") || "币种"
|
||||
}}</label>
|
||||
<el-select
|
||||
class="input"
|
||||
size="middle"
|
||||
ref="screen"
|
||||
@change="changeScreen(screenCurrency)"
|
||||
v-model="screenCurrency"
|
||||
clearable
|
||||
@clear="handleClearScreen"
|
||||
:placeholder="$t(`backendSystem.selectCurrency`)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in currencyList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
|
||||
<div style="display: flex; align-items: center">
|
||||
<img :src="item.imgUrl" style="float: left; width: 20px" />
|
||||
<span style="float: left; margin-left: 5px">
|
||||
{{ item.label }}</span
|
||||
>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑器区域 -->
|
||||
<div class="editor-section">
|
||||
<div class="section-header">
|
||||
<i class="el-icon-edit-outline"></i>
|
||||
<span>富文本编辑器</span>
|
||||
<span>{{ $t("backendSystem.richTextEditor") || "富文本编辑器" }}</span>
|
||||
</div>
|
||||
|
||||
<div class="editor-container">
|
||||
<Toolbar
|
||||
:editor="editor"
|
||||
:defaultConfig="toolbarConfig"
|
||||
:mode="mode"
|
||||
style="border-bottom: 1px solid #ccc"
|
||||
/>
|
||||
<Editor
|
||||
style="height: 600px; overflow-y: hidden"
|
||||
v-model="addParams.content"
|
||||
:defaultConfig="editorConfig"
|
||||
:mode="mode"
|
||||
@onCreated="onCreated"
|
||||
@onChange="handleEditorChange"
|
||||
/>
|
||||
<div ref="editor" style="height: 600px"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预览文档对话框 -->
|
||||
<el-dialog
|
||||
title="文档预览"
|
||||
:title="$t('backendSystem.documentPreview') || '文档预览'"
|
||||
:visible.sync="previewVisible"
|
||||
width="80%"
|
||||
:before-close="handlePreviewClose"
|
||||
class="preview-dialog"
|
||||
class="preview-dialog wangeditor-preview"
|
||||
>
|
||||
<div class="preview-content">
|
||||
<div v-html="addParams.content" class="dynamic-content"></div>
|
||||
|
||||
<div v-if="!addParams.content" class="preview-empty">
|
||||
<i class="el-icon-document"></i>
|
||||
<p>暂无内容</p>
|
||||
<p>{{ $t("backendSystem.noContent") || "暂无内容" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="previewVisible = false">关闭</el-button>
|
||||
<el-button type="primary" @click="handlePrintPreview"
|
||||
>打印预览</el-button
|
||||
>
|
||||
<el-button @click="previewVisible = false">{{
|
||||
$t("backendSystem.close") || "关闭"
|
||||
}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -158,36 +201,16 @@
|
||||
|
||||
<script>
|
||||
import Vue from "vue";
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
import E from "wangeditor";
|
||||
import { addDocument } from "../../../api/documentManagement";
|
||||
import Index from "./index";
|
||||
export default Vue.extend({
|
||||
components: { Editor, Toolbar },
|
||||
mixins: [Index],
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
html: "<p>hello</p>",
|
||||
toolbarConfig: {
|
||||
excludeKeys: [],
|
||||
insertKeys: {
|
||||
index: 0,
|
||||
keys: [
|
||||
"bold",
|
||||
"italic",
|
||||
"underline",
|
||||
"through",
|
||||
"code",
|
||||
"sub",
|
||||
"sup",
|
||||
"clearStyle",
|
||||
],
|
||||
},
|
||||
},
|
||||
editorConfig: {
|
||||
placeholder: "请在此输入文档内容...",
|
||||
MENU_CONF: {},
|
||||
},
|
||||
html: "", // 编辑器内容
|
||||
hasSetEditorContent: false, // 避免重复 set 内容
|
||||
mode: "default",
|
||||
addParams: {
|
||||
title: "",
|
||||
@@ -196,7 +219,8 @@ export default Vue.extend({
|
||||
lang: "",
|
||||
titleUrl: "",
|
||||
articleUrl: "",
|
||||
childType:""
|
||||
childType: "",
|
||||
coin: "",
|
||||
},
|
||||
lastSaveTime: "",
|
||||
autoSaveTimer: null,
|
||||
@@ -224,15 +248,19 @@ export default Vue.extend({
|
||||
|
||||
addLoading: false,
|
||||
typeArray: [],
|
||||
currencyList: [],
|
||||
screenCurrency: "",
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
|
||||
|
||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"));
|
||||
window.addEventListener("setItem", () => {
|
||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"));
|
||||
});
|
||||
try {
|
||||
this.TypeList = JSON.parse(localStorage.getItem("TypeList"));
|
||||
this.TypeList = this.TypeList.map((item) => ({ // 翻译label
|
||||
this.TypeList = this.TypeList.map((item) => ({
|
||||
// 翻译label
|
||||
...item,
|
||||
label: this.$t(item.label),
|
||||
children: item.children
|
||||
@@ -242,7 +270,6 @@ export default Vue.extend({
|
||||
}))
|
||||
: undefined,
|
||||
}));
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
@@ -253,39 +280,134 @@ export default Vue.extend({
|
||||
// 添加页面卸载前的保存保护
|
||||
window.addEventListener("beforeunload", this.handleBeforeUnload);
|
||||
|
||||
// 延迟设置默认内容,避免覆盖恢复的数据
|
||||
setTimeout(() => {
|
||||
if (!this.addParams.content) {
|
||||
this.html = "<p>模拟 Ajax 异步设置内容 HTML</p>";
|
||||
}
|
||||
}, 1500);
|
||||
// 删除默认内容设置,保持编辑器初始化为空
|
||||
// setTimeout(() => {
|
||||
// if (!this.addParams.content) {
|
||||
// this.html = "<p>模拟 Ajax 异步设置内容 HTML</p>";
|
||||
// }
|
||||
// }, 1500);
|
||||
|
||||
this.editor = new E(this.$refs.editor);
|
||||
this.editor.config.height = 600;
|
||||
this.editor.config.onchange = (html) => {
|
||||
this.html = html;
|
||||
this.addParams.content = html;
|
||||
};
|
||||
//配置颜色
|
||||
this.editor.config.colors = [
|
||||
`#651FFF`,
|
||||
`#FF4081`,
|
||||
`#FF9900`,
|
||||
`#FFC107`,
|
||||
`#FF5722`,
|
||||
`#9C27B0`,
|
||||
`#673AB7`,
|
||||
`#3F51B5`,
|
||||
"#000000", // 黑色
|
||||
"#ffffff", // 白色
|
||||
"#eeece0", // 浅米色
|
||||
"#1c487f", // 深蓝
|
||||
"#4d80bf", // 蓝色
|
||||
"#c24f4a", // 红色
|
||||
"#8baa4a", // 绿色
|
||||
"#a96b59", // 棕色
|
||||
"#2b2b2b", // 深灰
|
||||
"#b6975a", // 金色
|
||||
"#5b9bd5", // 天蓝
|
||||
"#70ad47", // 草绿
|
||||
"#ed7d31", // 橙色
|
||||
"#ffc000", // 黄色
|
||||
"#7030a0", // 紫色
|
||||
"#f4b084", // 浅橙
|
||||
"#bdd7ee", // 浅蓝
|
||||
"#a9d08e", // 浅绿
|
||||
"#ffe699", // 浅黄
|
||||
"#d9d9d9", // 浅灰
|
||||
"#f8cbad", // 浅棕
|
||||
"#e2efda", // 淡绿
|
||||
"#fff2cc", // 淡黄
|
||||
"#dbe5f1", // 淡蓝
|
||||
"#e4dfec", // 淡紫
|
||||
"#fbeee6", // 淡橙
|
||||
"#f6f6f6", // 极浅灰
|
||||
"#ff0000", // 纯红
|
||||
"#00b050", // 纯绿
|
||||
"#0070c0", // 纯蓝
|
||||
"#7030a0", // 纯紫
|
||||
"#ff9900", // 纯橙
|
||||
"#808080", // 中灰
|
||||
];
|
||||
//配置字体
|
||||
(this.editor.config.fontNames = [
|
||||
// 对象形式 v4.6.16
|
||||
{ name: "黑体", value: "黑体" },
|
||||
{ name: "绝绝字体", value: "Times New Roman" },
|
||||
// 字符串形式
|
||||
"黑体",
|
||||
"仿宋",
|
||||
"楷体",
|
||||
"标楷体",
|
||||
"华文仿宋",
|
||||
"华文楷体",
|
||||
"宋体",
|
||||
"微软雅黑",
|
||||
"Arial",
|
||||
"Tahoma",
|
||||
"Verdana",
|
||||
"Times New Roman",
|
||||
"Courier New",
|
||||
]),
|
||||
// 不自定义菜单,使用官方默认菜单栏
|
||||
this.editor.create();
|
||||
// 只在初始化时 set 一次内容
|
||||
if (this.addParams.content && !this.hasSetEditorContent) {
|
||||
this.editor.txt.html(this.addParams.content);
|
||||
this.html = this.addParams.content;
|
||||
this.hasSetEditorContent = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async fetchAddDocument(params) {
|
||||
this.setLoading("addLoading", true);
|
||||
const res = await addDocument(params);
|
||||
if (res && res.code == 200) {
|
||||
this.$message.success(this.$t("backendSystem.addSuccess"));
|
||||
this.$message.success(this.$t("backendSystem.updateSuccess"));
|
||||
// 发布成功后清除本地草稿
|
||||
const LOCAL_STORAGE_KEY = "editor_draft_add";
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
this.$router.push({ path: `/${this.$i18n.locale}/documentManagement` });
|
||||
for (const key in this.addParams) {
|
||||
this.addParams[key] = "";
|
||||
}
|
||||
if (this.editor) {
|
||||
this.editor.txt.clear();
|
||||
}
|
||||
}
|
||||
this.setLoading("addLoading", false);
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑器创建后回调,确保 this.editor 正确赋值
|
||||
* @param {Object} editor wangEditor 实例
|
||||
*/
|
||||
onCreated(editor) {
|
||||
this.editor = Object.seal(editor);
|
||||
this.editor = editor;
|
||||
console.log("编辑器已初始化", this.editor);
|
||||
|
||||
// 编辑器创建后,如果有恢复的内容,设置到编辑器中
|
||||
if (this.addParams.content) {
|
||||
this.$nextTick(() => {
|
||||
editor.setHtml(this.addParams.content);
|
||||
this.editor.txt.html(this.addParams.content);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
handelAddDocument() {
|
||||
if (!this.addParams.type) {
|
||||
if (!this.addParams.type || this.addParams.type == "0") {
|
||||
this.$message({
|
||||
message: "请填写文档类型",
|
||||
message:
|
||||
this.$t("backendSystem.pleaseSelectDocumentType") ||
|
||||
"请填写文档类型",
|
||||
type: "warning",
|
||||
duration: 4000,
|
||||
showClose: true,
|
||||
@@ -293,11 +415,31 @@ export default Vue.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
|
||||
if (this.addParams.type == "1" && !this.screenCurrency) {
|
||||
this.$message({
|
||||
message:
|
||||
this.$t("backendSystem.pleaseSelectCurrency2") ||
|
||||
"添加挖矿教程,请选择币种",
|
||||
type: "warning",
|
||||
duration: 4000,
|
||||
showClose: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.addParams.content) {
|
||||
//锚点定位的A标签 去掉target="_blank"
|
||||
this.addParams.content = this.addParams.content.replace(
|
||||
/<a([^>]*href="#[^"]*")[^>]*>/gi,
|
||||
function (match) {
|
||||
return match.replace(/\s*target="_blank"/gi, "");
|
||||
}
|
||||
);
|
||||
}
|
||||
this.addParams.coin = this.screenCurrency
|
||||
console.log(this.addParams.content, "this.addParams.content");
|
||||
|
||||
this.fetchAddDocument(this.addParams);
|
||||
},
|
||||
|
||||
@@ -317,49 +459,20 @@ export default Vue.extend({
|
||||
this.previewVisible = false;
|
||||
},
|
||||
|
||||
handlePrintPreview() {
|
||||
const printWindow = window.open("", "_blank");
|
||||
if (printWindow) {
|
||||
printWindow.document.write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>${this.addParams.title || "文档预览"}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
margin: 20px;
|
||||
}
|
||||
.preview-empty {
|
||||
text-align: center;
|
||||
padding: 50px 0;
|
||||
color: #95a5a6;
|
||||
}
|
||||
.preview-empty i {
|
||||
font-size: 40px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${
|
||||
this.addParams.content ||
|
||||
'<div class="preview-empty"><i>📄</i><p>暂无内容</p></div>'
|
||||
}
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
printWindow.print();
|
||||
printWindow.close();
|
||||
}
|
||||
},
|
||||
|
||||
handleSave() {
|
||||
// 保存前彻底去除所有锚点链接的 target="_blank"
|
||||
this.addParams.content = this.addParams.content.replace(
|
||||
/<a([^>]*href="#([^"]*)")[^>]*>/gi,
|
||||
function (match) {
|
||||
// 去掉 target="_blank"
|
||||
return match.replace(/\s*target="_blank"/gi, "");
|
||||
}
|
||||
);
|
||||
this.manualSave();
|
||||
this.$message({
|
||||
message: "内容已保存到本地,请尽快发布,关闭页面可能丢失内容",
|
||||
message:
|
||||
this.$t("backendSystem.contentSaved") ||
|
||||
"内容已保存到本地,请尽快发布,关闭页面可能丢失内容",
|
||||
type: "success",
|
||||
duration: 4000,
|
||||
showClose: true,
|
||||
@@ -378,7 +491,7 @@ export default Vue.extend({
|
||||
this.addParams.articleUrl = "";
|
||||
}
|
||||
this.addParams.type = type[0];
|
||||
this.addParams.childType= type[1];
|
||||
this.addParams.childType = type[1];
|
||||
} catch (error) {
|
||||
console.log(error, "error");
|
||||
}
|
||||
@@ -420,7 +533,7 @@ export default Vue.extend({
|
||||
try {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.addParams.content = this.editor.txt.html();
|
||||
}
|
||||
|
||||
const saveData = {
|
||||
@@ -439,7 +552,8 @@ export default Vue.extend({
|
||||
lastModified: Date.now(),
|
||||
};
|
||||
|
||||
localStorage.setItem("editor_draft", JSON.stringify(saveData));
|
||||
const LOCAL_STORAGE_KEY = "editor_draft_add";
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(saveData));
|
||||
this.lastSaveTime = saveData.timestamp;
|
||||
this.isSaving = false;
|
||||
} catch (error) {
|
||||
@@ -450,7 +564,8 @@ export default Vue.extend({
|
||||
|
||||
loadFromLocalStorage() {
|
||||
try {
|
||||
const savedData = localStorage.getItem("editor_draft");
|
||||
const LOCAL_STORAGE_KEY = "editor_draft_add";
|
||||
const savedData = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (savedData) {
|
||||
const data = JSON.parse(savedData);
|
||||
|
||||
@@ -460,7 +575,7 @@ export default Vue.extend({
|
||||
|
||||
if (isExpired) {
|
||||
console.log("本地数据已过期,清除缓存");
|
||||
localStorage.removeItem("editor_draft");
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -474,7 +589,7 @@ export default Vue.extend({
|
||||
|
||||
// 如果编辑器已经创建,直接设置内容
|
||||
if (this.editor) {
|
||||
this.editor.setHtml(data.content || "");
|
||||
this.editor.txt.html(data.content || "");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -484,7 +599,8 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
clearDraft() {
|
||||
localStorage.removeItem("editor_draft");
|
||||
const LOCAL_STORAGE_KEY = "editor_draft_add";
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
this.lastSaveTime = "";
|
||||
this.isSaving = false;
|
||||
},
|
||||
@@ -493,7 +609,7 @@ export default Vue.extend({
|
||||
manualSave() {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.addParams.content = this.editor.txt.html();
|
||||
}
|
||||
this.saveToLocalStorage();
|
||||
},
|
||||
@@ -504,7 +620,7 @@ export default Vue.extend({
|
||||
if (this.addParams.title || this.addParams.content) {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.addParams.content = this.editor.txt.html();
|
||||
}
|
||||
this.saveToLocalStorage();
|
||||
}
|
||||
@@ -525,31 +641,110 @@ export default Vue.extend({
|
||||
return "未知类型";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 插入锚点(源码模式下插入HTML)
|
||||
*/
|
||||
handleInsertAnchor() {
|
||||
if (!this.editor) {
|
||||
this.$message.warning("编辑器尚未初始化");
|
||||
return;
|
||||
}
|
||||
this.$prompt(
|
||||
this.$t("backendSystem.pleaseInputAnchorName") ||
|
||||
"请输入锚点名称(不能重复)",
|
||||
this.$t("backendSystem.insertAnchor") || "插入锚点",
|
||||
{
|
||||
confirmButtonText: this.$t("backendSystem.confirm") || "确定",
|
||||
cancelButtonText: this.$t("backendSystem.cancel") || "取消",
|
||||
inputPattern: /^[a-zA-Z0-9_-]+$/,
|
||||
inputErrorMessage:
|
||||
this.$t("backendSystem.anchorNameErrorMessage") ||
|
||||
"锚点名只能包含字母、数字、下划线和中划线",
|
||||
}
|
||||
)
|
||||
.then(({ value }) => {
|
||||
this.editor.cmd.do("insertHTML", `<span id="${value}"></span>`);
|
||||
this.html = this.editor.txt.html();
|
||||
this.addParams.content = this.html;
|
||||
this.$message.success(
|
||||
this.$t("backendSystem.anchorInserted") || "锚点已插入"
|
||||
);
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
|
||||
/**
|
||||
* 给选中的标题添加id属性作为锚点
|
||||
*/
|
||||
handleAddHeadingId() {
|
||||
if (!this.editor) {
|
||||
this.$message.warning("编辑器尚未初始化");
|
||||
return;
|
||||
}
|
||||
// 获取当前选中的标题节点
|
||||
const headers = this.editor.getElemsByTypePrefix("header");
|
||||
if (!headers || headers.length === 0) {
|
||||
this.$message.warning(
|
||||
this.$t("backendSystem.pleaseSelectHeader") ||
|
||||
"请先选中一个标题(h1~h6)"
|
||||
);
|
||||
return;
|
||||
}
|
||||
const node = headers[0];
|
||||
this.$prompt(
|
||||
this.$t("backendSystem.pleaseInputAnchorID") ||
|
||||
"请输入锚点ID(不能重复)",
|
||||
this.$t("backendSystem.titleAnchor") || "标题锚点",
|
||||
{
|
||||
confirmButtonText: this.$t("backendSystem.confirm") || "确定",
|
||||
cancelButtonText: this.$t("backendSystem.cancel") || "取消",
|
||||
inputPattern: /^[a-zA-Z0-9_-]+$/,
|
||||
inputErrorMessage:
|
||||
this.$t("backendSystem.anchorIDErrorMessage") ||
|
||||
"ID只能包含字母、数字、下划线和中划线",
|
||||
}
|
||||
)
|
||||
.then(({ value }) => {
|
||||
this.editor.setElemAttribute(node, "id", value);
|
||||
this.$message.success(
|
||||
this.$t("backendSystem.anchorIDAdded") || "锚点ID已添加"
|
||||
);
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
|
||||
/**
|
||||
* 重置表单和编辑器内容
|
||||
*/
|
||||
handleReset() {
|
||||
// 清空表单数据
|
||||
for (const key in this.addParams) {
|
||||
this.addParams[key] = "";
|
||||
}
|
||||
// 清空富文本编辑器内容
|
||||
if (this.editor) {
|
||||
this.editor.txt.clear();
|
||||
}
|
||||
// 清除本地草稿
|
||||
const LOCAL_STORAGE_KEY = "editor_draft_add";
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
this.$message.success(
|
||||
this.$t("backendSystem.contentReset") || "内容已重置"
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.editor.destroy();
|
||||
}
|
||||
this.saveToLocalStorage();
|
||||
|
||||
// 移除事件监听器
|
||||
window.removeEventListener("beforeunload", this.handleBeforeUnload);
|
||||
|
||||
if (this.autoSaveTimer) {
|
||||
clearTimeout(this.autoSaveTimer);
|
||||
}
|
||||
|
||||
const editor = this.editor;
|
||||
if (editor == null) return;
|
||||
editor.destroy();
|
||||
},
|
||||
|
||||
beforeRouteLeave(to, from, next) {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.addParams.content = this.editor.txt.html();
|
||||
}
|
||||
this.saveToLocalStorage();
|
||||
next();
|
||||
@@ -704,12 +899,20 @@ export default Vue.extend({
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
min-height: 650px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 设置编辑器高度 */
|
||||
.editor-container .w-e-text-container {
|
||||
::v-deep .editor-container .w-e-text-container {
|
||||
height: 600px !important;
|
||||
min-height: 600px !important;
|
||||
z-index: 1 !important;
|
||||
position: relative;
|
||||
}
|
||||
::v-deep .w-e-toolbar {
|
||||
z-index: 10 !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 编辑器内容区域样式 */
|
||||
@@ -752,6 +955,7 @@ export default Vue.extend({
|
||||
padding: 20px;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.preview-dialog .el-dialog__header {
|
||||
@@ -876,46 +1080,47 @@ export default Vue.extend({
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------富文本样式-------------- */
|
||||
.dynamic-content {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
:deep(th), :deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #f3f4f6;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong), :deep(b) {
|
||||
font-weight: bold !important;
|
||||
color: inherit !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
:deep(em), :deep(i) {
|
||||
font-style: italic !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #007bff !important;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
}
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
:deep(th),
|
||||
:deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #f3f4f6;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong),
|
||||
:deep(b) {
|
||||
font-weight: bold !important;
|
||||
color: inherit !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
:deep(em),
|
||||
:deep(i) {
|
||||
font-style: italic !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #007bff !important;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style src="@wangeditor/editor/dist/css/style.css"></style>
|
||||
.no-scroll {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
</style>
|
||||
@@ -13,7 +13,7 @@
|
||||
class="demo-form-inline"
|
||||
ref="formRef"
|
||||
>
|
||||
<el-form-item label="文档类型" prop="type">
|
||||
<el-form-item :label="$t('backendSystem.documentType')|| '文档类型'" prop="type">
|
||||
<el-select
|
||||
class="input"
|
||||
clearable
|
||||
@@ -38,7 +38,7 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="搜索" style="margin-left: 5vw" prop="minerUser">
|
||||
<el-form-item :label="$t('backendSystem.search')|| '搜索'" style="margin-left: 5vw" prop="minerUser">
|
||||
<el-input
|
||||
v-model="queryParams.keyword"
|
||||
:placeholder="$t('backendSystem.pleaseInput')"
|
||||
@@ -65,7 +65,7 @@
|
||||
<el-table-column prop="id" label="ID" width="60" />
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="创建时间"
|
||||
:label="$t('backendSystem.createTime')|| '创建时间'"
|
||||
width="160"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
@@ -76,20 +76,20 @@
|
||||
|
||||
<el-table-column
|
||||
prop="createUser"
|
||||
label="创建人"
|
||||
:label="$t('backendSystem.createUser')|| '创建人'"
|
||||
width="160"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column prop="content" label="文档内容" show-overflow-tooltip />
|
||||
<el-table-column prop="content" :label="$t('backendSystem.content')|| '文档内容'" show-overflow-tooltip />
|
||||
<el-table-column
|
||||
prop="title"
|
||||
label="文档标题"
|
||||
:label="$t('backendSystem.documentTitle')|| '文档标题'"
|
||||
width="200"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="type"
|
||||
label="文档类型"
|
||||
:label="$t('backendSystem.documentType')|| '文档类型'"
|
||||
width="100"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
<el-table-column
|
||||
prop="updateTime"
|
||||
label="修改时间"
|
||||
:label="$t('backendSystem.updateTime')|| '修改时间'"
|
||||
width="160"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
@@ -110,7 +110,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="updateUser"
|
||||
label="修改人"
|
||||
:label="$t('backendSystem.updateUser')|| '修改人'"
|
||||
width="160"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
|
||||
@@ -3,12 +3,17 @@ export default{
|
||||
data(){
|
||||
return{
|
||||
typeArray:[],
|
||||
currencyList: [],
|
||||
screenCurrency: "",
|
||||
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
// this.fetchDataInfo()
|
||||
|
||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"));
|
||||
window.addEventListener("setItem", () => {
|
||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"));
|
||||
});
|
||||
|
||||
if (this.$route.query.id) {
|
||||
this.fetchDataInfo({id:this.$route.query.id})
|
||||
@@ -27,8 +32,33 @@ export default{
|
||||
this.typeArray = [this.addParams.type]
|
||||
// 标记已从后台获取数据,避免被本地存储覆盖
|
||||
this.hasBackendData = true
|
||||
// 删除 editor.setHtml 的调用,内容初始化交由 onCreated 统一处理
|
||||
this.screenCurrency = this.addParams.coin
|
||||
// 强制用接口数据刷新编辑器内容
|
||||
if (this.editor && this.addParams.content) {
|
||||
this.editor.txt.html(this.addParams.content)
|
||||
this.html = this.addParams.content
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 币种选择变更处理
|
||||
* @param {string} scope - 选择的币种
|
||||
*/
|
||||
changeScreen(scope) {
|
||||
let brand = scope
|
||||
for (let index in this.currencyList) {
|
||||
let aa = this.currencyList[index];
|
||||
let value = aa.value;
|
||||
if (brand === value) {
|
||||
this.$refs.screen.$el.children[0].children[0].setAttribute('style', "background:url(" + aa.imgUrl + ") no-repeat 10PX;background-size: 20PX 20PX;color:#333;padding-left: 33PX;");
|
||||
}
|
||||
}
|
||||
|
||||
// 保存用户选择的币种到localStorage
|
||||
localStorage.setItem('userManagement_selectedCurrency', scope);
|
||||
|
||||
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,37 @@
|
||||
<template>
|
||||
<div class="editor-page" v-loading="addLoading">
|
||||
|
||||
<div class="editor-page" v-loading="addLoading" :class="{ 'no-scroll': addLoading }">
|
||||
|
||||
<h2 style="margin-bottom: 20px;">{{ $t('backendSystem.modifyDocument') || '修改文档' }}</h2>
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<div class="header-left">
|
||||
<div class="title-section">
|
||||
<i class="el-icon-edit-outline title-icon"></i>
|
||||
<h1 class="page-title">wangeditor 富文本文档编辑器</h1>
|
||||
<h1 class="page-title">{{ $t('backendSystem.wangeditor') || 'wangeditor 富文本文档编辑器' }}</h1>
|
||||
</div>
|
||||
<p class="page-description">
|
||||
使用富文本编辑器创建和管理文档,支持文本格式化、链接、列表等功能
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-link"
|
||||
@click="handleInsertAnchor"
|
||||
>
|
||||
{{ $t('backendSystem.insertAnchor') || '插入锚点' }}
|
||||
</el-button>
|
||||
<el-button type="info" icon="el-icon-view" @click="handlePreview">
|
||||
预览文档
|
||||
{{ $t('backendSystem.previewDocument') || '预览文档' }}
|
||||
</el-button>
|
||||
<el-button type="success" icon="el-icon-document" @click="handleSave">
|
||||
保存文档
|
||||
{{ $t('backendSystem.saveDocument') || '保存文档' }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="warning"
|
||||
icon="el-icon-upload2"
|
||||
@click="handelAddDocument"
|
||||
>
|
||||
修改文档
|
||||
{{ $t('backendSystem.modifyDocument') || '修改文档' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -32,36 +40,35 @@
|
||||
<div class="config-section">
|
||||
<div class="section-header">
|
||||
<i class="el-icon-setting"></i>
|
||||
<span>文档配置</span>
|
||||
<span>{{ $t('backendSystem.documentConfiguration') || '文档配置' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="config-content">
|
||||
<div class="config-row">
|
||||
<div class="config-item">
|
||||
<label>导航标题</label>
|
||||
<label>{{ $t('backendSystem.navigationTitle') || '导航标题' }}</label>
|
||||
<el-input
|
||||
v-model="addParams.title"
|
||||
placeholder="请输入文档标题"
|
||||
:placeholder="$t('backendSystem.pleaseInputDocumentTitle') || '请输入文档标题'"
|
||||
@input="handleAutoSave"
|
||||
size="medium"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<label class="required">文档类型</label>
|
||||
<label class="required">{{ $t('backendSystem.documentType') || '文档类型' }}</label>
|
||||
<el-cascader
|
||||
:options="TypeList"
|
||||
v-model="typeArray"
|
||||
@change="handleAutoSaveType(typeArray)"
|
||||
clearable
|
||||
placeholder="请选择文档类型"
|
||||
:placeholder="$t('backendSystem.pleaseSelectDocumentType') || '请选择文档类型'"
|
||||
:props="{
|
||||
label: 'label',
|
||||
value: 'value',
|
||||
children: 'children',
|
||||
}"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,113 +76,115 @@
|
||||
<div class="config-content">
|
||||
<div class="config-row">
|
||||
<div class="config-item">
|
||||
<label>标题图片地址</label>
|
||||
<label>{{ $t('backendSystem.titleImageAddress') || '标题图片地址' }}</label>
|
||||
<el-input
|
||||
v-model="addParams.titleUrl"
|
||||
placeholder="请输入图片地址"
|
||||
:placeholder="$t('backendSystem.pleaseInputImageAddress') || '请输入图片地址'"
|
||||
@input="handleAutoSave"
|
||||
size="medium"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<label>文章访问地址</label>
|
||||
<label>{{ $t('backendSystem.articleAccessAddress') || '文章访问地址' }}</label>
|
||||
<el-input
|
||||
v-model="addParams.articleUrl"
|
||||
placeholder="请输入访问地址"
|
||||
:placeholder="$t('backendSystem.pleaseInputAccessAddress') || '请输入访问地址'"
|
||||
@input="handleAutoSave"
|
||||
size="medium"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="config-content">
|
||||
<div class="config-row">
|
||||
<div class="config-item">
|
||||
<label >{{
|
||||
$t("backendSystem.coin2") || "币种"
|
||||
}}</label>
|
||||
<el-select
|
||||
class="input"
|
||||
size="middle"
|
||||
ref="screen"
|
||||
@change="changeScreen(screenCurrency)"
|
||||
v-model="screenCurrency"
|
||||
|
||||
:placeholder="$t(`backendSystem.selectCurrency`)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in currencyList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
>
|
||||
|
||||
<div style="display: flex; align-items: center">
|
||||
<img :src="item.imgUrl" style="float: left; width: 20px" />
|
||||
<span style="float: left; margin-left: 5px">
|
||||
{{ item.label }}</span
|
||||
>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑器区域 -->
|
||||
<div class="editor-section">
|
||||
<div class="section-header">
|
||||
<i class="el-icon-edit-outline"></i>
|
||||
<span>富文本编辑器</span>
|
||||
<span>{{ $t('backendSystem.richTextEditor') || '富文本编辑器' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="editor-container">
|
||||
<Toolbar
|
||||
:editor="editor"
|
||||
:defaultConfig="toolbarConfig"
|
||||
:mode="mode"
|
||||
style="border-bottom: 1px solid #ccc"
|
||||
/>
|
||||
<Editor
|
||||
style="height: 600px; overflow-y: hidden"
|
||||
v-model="addParams.content"
|
||||
:defaultConfig="editorConfig"
|
||||
:mode="mode"
|
||||
@onCreated="onCreated"
|
||||
@onChange="handleEditorChange"
|
||||
/>
|
||||
<div ref="editor" style="height: 600px"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 预览文档对话框 -->
|
||||
<el-dialog
|
||||
title="文档预览"
|
||||
:title="$t('backendSystem.documentPreview') || '文档预览'"
|
||||
:visible.sync="previewVisible"
|
||||
width="80%"
|
||||
:before-close="handlePreviewClose"
|
||||
class="preview-dialog wangeditor-preview"
|
||||
>
|
||||
<div class="preview-content">
|
||||
<div v-html="addParams.content" class="dynamic-content" ></div>
|
||||
<div v-html="addParams.content" class="dynamic-content"></div>
|
||||
|
||||
<div v-if="!addParams.content" class="preview-empty">
|
||||
<i class="el-icon-document"></i>
|
||||
<p>暂无内容</p>
|
||||
<p>{{ $t('backendSystem.noContent') || '暂无内容' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="previewVisible = false">关闭</el-button>
|
||||
<el-button type="primary" @click="handlePrintPreview"
|
||||
>打印预览</el-button
|
||||
>
|
||||
<el-button @click="previewVisible = false">{{ $t('backendSystem.close') || '关闭' }}</el-button>
|
||||
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from "vue";
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
import E from "wangeditor";
|
||||
import { updateDocument } from "../../../api/documentManagement";
|
||||
|
||||
import Index from "./index";
|
||||
export default Vue.extend({
|
||||
components: { Editor, Toolbar },
|
||||
mixins: [Index],
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
html: "<p>hello</p>",
|
||||
toolbarConfig: {
|
||||
excludeKeys: [],
|
||||
insertKeys: {
|
||||
index: 0,
|
||||
keys: [
|
||||
"bold",
|
||||
"italic",
|
||||
"underline",
|
||||
"through",
|
||||
"code",
|
||||
"sub",
|
||||
"sup",
|
||||
"clearStyle",
|
||||
],
|
||||
},
|
||||
},
|
||||
editorConfig: {
|
||||
placeholder: "请在此输入文档内容...",
|
||||
MENU_CONF: {},
|
||||
},
|
||||
html: "", // 编辑器内容
|
||||
hasSetEditorContent: false, // 避免重复 set 内容
|
||||
mode: "default",
|
||||
addParams: {
|
||||
title: "",
|
||||
@@ -184,7 +193,8 @@ export default Vue.extend({
|
||||
lang: "",
|
||||
titleUrl: "",
|
||||
articleUrl: "",
|
||||
childType:""
|
||||
childType: "",
|
||||
coin: "",
|
||||
},
|
||||
lastSaveTime: "",
|
||||
autoSaveTimer: null,
|
||||
@@ -215,11 +225,10 @@ export default Vue.extend({
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
|
||||
try {
|
||||
this.TypeList = JSON.parse(localStorage.getItem("TypeList"));
|
||||
this.TypeList = this.TypeList.map((item) => ({ // 翻译label
|
||||
this.TypeList = this.TypeList.map((item) => ({
|
||||
// 翻译label
|
||||
...item,
|
||||
label: this.$t(item.label),
|
||||
children: item.children
|
||||
@@ -229,7 +238,6 @@ export default Vue.extend({
|
||||
}))
|
||||
: undefined,
|
||||
}));
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
@@ -247,12 +255,87 @@ export default Vue.extend({
|
||||
}
|
||||
}, 1500);
|
||||
|
||||
|
||||
|
||||
this.editor = new E(this.$refs.editor);
|
||||
this.editor.config.height = 600;
|
||||
this.editor.config.onchange = (html) => {
|
||||
this.html = html;
|
||||
this.addParams.content = html;
|
||||
};
|
||||
//配置颜色
|
||||
this.editor.config.colors = [
|
||||
`#651FFF`,
|
||||
`#FF4081`,
|
||||
`#FF9900`,
|
||||
`#FFC107`,
|
||||
`#FF5722`,
|
||||
`#9C27B0`,
|
||||
`#673AB7`,
|
||||
`#3F51B5`,
|
||||
"#000000", // 黑色
|
||||
"#ffffff", // 白色
|
||||
"#eeece0", // 浅米色
|
||||
"#1c487f", // 深蓝
|
||||
"#4d80bf", // 蓝色
|
||||
"#c24f4a", // 红色
|
||||
"#8baa4a", // 绿色
|
||||
"#a96b59", // 棕色
|
||||
"#2b2b2b", // 深灰
|
||||
"#b6975a", // 金色
|
||||
"#5b9bd5", // 天蓝
|
||||
"#70ad47", // 草绿
|
||||
"#ed7d31", // 橙色
|
||||
"#ffc000", // 黄色
|
||||
"#7030a0", // 紫色
|
||||
"#f4b084", // 浅橙
|
||||
"#bdd7ee", // 浅蓝
|
||||
"#a9d08e", // 浅绿
|
||||
"#ffe699", // 浅黄
|
||||
"#d9d9d9", // 浅灰
|
||||
"#f8cbad", // 浅棕
|
||||
"#e2efda", // 淡绿
|
||||
"#fff2cc", // 淡黄
|
||||
"#dbe5f1", // 淡蓝
|
||||
"#e4dfec", // 淡紫
|
||||
"#fbeee6", // 淡橙
|
||||
"#f6f6f6", // 极浅灰
|
||||
"#ff0000", // 纯红
|
||||
"#00b050", // 纯绿
|
||||
"#0070c0", // 纯蓝
|
||||
"#7030a0", // 纯紫
|
||||
"#ff9900", // 纯橙
|
||||
"#808080", // 中灰
|
||||
];
|
||||
//配置字体
|
||||
this.editor.config.fontNames = [
|
||||
// 对象形式 v4.6.16
|
||||
{name:"黑体",value:"黑体"},
|
||||
{name:"绝绝字体",value:"Times New Roman"},
|
||||
// 字符串形式
|
||||
'黑体',
|
||||
'仿宋',
|
||||
'楷体',
|
||||
'标楷体',
|
||||
'华文仿宋',
|
||||
'华文楷体',
|
||||
'宋体',
|
||||
'微软雅黑',
|
||||
'Arial',
|
||||
'Tahoma',
|
||||
'Verdana',
|
||||
'Times New Roman',
|
||||
'Courier New',
|
||||
],
|
||||
|
||||
// 不自定义菜单,使用官方默认菜单栏
|
||||
this.editor.create();
|
||||
// 只在初始化时 set 一次内容
|
||||
if (this.addParams.content && !this.hasSetEditorContent) {
|
||||
this.editor.txt.html(this.addParams.content);
|
||||
this.html = this.addParams.content;
|
||||
this.hasSetEditorContent = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
async fetchUpdateDocument(params) {
|
||||
this.setLoading("addLoading", true);
|
||||
const res = await updateDocument(params);
|
||||
@@ -263,24 +346,28 @@ export default Vue.extend({
|
||||
this.setLoading("addLoading", false);
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑器创建后回调,确保 this.editor 正确赋值
|
||||
* @param {Object} editor wangEditor 实例
|
||||
*/
|
||||
onCreated(editor) {
|
||||
this.editor = Object.seal(editor);
|
||||
this.editor = editor;
|
||||
console.log("编辑器已初始化", this.editor);
|
||||
|
||||
// 编辑器创建后,如果有恢复的内容,设置到编辑器中
|
||||
if (this.addParams.content) {
|
||||
this.$nextTick(() => {
|
||||
editor.setHtml(this.addParams.content);
|
||||
this.editor.txt.html(this.addParams.content);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
console.log(editor.getAllMenuKeys(),"Editor.getAllMenuKe就啊哈啊ys()");
|
||||
},
|
||||
|
||||
handelAddDocument() {
|
||||
if (!this.addParams.type) {
|
||||
|
||||
|
||||
if (!this.addParams.type || this.addParams.type == "0") {
|
||||
this.$message({
|
||||
message: "请填写文档类型",
|
||||
message: this.$t('backendSystem.pleaseInputType') || '请填写文档类型',
|
||||
type: "warning",
|
||||
duration: 4000,
|
||||
showClose: true,
|
||||
@@ -288,11 +375,34 @@ export default Vue.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
console.log(this.screenCurrency, "this.screenCurrency",this.addParams.type);
|
||||
|
||||
if (this.addParams.type == "1" && !this.screenCurrency) {
|
||||
this.$message({
|
||||
message:
|
||||
this.$t("backendSystem.pleaseSelectCurrency2") ||
|
||||
"添加挖矿教程,请选择币种",
|
||||
type: "warning",
|
||||
duration: 4000,
|
||||
showClose: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.addParams.content) {
|
||||
//锚点定位的A标签 去掉target="_blank"
|
||||
this.addParams.content = this.addParams.content.replace(
|
||||
/<a([^>]*href="#[^"]*")[^>]*>/gi,
|
||||
function (match) {
|
||||
return match.replace(/\s*target="_blank"/gi, "");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this.addParams.coin = this.screenCurrency
|
||||
|
||||
console.log(this.addParams.content, "this.addParams.content");
|
||||
|
||||
this.fetchUpdateDocument(this.addParams);
|
||||
},
|
||||
|
||||
@@ -312,49 +422,20 @@ export default Vue.extend({
|
||||
this.previewVisible = false;
|
||||
},
|
||||
|
||||
handlePrintPreview() {
|
||||
const printWindow = window.open("", "_blank");
|
||||
if (printWindow) {
|
||||
printWindow.document.write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>${this.addParams.title || "文档预览"}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
margin: 20px;
|
||||
}
|
||||
.preview-empty {
|
||||
text-align: center;
|
||||
padding: 50px 0;
|
||||
color: #95a5a6;
|
||||
}
|
||||
.preview-empty i {
|
||||
font-size: 40px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${
|
||||
this.addParams.content ||
|
||||
'<div class="preview-empty"><i>📄</i><p>暂无内容</p></div>'
|
||||
}
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
printWindow.print();
|
||||
printWindow.close();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
handleSave() {
|
||||
// 保存前彻底去除所有锚点链接的 target="_blank"
|
||||
this.addParams.content = this.addParams.content.replace(
|
||||
/<a([^>]*href="#([^"]*)")[^>]*>/gi,
|
||||
function (match) {
|
||||
// 去掉 target="_blank"
|
||||
return match.replace(/\s*target="_blank"/gi, "");
|
||||
}
|
||||
);
|
||||
this.manualSave();
|
||||
this.$message({
|
||||
message: "内容已保存到本地,请尽快发布,关闭页面可能丢失内容",
|
||||
message: this.$t('backendSystem.contentSaved') || '内容已保存到本地,请尽快发布,关闭页面可能丢失内容',
|
||||
type: "success",
|
||||
duration: 4000,
|
||||
showClose: true,
|
||||
@@ -373,7 +454,7 @@ export default Vue.extend({
|
||||
this.addParams.articleUrl = "";
|
||||
}
|
||||
this.addParams.type = type[0];
|
||||
this.addParams.childType= type[1];
|
||||
this.addParams.childType = type[1];
|
||||
} catch (error) {
|
||||
console.log(error, "error");
|
||||
}
|
||||
@@ -415,7 +496,7 @@ export default Vue.extend({
|
||||
try {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.addParams.content = this.editor.txt.html();
|
||||
}
|
||||
|
||||
const saveData = {
|
||||
@@ -469,7 +550,7 @@ export default Vue.extend({
|
||||
|
||||
// 如果编辑器已经创建,直接设置内容
|
||||
if (this.editor) {
|
||||
this.editor.setHtml(data.content || "");
|
||||
this.editor.txt.html(data.content || "");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -488,7 +569,7 @@ export default Vue.extend({
|
||||
manualSave() {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.addParams.content = this.editor.txt.html();
|
||||
}
|
||||
this.saveToLocalStorage();
|
||||
},
|
||||
@@ -499,7 +580,7 @@ export default Vue.extend({
|
||||
if (this.addParams.title || this.addParams.content) {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.addParams.content = this.editor.txt.html();
|
||||
}
|
||||
this.saveToLocalStorage();
|
||||
}
|
||||
@@ -509,46 +590,80 @@ export default Vue.extend({
|
||||
getDocumentTypeName(type) {
|
||||
switch (type) {
|
||||
case "1":
|
||||
return "服务条款";
|
||||
return "home.serviceTerms";//服务条款
|
||||
case "2":
|
||||
return "api文档";
|
||||
return "home.APIfile";//api文档
|
||||
case "3":
|
||||
return "挖矿教程";
|
||||
return "home.miningTutorial";//挖矿教程
|
||||
case "0":
|
||||
return "其他";
|
||||
return "home.other";//其他
|
||||
default:
|
||||
return "未知类型";
|
||||
return "home.unknownType";//未知类型
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 插入锚点(源码模式下插入HTML)
|
||||
*/
|
||||
handleInsertAnchor() {
|
||||
if (!this.editor) {
|
||||
this.$message.warning("编辑器尚未初始化");
|
||||
return;
|
||||
}
|
||||
this.$prompt(this.$t('backendSystem.pleaseInputAnchorName') || '请输入锚点名称(不能重复)', this.$t('backendSystem.insertAnchor') || '插入锚点', {
|
||||
confirmButtonText: this.$t('backendSystem.confirm') || '确定',
|
||||
cancelButtonText: this.$t('backendSystem.cancel') || '取消',
|
||||
inputPattern: /^[a-zA-Z0-9_-]+$/,
|
||||
inputErrorMessage: this.$t('backendSystem.anchorNameErrorMessage') || '锚点名只能包含字母、数字、下划线和中划线',
|
||||
})
|
||||
.then(({ value }) => {
|
||||
this.editor.cmd.do("insertHTML", `<span id="${value}"></span>`);
|
||||
this.html = this.editor.txt.html();
|
||||
this.addParams.content = this.html;
|
||||
this.$message.success(this.$t('backendSystem.anchorInserted') || '锚点已插入');
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
|
||||
/**
|
||||
* 给选中的标题添加id属性作为锚点
|
||||
*/
|
||||
handleAddHeadingId() {
|
||||
if (!this.editor) {
|
||||
this.$message.warning("编辑器尚未初始化");
|
||||
return;
|
||||
}
|
||||
// 获取当前选中的标题节点
|
||||
const headers = this.editor.getElemsByTypePrefix("header");
|
||||
if (!headers || headers.length === 0) {
|
||||
this.$message.warning(this.$t('backendSystem.pleaseSelectHeader') || '请先选中一个标题(h1~h6)');
|
||||
return;
|
||||
}
|
||||
const node = headers[0];
|
||||
this.$prompt(this.$t('backendSystem.pleaseInputAnchorID') || '请输入锚点ID(不能重复)', this.$t('backendSystem.titleAnchor') || '标题锚点', {
|
||||
confirmButtonText: this.$t('backendSystem.confirm') || '确定',
|
||||
cancelButtonText: this.$t('backendSystem.cancel') || '取消',
|
||||
inputPattern: /^[a-zA-Z0-9_-]+$/,
|
||||
inputErrorMessage: this.$t('backendSystem.anchorIDErrorMessage') || 'ID只能包含字母、数字、下划线和中划线',
|
||||
})
|
||||
.then(({ value }) => {
|
||||
this.editor.setElemAttribute(node, "id", value);
|
||||
this.$message.success(this.$t('backendSystem.anchorIDAdded') || '锚点ID已添加');
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.editor.destroy();
|
||||
}
|
||||
this.saveToLocalStorage();
|
||||
|
||||
// 移除事件监听器
|
||||
window.removeEventListener("beforeunload", this.handleBeforeUnload);
|
||||
|
||||
if (this.autoSaveTimer) {
|
||||
clearTimeout(this.autoSaveTimer);
|
||||
}
|
||||
|
||||
const editor = this.editor;
|
||||
if (editor == null) return;
|
||||
editor.destroy();
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
|
||||
beforeRouteLeave(to, from, next) {
|
||||
// 确保获取最新的编辑器内容
|
||||
if (this.editor) {
|
||||
this.addParams.content = this.editor.getHtml();
|
||||
this.addParams.content = this.editor.txt.html();
|
||||
}
|
||||
this.saveToLocalStorage();
|
||||
next();
|
||||
@@ -565,6 +680,7 @@ export default Vue.extend({
|
||||
background: #f8f9fa;
|
||||
min-height: 60vh;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
/* 页面头部样式 */
|
||||
@@ -703,12 +819,20 @@ export default Vue.extend({
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
min-height: 650px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* 设置编辑器高度 */
|
||||
.editor-container .w-e-text-container {
|
||||
::v-deep .editor-container .w-e-text-container {
|
||||
height: 600px !important;
|
||||
min-height: 600px !important;
|
||||
z-index: 1 !important;
|
||||
position: relative;
|
||||
}
|
||||
::v-deep .w-e-toolbar {
|
||||
z-index: 10 !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 编辑器内容区域样式 */
|
||||
@@ -751,6 +875,7 @@ export default Vue.extend({
|
||||
padding: 20px;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.preview-dialog .el-dialog__header {
|
||||
@@ -877,42 +1002,44 @@ export default Vue.extend({
|
||||
|
||||
/* -------富文本样式-------------- */
|
||||
.dynamic-content {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
:deep(th), :deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #f3f4f6;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong), :deep(b) {
|
||||
font-weight: bold !important;
|
||||
color: inherit !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
:deep(em), :deep(i) {
|
||||
font-style: italic !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #007bff !important;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
}
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
:deep(th),
|
||||
:deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #f3f4f6;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong),
|
||||
:deep(b) {
|
||||
font-weight: bold !important;
|
||||
color: inherit !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
:deep(em),
|
||||
:deep(i) {
|
||||
font-style: italic !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #007bff !important;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style src="@wangeditor/editor/dist/css/style.css"></style>
|
||||
}
|
||||
}
|
||||
.no-scroll {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
</style>
|
||||
@@ -114,11 +114,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||
import { addDocument } from '../api/documentManagement'
|
||||
import Vue from "vue";
|
||||
import E from "wangeditor";
|
||||
import { addDocument } from '../api/documentManagement'
|
||||
|
||||
export default Vue.extend({
|
||||
export default Vue.extend({
|
||||
components: { Editor, Toolbar },
|
||||
data() {
|
||||
return {
|
||||
@@ -757,6 +757,4 @@
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style src="@wangeditor/editor/dist/css/style.css"></style>
|
||||
</style>
|
||||
@@ -10,17 +10,17 @@ export default{
|
||||
selectedLanguage: 'zh',
|
||||
/** 分类按钮数据 */
|
||||
categories: [
|
||||
{ id: 1, name: 'API文档', route: 'apiFile' },
|
||||
{ id: 2, name: '挖矿教程', route: 'AccessMiningPool/nexaAccess' },
|
||||
{ id: 3, name: '服务条款', route: 'ServiceTerms' },
|
||||
{ id: 4, name: '费率', route: 'rate' },
|
||||
{ id: 5, name: '公告中心', route: 'announcements' },
|
||||
{ id: 6, name: '常见问题', route: 'commonProblem' },
|
||||
{ id: 1, name: 'home.APIfile', route: 'apiFile' },//API文档
|
||||
{ id: 2, name: 'home.miningTutorial', route: 'AccessMiningPool/nexaAccess' },//挖矿教程
|
||||
{ id: 3, name: 'home.serviceTerms', route: 'ServiceTerms' },//服务条款
|
||||
{ id: 4, name: 'home.rate', route: 'rate' },//费率
|
||||
{ id: 5, name: 'home.announcements', route: 'announcements' },//公告中心
|
||||
{ id: 6, name: 'home.commonProblem', route: 'commonProblem' },//常见问题
|
||||
|
||||
],
|
||||
/** 推荐内容数据 */
|
||||
recommendedItems: [
|
||||
{ id: 1, description: '矿池分配及转账规则' ,route:"allocationExplanation"},
|
||||
{ id: 1, description: 'home.allocationExplanation' ,route:"allocationExplanation"},//矿池分配及转账规则
|
||||
// { id: 2, description: '余额不足如何任何偿还,该如何规划运营?' },
|
||||
// { id: 3, description: '矿池选择它已经拥有综合的优势时间,怎么办?' }
|
||||
],
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
placeholder="搜索"
|
||||
:placeholder="$t('backendSystem.search') || '搜索'"
|
||||
class="search-input"
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
@@ -32,13 +32,13 @@
|
||||
@keydown.enter="handleCategoryClick(category)"
|
||||
tabindex="0"
|
||||
>
|
||||
{{ category.name }}
|
||||
{{ $t(category.name )}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 推荐内容区域 -->
|
||||
<div class="recommended-section">
|
||||
<h3 class="section-title">推荐的内容</h3>
|
||||
<h3 class="section-title">{{ $t('backendSystem.recommendContent') || '推荐的内容' }}</h3>
|
||||
<div class="recommended-items">
|
||||
<div
|
||||
v-for="item in recommendedItems"
|
||||
@@ -46,14 +46,14 @@
|
||||
class="recommended-item"
|
||||
@click="handleCategoryClick(item)"
|
||||
>
|
||||
<p class="item-description" >{{ item.description }}</p>
|
||||
<p class="item-description" >{{ $t(item.description) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最近活动区域 -->
|
||||
<div class="recent-activities">
|
||||
<h3 class="section-title">最近的活动</h3>
|
||||
<h3 class="section-title">{{ $t('backendSystem.recentActivities') || '最近活动' }}</h3>
|
||||
<div class="activities-list">
|
||||
<div
|
||||
v-for="activity in activities"
|
||||
@@ -75,7 +75,7 @@
|
||||
<!-- 查看更多链接 -->
|
||||
<div class="view-more">
|
||||
<a href="#" class="view-more-link" @click="handleViewMore">
|
||||
查看更多活动公告
|
||||
{{ $t('backendSystem.viewMore') || '查看更多活动公告' }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1569,7 +1569,7 @@ export default {
|
||||
// 使用 name 进行导航,避免重复的路由参数
|
||||
this.$router.push({
|
||||
path:url,
|
||||
params: {
|
||||
query: {
|
||||
lang: this.lang,
|
||||
coin: this.params.coin,
|
||||
imgUrl: this.currencyPath
|
||||
|
||||
@@ -257,6 +257,133 @@ export default {
|
||||
countDownTime: 60,
|
||||
timer: null,
|
||||
lang: "en",
|
||||
currencyList: [
|
||||
{
|
||||
path: "nexaAccess",
|
||||
value: "nexa",
|
||||
label: "nexa",
|
||||
img: require("../../assets/img/currency-nexa.png"),
|
||||
imgUrl: `${this.$baseApi}img/nexa.png`,
|
||||
name: "course.NEXAcourse",
|
||||
show: true,
|
||||
amount: 10000,
|
||||
|
||||
},
|
||||
{
|
||||
path: "grsAccess",
|
||||
value: "grs",
|
||||
label: "grs",
|
||||
img: require("../../assets/img/currency/grs.svg"),
|
||||
imgUrl: `${this.$baseApi}img/grs.svg`,
|
||||
name: "course.GRScourse",
|
||||
show: true,
|
||||
amount: 1,
|
||||
|
||||
},
|
||||
{
|
||||
path: "monaAccess",
|
||||
value: "mona",
|
||||
label: "mona",
|
||||
img: require("../../assets/img/currency/mona.svg"),
|
||||
imgUrl: `${this.$baseApi}img/mona.svg`,
|
||||
name: "course.MONAcourse",
|
||||
show: true,
|
||||
amount: 1,
|
||||
|
||||
},
|
||||
{
|
||||
path: "dgbsAccess",
|
||||
value: "dgbs",
|
||||
// label: "dgb-skein-pool1",
|
||||
label: "dgb(skein)",
|
||||
img: require("../../assets/img/currency/DGB.svg"),
|
||||
imgUrl: `${this.$baseApi}img/dgb.svg`,
|
||||
name: "course.dgbsCourse",
|
||||
show: true,
|
||||
amount: 1,
|
||||
},
|
||||
{
|
||||
path: "dgbqAccess",
|
||||
value: "dgbq",
|
||||
// label: "dgb(qubit-pool1)",
|
||||
label: "dgb(qubit)",
|
||||
img: require("../../assets/img/currency/DGB.svg"),
|
||||
imgUrl: `${this.$baseApi}img/dgb.svg`,
|
||||
name: "course.dgbqCourse",
|
||||
show: true,
|
||||
amount: 1,
|
||||
},
|
||||
{
|
||||
path: "dgboAccess",
|
||||
value: "dgbo",
|
||||
// label: "dgb-odocrypt-pool1",
|
||||
label: "dgb(odocrypt)",
|
||||
img: require("../../assets/img/currency/DGB.svg"),
|
||||
imgUrl: `${this.$baseApi}img/dgb.svg`,
|
||||
name: "course.dgboCourse",
|
||||
show: true,
|
||||
amount: 1,
|
||||
},
|
||||
{
|
||||
path: "rxdAccess",
|
||||
value: "rxd",
|
||||
label: "radiant(rxd)",
|
||||
img: require("../../assets/img/currency/rxd.png"),
|
||||
imgUrl: `${this.$baseApi}img/rxd.png`,
|
||||
name: "course.RXDcourse",
|
||||
show: true,
|
||||
amount: 100,
|
||||
|
||||
},
|
||||
{
|
||||
path: "enxAccess",
|
||||
value: "enx",
|
||||
label: "Entropyx(enx)",
|
||||
img: require("../../assets/img/currency/enx.svg"),
|
||||
imgUrl: `${this.$baseApi}img/enx.svg`,
|
||||
name: "course.ENXcourse",
|
||||
show: true,
|
||||
amount: 5000,
|
||||
|
||||
},
|
||||
{
|
||||
path: "alphminingPool",
|
||||
value: "alph",
|
||||
label: "alephium",
|
||||
img: require("../../assets/img/currency/alph.svg"),
|
||||
imgUrl: `${this.$baseApi}img/alph.svg`,
|
||||
name: "course.alphCourse",
|
||||
show: true,
|
||||
amount: 1,
|
||||
|
||||
},
|
||||
|
||||
// { //告知已删除此币种 Radiant
|
||||
// value: "dgb2_odo",
|
||||
// label: "dgb-odocrypt-pool2",
|
||||
// img: require("../../assets/img/currency/DGB.svg"),
|
||||
// imgUrl: "https://s2.coinmarketcap.com/static/img/coins/64x64/109.png",
|
||||
// },
|
||||
// {
|
||||
// value: "dgb_qubit_a10",
|
||||
// label: "dgb-qubit-pool2",
|
||||
// img: require("../../assets/img/currency/DGB.svg"),
|
||||
// imgUrl: "https://s2.coinmarketcap.com/static/img/coins/64x64/109.png",
|
||||
// },
|
||||
// {
|
||||
// value: "dgb_skein_a10",
|
||||
// label: "dgb-skein-pool2",
|
||||
// img: require("../../assets/img/currency/DGB.svg"),
|
||||
// imgUrl: "https://s2.coinmarketcap.com/static/img/coins/64x64/109.png",
|
||||
// },
|
||||
// {
|
||||
// value: "dgb_odo_b20",
|
||||
// label: "dgb-odoscrypt-pool3",
|
||||
// img: require("../../assets/img/currency/DGB.svg"),
|
||||
// imgUrl: "https://s2.coinmarketcap.com/static/img/coins/64x64/109.png",
|
||||
// },
|
||||
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
@@ -300,6 +427,7 @@ export default {
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
this.$addStorageEvent(1, `currencyList`, JSON.stringify(this.currencyList))
|
||||
// this.lang = this.$i18n.locale; // 初始化语言值
|
||||
// this.radio = localStorage.getItem("lang")
|
||||
// ? localStorage.getItem("lang")
|
||||
|
||||
@@ -93,15 +93,48 @@ export default {
|
||||
DetailsParams:{
|
||||
lang:this.$i18n.locale,
|
||||
childType:2,//1服务条款、2费率、3API文档 childType
|
||||
id:'',
|
||||
},
|
||||
info:"",
|
||||
rateLoading:false
|
||||
rateLoading:false,
|
||||
|
||||
listParams:{
|
||||
// type:"1",//挖矿教程
|
||||
lang:this.$i18n.locale,
|
||||
pageNum:1,
|
||||
pageSize:50,
|
||||
childType:2,//1服务条款、2费率、3API文档 childType
|
||||
},
|
||||
navList:[],
|
||||
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.fetchProblemDetails(this.DetailsParams)
|
||||
this.fetchAllList(this.listParams)
|
||||
// this.fetchProblemDetails(this.DetailsParams)
|
||||
},
|
||||
methods:{
|
||||
async fetchAllList(params){
|
||||
this.setLoading('rateLoading', true);
|
||||
const res = await documentsList(params)
|
||||
console.log(res,"res");
|
||||
|
||||
if (res && res.code === 200) {
|
||||
this.navList = res.rows
|
||||
|
||||
if (this.$route.query.id) {
|
||||
this.DetailsParams.id = this.$route.query.id
|
||||
|
||||
}else{
|
||||
this.DetailsParams.id = res.rows[0].id;
|
||||
}
|
||||
if (this.DetailsParams.id) {
|
||||
this.fetchProblemDetails(this.DetailsParams)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
async fetchProblemDetails(params) {
|
||||
this.setLoading('rateLoading', true);
|
||||
const res = await findDataInfo(params)
|
||||
@@ -112,5 +145,16 @@ export default {
|
||||
}
|
||||
this.setLoading('rateLoading', false);
|
||||
},
|
||||
|
||||
|
||||
clickJump(item) {
|
||||
|
||||
this.DetailsParams.id = item.id
|
||||
this.fetchProblemDetails(this.DetailsParams)
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -57,8 +57,12 @@
|
||||
<section class="rateBox" v-else>
|
||||
|
||||
<section class="leftMenu">
|
||||
<ul>
|
||||
<!-- <ul>
|
||||
<li>{{$t(`course.rateRelated`)}}</li>
|
||||
</ul> -->
|
||||
|
||||
<ul>
|
||||
<li v-for="item in navList" :class="{navActive:String(item.id) === String(DetailsParams.id)}" :key="item.id" @click="clickJump(item)">{{item.title}}</li>
|
||||
</ul>
|
||||
|
||||
</section>
|
||||
@@ -66,11 +70,11 @@
|
||||
|
||||
<section class="rightContent">
|
||||
<div v-if="rateLoading" class="loading-container">
|
||||
<span class="loading-text">正在加载内容...</span>
|
||||
<span class="loading-text">{{ $t('home.loadingContent') || '正在加载内容...' }}</span>
|
||||
</div>
|
||||
<div v-else-if="info && info.trim()" class="dynamic-content" v-html="info"></div>
|
||||
<div v-else class="no-content">
|
||||
<p>暂无内容</p>
|
||||
<p>{{ $t('home.noContent') || '暂无内容' }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -242,6 +246,7 @@ export default {
|
||||
font-size: 0.9rem;
|
||||
|
||||
}
|
||||
|
||||
.rateBox{
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
@@ -265,11 +270,11 @@ export default {
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
ul{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
li{
|
||||
width: 100%;
|
||||
list-style: none;
|
||||
min-height: 40PX;
|
||||
display: flex;
|
||||
@@ -283,9 +288,14 @@ export default {
|
||||
padding:8px 8px;
|
||||
font-size: 0.9rem;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
background: #D2C3EA;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rightText{
|
||||
box-sizing: border-box;
|
||||
width: 80%;
|
||||
@@ -368,42 +378,50 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.dynamic-content {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.7;
|
||||
color: #222;
|
||||
// 富文本样式
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
||||
// 富文本样式
|
||||
:deep(table) {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 16px 0;
|
||||
}
|
||||
:deep(th), :deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #f3f4f6;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong), :deep(b) {
|
||||
font-weight: bold !important;
|
||||
color: inherit !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
:deep(em), :deep(i) {
|
||||
font-style: italic !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #007bff !important;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
:deep(th), :deep(td) {
|
||||
border: 1px solid #d1d5db;
|
||||
padding: 8px 8px;
|
||||
text-align: left;
|
||||
}
|
||||
:deep(th) {
|
||||
background: #D2C3EA;
|
||||
font-weight: bold;
|
||||
}
|
||||
:deep(strong), :deep(b) {
|
||||
font-weight: bold !important;
|
||||
color: inherit !important;
|
||||
font-style: normal !important;
|
||||
}
|
||||
:deep(em), :deep(i) {
|
||||
font-style: italic !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
:deep(a) {
|
||||
color: #661FFB !important;
|
||||
text-decoration: none !important;
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.navActive{
|
||||
background: #AC85E0 !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,851 +0,0 @@
|
||||
<template>
|
||||
<div class="rich-text-editor-page">
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1 class="page-title">
|
||||
<i class="el-icon-edit-outline"></i>
|
||||
富文本文档编辑器
|
||||
</h1>
|
||||
<p class="page-subtitle">使用富文本编辑器创建和管理文档,支持文本格式化、链接、列表等功能</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<el-button @click="previewDocument" icon="el-icon-view" size="small" type="primary">预览文档</el-button>
|
||||
<el-button @click="saveDocument" :loading="saveLoading" icon="el-icon-document" size="small" type="success">保存文档</el-button>
|
||||
<el-button @click="publishDocument" :loading="publishLoading" icon="el-icon-upload" size="small" type="warning">发布文档</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文档配置区域 -->
|
||||
<el-card class="document-config" shadow="never">
|
||||
<div slot="header">
|
||||
<span><i class="el-icon-setting"></i> 文档配置</span>
|
||||
</div>
|
||||
|
||||
<el-form :model="documentForm" label-width="100px" class="config-form">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="文档标题" required>
|
||||
<el-input v-model="documentForm.title" placeholder="请输入文档标题" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="文档类型" required>
|
||||
<el-select v-model="documentForm.type" placeholder="请选择文档类型" style="width: 100%">
|
||||
<el-option label="服务条款" value="1" />
|
||||
<el-option label="API文档" value="2" />
|
||||
<el-option label="挖矿教程" value="3" />
|
||||
<el-option label="其他" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="文档状态">
|
||||
<el-tag :type="documentForm.status === 'published' ? 'success' : 'info'">
|
||||
{{ documentForm.status === 'published' ? '已发布' : '草稿' }}
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- TinyMCE编辑器区域 -->
|
||||
<el-card class="editor-container" shadow="never">
|
||||
<div slot="header">
|
||||
<span><i class="el-icon-edit"></i> Quill文本编辑器</span>
|
||||
</div>
|
||||
|
||||
<!-- Quill编辑器 -->
|
||||
<div class="quill-wrapper">
|
||||
<quill-editor
|
||||
ref="quillEditor"
|
||||
v-model="documentForm.content"
|
||||
:options="quillConfig"
|
||||
@blur="onEditorBlur($event)"
|
||||
@focus="onEditorFocus($event)"
|
||||
@ready="onEditorReady($event)"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 使用指南 -->
|
||||
<el-card class="usage-guide" shadow="never">
|
||||
<div slot="header">
|
||||
<span><i class="el-icon-question"></i> 使用指南</span>
|
||||
</div>
|
||||
|
||||
<el-collapse v-model="activeGuide" accordion>
|
||||
<el-collapse-item title="📝 基本操作指南" name="basic">
|
||||
<div class="guide-content">
|
||||
<h4>工具栏功能说明:</h4>
|
||||
<ul>
|
||||
<li><strong>文字格式:</strong>粗体、斜体、下划线、删除线</li>
|
||||
<li><strong>字体颜色:</strong>选中文字后点击颜色按钮,选择文字颜色</li>
|
||||
<li><strong>背景颜色:</strong>选中文字后点击背景色按钮,设置文字背景色</li>
|
||||
<li><strong>字体大小:</strong>选择小号、正常、大号、超大字体</li>
|
||||
<li><strong>文本对齐:</strong>设置段落的左对齐、居中、右对齐</li>
|
||||
<li><strong>有序/无序列表:</strong>创建编号列表或项目符号列表,圆点会紧靠文字显示</li>
|
||||
<li><strong>链接:</strong>选中文字后点击链接按钮,输入网址创建超链接</li>
|
||||
<li><strong>标题:</strong>选择不同级别的标题格式</li>
|
||||
<li><strong>代码块:</strong>插入代码片段</li>
|
||||
<li><strong>清除格式:</strong>移除选中文字的所有格式</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item title="💾 文档管理" name="document">
|
||||
<div class="guide-content">
|
||||
<h4>文档配置:</h4>
|
||||
<ul>
|
||||
<li><strong>文档标题:</strong>必填项,为您的文档起一个有意义的标题</li>
|
||||
<li><strong>文档类型:</strong>选择合适的文档类型(服务条款、API文档、挖矿教程等)</li>
|
||||
<li><strong>文档状态:</strong>显示当前文档是草稿还是已发布状态</li>
|
||||
</ul>
|
||||
|
||||
<h4>保存和发布:</h4>
|
||||
<ul>
|
||||
<li><strong>保存文档:</strong>将文档保存为草稿,可以稍后继续编辑</li>
|
||||
<li><strong>发布文档:</strong>正式发布文档,用户可以查看</li>
|
||||
<li><strong>预览文档:</strong>在发布前查看文档的最终效果</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item title="🔧 使用技巧" name="tips">
|
||||
<div class="guide-content">
|
||||
<h4>编辑技巧:</h4>
|
||||
<ul>
|
||||
<li><strong>快速格式化:</strong>选中文字后直接点击工具栏按钮</li>
|
||||
<li><strong>颜色设置:</strong>先选中文字,再点击颜色按钮选择颜色</li>
|
||||
<li><strong>段落格式:</strong>光标在段落中时,点击标题按钮可设置整个段落</li>
|
||||
<li><strong>段落缩进:</strong>使用工具栏的缩进按钮或Tab键进行段落缩进,空格缩进在预览时可能不显示</li>
|
||||
<li><strong>列表嵌套:</strong>在列表项中按Tab键可以创建子列表</li>
|
||||
<li><strong>列表格式:</strong>无序列表的圆点现在会紧靠文字第一个字显示,编辑器和预览保持一致</li>
|
||||
<li><strong>链接编辑:</strong>点击已有链接可以修改链接地址</li>
|
||||
<li><strong>代码块:</strong>适合插入代码示例或技术文档</li>
|
||||
<li><strong>组合格式:</strong>可以同时使用多种格式(如红色粗体字)</li>
|
||||
<li><strong>空格保持:</strong>现在预览功能已优化,能正确显示文本前的空格缩进</li>
|
||||
</ul>
|
||||
|
||||
<h4>注意事项:</h4>
|
||||
<ul>
|
||||
<li>发布前建议先使用预览功能检查文档效果</li>
|
||||
<li>文档标题和类型是必填项,发布时会进行验证</li>
|
||||
<li>定期保存草稿以防止内容丢失</li>
|
||||
<li>使用适当的标题层级可以让文档结构更清晰</li>
|
||||
<li><strong>颜色使用建议:</strong>适度使用颜色,避免过多颜色影响阅读</li>
|
||||
<li><strong>对比度:</strong>确保文字颜色与背景有足够对比度,便于阅读</li>
|
||||
<li><strong>内容一致性:</strong>系统已优化,确保编辑器、预览、保存后显示的效果完全一致</li>
|
||||
<li><strong>空格缩进:</strong>现在完美支持空格缩进,编辑器中的空格会在预览和最终显示中保持</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item title="⌨️ 快捷键" name="shortcuts">
|
||||
<div class="guide-content">
|
||||
<h4>常用快捷键:</h4>
|
||||
<div class="shortcut-list">
|
||||
<div class="shortcut-item">
|
||||
<span class="shortcut-key">Ctrl + B</span>
|
||||
<span class="shortcut-desc">粗体</span>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<span class="shortcut-key">Ctrl + I</span>
|
||||
<span class="shortcut-desc">斜体</span>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<span class="shortcut-key">Ctrl + U</span>
|
||||
<span class="shortcut-desc">下划线</span>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<span class="shortcut-key">Ctrl + K</span>
|
||||
<span class="shortcut-desc">插入链接</span>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<span class="shortcut-key">Ctrl + Z</span>
|
||||
<span class="shortcut-desc">撤销</span>
|
||||
</div>
|
||||
<div class="shortcut-item">
|
||||
<span class="shortcut-key">Ctrl + Y</span>
|
||||
<span class="shortcut-desc">重做</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-card>
|
||||
|
||||
<!-- 预览对话框 -->
|
||||
<el-dialog
|
||||
title="文档预览"
|
||||
:visible.sync="previewVisible"
|
||||
width="80%"
|
||||
top="5vh"
|
||||
class="preview-dialog"
|
||||
>
|
||||
<div class="preview-content content-display" v-html="getPreviewContent()"></div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="previewVisible = false">关闭预览</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { quillEditor } from 'vue-quill-editor'
|
||||
import 'quill/dist/quill.core.css'
|
||||
import 'quill/dist/quill.snow.css'
|
||||
import 'quill/dist/quill.bubble.css'
|
||||
import { addDocument } from '../api/documentManagement'
|
||||
|
||||
export default {
|
||||
name: 'QuillEditor',
|
||||
components: {
|
||||
quillEditor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 文档表单数据
|
||||
documentForm: {
|
||||
title: '',
|
||||
type: '',
|
||||
content: '',
|
||||
status: 'draft'
|
||||
},
|
||||
|
||||
// 加载状态
|
||||
saveLoading: false,
|
||||
publishLoading: false,
|
||||
|
||||
// 预览对话框
|
||||
previewVisible: false,
|
||||
|
||||
// 使用指南折叠面板
|
||||
activeGuide: '',
|
||||
|
||||
// Quill编辑器配置 - 包含颜色功能
|
||||
quillConfig: {
|
||||
theme: 'snow',
|
||||
placeholder: '请在此输入文档内容...',
|
||||
modules: {
|
||||
toolbar: [
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ 'color': [] }, { 'background': [] }], // 字体颜色和背景颜色
|
||||
[{ 'align': [] }],
|
||||
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
||||
['link'],
|
||||
[{ 'header': [1, 2, 3, false] }],
|
||||
[{ 'size': ['small', false, 'large', 'huge'] }], // 字体大小
|
||||
['code-block'],
|
||||
['clean']
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 编辑器准备就绪
|
||||
*/
|
||||
onEditorReady(quill) {
|
||||
console.log('编辑器已准备就绪:', quill)
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑器获取焦点
|
||||
*/
|
||||
onEditorFocus(quill) {
|
||||
console.log('编辑器获取焦点:', quill)
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑器失去焦点
|
||||
*/
|
||||
onEditorBlur(quill) {
|
||||
console.log('编辑器失去焦点:', quill)
|
||||
// 确保内容一致性
|
||||
this.normalizeContent()
|
||||
},
|
||||
|
||||
/**
|
||||
* 规范化内容 - 确保编辑器、预览、后端传输内容一致
|
||||
*/
|
||||
normalizeContent() {
|
||||
if (this.documentForm.content) {
|
||||
// 统一空格和换行处理
|
||||
let normalizedContent = this.documentForm.content
|
||||
|
||||
// 确保HTML标签正确闭合
|
||||
normalizedContent = this.ensureProperHTMLStructure(normalizedContent)
|
||||
|
||||
// 更新绑定的内容
|
||||
this.documentForm.content = normalizedContent
|
||||
|
||||
console.log('内容规范化完成:', {
|
||||
original: this.documentForm.content.substring(0, 100),
|
||||
normalized: normalizedContent.substring(0, 100)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 确保HTML结构正确
|
||||
*/
|
||||
ensureProperHTMLStructure(content) {
|
||||
// 创建临时DOM元素来规范化HTML
|
||||
const tempDiv = document.createElement('div')
|
||||
tempDiv.innerHTML = content
|
||||
|
||||
// 返回规范化后的HTML
|
||||
return tempDiv.innerHTML
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取用于传输的内容(确保与预览一致)
|
||||
*/
|
||||
getContentForTransfer() {
|
||||
// 先规范化内容
|
||||
this.normalizeContent()
|
||||
|
||||
// 返回最终要传给后端的内容
|
||||
return this.documentForm.content
|
||||
},
|
||||
|
||||
/**
|
||||
* 预览文档
|
||||
*/
|
||||
previewDocument() {
|
||||
if (!this.documentForm.content.trim()) {
|
||||
this.$message.warning('文档内容为空')
|
||||
return
|
||||
}
|
||||
|
||||
// 确保预览使用规范化的内容
|
||||
this.normalizeContent()
|
||||
|
||||
console.log('预览文档:', {
|
||||
contentLength: this.documentForm.content.length,
|
||||
contentPreview: this.documentForm.content.substring(0, 200)
|
||||
})
|
||||
|
||||
this.previewVisible = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取用于预览的内容(确保与后端传输一致)
|
||||
*/
|
||||
getPreviewContent() {
|
||||
// 返回规范化的内容用于预览
|
||||
return this.getContentForTransfer()
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存文档
|
||||
*/
|
||||
async saveDocument() {
|
||||
if (!this.documentForm.title.trim()) {
|
||||
this.$message.warning('请输入文档标题')
|
||||
return
|
||||
}
|
||||
|
||||
this.saveLoading = true
|
||||
|
||||
try {
|
||||
// 获取规范化的内容
|
||||
const normalizedContent = this.getContentForTransfer()
|
||||
|
||||
const documentData = {
|
||||
title: this.documentForm.title,
|
||||
content: normalizedContent,
|
||||
type: this.documentForm.type || '0',
|
||||
lang: this.$i18n?.locale || 'zh',
|
||||
isDraft: true
|
||||
}
|
||||
|
||||
console.log('保存文档数据:', {
|
||||
title: documentData.title,
|
||||
contentLength: documentData.content.length,
|
||||
contentPreview: documentData.content.substring(0, 200)
|
||||
})
|
||||
|
||||
const response = await addDocument(documentData)
|
||||
|
||||
if (response && response.code === 200) {
|
||||
this.$message.success('文档保存成功')
|
||||
this.documentForm.status = 'draft'
|
||||
} else {
|
||||
throw new Error(response?.message || '保存失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存文档失败:', error)
|
||||
this.$message.error('保存失败: ' + (error.message || '未知错误'))
|
||||
} finally {
|
||||
this.saveLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 发布文档
|
||||
*/
|
||||
async publishDocument() {
|
||||
if (!this.documentForm.title.trim()) {
|
||||
this.$message.warning('请输入文档标题')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.documentForm.content.trim()) {
|
||||
this.$message.warning('请输入文档内容')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.documentForm.type) {
|
||||
this.$message.warning('请选择文档类型')
|
||||
return
|
||||
}
|
||||
|
||||
this.publishLoading = true
|
||||
|
||||
try {
|
||||
// 获取规范化的内容
|
||||
const normalizedContent = this.getContentForTransfer()
|
||||
|
||||
const documentData = {
|
||||
title: this.documentForm.title,
|
||||
content: normalizedContent,
|
||||
type: this.documentForm.type,
|
||||
lang: this.$i18n?.locale || 'zh',
|
||||
isDraft: false
|
||||
}
|
||||
|
||||
console.log('发布文档数据:', {
|
||||
title: documentData.title,
|
||||
contentLength: documentData.content.length,
|
||||
contentPreview: documentData.content.substring(0, 200),
|
||||
hasIndentation: documentData.content.includes(' '), // 检查是否包含缩进
|
||||
hasNbsp: documentData.content.includes(' ') // 检查是否包含不间断空格
|
||||
})
|
||||
|
||||
const response = await addDocument(documentData)
|
||||
|
||||
if (response && response.code === 200) {
|
||||
this.$message.success('文档发布成功')
|
||||
this.documentForm.status = 'published'
|
||||
|
||||
this.$notify({
|
||||
title: '发布成功',
|
||||
message: `文档 "${this.documentForm.title}" 已成功发布`,
|
||||
type: 'success',
|
||||
duration: 3000
|
||||
})
|
||||
} else {
|
||||
throw new Error(response?.message || '发布失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发布文档失败:', error)
|
||||
this.$message.error('发布失败: ' + (error.message || '未知错误'))
|
||||
} finally {
|
||||
this.publishLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rich-text-editor-page {
|
||||
padding: 20px;
|
||||
background: #f5f7fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 页面头部 */
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0 0 8px 0;
|
||||
color: #2c3e50;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
i {
|
||||
color: #5721E4;
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
margin: 0;
|
||||
color: #7f8c8d;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* 文档配置 */
|
||||
.document-config {
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-card__header) {
|
||||
background: #f8f9fa;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
|
||||
i {
|
||||
color: #5721E4;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.config-form {
|
||||
.el-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 编辑器容器 */
|
||||
.editor-container {
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-card__header) {
|
||||
background: #f8f9fa;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
|
||||
i {
|
||||
color: #5721E4;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.quill-wrapper {
|
||||
:deep(.ql-editor) {
|
||||
min-height: 400px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap; /* 保持编辑器中的空格 */
|
||||
}
|
||||
|
||||
/* 编辑器中的列表样式 - 确保圆点显示正确 */
|
||||
:deep(.ql-editor ul) {
|
||||
padding-left: 0 !important;
|
||||
list-style-position: inside !important;
|
||||
}
|
||||
|
||||
:deep(.ql-editor ol) {
|
||||
padding-left: 0 !important;
|
||||
list-style-position: inside !important;
|
||||
}
|
||||
|
||||
:deep(.ql-editor li) {
|
||||
padding-left: 0 !important;
|
||||
text-indent: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.ql-toolbar) {
|
||||
border-top: 1px solid #e0e0e0;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
:deep(.ql-container) {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
border-left: 1px solid #e0e0e0;
|
||||
border-right: 1px solid #e0e0e0;
|
||||
border-radius: 0 0 6px 6px;
|
||||
}
|
||||
|
||||
:deep(.ql-toolbar) {
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 使用指南 */
|
||||
.usage-guide {
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-card__header) {
|
||||
background: #f8f9fa;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
|
||||
i {
|
||||
color: #5721E4;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.guide-content {
|
||||
padding: 16px 0;
|
||||
|
||||
h4 {
|
||||
color: #2c3e50;
|
||||
margin-top: 0;
|
||||
margin-bottom: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
|
||||
li {
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.6;
|
||||
color: #555;
|
||||
|
||||
strong {
|
||||
color: #2c3e50;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.shortcut-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e0e0e0;
|
||||
|
||||
.shortcut-key {
|
||||
font-family: 'Monaco', 'Consolas', monospace;
|
||||
background: #2c3e50;
|
||||
color: white;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.shortcut-desc {
|
||||
color: #555;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.usage-guide .el-collapse) {
|
||||
border: none;
|
||||
|
||||
.el-collapse-item__header {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
padding: 0 16px;
|
||||
font-weight: 500;
|
||||
color: #2c3e50;
|
||||
|
||||
&:hover {
|
||||
background: #e9ecef;
|
||||
}
|
||||
}
|
||||
|
||||
.el-collapse-item__content {
|
||||
padding: 0 16px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-collapse-item__wrap {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* 统一的内容显示样式 - 确保编辑器、预览、后端显示一致 */
|
||||
.content-display {
|
||||
/* 核心样式 - 确保空格和格式保持 */
|
||||
white-space: pre-wrap !important; /* 保持空格和换行 */
|
||||
word-wrap: break-word !important; /* 防止长单词溢出 */
|
||||
word-break: break-word !important; /* 长单词换行 */
|
||||
|
||||
/* 字体和行高 */
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
||||
font-size: 14px !important;
|
||||
line-height: 1.6 !important;
|
||||
color: #2c3e50 !important;
|
||||
|
||||
/* 段落和元素间距 */
|
||||
:deep(p) {
|
||||
margin: 10px 0 !important;
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
|
||||
:deep(h1), :deep(h2), :deep(h3) {
|
||||
color: #2c3e50 !important;
|
||||
margin: 24px 0 12px 0 !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
:deep(ul), :deep(ol) {
|
||||
margin: 10px 0 !important;
|
||||
padding-left: 0 !important; /* 移除默认的左边距 */
|
||||
list-style-position: inside !important; /* 圆点在内部,紧靠文字 */
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
|
||||
:deep(li) {
|
||||
margin: 6px 0 !important;
|
||||
line-height: 1.6 !important;
|
||||
padding-left: 0 !important; /* 移除li的内边距 */
|
||||
text-indent: 0 !important; /* 确保文字不缩进 */
|
||||
}
|
||||
|
||||
/* 表格样式 */
|
||||
:deep(table) {
|
||||
border-collapse: collapse !important;
|
||||
width: 100% !important;
|
||||
margin: 16px 0 !important;
|
||||
|
||||
th, td {
|
||||
border: 1px solid #ddd !important;
|
||||
padding: 8px !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f5f5f5 !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 代码样式 */
|
||||
:deep(pre) {
|
||||
background: #f8f9fa !important;
|
||||
padding: 16px !important;
|
||||
border-radius: 4px !important;
|
||||
overflow-x: auto !important;
|
||||
white-space: pre-wrap !important;
|
||||
}
|
||||
|
||||
:deep(code) {
|
||||
background: #f4f4f4 !important;
|
||||
padding: 2px 4px !important;
|
||||
border-radius: 3px !important;
|
||||
font-family: 'Monaco', 'Consolas', monospace !important;
|
||||
}
|
||||
|
||||
/* 链接样式 */
|
||||
:deep(a) {
|
||||
color: #5721E4 !important;
|
||||
text-decoration: none !important;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 强调样式 */
|
||||
:deep(strong) {
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
:deep(em) {
|
||||
font-style: italic !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 预览对话框 */
|
||||
.preview-dialog {
|
||||
:deep(.el-dialog__body) {
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
/* 特殊样式组件 */
|
||||
:deep(.anchor-point) {
|
||||
background: #e6f7ff !important;
|
||||
border: 1px dashed #1890ff !important;
|
||||
padding: 2px 6px !important;
|
||||
border-radius: 3px !important;
|
||||
color: #1890ff !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
:deep(.important-note) {
|
||||
background: #f6ffed !important;
|
||||
border: 1px solid #b7eb8f !important;
|
||||
border-radius: 4px !important;
|
||||
padding: 12px !important;
|
||||
margin: 12px 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.rich-text-editor-page {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.config-form .el-row .el-col {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.shortcut-list {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.shortcut-item {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user