优化编辑器和前端内容页显示

This commit is contained in:
李志强 2026-01-28 14:36:40 +08:00
parent da378a01be
commit b714df5f43
3 changed files with 945 additions and 482 deletions

View File

@ -5,15 +5,15 @@
// body 样式
body {
background-color: var(--el-bg-color-page);
color: var(--el-text-color-primary);
background-color: #f5f7fa;
color: #303133;
transition: background-color 0.3s ease, color 0.3s ease;
}
// container-box 样式
.container-box {
background-color: var(--el-bg-color);
border: 1px solid var(--el-border-color-lighter);
background-color: #ffffff;
border: 1px solid #ebeef5;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.04);
border-radius: 8px;
padding: 24px;
@ -48,6 +48,382 @@ body {
.toolbar-container{
border-bottom: 1px solid #dcdfe6 !important;
}
.editor-container {
background-color: #ffffff !important;
}
:deep(.w-e-text),
:deep(.w-e-text-container) {
background-color: transparent !important;
* {
color: #1a1a2e !important;
}
p {
color: #1a1a2e !important;
margin: 8px 0 !important;
line-height: 1.8 !important;
font-size: 14px !important;
text-indent: 0 !important;
}
span {
color: #1a1a2e !important;
font-size: 14px !important;
line-height: 1.8 !important;
}
strong, b {
font-weight: 600 !important;
color: #1a1a2e !important;
}
em, i {
font-style: italic !important;
}
u {
text-decoration: underline !important;
}
s, del {
text-decoration: line-through !important;
}
h1 {
color: #1a1a2e !important;
font-size: 28px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h2 {
color: #1a1a2e !important;
font-size: 24px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h3 {
color: #1a1a2e !important;
font-size: 20px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h4 {
color: #1a1a2e !important;
font-size: 18px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h5 {
color: #1a1a2e !important;
font-size: 16px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h6 {
color: #1a1a2e !important;
font-size: 14px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
a {
color: #3973ff !important;
text-decoration: underline !important;
&:hover {
color: #3973ff !important;
opacity: 0.8 !important;
}
}
code {
background-color: #f5f7fa !important;
color: #1a1a2e !important;
border: 1px solid #e4e7ed !important;
border-radius: 3px !important;
padding: 2px 6px !important;
font-family: 'Consolas', 'Monaco', monospace !important;
font-size: 13px !important;
}
pre {
background-color: #f5f7fa !important;
border: 1px solid #e4e7ed !important;
border-radius: 4px !important;
color: #1a1a2e !important;
padding: 12px 16px !important;
margin: 12px 0 !important;
overflow-x: auto;
code {
background-color: transparent !important;
border: none !important;
padding: 0 !important;
color: #1a1a2e !important;
font-size: 13px !important;
line-height: 1.6 !important;
}
}
blockquote {
border-left: 4px solid #3973ff !important;
background-color: #f5f7fa !important;
color: #606266 !important;
padding: 8px 16px !important;
margin: 12px 0 !important;
}
table {
border-collapse: collapse !important;
border: 1px solid #e4e7ed !important;
width: 100% !important;
th, td {
border: 1px solid #e4e7ed !important;
background-color: #ffffff !important;
color: #1a1a2e !important;
padding: 8px 12px !important;
min-width: 60px;
}
th {
background-color: #f5f7fa !important;
font-weight: 600 !important;
}
}
ul {
list-style-type: disc !important;
color: #1a1a2e !important;
padding-left: 24px !important;
margin: 8px 0 !important;
}
ol {
list-style-type: decimal !important;
color: #1a1a2e !important;
padding-left: 24px !important;
margin: 8px 0 !important;
}
li {
color: #1a1a2e !important;
line-height: 1.8 !important;
margin: 4px 0 !important;
}
hr {
border-top: 1px solid #e4e7ed !important;
margin: 16px 0 !important;
}
img {
max-width: 100% !important;
border-radius: 4px !important;
margin: 8px 0 !important;
}
video {
max-width: 100% !important;
border-radius: 4px !important;
margin: 8px 0 !important;
}
.w-e-panel-tab-content {
color: #1a1a2e !important;
}
}
}
html.dark {
.wang-editor-wrapper {
border-color: #3d3d3d !important;
background-color: #1a1a1a !important;
.toolbar-container {
background-color: #2d2d2d !important;
border-color: #3d3d3d !important;
}
.editor-container {
background-color: #1a1a1a !important;
&::-webkit-scrollbar-thumb {
background: #4d4d4d !important;
}
&::-webkit-scrollbar-track {
background: #2d2d2d !important;
}
}
:deep(.w-e-text),
:deep(.w-e-text-container) {
background-color: transparent !important;
* {
color: #e0e0e0 !important;
}
p {
color: #e0e0e0 !important;
margin: 8px 0 !important;
line-height: 1.8 !important;
font-size: 14px !important;
text-indent: 0 !important;
}
span {
color: #e0e0e0 !important;
font-size: 14px !important;
line-height: 1.8 !important;
}
strong, b {
font-weight: 600 !important;
color: #e0e0e0 !important;
}
em, i {
font-style: italic !important;
}
u {
text-decoration: underline !important;
}
s, del {
text-decoration: line-through !important;
}
h1 {
color: #e0e0e0 !important;
font-size: 28px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h2 {
color: #e0e0e0 !important;
font-size: 24px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h3 {
color: #e0e0e0 !important;
font-size: 20px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h4 {
color: #e0e0e0 !important;
font-size: 18px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h5 {
color: #e0e0e0 !important;
font-size: 16px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
h6 {
color: #e0e0e0 !important;
font-size: 14px !important;
font-weight: 600 !important;
margin: 16px 0 12px !important;
line-height: 1.4 !important;
}
a {
color: #4f84ff !important;
text-decoration: underline !important;
&:hover {
color: #4f84ff !important;
opacity: 0.8 !important;
}
}
code {
background-color: #2d2d2d !important;
color: #e0e0e0 !important;
border-color: #3d3d3d !important;
}
pre {
background-color: #2d2d2d !important;
border-color: #3d3d3d !important;
color: #e0e0e0 !important;
code {
background-color: transparent !important;
border: none !important;
color: #e0e0e0 !important;
}
}
blockquote {
border-left-color: #4f84ff !important;
background-color: #2d2d2d !important;
color: #b0b0b0 !important;
}
table {
border-color: #3d3d3d !important;
th, td {
border-color: #3d3d3d !important;
background-color: #1a1a1a !important;
color: #e0e0e0 !important;
}
th {
background-color: #2d2d2d !important;
}
}
ul, ol, li {
color: #e0e0e0 !important;
}
hr {
border-top-color: #3d3d3d !important;
}
img, video {
max-width: 100% !important;
border-radius: 4px !important;
}
.w-e-panel-tab-content {
color: #e0e0e0 !important;
}
}
}
}
.el-form-item__label{
min-width: 80px !important;

View File

@ -1,5 +1,10 @@
<template>
<el-drawer v-model="visible" :title="isEdit ? '编辑文章' : '新增文章'" size="60%" :before-close="handleBeforeClose">
<el-drawer
v-model="visible"
:title="isEdit ? '编辑文章' : '新增文章'"
size="60%"
:before-close="handleBeforeClose"
>
<el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" placeholder="请输入文章标题" />
@ -25,37 +30,71 @@
</el-row>
<el-form-item label="简介" prop="desc">
<el-input v-model="form.desc" :rows="4" type="textarea" placeholder="请输入简介" />
<el-input
v-model="form.desc"
:rows="4"
type="textarea"
placeholder="请输入简介"
/>
</el-form-item>
<el-form-item label="封面图片" prop="image">
<div class="uploads">
<!-- 已有图片显示 -->
<div v-if="form.image && fileList.length === 0" class="existing-image">
<img :src="API_BASE_URL + form.image.replace(/\\\//g, '/')" alt="已有图片" />
<div
v-if="form.image && fileList.length === 0"
class="existing-image"
>
<img
:src="API_BASE_URL + form.image.replace(/\\\//g, '/')"
alt="已有图片"
/>
<div class="image-actions">
<el-button type="primary" size="small" @click="previewExistingImage">预览</el-button>
<el-button type="danger" size="small" @click="removeExistingImage">删除</el-button>
<el-button
type="primary"
size="small"
@click="previewExistingImage"
>预览</el-button
>
<el-button type="danger" size="small" @click="removeExistingImage"
>删除</el-button
>
</div>
</div>
<!-- 上传组件 -->
<el-upload v-model:file-list="fileList" :auto-upload="false" :before-upload="beforeImgUpload"
list-type="picture-card" :limit="1" :show-file-list="fileList.length > 0">
<el-upload
v-model:file-list="fileList"
:auto-upload="false"
:before-upload="beforeImgUpload"
list-type="picture-card"
:limit="1"
:show-file-list="fileList.length > 0"
>
<el-icon>
<Plus />
</el-icon>
<template #file="{ file }">
<div>
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<img
class="el-upload-list__item-thumbnail"
:src="file.url"
alt=""
/>
<span class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<el-icon>
<ZoomIn />
</el-icon>
</span>
<span class="el-upload-list__item-delete" @click="handleRemove(file)">
<span
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<el-icon>
<Delete />
</el-icon>
@ -66,9 +105,18 @@
</el-upload>
<el-drawer v-model="drawerVisible" width="60%" center>
<div style="display: flex; justify-content: center;align-items:center;">
<img :src="drawerImageUrl" alt="Preview Image"
style="max-width: 100%; max-height: 70vh; object-fit: contain;" />
<div
style="
display: flex;
justify-content: center;
align-items: center;
"
>
<img
:src="drawerImageUrl"
alt="Preview Image"
style="max-width: 100%; max-height: 70vh; object-fit: contain"
/>
</div>
</el-drawer>
@ -102,36 +150,47 @@
<el-divider></el-divider>
<span class="drawer-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button v-if="!isEdit" type="warning" @click="handleConfirm(0)" :loading="submitLoading">草稿</el-button>
<el-button type="primary" @click="handleConfirm(1)" :loading="submitLoading">提交</el-button>
<el-button
v-if="!isEdit"
type="warning"
@click="handleConfirm(0)"
:loading="submitLoading"
>草稿</el-button
>
<el-button
type="primary"
@click="handleConfirm(1)"
:loading="submitLoading"
>提交</el-button
>
</span>
</template>
</el-drawer>
</template>
<script lang="ts" setup>
import { ref, reactive, watch, nextTick, onMounted, computed } from 'vue';
import { ElMessage, ElUpload } from 'element-plus'
import WangEditor from '@/views/components/WangEditor.vue';
import { createArticle, editArticle, listCategories } from '@/api/article.js';
import { uploadFile } from '@/api/file.js';
import { ref, reactive, watch, nextTick, onMounted, computed } from "vue";
import { ElMessage, ElUpload } from "element-plus";
import WangEditor from "@/views/components/WangEditor.vue";
import { createArticle, editArticle, listCategories } from "@/api/article.js";
import { uploadFile } from "@/api/file.js";
const props = defineProps({
modelValue: {
type: Boolean,
default: false
default: false,
},
isEdit: {
type: Boolean,
default: false
default: false,
},
model: {
type: Object,
default: () => null
}
default: () => null,
},
});
const emit = defineEmits(['update:modelValue', 'saved']);
const emit = defineEmits(["update:modelValue", "saved"]);
const visible = ref(false);
const submitLoading = ref(false);
@ -145,28 +204,31 @@ const handleBeforeClose = (done: () => void) => {
const cateOptions = ref([]);
const form = reactive({
title: '',
author: '云泽网',
cate: '',
content: '',
image: '',
desc: '',
title: "",
author: "云泽网",
cate: "",
content: "",
image: "",
desc: "",
is_trans: 0,
transurl: null
transurl: null,
});
const rules = {
title: [
{ required: true, message: '请输入文章标题', trigger: 'blur' },
{ min: 2, max: 200, message: '标题长度在 2 到 200 个字符', trigger: 'blur' }
{ required: true, message: "请输入文章标题", trigger: "blur" },
{
min: 2,
max: 200,
message: "标题长度在 2 到 200 个字符",
trigger: "blur",
},
],
author: [
{ required: true, message: '请输入作者', trigger: 'blur' },
{ max: 50, message: '作者姓名不能超过50个字符', trigger: 'blur' }
],
content: [
{ required: true, message: '请输入文章内容', trigger: 'blur' }
{ required: true, message: "请输入作者", trigger: "blur" },
{ max: 50, message: "作者姓名不能超过50个字符", trigger: "blur" },
],
content: [{ required: true, message: "请输入文章内容", trigger: "blur" }],
};
//
@ -179,88 +241,91 @@ async function fetchCategories() {
cateOptions.value = buildCategoryTree(categories);
}
} catch (error) {
console.error('获取分类失败:', error);
console.error("获取分类失败:", error);
}
}
//
function buildCategoryTree(categories, parentCid = 0) {
return categories
.filter(cate => Number(cate.cid) === Number(parentCid))
.map(cate => {
.filter((cate) => Number(cate.cid) === Number(parentCid))
.map((cate) => {
const children = buildCategoryTree(categories, cate.id);
return {
...cate,
label: cate.name,
value: cate.id,
children: children.length > 0 ? children : undefined
children: children.length > 0 ? children : undefined,
};
});
}
//
const fileList = ref<any[]>([])
const drawerVisible = ref(false)
const drawerImageUrl = ref('')
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL
const fileList = ref<any[]>([]);
const drawerVisible = ref(false);
const drawerImageUrl = ref("");
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
function beforeImgUpload(file: File) {
const isImage = file.type.startsWith('image/')
const isLt10M = file.size / 1024 / 1024 < 10
if (!isImage) ElMessage.error('仅支持图片格式')
if (!isLt10M) ElMessage.error('图片大小不能超过10MB')
return isImage && isLt10M
const isImage = file.type.startsWith("image/");
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isImage) ElMessage.error("仅支持图片格式");
if (!isLt10M) ElMessage.error("图片大小不能超过10MB");
return isImage && isLt10M;
}
function handlePictureCardPreview(file: any) {
drawerImageUrl.value = file.url
drawerVisible.value = true
drawerImageUrl.value = file.url;
drawerVisible.value = true;
}
function handleRemove(file: any) {
fileList.value = []
form.image = ''
fileList.value = [];
form.image = "";
}
function removeExistingImage() {
form.image = ''
form.image = "";
}
function previewExistingImage() {
const imagePath = form.image.replace(/\\\//g, '/');
const imagePath = form.image.replace(/\\\//g, "/");
drawerImageUrl.value = API_BASE_URL + imagePath;
drawerVisible.value = true;
}
//
watch(() => props.modelValue, (newVal) => {
visible.value = newVal;
if (newVal) {
if (props.isEdit && props.model) {
//
const modelData = props.model._raw || props.model;
nextTick(() => {
Object.assign(form, {
title: modelData.title || '',
author: modelData.author || '',
cate: modelData.cate || '',
content: modelData.content || '',
desc: modelData.desc || '',
is_trans: modelData.is_trans || 0,
transurl: modelData.transurl || null,
image: modelData.image || ''
watch(
() => props.modelValue,
(newVal) => {
visible.value = newVal;
if (newVal) {
if (props.isEdit && props.model) {
//
const modelData = props.model._raw || props.model;
nextTick(() => {
Object.assign(form, {
title: modelData.title || "",
author: modelData.author || "",
cate: modelData.cate || "",
content: modelData.content || "",
desc: modelData.desc || "",
is_trans: modelData.is_trans || 0,
transurl: modelData.transurl || null,
image: modelData.image || "",
});
fileList.value = []; //
});
fileList.value = []; //
});
} else {
//
resetForm();
} else {
//
resetForm();
}
}
}
});
},
);
function handleCancel() {
emit('update:modelValue', false);
emit("update:modelValue", false);
resetForm();
}
@ -274,16 +339,20 @@ async function handleConfirm(status = 1) {
//
if (fileList.value.length > 0 && fileList.value[0].raw) {
const uploadFormData = new FormData()
uploadFormData.append('file', fileList.value[0].raw)
uploadFormData.append('cate', 'article')
const uploadFormData = new FormData();
uploadFormData.append("file", fileList.value[0].raw);
uploadFormData.append("cate", "article");
const uploadRes = await uploadFile(uploadFormData);
// 200=201=使
if ((uploadRes.code === 200 || uploadRes.code === 201) && uploadRes.data && uploadRes.data.url) {
if (
(uploadRes.code === 200 || uploadRes.code === 201) &&
uploadRes.data &&
uploadRes.data.url
) {
imageUrl = uploadRes.data.url;
} else {
ElMessage.error('图片上传失败:' + (uploadRes.msg || '未知错误'));
ElMessage.error("图片上传失败:" + (uploadRes.msg || "未知错误"));
return;
}
}
@ -298,7 +367,7 @@ async function handleConfirm(status = 1) {
image: imageUrl,
is_trans: form.is_trans,
transurl: form.is_trans === 1 ? form.transurl : null,
status: status // 0稿1
status: status, // 0稿1
};
// /API
@ -311,38 +380,49 @@ async function handleConfirm(status = 1) {
const createArticleWithCheck = async (ignoreSimilarity = false) => {
const data = {
...submitData,
...(ignoreSimilarity && { ignore_similarity: 1 })
...(ignoreSimilarity && { ignore_similarity: 1 }),
};
return await createArticle(data);
};
res = await createArticleWithCheck();
resp = (res && typeof res.code !== 'undefined') ? res : (res && res.data ? res.data : res);
resp =
res && typeof res.code !== "undefined"
? res
: res && res.data
? res.data
: res;
//
if (resp && resp.code === 409) {
const similarArticles = resp.data?.similar_articles || [];
//
const similarArticlesList = similarArticles.map((article: any) => `\n<div style="margin: 8px 0; padding: 8px; background: #f5f7fa; border-radius: 4px;">\n<div style="font-weight: bold; color: #303133;">${article.title}</div>\n<div style="color: #606266; font-size: 14px; margin-top: 4px;">相似度:${article.similarity}%</div>\n</div>\n`).join('');
const similarArticlesList = similarArticles
.map(
(article: any) =>
`\n<div style="margin: 8px 0; padding: 8px; background: #f5f7fa; border-radius: 4px;">\n<div style="font-weight: bold; color: #303133;">${article.title}</div>\n<div style="color: #606266; font-size: 14px; margin-top: 4px;">相似度:${article.similarity}%</div>\n</div>\n`,
)
.join("");
const confirmMessage = `\n<div>\n\n${similarArticlesList} \n<p style="margin-top: 16px; color: #303133;">是否继续创建?</p>\n</div>\n`;
// 使Element Plusconfirm
const { ElMessageBox } = await import('element-plus');
const { ElMessageBox } = await import("element-plus");
try {
await ElMessageBox.confirm(
confirmMessage,
'检测到相似标题',
{
confirmButtonText: '继续创建',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true,
}
);
await ElMessageBox.confirm(confirmMessage, "检测到相似标题", {
confirmButtonText: "继续创建",
cancelButtonText: "取消",
type: "warning",
dangerouslyUseHTMLString: true,
});
//
res = await createArticleWithCheck(true);
resp = (res && typeof res.code !== 'undefined') ? res : (res && res.data ? res.data : res);
resp =
res && typeof res.code !== "undefined"
? res
: res && res.data
? res.data
: res;
} catch (error) {
//
return;
@ -355,28 +435,57 @@ async function handleConfirm(status = 1) {
const articleId = modelData.id;
if (!articleId) {
ElMessage.error('文章ID不存在无法更新');
ElMessage.error("文章ID不存在无法更新");
return;
}
// IDIDURL
const editData = {
...submitData
...submitData,
};
res = await editArticle(articleId, editData);
resp = (res && typeof res.code !== 'undefined') ? res : (res && res.data ? res.data : res);
resp =
res && typeof res.code !== "undefined"
? res
: res && res.data
? res.data
: res;
}
if (resp && resp.code === 200 && (resp.message === 'success' || resp.msg === 'success')) {
ElMessage.success(status === 0 ? '保存草稿成功' : (props.isEdit ? '更新成功' : '创建成功'));
emit('update:modelValue', false);
emit('saved');
if (
resp &&
resp.code === 200 &&
(resp.message === "success" || resp.msg === "success")
) {
ElMessage.success(
status === 0
? "保存草稿成功"
: props.isEdit
? "更新成功"
: "创建成功",
);
emit("update:modelValue", false);
emit("saved");
} else {
ElMessage.error((resp && resp.message) || (resp && resp.msg) || (status === 0 ? '保存草稿失败' : (props.isEdit ? '更新失败' : '创建失败')));
ElMessage.error(
(resp && resp.message) ||
(resp && resp.msg) ||
(status === 0
? "保存草稿失败"
: props.isEdit
? "更新失败"
: "创建失败"),
);
}
} catch (error) {
ElMessage.error(status === 0 ? '保存草稿失败' : (props.isEdit ? '更新失败' : '创建失败'));
ElMessage.error(
status === 0
? "保存草稿失败"
: props.isEdit
? "更新失败"
: "创建失败",
);
} finally {
submitLoading.value = false;
}
@ -393,14 +502,14 @@ function resetForm() {
fileList.value = [];
//
Object.assign(form, {
title: '',
author: '云泽网',
cate: '',
content: '',
image: '',
desc: '',
title: "",
author: "云泽网",
cate: "",
content: "",
image: "",
desc: "",
is_trans: 0,
transurl: null
transurl: null,
});
}
@ -408,12 +517,12 @@ function resetForm() {
defineExpose({
resetForm: () => {
formRef.value?.resetFields();
}
},
});
onMounted(() => {
fetchCategories();
})
});
</script>
<style lang="scss" scoped>
@ -421,6 +530,106 @@ onMounted(() => {
border: 1px solid #dcdfe6;
border-radius: 4px;
overflow: hidden;
&:focus {
outline: none !important;
}
:deep(.w-e-text),
:deep(.w-e-text-container) {
p {
color: #1a1a2e !important;
margin: 0.5em 0 !important;
}
h1, h2, h3, h4, h5, h6 {
color: #1a1a2e !important;
font-weight: 600 !important;
}
a {
color: #3973ff !important;
text-decoration: underline !important;
&:hover {
color: #3973ff !important;
opacity: 0.8 !important;
}
}
code {
background-color: #f5f7fa !important;
color: #1a1a2e !important;
border: 1px solid #e4e7ed !important;
padding: 2px 6px !important;
border-radius: 3px !important;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 13px;
}
pre {
background-color: #f5f7fa !important;
border: 1px solid #e4e7ed !important;
color: #1a1a2e !important;
border-radius: 4px !important;
padding: 12px 16px;
margin: 12px 0;
overflow-x: auto;
code {
background-color: transparent !important;
border: none !important;
padding: 0 !important;
}
}
blockquote {
border-left: 4px solid #3973ff !important;
background-color: #f5f7fa !important;
color: #606266 !important;
padding: 0.6em 1.2em !important;
margin: 1em 0 !important;
}
table {
border-collapse: collapse !important;
border: 1px solid #e4e7ed !important;
th, td {
border: 1px solid #e4e7ed !important;
background-color: #ffffff !important;
color: #1a1a2e !important;
padding: 8px 12px;
}
th {
background-color: #f5f7fa !important;
}
}
ul, ol {
color: #1a1a2e !important;
padding-left: 24px;
margin: 8px 0;
}
li {
color: #1a1a2e !important;
line-height: 1.8;
margin: 4px 0;
}
hr {
border-top: 1px solid #e4e7ed !important;
margin: 16px 0;
}
img {
max-width: 100%;
border-radius: 4px;
margin: 8px 0;
}
}
}
.drawer-footer {

View File

@ -325,380 +325,258 @@ onBeforeUnmount(() => {
});
</script>
<style scoped lang="less">
<style lang="less">
.wang-editor-wrapper {
display: flex;
flex-direction: column;
height: 650px; //
border: 1px solid var(--border-color);
height: 650px;
border: 1px solid #dcdfe6;
border-radius: 4px;
overflow: hidden;
background-color: var(--fill-color-blank);
background: #ffffff;
.toolbar-container {
.toolbar-container {--fill-color-light
position: sticky;
top: 0;
z-index: 10;
background-color: var(--fill-color-light);
border-bottom: 1px solid var(--border-color-lighter);
background: #f5f7fa;
border-bottom: 1px solid #dcdfe6;
flex-shrink: 0;
}
.editor-container {
flex: 1;
overflow-y: auto;
padding: 10px;
overflow-x: hidden;
padding: 0;
&::-webkit-scrollbar {
width: 6px;
height: 6px;
}
&::-webkit-scrollbar-thumb {
background: #c0c4cc;
border-radius: 3px;
}
&::-webkit-scrollbar-track {
background: #f5f7fa;
border-radius: 3px;
}
}
:deep(.w-e-text),
:deep(.w-e-text-container) {
p {
color: #1a1a2e !important;
margin: 8px 0 !important;
line-height: 1.8 !important;
}
h1, h2, h3, h4, h5, h6 {
color: #1a1a2e !important;
font-weight: 600 !important;
margin: 16px 0 8px !important;
}
a {
color: #3973ff !important;
text-decoration: underline !important;
}
code {
background: #f5f7fa !important;
color: #1a1a2e !important;
border: 1px solid #e4e7ed !important;
border-radius: 3px;
padding: 2px 6px;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 13px;
}
pre {
background: #f5f7fa !important;
border: 1px solid #e4e7ed !important;
border-radius: 4px;
padding: 12px 16px;
margin: 12px 0;
overflow-x: auto;
color: #1a1a2e !important;
code {
background: transparent !important;
border: none !important;
padding: 0;
font-size: 13px;
line-height: 1.6;
color: #1a1a2e !important;
}
}
blockquote {
border-left: 4px solid #3973ff !important;
background: #f5f7fa !important;
color: #606266 !important;
padding: 8px 16px;
margin: 12px 0;
}
table {
border-collapse: collapse !important;
border: 1px solid #e4e7ed !important;
width: 100% !important;
margin: 12px 0;
th, td {
border: 1px solid #e4e7ed !important;
padding: 8px 12px !important;
min-width: 60px;
}
th {
background: #f5f7fa !important;
font-weight: 600;
}
}
ul, ol {
color: #1a1a2e !important;
padding-left: 24px !important;
margin: 8px 0;
}
li {
color: #1a1a2e !important;
line-height: 1.8 !important;
margin: 4px 0;
}
hr {
border-top: 1px solid #e4e7ed !important;
margin: 16px 0 !important;
}
img {
max-width: 100% !important;
border-radius: 4px !important;
margin: 8px 0;
}
}
}
html.dark {
.wang-editor-wrapper {
border-color: #3d3d3d;
background: #1a1a1a;
.toolbar-container {
background: #2d2d2d;
border-color: #3d3d3d;
}
.editor-container {
&::-webkit-scrollbar {
width: 6px;
height: 6px;
}
&::-webkit-scrollbar-thumb {
background: #4d4d4d;
border-radius: 3px;
}
&::-webkit-scrollbar-track {
background: #2d2d2d;
border-radius: 3px;
}
}
:deep(.w-e-text),
:deep(.w-e-text-container) {
background: transparent !important;
p, h1, h2, h3, h4, h5, h6 {
color: #e0e0e0 !important;
}
a {
color: #4f84ff !important;
text-decoration: underline !important;
}
code {
background: #2d2d2d !important;
color: #e0e0e0 !important;
border-color: #3d3d3d !important;
}
pre {
background: #2d2d2d !important;
border-color: #3d3d3d !important;
color: #e0e0e0 !important;
code {
background: transparent !important;
border: none !important;
color: #e0e0e0 !important;
}
}
blockquote {
border-color: #4f84ff !important;
background: #2d2d2d !important;
color: #b0b0b0 !important;
}
table {
border-color: #3d3d3d !important;
th, td {
border-color: #3d3d3d !important;
background: #1a1a1a !important;
color: #e0e0e0 !important;
}
th {
background: #2d2d2d !important;
}
}
ul, ol {
color: #e0e0e0 !important;
padding-left: 24px !important;
margin: 8px 0;
}
li {
color: #e0e0e0 !important;
line-height: 1.8 !important;
margin: 4px 0;
}
hr {
border-color: #3d3d3d !important;
}
img {
max-width: 100% !important;
border-radius: 4px !important;
margin: 8px 0;
}
}
}
}
.toolbar-container {
border-bottom: 1px solid var(--border-color-lighter);
background-color: var(--fill-color-light);
border-bottom: 1px solid #dcdfe6;
background-color: #f5f7fa;
transition: all 0.3s ease;
}
.editor-container {
min-height: 400px;
background-color: var(--fill-color-blank);
background-color: #ffffff;
transition: background-color 0.3s ease;
}
</style>
<style lang="less">
// WangEditor
.wang-editor-wrapper {
//
:deep(.w-e-toolbar) {
background-color: var(--fill-color-light) !important;
border-bottom-color: var(--border-color-lighter) !important;
border-bottom: 1px solid var(--border-color-lighter) !important;
//
.w-e-bar-item {
button {
color: var(--text-color-primary) !important;
background-color: transparent !important;
border: none !important;
transition: all 0.2s ease !important;
&:hover:not(.disabled) {
background-color: var(--fill-color) !important;
color: var(--primary-color) !important;
}
&:active:not(.disabled) {
background-color: var(--fill-color-dark) !important;
}
&.active {
background-color: var(--fill-color-dark) !important;
color: var(--primary-color) !important;
}
&.disabled {
color: var(--text-color-disabled) !important;
cursor: not-allowed !important;
opacity: 0.5 !important;
}
}
// 线
&::after {
background-color: var(--border-color-lighter) !important;
}
}
// 线
.w-e-bar-divider {
background-color: var(--border-color-lighter) !important;
}
}
//
:deep(.w-e-text-container) {
background-color: var(--el-bg-color) !important;
color: var(--text-color-primary) !important;
border: none !important;
//
.w-e-text {
color: var(--text-color-primary) !important;
background-color: transparent !important;
min-height: 400px !important;
//
&:focus {
outline: none !important;
}
//
p {
color: var(--text-color-primary) !important;
margin: 0.5em 0 !important;
}
//
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--text-color-primary) !important;
font-weight: 600 !important;
}
//
a {
color: var(--primary-color) !important;
text-decoration: underline !important;
&:hover {
color: var(--primary-color) !important;
opacity: 0.8 !important;
}
}
//
code {
background-color: var(--fill-color-light) !important;
color: var(--text-color-primary) !important;
border: 1px solid var(--border-color-lighter) !important;
padding: 2px 6px !important;
border-radius: 3px !important;
}
//
pre {
background-color: var(--fill-color-light) !important;
border: 1px solid var(--border-color-lighter) !important;
color: var(--text-color-primary) !important;
border-radius: 4px !important;
code {
background-color: transparent !important;
border: none !important;
padding: 0 !important;
}
}
//
blockquote {
border-left: 4px solid var(--border-color) !important;
background-color: var(--fill-color-light) !important;
color: var(--text-color-primary) !important;
padding: 0.6em 1.2em !important;
margin: 1em 0 !important;
}
//
table {
border-collapse: collapse !important;
border: 1px solid var(--border-color-lighter) !important;
th,
td {
border: 1px solid var(--border-color-lighter) !important;
background-color: var(--fill-color-blank) !important;
color: var(--text-color-primary) !important;
}
th {
background-color: var(--fill-color-light) !important;
}
}
//
ul,
ol {
color: var(--text-color-primary) !important;
}
li {
color: var(--text-color-primary) !important;
}
}
//
.placeholder {
color: var(--text-color-placeholder) !important;
}
}
//
:deep(.w-e-drop-panel) {
background-color: var(--bg-color-overlay) !important;
border: 1px solid var(--border-color) !important;
box-shadow: var(--box-shadow) !important;
color: var(--text-color-primary) !important;
.w-e-list-item {
color: var(--text-color-primary) !important;
transition: all 0.2s ease !important;
&:hover {
background-color: var(--fill-color-light) !important;
color: var(--text-color-primary) !important;
}
&.selected {
background-color: var(--fill-color-light) !important;
color: var(--primary-color) !important;
}
&.disabled {
color: var(--text-color-disabled) !important;
cursor: not-allowed !important;
&:hover {
background-color: transparent !important;
}
}
}
// 线
.w-e-drop-panel-divider {
background-color: var(--border-color-lighter) !important;
}
}
//
:deep(.w-e-toolbar-menu) {
background-color: var(--bg-color-overlay) !important;
border: 1px solid var(--border-color) !important;
box-shadow: var(--box-shadow) !important;
.w-e-menu-item {
color: var(--text-color-primary) !important;
&:hover {
background-color: var(--fill-color-light) !important;
color: var(--text-color-primary) !important;
}
&.active {
background-color: var(--fill-color-light) !important;
color: var(--primary-color) !important;
}
}
}
//
:deep(.w-e-modal) {
background-color: var(--bg-color-overlay) !important;
border: 1px solid var(--border-color) !important;
box-shadow: var(--box-shadow) !important;
.w-e-modal-header {
border-bottom: 1px solid var(--border-color-lighter) !important;
color: var(--text-color-primary) !important;
}
.w-e-modal-body {
background-color: var(--bg-color-overlay) !important;
color: var(--text-color-primary) !important;
input,
textarea,
select {
background-color: var(--fill-color-blank) !important;
border-color: var(--border-color) !important;
color: var(--text-color-primary) !important;
&:focus {
border-color: var(--primary-color) !important;
}
}
}
.w-e-modal-footer {
border-top: 1px solid var(--border-color-lighter) !important;
button {
background-color: var(--fill-color-blank) !important;
border-color: var(--border-color) !important;
color: var(--text-color-primary) !important;
&:hover {
background-color: var(--fill-color-light) !important;
border-color: var(--primary-color) !important;
color: var(--primary-color) !important;
}
}
}
}
//
:deep(.w-e-bar-item svg),
:deep(.w-e-bar-item .w-e-icon) {
fill: var(--text-color-primary) !important;
color: var(--text-color-primary) !important;
transition:
fill 0.2s ease,
color 0.2s ease !important;
}
:deep(.w-e-bar-item:hover:not(.disabled) svg),
:deep(.w-e-bar-item:hover:not(.disabled) .w-e-icon),
:deep(.w-e-bar-item.active svg),
:deep(.w-e-bar-item.active .w-e-icon) {
fill: var(--primary-color) !important;
color: var(--primary-color) !important;
}
//
:deep(.w-e-bar-divider) {
background-color: var(--border-color-lighter) !important;
}
//
&.focused {
border-color: var(--primary-color) !important;
box-shadow: 0 0 0 1px var(--primary-color) inset !important;
}
}
:deep(.w-e-text-container) {
background-color: var(--el-bg-color) !important;
}
//
[data-theme="dark"] {
.wang-editor-wrapper {
background-color: var(--fill-color-darker) !important;
border-color: var(--border-color) !important;
:deep(.w-e-text-container) {
background-color: var(--fill-color-darker) !important;
}
:deep(.w-e-text-container .w-e-text) {
background-color: var(--fill-color-darker) !important;
color: var(--text-color-primary) !important;
//
img {
border: 1px solid var(--border-color-lighter) !important;
border-radius: 4px !important;
}
// 线
hr {
border-top-color: var(--border-color-lighter) !important;
}
//
table tr:nth-child(even) {
background-color: var(--fill-color-extra-light) !important;
}
}
}
}
// Fix z-index for full-screen/maximize mode
:deep(.w-e-fullscreen),
:deep(.w-e-fullscreen *),
:deep(.w-e-modal),
:deep(.w-e-drop-panel) {
z-index: 99999 !important;
}
</style>