公众号助手新增图片
This commit is contained in:
@@ -17,3 +17,11 @@ export function executeOfficialAccountWorkflowStep(taskId, stepKey, data) {
|
||||
timeout: 0,
|
||||
})
|
||||
}
|
||||
|
||||
export function exportOfficialAccountDocument(taskId, format) {
|
||||
return http.get(`/official-account/tasks/${taskId}/export`, {
|
||||
params: { format },
|
||||
responseType: 'blob',
|
||||
timeout: 0,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -330,6 +330,82 @@
|
||||
<pre class="content-preview">{{ workflow.shared.content || '还没有生成正文草稿。' }}</pre>
|
||||
</template>
|
||||
|
||||
<template v-else-if="id === stepKeyImagePrompts">
|
||||
<div class="inline-meta">当前已提炼 {{ (workflow.shared.image_prompts || []).length }} 条配图提示词</div>
|
||||
<div v-if="(workflow.shared.image_prompts || []).length" class="prompt-list">
|
||||
<div v-for="(item, promptIndex) in workflow.shared.image_prompts || []" :key="item.key" class="prompt-card">
|
||||
<div class="prompt-header">
|
||||
<div>
|
||||
<div class="prompt-badge">{{ getPromptSlotLabel(item, promptIndex) }}</div>
|
||||
<div class="prompt-title">{{ item.section || getPromptSlotLabel(item, promptIndex) }}</div>
|
||||
</div>
|
||||
<div class="prompt-chip">用于配图</div>
|
||||
</div>
|
||||
<div class="prompt-meta">用途:{{ getPromptPurpose(item, promptIndex) }}</div>
|
||||
<div class="prompt-body">{{ item.prompt }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-text">当前还没有生成配图提示词。</div>
|
||||
<div class="node-panel-title">原始标记稿</div>
|
||||
<div class="inline-meta">下面这段是给系统继续传递用的结构化正文,不是给人直接阅读的最终文案。</div>
|
||||
<pre class="content-preview prompt-raw-preview">{{ workflow.shared.content_with_prompts || '还没有生成带提示词的正文稿。' }}</pre>
|
||||
</template>
|
||||
|
||||
<template v-else-if="id === stepKeyImages">
|
||||
<div class="node-panel-title">图片结果</div>
|
||||
<div class="inline-meta">当前已生成 {{ (workflow.shared.image_refs || []).length }} 张图片</div>
|
||||
<div v-if="(workflow.shared.image_refs || []).length" class="image-grid">
|
||||
<div v-for="item in workflow.shared.image_refs || []" :key="item.key" class="image-card">
|
||||
<img class="image-thumb" :src="item.url" :alt="item.section || item.key" />
|
||||
<div class="image-section">{{ item.section || item.key }}</div>
|
||||
<div class="image-prompt">{{ item.prompt }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-text">当前还没有图片结果。</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="id === stepKeyPreview">
|
||||
<div class="node-panel-title">预览与导出</div>
|
||||
<div class="action-row action-row-start">
|
||||
<el-button
|
||||
size="small"
|
||||
:loading="exportingFormat === 'preview_md'"
|
||||
@click.stop="downloadExport('preview_md', 'official-account-preview.md')"
|
||||
>
|
||||
导出预览 MD
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
:loading="exportingFormat === 'preview_html'"
|
||||
@click.stop="downloadExport('preview_html', 'official-account-preview.html')"
|
||||
>
|
||||
导出预览 HTML
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="workflow.shared.preview_html" class="preview-render" v-html="workflow.shared.preview_html" />
|
||||
<div v-else class="empty-text">当前还没有生成预览稿。</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="id === stepKeyPageMD">
|
||||
<div class="node-panel-title">分页 MD</div>
|
||||
<div class="action-row action-row-start">
|
||||
<el-button
|
||||
size="small"
|
||||
:loading="exportingFormat === 'pagemd'"
|
||||
@click.stop="downloadExport('pagemd', 'official-account-pagemd.md')"
|
||||
>
|
||||
导出分页 MD
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="inline-meta">当前共 {{ (workflow.shared.pages || []).length }} 页</div>
|
||||
<div v-if="(workflow.shared.pages || []).length" class="page-chip-list">
|
||||
<span v-for="item in workflow.shared.pages || []" :key="`${item.index}-${item.title}`" class="page-chip">
|
||||
第 {{ item.index }} 页 · {{ item.title }}
|
||||
</span>
|
||||
</div>
|
||||
<pre class="content-preview pagemd-preview">{{ workflow.shared.page_markdown || '还没有生成分页 MD。' }}</pre>
|
||||
</template>
|
||||
|
||||
<div class="node-panel-title">节点输出</div>
|
||||
<div v-if="getOutputRows(id).length" class="output-list">
|
||||
<div v-for="row in getOutputRows(id)" :key="row.label" class="output-row">
|
||||
@@ -372,6 +448,7 @@ import { useWorkerRuntimeStore } from '@/store/workerRuntime'
|
||||
import {
|
||||
createOfficialAccountTask,
|
||||
executeOfficialAccountWorkflowStep,
|
||||
exportOfficialAccountDocument,
|
||||
getOfficialAccountWorkflow,
|
||||
updateOfficialAccountTask,
|
||||
} from '@/api/officialAccount'
|
||||
@@ -384,6 +461,10 @@ const stepKeyTopic = 'topic_recommendation'
|
||||
const stepKeyTitle = 'title_generation'
|
||||
const stepKeyOutline = 'outline_generation'
|
||||
const stepKeyContent = 'content_creation'
|
||||
const stepKeyImagePrompts = 'image_prompt_generation'
|
||||
const stepKeyImages = 'image_generation'
|
||||
const stepKeyPreview = 'preview_export'
|
||||
const stepKeyPageMD = 'page_markdown'
|
||||
const stepKeyConfig = 'task_configuration'
|
||||
|
||||
const creatingTask = ref(false)
|
||||
@@ -398,11 +479,12 @@ const fittedTaskId = ref('')
|
||||
const canvasNodes = ref([])
|
||||
const canvasEdges = ref([])
|
||||
const canvasZoomOnScroll = ref(true)
|
||||
const canvasTranslateExtent = [[-320, -260], [3280, 1560]]
|
||||
const canvasNodeExtent = [[40, 80], [2480, 1120]]
|
||||
const canvasTranslateExtent = [[-320, -260], [4680, 1680]]
|
||||
const canvasNodeExtent = [[40, 80], [4320, 1320]]
|
||||
const expandedHotspotKeys = ref([])
|
||||
const pollingToken = ref(0)
|
||||
const pollingStepKey = ref('')
|
||||
const exportingFormat = ref('')
|
||||
|
||||
const taskForm = reactive({
|
||||
keyword: '',
|
||||
@@ -420,6 +502,8 @@ const stepPayload = reactive({
|
||||
topic: '',
|
||||
title: '',
|
||||
outline: '',
|
||||
content: '',
|
||||
contentWithPrompts: '',
|
||||
requirements: '',
|
||||
})
|
||||
|
||||
@@ -524,6 +608,10 @@ const workflowSteps = computed(() => {
|
||||
buildStepCard(3, stepKeyTitle, steps[stepKeyTitle]),
|
||||
buildStepCard(4, stepKeyOutline, steps[stepKeyOutline]),
|
||||
buildStepCard(5, stepKeyContent, steps[stepKeyContent]),
|
||||
buildStepCard(6, stepKeyImagePrompts, steps[stepKeyImagePrompts]),
|
||||
buildStepCard(7, stepKeyImages, steps[stepKeyImages]),
|
||||
buildStepCard(8, stepKeyPreview, steps[stepKeyPreview]),
|
||||
buildStepCard(9, stepKeyPageMD, steps[stepKeyPageMD]),
|
||||
]
|
||||
})
|
||||
|
||||
@@ -558,6 +646,18 @@ function getOutputRows(stepKey) {
|
||||
if (stepKey === stepKeyContent) {
|
||||
return [{ label: '正文状态', value: output.content ? '已生成' : '未生成' }]
|
||||
}
|
||||
if (stepKey === stepKeyImagePrompts) {
|
||||
return [{ label: '提示词数量', value: String((output.image_prompts || []).length || 0) }]
|
||||
}
|
||||
if (stepKey === stepKeyImages) {
|
||||
return [{ label: '图片数量', value: String((output.image_refs || []).length || 0) }]
|
||||
}
|
||||
if (stepKey === stepKeyPreview) {
|
||||
return [{ label: '预览状态', value: output.preview_html ? '已生成' : '未生成' }]
|
||||
}
|
||||
if (stepKey === stepKeyPageMD) {
|
||||
return [{ label: '分页数量', value: String((output.pages || []).length || 0) }]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -596,7 +696,7 @@ const flowNodes = computed(() => {
|
||||
return nodes.map((item, index) => ({
|
||||
id: item.id,
|
||||
type: 'official-step',
|
||||
position: { x: 80 + index * 456, y: 150 },
|
||||
position: { x: 80 + index * 410, y: 150 },
|
||||
selectable: true,
|
||||
draggable: true,
|
||||
data: {
|
||||
@@ -612,6 +712,10 @@ const flowEdges = computed(() => {
|
||||
[stepKeyTopic, stepKeyTitle],
|
||||
[stepKeyTitle, stepKeyOutline],
|
||||
[stepKeyOutline, stepKeyContent],
|
||||
[stepKeyContent, stepKeyImagePrompts],
|
||||
[stepKeyImagePrompts, stepKeyImages],
|
||||
[stepKeyImages, stepKeyPreview],
|
||||
[stepKeyPreview, stepKeyPageMD],
|
||||
]
|
||||
return chain.map(([source, target], index) => ({
|
||||
id: `edge-${source}-${target}`,
|
||||
@@ -670,6 +774,10 @@ function stepPreview(key) {
|
||||
if (key === stepKeyTitle) return workflow.value?.shared?.selected_title || '围绕选题生成标题候选'
|
||||
if (key === stepKeyOutline) return workflow.value?.shared?.outline ? firstLine(workflow.value.shared.outline) : '输出文章结构提纲'
|
||||
if (key === stepKeyContent) return workflow.value?.shared?.content ? `${workflow.value.shared.content.slice(0, 28)}...` : '输出正文草稿'
|
||||
if (key === stepKeyImagePrompts) return (workflow.value?.shared?.image_prompts || []).length ? `已提炼 ${(workflow.value?.shared?.image_prompts || []).length} 条配图提示词` : '从正文提炼配图提示词'
|
||||
if (key === stepKeyImages) return (workflow.value?.shared?.image_refs || []).length ? `已生成 ${(workflow.value?.shared?.image_refs || []).length} 张图片` : '根据提示词生成配图'
|
||||
if (key === stepKeyPreview) return workflow.value?.shared?.preview_html ? '已生成图文预览稿' : '生成图文预览与导出稿'
|
||||
if (key === stepKeyPageMD) return workflow.value?.shared?.page_markdown ? '已生成分页 Markdown' : '输出分页 MD'
|
||||
return '等待执行'
|
||||
}
|
||||
|
||||
@@ -680,6 +788,10 @@ function canRunStep(key) {
|
||||
if (key === stepKeyTitle) return Boolean(stepPayload.topic || workflow.value?.shared?.selected_topic)
|
||||
if (key === stepKeyOutline) return Boolean(stepPayload.title || workflow.value?.shared?.selected_title)
|
||||
if (key === stepKeyContent) return Boolean(stepPayload.outline || workflow.value?.shared?.outline)
|
||||
if (key === stepKeyImagePrompts) return Boolean(stepPayload.content || workflow.value?.shared?.content)
|
||||
if (key === stepKeyImages) return Boolean(stepPayload.contentWithPrompts || workflow.value?.shared?.content_with_prompts || (workflow.value?.shared?.image_prompts || []).length)
|
||||
if (key === stepKeyPreview) return Boolean(workflow.value?.shared?.content)
|
||||
if (key === stepKeyPageMD) return Boolean(workflow.value?.shared?.content)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -689,6 +801,10 @@ function stepHintText(key) {
|
||||
if (key === stepKeyTitle) return '请先在上一节点确认选题'
|
||||
if (key === stepKeyOutline) return '请先生成或选择标题'
|
||||
if (key === stepKeyContent) return '请先生成或填写提纲'
|
||||
if (key === stepKeyImagePrompts) return '请先生成正文'
|
||||
if (key === stepKeyImages) return '请先生成配图提示词'
|
||||
if (key === stepKeyPreview) return '请先生成正文与图片'
|
||||
if (key === stepKeyPageMD) return '请先生成预览稿'
|
||||
return '当前节点暂不可执行'
|
||||
}
|
||||
|
||||
@@ -712,6 +828,10 @@ function stepLabel(key) {
|
||||
if (key === stepKeyTitle) return '选题后生成标题'
|
||||
if (key === stepKeyOutline) return '提纲生成'
|
||||
if (key === stepKeyContent) return '正文创作'
|
||||
if (key === stepKeyImagePrompts) return '配图提示词'
|
||||
if (key === stepKeyImages) return '图片生成'
|
||||
if (key === stepKeyPreview) return '预览与导出'
|
||||
if (key === stepKeyPageMD) return '分页 MD'
|
||||
return '节点'
|
||||
}
|
||||
|
||||
@@ -762,12 +882,33 @@ function toggleNodeExpand(stepKey) {
|
||||
|
||||
function getNodeBubbleAlign(stepKey) {
|
||||
if (stepKey === stepKeyContent) return 'end'
|
||||
if (stepKey === stepKeyImagePrompts) return 'center'
|
||||
if (stepKey === stepKeyImages) return 'center'
|
||||
if (stepKey === stepKeyPreview) return 'end'
|
||||
if (stepKey === stepKeyPageMD) return 'end'
|
||||
if (stepKey === stepKeyOutline) return 'center'
|
||||
return 'start'
|
||||
}
|
||||
|
||||
function getNodeBubbleWidth(stepKey) {
|
||||
return stepKey === stepKeyConfig ? 560 : 500
|
||||
if (stepKey === stepKeyConfig) return 560
|
||||
if (stepKey === stepKeyPreview) return 700
|
||||
if (stepKey === stepKeyPageMD) return 660
|
||||
if (stepKey === stepKeyImages) return 620
|
||||
return 500
|
||||
}
|
||||
|
||||
function getPromptSlotLabel(item, index) {
|
||||
if (item?.key === 'cover' || index === 0) return '封面配图'
|
||||
return `内容配图 ${index}`
|
||||
}
|
||||
|
||||
function getPromptPurpose(item, index) {
|
||||
if (item?.key === 'cover' || index === 0) {
|
||||
return '用于文章封面或头图,先传达主题和整体氛围'
|
||||
}
|
||||
const sectionName = item?.section || `内容段落 ${index}`
|
||||
return `用于“${sectionName}”这一段的说明配图,帮助读者更直观理解内容`
|
||||
}
|
||||
|
||||
function handleNodePanelWheel() {
|
||||
@@ -805,6 +946,10 @@ function stepShortLabel(key) {
|
||||
if (key === stepKeyTitle) return '标题'
|
||||
if (key === stepKeyOutline) return '提纲'
|
||||
if (key === stepKeyContent) return '正文'
|
||||
if (key === stepKeyImagePrompts) return '提示词'
|
||||
if (key === stepKeyImages) return '图片'
|
||||
if (key === stepKeyPreview) return '预览'
|
||||
if (key === stepKeyPageMD) return '分页'
|
||||
return '节点'
|
||||
}
|
||||
|
||||
@@ -877,7 +1022,7 @@ async function createTask() {
|
||||
}
|
||||
|
||||
async function loadWorkflow(taskId = selectedTaskId.value, options = {}) {
|
||||
const { silent = false, preserveNodeState = false, syncRuntime = true } = options
|
||||
const { silent = false, preserveNodeState = false, syncRuntime = false } = options
|
||||
if (!taskId) {
|
||||
workflowDetail.value = null
|
||||
return
|
||||
@@ -894,7 +1039,7 @@ async function loadWorkflow(taskId = selectedTaskId.value, options = {}) {
|
||||
expandedNodes.value = []
|
||||
}
|
||||
if (syncRuntime) {
|
||||
await workerRuntime.loadTaskDetail(taskId)
|
||||
void workerRuntime.loadTaskDetail(taskId)
|
||||
}
|
||||
if (fittedTaskId.value !== String(taskId)) {
|
||||
await nextTick()
|
||||
@@ -920,6 +1065,8 @@ function syncSelectionsFromWorkflow() {
|
||||
stepPayload.topic = shared.selected_topic || ''
|
||||
stepPayload.title = shared.selected_title || ''
|
||||
stepPayload.outline = shared.outline || ''
|
||||
stepPayload.content = shared.content || ''
|
||||
stepPayload.contentWithPrompts = shared.content_with_prompts || ''
|
||||
stepPayload.requirements = workflow.value?.form?.requirements || ''
|
||||
configForm.keyword = workflow.value?.form?.keyword || ''
|
||||
configForm.businessDomain = workflow.value?.form?.business_domain || 'auto'
|
||||
@@ -1016,14 +1163,16 @@ async function runStep(stepKey) {
|
||||
runningStepKey.value = stepKey
|
||||
pollingStepKey.value = stepKey
|
||||
await nextTick()
|
||||
ElMessage.success(`${stepLabel(stepKey)}已开始执行`)
|
||||
await executeOfficialAccountWorkflowStep(selectedTaskId.value, stepKey, {
|
||||
topic: stepPayload.topic,
|
||||
title: stepPayload.title,
|
||||
outline: stepPayload.outline,
|
||||
content: stepPayload.content,
|
||||
content_with_prompts: stepPayload.contentWithPrompts,
|
||||
requirements: stepPayload.requirements,
|
||||
})
|
||||
await loadWorkflow(selectedTaskId.value, { silent: true, preserveNodeState: true, syncRuntime: false })
|
||||
ElMessage.success(`${stepLabel(stepKey)}已开始执行`)
|
||||
await pollWorkflowUntilStepSettled(String(selectedTaskId.value), stepKey, { notifyOnFinish: true })
|
||||
} catch (error) {
|
||||
runningStepKey.value = ''
|
||||
@@ -1035,10 +1184,31 @@ async function runStep(stepKey) {
|
||||
|
||||
function findRunningStepKey(workflowState = workflow.value) {
|
||||
const steps = workflowState?.steps || {}
|
||||
return [stepKeyTopic, stepKeyTitle, stepKeyOutline, stepKeyContent]
|
||||
return [stepKeyTopic, stepKeyTitle, stepKeyOutline, stepKeyContent, stepKeyImagePrompts, stepKeyImages, stepKeyPreview, stepKeyPageMD]
|
||||
.find(key => steps?.[key]?.status === 'running') || ''
|
||||
}
|
||||
|
||||
async function downloadExport(format, filename) {
|
||||
if (!selectedTaskId.value) return
|
||||
try {
|
||||
exportingFormat.value = format
|
||||
const blob = await exportOfficialAccountDocument(selectedTaskId.value, format)
|
||||
const url = window.URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = filename
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
link.remove()
|
||||
window.URL.revokeObjectURL(url)
|
||||
ElMessage.success('导出文件已准备好')
|
||||
} catch (error) {
|
||||
ElMessage.error(error?.message || '导出失败')
|
||||
} finally {
|
||||
exportingFormat.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
async function pollWorkflowUntilStepSettled(taskId, stepKey, options = {}) {
|
||||
const { notifyOnFinish = false } = options
|
||||
const token = pollingToken.value + 1
|
||||
@@ -1532,12 +1702,187 @@ onMounted(async () => {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.pagemd-preview {
|
||||
max-height: 420px;
|
||||
}
|
||||
|
||||
.prompt-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.prompt-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.prompt-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(37, 99, 235, 0.1);
|
||||
color: #2563eb;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.prompt-card,
|
||||
.image-card {
|
||||
padding: 12px;
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(228, 231, 237, 0.9);
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.prompt-title,
|
||||
.image-section {
|
||||
margin-top: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
|
||||
.prompt-chip {
|
||||
flex: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(15, 23, 42, 0.06);
|
||||
color: #475569;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.prompt-meta {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.prompt-body,
|
||||
.image-prompt {
|
||||
margin-top: 8px;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: #526071;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.prompt-raw-preview {
|
||||
max-height: 260px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.image-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.image-thumb {
|
||||
width: 100%;
|
||||
aspect-ratio: 16 / 9;
|
||||
object-fit: cover;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(191, 219, 254, 0.9);
|
||||
background: #e2e8f0;
|
||||
}
|
||||
|
||||
.action-row {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.action-row-start {
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.preview-render {
|
||||
border-radius: 18px;
|
||||
border: 1px solid rgba(228, 231, 237, 0.9);
|
||||
background: #fff;
|
||||
padding: 18px;
|
||||
max-height: min(60vh, 680px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.page-chip-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-chip {
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
background: rgba(37, 99, 235, 0.08);
|
||||
color: #2563eb;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
:deep(.oa-preview) {
|
||||
color: #1f2d3d;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
:deep(.oa-preview h1) {
|
||||
margin: 0 0 14px;
|
||||
font-size: 22px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
:deep(.oa-preview h2) {
|
||||
margin: 22px 0 10px;
|
||||
font-size: 18px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
:deep(.oa-preview p),
|
||||
:deep(.oa-preview blockquote),
|
||||
:deep(.oa-preview li) {
|
||||
font-size: 14px;
|
||||
line-height: 1.85;
|
||||
}
|
||||
|
||||
:deep(.oa-preview blockquote) {
|
||||
margin: 10px 0;
|
||||
padding: 10px 12px;
|
||||
border-left: 3px solid rgba(37, 99, 235, 0.35);
|
||||
background: rgba(37, 99, 235, 0.05);
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
:deep(.oa-preview ul) {
|
||||
margin: 10px 0 10px 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:deep(.oa-preview-figure) {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
:deep(.oa-preview-figure img) {
|
||||
width: 100%;
|
||||
border-radius: 14px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
:deep(.oa-preview-figure figcaption) {
|
||||
margin-top: 8px;
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.oa-node {
|
||||
width: 360px;
|
||||
padding: 20px;
|
||||
|
||||
Reference in New Issue
Block a user