1453 lines
39 KiB
Vue
1453 lines
39 KiB
Vue
<template>
|
||
<div class="detail-page">
|
||
<header class="article-hero">
|
||
<nav class="breadcrumbs" aria-label="面包屑导航">
|
||
<router-link to="/">首页</router-link>
|
||
<i class="el-icon-arrow-right"></i>
|
||
<router-link v-if="primaryCategory" :to="`/category/${primaryCategory.typeId}`">
|
||
{{ primaryCategory.typeName }}
|
||
</router-link>
|
||
<span v-else>内容详情</span>
|
||
</nav>
|
||
|
||
<div class="hero-layout">
|
||
<div class="article-heading">
|
||
<div class="hero-heading-top">
|
||
<div class="category-row">
|
||
<span class="project-code-label">{{ projectCode }}</span>
|
||
<router-link v-for="type in blog.types" :key="type.typeId" :to="`/category/${type.typeId}`">
|
||
{{ type.typeName }}
|
||
</router-link>
|
||
</div>
|
||
<span class="hero-section-label">PROJECT DETAIL</span>
|
||
</div>
|
||
<h1>{{ cleanProjectTitle || '正在加载项目…' }}</h1>
|
||
<p v-if="blog.blogDesc" class="article-lead">{{ blog.blogDesc }}</p>
|
||
<div class="hero-footer">
|
||
<div class="article-meta">
|
||
<span class="author-avatar">{{ (blog.createBy || '南').slice(0, 1) }}</span>
|
||
<div class="author-copy">
|
||
<strong>{{ blog.createBy || '南音' }}</strong>
|
||
<span>
|
||
<time :datetime="isoDate(blog.createTime)">{{ blog.createTime }}</time>
|
||
<i></i>{{ blog.views || 0 }} 次阅读
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<router-link to="/projects" class="hero-catalog-link">
|
||
浏览全部源码 <i class="el-icon-right"></i>
|
||
</router-link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="article-wrap">
|
||
<div class="project-detail-grid">
|
||
<div class="project-main-column">
|
||
<article class="article-paper">
|
||
<section class="project-overview" aria-labelledby="overview-title">
|
||
<div class="content-section-title">
|
||
<span>PROJECT OVERVIEW</span>
|
||
<h2 id="overview-title">项目概览</h2>
|
||
</div>
|
||
<div class="overview-grid">
|
||
<div><span>项目编号</span><strong>{{ projectCode }}</strong></div>
|
||
<div><span>项目类型</span><strong>{{ projectTypeText }}</strong></div>
|
||
<div><span>核心技术</span><strong>{{ techStackText }}</strong></div>
|
||
<div><span>运行环境</span><strong>JDK · MySQL · Node.js</strong></div>
|
||
</div>
|
||
<div class="delivery-strip">
|
||
<span><i class="el-icon-circle-check"></i> 完整源码</span>
|
||
<span><i class="el-icon-circle-check"></i> 数据库文件</span>
|
||
<span><i class="el-icon-circle-check"></i> 项目截图</span>
|
||
<span><i class="el-icon-circle-check"></i> 运行说明</span>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="content-section-title project-detail-title">
|
||
<span>PROJECT DETAILS</span>
|
||
<h2>项目功能与说明</h2>
|
||
</div>
|
||
<div v-if="blog.contentType === '1'" class="article-content typo ql-editor" v-html="blog.content"></div>
|
||
<div v-if="blog.contentType === '3'" class="article-content" v-html="blog.content"></div>
|
||
<div v-if="blog.contentType === '2'" class="article-content markdown-content">
|
||
<CherryMarkdown ref="CherryMarkdown" v-model="blog.contentMarkdown" :defaultModel="'previewOnly'" />
|
||
</div>
|
||
|
||
<section v-if="blog.blogFilesNew && blog.blogFilesNew.length" class="attachments" aria-labelledby="attachment-title">
|
||
<div class="content-section-title">
|
||
<span>FILES</span>
|
||
<h2 id="attachment-title">项目附件</h2>
|
||
</div>
|
||
<div class="attachment-list">
|
||
<div v-for="file in blog.blogFilesNew" :key="file.filePath" class="attachment-card">
|
||
<span class="file-icon"><i class="el-icon-document"></i></span>
|
||
<div class="file-copy">
|
||
<strong>{{ file.fileOriginName }}</strong>
|
||
<span>{{ file.fileSuffix || '文件' }} · {{ file.fileSize || '未知大小' }}</span>
|
||
<p v-if="file.remark">{{ file.remark }}</p>
|
||
</div>
|
||
<div class="file-actions">
|
||
<button type="button" @click="handlePreview(file)"><i class="el-icon-view"></i> 预览</button>
|
||
<button type="button" class="download" @click="handleDownload(file)"><i class="el-icon-download"></i> 下载</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<footer class="article-footer">
|
||
<div class="article-tags">
|
||
<router-link v-for="tag in blog.tags" :key="tag.tagId" :to="`/tag/${tag.tagId}`">
|
||
# {{ tag.tagName }}
|
||
</router-link>
|
||
</div>
|
||
<div class="author-note">
|
||
<span class="note-mark">NY</span>
|
||
<div>
|
||
<strong>由 {{ blog.createBy || '南音' }} 整理发布</strong>
|
||
<p>记录真实开发过程,分享可以运行、可以复用的代码与经验。</p>
|
||
</div>
|
||
<time v-if="blog.updateTime" :datetime="isoDate(blog.updateTime)">更新于 {{ blog.updateTime }}</time>
|
||
</div>
|
||
</footer>
|
||
</article>
|
||
</div>
|
||
|
||
<aside class="source-panel">
|
||
<div class="source-panel-head">
|
||
<span>{{ projectCode }}</span>
|
||
<small>SOURCE PACKAGE</small>
|
||
</div>
|
||
<h2>{{ cleanProjectTitle }}</h2>
|
||
<p>{{ blog.blogDesc || '完整项目源码与运行资料,适合学习、课程设计和毕业设计参考。' }}</p>
|
||
<dl>
|
||
<div><dt>技术栈</dt><dd>{{ techStackText }}</dd></div>
|
||
<div><dt>数据库</dt><dd>MySQL</dd></div>
|
||
<div><dt>更新时间</dt><dd>{{ shortDate(blog.updateTime || blog.createTime) }}</dd></div>
|
||
<div><dt>浏览量</dt><dd>{{ blog.views || 0 }}</dd></div>
|
||
</dl>
|
||
<ul>
|
||
<li><i class="el-icon-check"></i> 项目源代码</li>
|
||
<li><i class="el-icon-check"></i> 数据库脚本</li>
|
||
<li><i class="el-icon-check"></i> 配置与运行说明</li>
|
||
</ul>
|
||
<button type="button" class="get-source-button" @click="getSourcePackage">
|
||
<i class="el-icon-download"></i> 获取源码
|
||
</button>
|
||
<router-link to="/cms/doucument" class="document-link">
|
||
<i class="el-icon-document"></i> 查看运行教程
|
||
</router-link>
|
||
<small class="source-tip">获取前请先确认技术栈与运行环境</small>
|
||
</aside>
|
||
</div>
|
||
|
||
<aside v-if="relatedBlogs.length" class="related-section" aria-labelledby="related-content-title">
|
||
<div class="content-section-title">
|
||
<span>KEEP READING</span>
|
||
<h2 id="related-content-title">相似源码项目</h2>
|
||
</div>
|
||
<div class="related-grid">
|
||
<router-link v-for="(related, index) in relatedBlogs" :key="related.id" :to="contentPath(related)" class="related-card">
|
||
<span>{{ String(index + 1).padStart(2, '0') }}</span>
|
||
<h3>{{ related.title }}</h3>
|
||
<i class="el-icon-right"></i>
|
||
</router-link>
|
||
</div>
|
||
</aside>
|
||
|
||
<section class="comments-section">
|
||
<div class="content-section-title">
|
||
<span>DISCUSSION</span>
|
||
<h2>项目咨询与交流</h2>
|
||
</div>
|
||
<comment />
|
||
</section>
|
||
</main>
|
||
|
||
<el-dialog
|
||
:visible.sync="sourceQrVisible"
|
||
custom-class="source-qr-dialog"
|
||
:show-close="true"
|
||
:close-on-click-modal="true"
|
||
:modal-append-to-body="false"
|
||
aria-label="小程序源码获取二维码"
|
||
>
|
||
<div class="source-qr-content">
|
||
<span class="source-qr-kicker">MINI PROGRAM</span>
|
||
<h2>扫码进入小程序获取源码</h2>
|
||
<p>打开微信扫一扫,在小程序内搜索当前项目编号即可查看源码获取方式。</p>
|
||
<div class="source-qr-image">
|
||
<img src="https://img.yidaima.cn/qrcode.jpg" alt="南音源码库微信小程序二维码">
|
||
</div>
|
||
<div class="source-qr-project">
|
||
<span>当前项目</span>
|
||
<strong>{{ projectCode }} · {{ cleanProjectTitle }}</strong>
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-backtop :bottom="32" :right="28">
|
||
<div class="back-top"><i class="el-icon-top"></i></div>
|
||
</el-backtop>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
// import 'cherry-markdown/dist/cherry-markdown.min.css'
|
||
//使用prism.js代码高亮
|
||
import {
|
||
getBlogDetail,
|
||
addBlogViews,
|
||
cmsListByTypeId,
|
||
} from "@/api/cms/blog";
|
||
import {mapState} from 'vuex'
|
||
import {
|
||
blogImageUrl,
|
||
canonicalUrl,
|
||
contentPath,
|
||
isoDate,
|
||
jsonLdScript,
|
||
seoDescription,
|
||
siteIdentity
|
||
} from '@/utils/seo'
|
||
|
||
export default {
|
||
components: {
|
||
comment: () => import(/* webpackChunkName: "cms-comments" */ './comment/Ipcomment'),
|
||
CherryMarkdown: () => import(/* webpackChunkName: "cherry-markdown" */ '@/components/CherryMarkdown'),
|
||
},
|
||
data() {
|
||
return {
|
||
blog: {
|
||
blogFilesNew: []
|
||
},
|
||
relatedBlogs: [],
|
||
commentForm: {
|
||
content: ''
|
||
},
|
||
sourceQrVisible: false,
|
||
}
|
||
},
|
||
watch: {
|
||
blogId() {
|
||
this.getBlogInfomation()
|
||
}
|
||
},
|
||
created() {
|
||
this.getBlogInfomation()
|
||
},
|
||
computed: {
|
||
...mapState([
|
||
'userInfo',
|
||
'administrator',
|
||
]),
|
||
blogId() {
|
||
return this.$route.params.id || this.$route.query.id
|
||
},
|
||
articleDescription() {
|
||
return seoDescription(this.blog) || '南音源码库项目源码、开发教程与技术文档。'
|
||
},
|
||
articleImage() {
|
||
return blogImageUrl(this.blog)
|
||
},
|
||
articleUrl() {
|
||
const path = this.blog.id ? contentPath(this.blog) : this.$route.path
|
||
return canonicalUrl(path)
|
||
},
|
||
primaryCategory() {
|
||
return this.blog.types && this.blog.types.length ? this.blog.types[0] : null
|
||
},
|
||
projectCode() {
|
||
const title = this.blog.title ? String(this.blog.title) : ''
|
||
const match = title.match(/[【\[]\s*([A-Za-z]*\d+)\s*[】\]]/)
|
||
return match ? match[1].toUpperCase() : `SRC-${String(this.blog.id || 0).padStart(4, '0')}`
|
||
},
|
||
cleanProjectTitle() {
|
||
return String(this.blog.title || '')
|
||
.replace(/^[【\[]\s*[A-Za-z]*\d+\s*[】\]]\s*/, '')
|
||
.trim()
|
||
},
|
||
projectTypeText() {
|
||
const types = (this.blog.types || []).map(type => type.typeName).filter(Boolean)
|
||
return types.length ? types.slice(0, 2).join(' · ') : '管理系统'
|
||
},
|
||
techStack() {
|
||
const tags = (this.blog.tags || []).map(tag => tag.tagName).filter(Boolean)
|
||
if (tags.length) return tags.slice(0, 4)
|
||
const source = `${this.blog.title || ''} ${this.blog.blogDesc || ''} ${this.blog.content || ''}`.toLowerCase()
|
||
const candidates = [
|
||
['Spring Boot', /spring\s*boot|springboot/],
|
||
['SSM', /\bssm\b/],
|
||
['Vue3', /vue\s*3|vue3/],
|
||
['Vue2', /vue\s*2|vue2/],
|
||
['微信小程序', /微信小程序|小程序/],
|
||
['Java', /\bjava\b|jdk/],
|
||
['MySQL', /mysql/],
|
||
['Python', /python/]
|
||
]
|
||
const inferred = candidates.filter(item => item[1].test(source)).map(item => item[0])
|
||
return inferred.length ? inferred.slice(0, 4) : ['Java Web', 'MySQL']
|
||
},
|
||
techStackText() {
|
||
return this.techStack.join(' · ')
|
||
}
|
||
},
|
||
metaInfo() {
|
||
const identity = siteIdentity()
|
||
const fullTitle = this.blog.title ? `${this.blog.title} - ${identity.name}` : `内容详情 - ${identity.name}`
|
||
const meta = [
|
||
{
|
||
vmid: 'description',
|
||
name: 'description',
|
||
content: this.articleDescription
|
||
},
|
||
{
|
||
vmid: 'robots',
|
||
name: 'robots',
|
||
content: this.blog.id ? 'index,follow,max-image-preview:large' : 'noindex,follow'
|
||
},
|
||
{
|
||
vmid: 'og:title',
|
||
property: 'og:title',
|
||
content: fullTitle
|
||
},
|
||
{
|
||
vmid: 'og:description',
|
||
property: 'og:description',
|
||
content: this.articleDescription
|
||
},
|
||
{
|
||
vmid: 'og:type',
|
||
property: 'og:type',
|
||
content: 'article'
|
||
},
|
||
{
|
||
vmid: 'og:url',
|
||
property: 'og:url',
|
||
content: this.articleUrl
|
||
},
|
||
{
|
||
vmid: 'twitter:card',
|
||
name: 'twitter:card',
|
||
content: this.articleImage ? 'summary_large_image' : 'summary'
|
||
},
|
||
{
|
||
vmid: 'twitter:title',
|
||
name: 'twitter:title',
|
||
content: fullTitle
|
||
},
|
||
{
|
||
vmid: 'twitter:description',
|
||
name: 'twitter:description',
|
||
content: this.articleDescription
|
||
}
|
||
]
|
||
if (this.articleImage) {
|
||
meta.push(
|
||
{
|
||
vmid: 'og:image',
|
||
property: 'og:image',
|
||
content: this.articleImage
|
||
},
|
||
{
|
||
vmid: 'twitter:image',
|
||
name: 'twitter:image',
|
||
content: this.articleImage
|
||
}
|
||
)
|
||
}
|
||
if (this.blog.createTime) {
|
||
meta.push({
|
||
vmid: 'article:published_time',
|
||
property: 'article:published_time',
|
||
content: isoDate(this.blog.createTime)
|
||
})
|
||
}
|
||
if (this.blog.updateTime) {
|
||
meta.push({
|
||
vmid: 'article:modified_time',
|
||
property: 'article:modified_time',
|
||
content: isoDate(this.blog.updateTime)
|
||
})
|
||
}
|
||
const scripts = []
|
||
if (this.blog.id) {
|
||
const article = {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'BlogPosting',
|
||
headline: this.blog.title,
|
||
description: this.articleDescription,
|
||
url: this.articleUrl,
|
||
mainEntityOfPage: this.articleUrl,
|
||
image: this.articleImage || undefined,
|
||
datePublished: isoDate(this.blog.createTime),
|
||
dateModified: isoDate(this.blog.updateTime || this.blog.createTime),
|
||
author: {
|
||
'@type': 'Person',
|
||
name: this.blog.createBy || identity.name
|
||
},
|
||
publisher: {
|
||
'@type': 'Organization',
|
||
name: identity.name,
|
||
url: identity.url
|
||
},
|
||
articleSection: this.primaryCategory && this.primaryCategory.typeName,
|
||
keywords: (this.blog.tags || []).map(tag => tag.tagName).join(',')
|
||
}
|
||
if (contentPath(this.blog).startsWith('/source/')) {
|
||
article.about = {
|
||
'@type': 'SoftwareSourceCode',
|
||
name: this.blog.title,
|
||
description: this.articleDescription
|
||
}
|
||
}
|
||
const breadcrumbItems = [
|
||
{
|
||
'@type': 'ListItem',
|
||
position: 1,
|
||
name: '首页',
|
||
item: identity.url
|
||
}
|
||
]
|
||
if (this.primaryCategory) {
|
||
breadcrumbItems.push({
|
||
'@type': 'ListItem',
|
||
position: 2,
|
||
name: this.primaryCategory.typeName,
|
||
item: canonicalUrl(`/category/${this.primaryCategory.typeId}`)
|
||
})
|
||
}
|
||
breadcrumbItems.push({
|
||
'@type': 'ListItem',
|
||
position: breadcrumbItems.length + 1,
|
||
name: this.blog.title,
|
||
item: this.articleUrl
|
||
})
|
||
scripts.push(
|
||
jsonLdScript('article-jsonld', article),
|
||
jsonLdScript('breadcrumb-jsonld', {
|
||
'@context': 'https://schema.org',
|
||
'@type': 'BreadcrumbList',
|
||
itemListElement: breadcrumbItems
|
||
})
|
||
)
|
||
}
|
||
return {
|
||
title: fullTitle,
|
||
titleTemplate: null,
|
||
meta: [
|
||
...meta
|
||
],
|
||
link: [
|
||
{
|
||
vmid: 'canonical',
|
||
rel: 'canonical',
|
||
href: this.articleUrl
|
||
}
|
||
],
|
||
script: scripts
|
||
}
|
||
},
|
||
methods: {
|
||
contentPath,
|
||
isoDate,
|
||
shortDate(value) {
|
||
return value ? String(value).slice(0, 10) : '持续维护'
|
||
},
|
||
getSourcePackage() {
|
||
this.sourceQrVisible = true
|
||
},
|
||
// 获取博客详情信息
|
||
async getBlogInfomation() {
|
||
if (!this.blogId) {
|
||
this.$router.replace('/404')
|
||
return
|
||
}
|
||
this.blog = {
|
||
blogFilesNew: []
|
||
}
|
||
this.relatedBlogs = []
|
||
try {
|
||
const response = await getBlogDetail(this.blogId)
|
||
if (!response.data) {
|
||
throw new Error('文章不存在')
|
||
}
|
||
this.blog = response.data
|
||
this.blog.blogFilesNew = []
|
||
if (response.data.blogFiles !== null) {
|
||
try {
|
||
this.blog.blogFilesNew = JSON.parse(response.data.blogFiles)
|
||
} catch (error) {
|
||
this.blog.blogFilesNew = []
|
||
}
|
||
}
|
||
const preferredPath = contentPath(this.blog)
|
||
if (this.$route.path !== preferredPath) {
|
||
this.$router.replace(preferredPath).catch(() => {})
|
||
}
|
||
this.loadSyntaxHighlighting()
|
||
this.loadRelatedBlogs()
|
||
addBlogViews(this.blogId).catch(() => {})
|
||
} catch (error) {
|
||
this.blog = {
|
||
blogFilesNew: []
|
||
}
|
||
this.$router.replace('/404')
|
||
}
|
||
},
|
||
async loadRelatedBlogs() {
|
||
const primaryType = this.primaryCategory
|
||
if (!primaryType) {
|
||
return
|
||
}
|
||
try {
|
||
const response = await cmsListByTypeId(primaryType.typeId, {
|
||
pageNum: 1,
|
||
pageSize: 6
|
||
})
|
||
this.relatedBlogs = response.rows
|
||
.filter(blog => String(blog.id) !== String(this.blog.id))
|
||
.slice(0, 4)
|
||
} catch (error) {
|
||
this.relatedBlogs = []
|
||
}
|
||
},
|
||
async loadSyntaxHighlighting() {
|
||
if (!['1', '3'].includes(String(this.blog.contentType))) {
|
||
return
|
||
}
|
||
try {
|
||
const modules = await Promise.all([
|
||
import(/* webpackChunkName: "prism-highlighter" */ '@/views/cms/plugins/prism.js'),
|
||
import(/* webpackChunkName: "prism-highlighter" */ '@/views/cms/plugins/prism.css')
|
||
])
|
||
const prism = modules[0].default || window.Prism
|
||
this.$nextTick(() => {
|
||
if (prism && prism.highlightAllUnder) {
|
||
prism.highlightAllUnder(this.$el)
|
||
}
|
||
})
|
||
} catch (error) {
|
||
// Optional highlighting must not prevent the article from rendering.
|
||
}
|
||
},
|
||
// 文件下载处理
|
||
handleDownload(row) {
|
||
var name = row.fileOriginName;
|
||
var url = row.filePath;
|
||
const a = document.createElement('a')
|
||
a.setAttribute('download', name)
|
||
a.setAttribute('target', '_blank')
|
||
a.setAttribute('href', process.env.VUE_APP_BASE_API + url)
|
||
a.click()
|
||
},
|
||
// 文件预览处理
|
||
async handlePreview(row) {
|
||
var name = row.fileOriginName;
|
||
var filePath = row.filePath;
|
||
var url = process.env.VUE_APP_BASE_API + filePath;
|
||
const response = await fetch(url);
|
||
if(response.status === 200){
|
||
const blob = await response.blob()
|
||
var objectURL = window.URL.createObjectURL(blob);
|
||
var openUrl = window.location.origin + '/fileViewer/index.html' + '?name=' + name + '&url=' + objectURL
|
||
window.open(openUrl);
|
||
} else {
|
||
this.$message.error("文件不存在!")
|
||
}
|
||
},
|
||
},
|
||
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
|
||
.el-card {
|
||
width: 100%;
|
||
}
|
||
|
||
.el-popper /deep/ {
|
||
box-shadow: 0 2px 4px 0 rgb(34 36 38 / 12%),
|
||
}
|
||
|
||
.first-card {
|
||
border-radius: 10px 10px 10px 10px;
|
||
position: relative;
|
||
padding-bottom: 10px;
|
||
/*text-align: center;*/
|
||
font: 300 1em/1.8 PingFang SC, Lantinghei SC, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif;
|
||
|
||
}
|
||
|
||
hr.style-one {
|
||
width: 100%;
|
||
background-image: linear-gradient(to right, rgba(64, 158, 255, 0), rgba(64, 158, 255, 0.75), rgba(64, 158, 255, 0));
|
||
}
|
||
|
||
.appreciate {
|
||
text-align: center;
|
||
}
|
||
|
||
.tags {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-left: 50px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.tag-item {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
align-items: center;
|
||
margin-left: 10px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.tag {
|
||
padding-left: 10px;
|
||
padding-right: 10px;
|
||
border-radius: 5px;
|
||
background-color: #ecf5ff;
|
||
border: 1px solid #409eff;
|
||
color: #409eff;
|
||
display: flex;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.type-link {
|
||
margin-left: 6px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.related-content {
|
||
margin: 24px 0;
|
||
padding: 16px 20px;
|
||
border-left: 4px solid #409eff;
|
||
background: #f7fbff;
|
||
}
|
||
|
||
.related-content h2 {
|
||
margin: 0 0 10px;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.related-content ul {
|
||
margin: 0;
|
||
padding-left: 20px;
|
||
}
|
||
|
||
.related-content a {
|
||
color: #3a8ee6;
|
||
line-height: 2;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.related-content a:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.sjx-outer {
|
||
width: 0;
|
||
height: 0;
|
||
border-top: 7px solid transparent;
|
||
border-bottom: 7px solid transparent;
|
||
border-right: 7px solid #409eff;
|
||
position: relative;
|
||
}
|
||
|
||
.sjx-inner {
|
||
border-top: 7px solid transparent;
|
||
border-bottom: 7px solid transparent;
|
||
border-right: 7px solid #ecf5ff;
|
||
top: -7px;
|
||
left: 1px;
|
||
position: absolute;
|
||
}
|
||
|
||
.author {
|
||
text-align: left;
|
||
background-color: #fcfff5;
|
||
box-shadow: 0 0 0 1px #a3c293 inset;
|
||
color: #2c662d;
|
||
width: 100%;
|
||
position: absolute;
|
||
left: 0;
|
||
margin: 20px 0;
|
||
padding: 20px 0;
|
||
font-size: small;
|
||
font-family: PingFang SC, Lantinghei SC, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif;
|
||
}
|
||
|
||
.comments {
|
||
margin-top: 150px;
|
||
box-shadow: 0 1px 2px 0 rgb(34 36 38 / 15%);
|
||
border: 1px solid rgba(34, 36, 38, .15);
|
||
border-top: 2px solid #409EFF;
|
||
text-align: left;
|
||
}
|
||
.blog-title {
|
||
text-align: center;
|
||
}
|
||
|
||
.blog-info {
|
||
display: flex;
|
||
align-items: center;
|
||
color: rgba(0, 0, 0, .4);
|
||
font-size: 13px;
|
||
}
|
||
.blog-date {
|
||
margin-right: 5px;
|
||
float: right;
|
||
}
|
||
|
||
.blog-views {
|
||
margin-right: 5px;
|
||
float: right;
|
||
}
|
||
|
||
.user-info {
|
||
justify-content: space-around;
|
||
align-items: center;
|
||
margin-right: 15px;
|
||
float: left;
|
||
}
|
||
|
||
.header {
|
||
text-decoration: none;
|
||
color: #3a8ee6;
|
||
font-weight: bold;
|
||
}
|
||
|
||
@media screen and (max-width: 768px) {
|
||
.tags {
|
||
margin-left: 0;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
hr {
|
||
display: none;
|
||
}
|
||
|
||
.comment-content {
|
||
font-size: 12px !important;
|
||
}
|
||
}
|
||
|
||
@media only screen and (max-width: 480px) {
|
||
h2 {
|
||
font-weight: normal;
|
||
}
|
||
|
||
code, pre {
|
||
font-size: 13px !important;
|
||
}
|
||
}
|
||
.blogFilesInfoName {
|
||
text-align: center;
|
||
padding-top: 5px;
|
||
}
|
||
|
||
/* 限制文章内容中图片的大小 */
|
||
.ql-editor img,
|
||
.typo img {
|
||
max-width: 100%;
|
||
height: auto;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
margin: 10px 0;
|
||
}
|
||
|
||
/* Markdown 内容中的图片样式 */
|
||
/deep/ .cherry-markdown img {
|
||
max-width: 100%;
|
||
height: auto;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
margin: 10px 0;
|
||
}
|
||
</style>
|
||
|
||
<style scoped>
|
||
.detail-page {
|
||
padding-bottom: 76px;
|
||
color: #17273c;
|
||
}
|
||
|
||
.article-hero {
|
||
position: relative;
|
||
padding: 28px 0 42px;
|
||
color: #fff;
|
||
background:
|
||
radial-gradient(circle at 85% 15%, rgba(239, 106, 58, .18), transparent 26%),
|
||
#172941;
|
||
}
|
||
|
||
.article-hero::after {
|
||
content: '';
|
||
height: 1px;
|
||
position: absolute;
|
||
right: 0;
|
||
bottom: 0;
|
||
left: 0;
|
||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .15), transparent);
|
||
}
|
||
|
||
.breadcrumbs,
|
||
.hero-layout,
|
||
.article-wrap {
|
||
width: min(980px, calc(100% - 40px));
|
||
margin-right: auto;
|
||
margin-left: auto;
|
||
}
|
||
|
||
.breadcrumbs {
|
||
margin-bottom: 22px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 9px;
|
||
color: rgba(255, 255, 255, .46);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.breadcrumbs a {
|
||
color: rgba(255, 255, 255, .62);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.breadcrumbs a:hover { color: #fff; }
|
||
.breadcrumbs i { font-size: 10px; }
|
||
|
||
.hero-layout {
|
||
position: relative;
|
||
display: block;
|
||
overflow: hidden;
|
||
padding: 30px 34px 26px;
|
||
border: 1px solid rgba(255, 255, 255, .1);
|
||
border-radius: 18px;
|
||
background:
|
||
linear-gradient(135deg, rgba(255, 255, 255, .055), rgba(255, 255, 255, .018)),
|
||
rgba(10, 24, 42, .22);
|
||
box-shadow: 0 22px 48px rgba(7, 17, 30, .18);
|
||
}
|
||
|
||
.hero-layout::before {
|
||
content: '';
|
||
width: 4px;
|
||
position: absolute;
|
||
top: 28px;
|
||
bottom: 28px;
|
||
left: 0;
|
||
border-radius: 0 999px 999px 0;
|
||
background: linear-gradient(180deg, #ef6a3a, #f5aa76);
|
||
}
|
||
|
||
.hero-layout::after {
|
||
content: '';
|
||
width: 260px;
|
||
height: 260px;
|
||
position: absolute;
|
||
top: -150px;
|
||
right: -80px;
|
||
border: 1px solid rgba(255, 255, 255, .04);
|
||
border-radius: 50%;
|
||
box-shadow: 0 0 0 38px rgba(255, 255, 255, .012), 0 0 0 78px rgba(255, 255, 255, .008);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.article-heading {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.hero-heading-top {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 20px;
|
||
}
|
||
|
||
.hero-section-label {
|
||
color: rgba(255, 255, 255, .28);
|
||
font: 700 9px/1 Consolas, monospace;
|
||
letter-spacing: .18em;
|
||
}
|
||
|
||
.category-row {
|
||
min-height: 22px;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.category-row a {
|
||
padding: 5px 9px;
|
||
border: 1px solid rgba(239, 106, 58, .4);
|
||
border-radius: 6px;
|
||
color: #f6a283;
|
||
background: rgba(239, 106, 58, .08);
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
text-decoration: none;
|
||
letter-spacing: .06em;
|
||
}
|
||
|
||
.article-heading h1 {
|
||
margin: 20px 0 18px;
|
||
overflow: hidden;
|
||
color: #fff;
|
||
font-size: clamp(30px, 3.2vw, 42px);
|
||
line-height: 1.18;
|
||
letter-spacing: -.04em;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.article-lead {
|
||
max-width: 680px;
|
||
margin: 0 0 26px;
|
||
color: rgba(255, 255, 255, .58);
|
||
font-size: 15px;
|
||
line-height: 1.8;
|
||
}
|
||
|
||
.hero-footer {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 24px;
|
||
margin-top: 22px;
|
||
padding-top: 20px;
|
||
border-top: 1px solid rgba(255, 255, 255, .09);
|
||
}
|
||
|
||
.article-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 11px;
|
||
}
|
||
|
||
.author-avatar {
|
||
width: 38px;
|
||
height: 38px;
|
||
display: grid;
|
||
place-items: center;
|
||
flex: 0 0 auto;
|
||
border-radius: 50%;
|
||
color: #fff;
|
||
background: #ef6a3a;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.author-copy {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 5px;
|
||
}
|
||
|
||
.author-copy strong { color: rgba(255, 255, 255, .9); font-size: 12px; }
|
||
|
||
.author-copy span {
|
||
display: flex;
|
||
align-items: center;
|
||
color: rgba(255, 255, 255, .4);
|
||
font-size: 10px;
|
||
}
|
||
|
||
.author-copy i {
|
||
width: 3px;
|
||
height: 3px;
|
||
margin: 0 8px;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, .35);
|
||
}
|
||
|
||
.hero-catalog-link {
|
||
min-height: 36px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 9px;
|
||
padding: 0 14px;
|
||
border: 1px solid rgba(255, 255, 255, .13);
|
||
border-radius: 9px;
|
||
color: rgba(255, 255, 255, .7);
|
||
background: rgba(255, 255, 255, .045);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
text-decoration: none;
|
||
transition: color .2s ease, border-color .2s ease, background .2s ease;
|
||
}
|
||
|
||
.hero-catalog-link:hover {
|
||
color: #fff;
|
||
border-color: rgba(239, 106, 58, .62);
|
||
background: rgba(239, 106, 58, .14);
|
||
}
|
||
|
||
.article-wrap {
|
||
margin-top: 34px;
|
||
}
|
||
|
||
.article-paper,
|
||
.comments-section {
|
||
padding: 54px 68px;
|
||
border: 1px solid #e4dfd5;
|
||
border-radius: 20px;
|
||
background: #fffdf8;
|
||
box-shadow: 0 16px 44px rgba(19, 34, 56, .07);
|
||
}
|
||
|
||
.article-content {
|
||
color: #2f3d50;
|
||
font-size: 16px;
|
||
line-height: 1.9;
|
||
}
|
||
|
||
.article-content /deep/ h1,
|
||
.article-content /deep/ h2,
|
||
.article-content /deep/ h3,
|
||
.article-content /deep/ h4 {
|
||
color: #17273c;
|
||
line-height: 1.4;
|
||
scroll-margin-top: 24px;
|
||
}
|
||
|
||
.article-content /deep/ h2 {
|
||
margin: 2.2em 0 .8em;
|
||
padding-bottom: .45em;
|
||
border-bottom: 1px solid #e9e3d9;
|
||
font-size: 25px;
|
||
}
|
||
|
||
.article-content /deep/ h3 { margin-top: 1.9em; font-size: 20px; }
|
||
.article-content /deep/ p { margin: 1em 0; }
|
||
.article-content /deep/ a { color: #d85831; text-decoration-thickness: 1px; text-underline-offset: 3px; }
|
||
.article-content /deep/ strong { color: #17273c; }
|
||
|
||
.article-content /deep/ blockquote {
|
||
margin: 24px 0;
|
||
padding: 16px 20px;
|
||
border-left: 3px solid #ef6a3a;
|
||
color: #5d6878;
|
||
background: #fff2eb;
|
||
}
|
||
|
||
.article-content /deep/ pre {
|
||
margin: 24px 0;
|
||
padding: 20px;
|
||
overflow-x: auto;
|
||
border: 0;
|
||
border-radius: 13px;
|
||
background: #172941;
|
||
box-shadow: 0 10px 24px rgba(19, 34, 56, .12);
|
||
}
|
||
|
||
.article-content /deep/ code {
|
||
padding: 2px 5px;
|
||
border-radius: 4px;
|
||
color: #c7532e;
|
||
background: #fff0e8;
|
||
font-family: Consolas, Monaco, monospace;
|
||
}
|
||
|
||
.article-content /deep/ pre code {
|
||
padding: 0;
|
||
color: inherit;
|
||
background: transparent;
|
||
}
|
||
|
||
.article-content /deep/ img,
|
||
.markdown-content /deep/ img {
|
||
max-width: 100%;
|
||
height: auto;
|
||
margin: 22px auto;
|
||
display: block;
|
||
border-radius: 13px;
|
||
box-shadow: 0 12px 30px rgba(19, 34, 56, .12);
|
||
}
|
||
|
||
.content-section-title {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.content-section-title span {
|
||
color: #d85831;
|
||
font: 700 10px/1.4 Consolas, monospace;
|
||
letter-spacing: .17em;
|
||
}
|
||
|
||
.content-section-title h2 {
|
||
margin: 6px 0 0;
|
||
color: #17273c;
|
||
font-size: 25px;
|
||
letter-spacing: -.02em;
|
||
}
|
||
|
||
.attachments {
|
||
margin-top: 48px;
|
||
padding-top: 38px;
|
||
border-top: 1px solid #e8e2d8;
|
||
}
|
||
|
||
.attachment-list {
|
||
display: grid;
|
||
gap: 12px;
|
||
}
|
||
|
||
.attachment-card {
|
||
padding: 15px;
|
||
display: grid;
|
||
grid-template-columns: 42px minmax(0, 1fr) auto;
|
||
align-items: center;
|
||
gap: 14px;
|
||
border: 1px solid #e5e0d7;
|
||
border-radius: 12px;
|
||
background: #faf8f2;
|
||
}
|
||
|
||
.file-icon {
|
||
width: 42px;
|
||
height: 42px;
|
||
display: grid;
|
||
place-items: center;
|
||
border-radius: 10px;
|
||
color: #28727a;
|
||
background: #e6f0ef;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.file-copy {
|
||
min-width: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
|
||
.file-copy strong { overflow: hidden; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
|
||
.file-copy span { color: #969ca5; font-size: 10px; }
|
||
.file-copy p { margin: 2px 0 0; color: #737c89; font-size: 11px; }
|
||
|
||
.file-actions { display: flex; gap: 7px; }
|
||
|
||
.file-actions button {
|
||
height: 34px;
|
||
padding: 0 12px;
|
||
border: 1px solid #d8d4cb;
|
||
border-radius: 8px;
|
||
color: #596678;
|
||
background: #fff;
|
||
font-size: 11px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.file-actions .download { border-color: #ef6a3a; color: #fff; background: #ef6a3a; }
|
||
|
||
.article-footer {
|
||
margin-top: 48px;
|
||
padding-top: 30px;
|
||
border-top: 1px solid #e8e2d8;
|
||
}
|
||
|
||
.article-tags {
|
||
margin-bottom: 24px;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.article-tags a {
|
||
padding: 7px 11px;
|
||
border-radius: 8px;
|
||
color: #28727a;
|
||
background: #eaf2f1;
|
||
font-size: 11px;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.author-note {
|
||
padding: 18px;
|
||
display: grid;
|
||
grid-template-columns: 48px minmax(0, 1fr) auto;
|
||
align-items: center;
|
||
gap: 14px;
|
||
border-radius: 14px;
|
||
background: #172941;
|
||
}
|
||
|
||
.note-mark {
|
||
width: 48px;
|
||
height: 48px;
|
||
display: grid;
|
||
place-items: center;
|
||
border: 1px solid rgba(255, 255, 255, .14);
|
||
border-radius: 12px;
|
||
color: #fff;
|
||
background: rgba(255, 255, 255, .06);
|
||
font: 700 14px/1 Consolas, monospace;
|
||
}
|
||
|
||
.author-note strong { color: #fff; font-size: 12px; }
|
||
.author-note p { margin: 5px 0 0; color: rgba(255, 255, 255, .45); font-size: 10px; }
|
||
.author-note time { color: rgba(255, 255, 255, .32); font-size: 9px; }
|
||
|
||
.related-section {
|
||
margin-top: 48px;
|
||
}
|
||
|
||
.related-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 12px;
|
||
}
|
||
|
||
.related-card {
|
||
min-height: 110px;
|
||
padding: 19px;
|
||
display: grid;
|
||
grid-template-columns: 28px minmax(0, 1fr) 18px;
|
||
align-items: center;
|
||
gap: 8px;
|
||
border: 1px solid #dfdbd2;
|
||
border-radius: 14px;
|
||
color: #17273c;
|
||
background: rgba(255, 253, 248, .88);
|
||
text-decoration: none;
|
||
transition: transform .2s ease, border-color .2s ease;
|
||
}
|
||
|
||
.related-card:hover { border-color: #ef6a3a; transform: translateY(-2px); }
|
||
.related-card > span { color: #ef6a3a; font: 700 10px/1 Consolas, monospace; }
|
||
.related-card h3 { margin: 0; font-size: 14px; line-height: 1.55; }
|
||
.related-card i { color: #9ca2aa; }
|
||
|
||
.comments-section {
|
||
margin-top: 48px;
|
||
padding-top: 42px;
|
||
}
|
||
|
||
.back-top {
|
||
width: 44px;
|
||
height: 44px;
|
||
display: grid;
|
||
place-items: center;
|
||
border-radius: 12px;
|
||
color: #fff;
|
||
background: #172941;
|
||
box-shadow: 0 12px 24px rgba(19, 34, 56, .2);
|
||
}
|
||
|
||
@media (max-width: 820px) {
|
||
.article-hero { padding: 24px 0 36px; }
|
||
.breadcrumbs,
|
||
.hero-layout,
|
||
.article-wrap { width: min(100% - 28px, 980px); }
|
||
.breadcrumbs { margin-bottom: 18px; }
|
||
.hero-layout { padding: 26px 26px 23px; }
|
||
.article-heading h1 { white-space: normal; }
|
||
.article-paper,
|
||
.comments-section { padding: 38px 34px; }
|
||
}
|
||
|
||
@media (max-width: 560px) {
|
||
.hero-layout { padding: 22px 20px 20px; border-radius: 14px; }
|
||
.hero-layout::before { top: 20px; bottom: 20px; }
|
||
.hero-section-label { display: none; }
|
||
.article-heading h1 { font-size: 32px; }
|
||
.article-lead { font-size: 14px; }
|
||
.hero-footer { align-items: flex-start; flex-direction: column; gap: 16px; margin-top: 18px; padding-top: 17px; }
|
||
.hero-catalog-link { width: 100%; justify-content: center; }
|
||
.article-wrap { margin-top: 20px; }
|
||
.article-paper,
|
||
.comments-section { padding: 28px 20px; border-radius: 15px; }
|
||
.article-content { font-size: 15px; line-height: 1.8; }
|
||
.attachment-card { grid-template-columns: 38px minmax(0, 1fr); }
|
||
.file-actions { grid-column: 1 / -1; }
|
||
.file-actions button { flex: 1; }
|
||
.author-note { grid-template-columns: 42px minmax(0, 1fr); }
|
||
.author-note time { display: none; }
|
||
.related-grid { grid-template-columns: 1fr; }
|
||
}
|
||
</style>
|
||
|
||
<style scoped>
|
||
.project-code-label {
|
||
padding: 5px 9px;
|
||
border-radius: 6px;
|
||
color: #fff;
|
||
background: #ef6a3a;
|
||
font: 700 10px/1.2 Consolas, monospace;
|
||
letter-spacing: .06em;
|
||
}
|
||
|
||
.article-hero .breadcrumbs,
|
||
.article-hero .hero-layout,
|
||
.article-wrap {
|
||
width: min(1180px, calc(100% - 40px));
|
||
}
|
||
|
||
.project-detail-grid {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) 300px;
|
||
align-items: start;
|
||
gap: 28px;
|
||
}
|
||
|
||
.project-main-column { min-width: 0; }
|
||
|
||
.project-overview {
|
||
margin-bottom: 44px;
|
||
padding-bottom: 34px;
|
||
border-bottom: 1px solid #e8e2d8;
|
||
}
|
||
|
||
.overview-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 10px;
|
||
}
|
||
|
||
.overview-grid > div {
|
||
min-width: 0;
|
||
padding: 15px 17px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 7px;
|
||
border: 1px solid #e5e0d7;
|
||
border-radius: 11px;
|
||
background: #faf8f2;
|
||
}
|
||
|
||
.overview-grid span { color: #9298a1; font-size: 9px; }
|
||
.overview-grid strong { overflow: hidden; color: #24364c; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
|
||
|
||
.delivery-strip {
|
||
margin-top: 12px;
|
||
padding: 14px 16px;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 18px;
|
||
border-radius: 10px;
|
||
color: #687485;
|
||
background: #eaf2f1;
|
||
font-size: 10px;
|
||
}
|
||
|
||
.delivery-strip i { margin-right: 4px; color: #299274; }
|
||
.project-detail-title { margin: 0 0 28px; scroll-margin-top: 18px; }
|
||
|
||
.source-panel {
|
||
position: sticky;
|
||
top: 18px;
|
||
padding: 24px;
|
||
border: 1px solid #ded8ce;
|
||
border-radius: 17px;
|
||
background: #fffdf8;
|
||
box-shadow: 0 16px 38px rgba(19, 34, 56, .1);
|
||
}
|
||
|
||
.source-panel-head { display: flex; align-items: center; justify-content: space-between; }
|
||
.source-panel-head > span { padding: 7px 9px; border-radius: 7px; color: #fff; background: #ef6a3a; font: 700 10px/1 Consolas, monospace; }
|
||
.source-panel-head small { color: #a3a7ad; font: 700 8px/1 Consolas, monospace; letter-spacing: .13em; }
|
||
.source-panel h2 { margin: 18px 0 10px; color: #17273c; font-size: 20px; line-height: 1.45; }
|
||
.source-panel > p { margin: 0 0 19px; color: #747e8c; font-size: 11px; line-height: 1.75; }
|
||
|
||
.source-panel dl { margin: 0; padding: 4px 0; border-top: 1px solid #e9e4da; border-bottom: 1px solid #e9e4da; }
|
||
.source-panel dl > div { padding: 9px 0; display: grid; grid-template-columns: 62px minmax(0, 1fr); gap: 8px; font-size: 10px; }
|
||
.source-panel dt { color: #9298a1; }
|
||
.source-panel dd { margin: 0; overflow: hidden; color: #303f52; text-align: right; text-overflow: ellipsis; white-space: nowrap; }
|
||
|
||
.source-panel ul { margin: 17px 0; padding: 0; display: grid; gap: 8px; list-style: none; color: #687485; font-size: 10px; }
|
||
.source-panel li i { width: 18px; height: 18px; margin-right: 6px; display: inline-grid; place-items: center; border-radius: 50%; color: #299274; background: #e7f3ef; font-size: 9px; }
|
||
|
||
.get-source-button,
|
||
.document-link {
|
||
width: 100%;
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 7px;
|
||
border-radius: 10px;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.get-source-button { border: 0; color: #fff; background: #ef6a3a; box-shadow: 0 10px 20px rgba(239, 106, 58, .22); }
|
||
.document-link { height: 40px; margin-top: 9px; border: 1px solid #dcd7ce; color: #536174; background: #fff; }
|
||
.source-tip { margin-top: 12px; display: block; color: #a1a5ab; text-align: center; font-size: 8px; }
|
||
|
||
.detail-page /deep/ .source-qr-dialog {
|
||
width: min(460px, calc(100% - 28px));
|
||
margin-top: 10vh !important;
|
||
overflow: hidden;
|
||
border-radius: 20px;
|
||
background: #fffdf8;
|
||
box-shadow: 0 24px 70px rgba(18, 34, 55, .24);
|
||
}
|
||
|
||
.detail-page /deep/ .source-qr-dialog .el-dialog__header { padding: 18px 20px 0; }
|
||
.detail-page /deep/ .source-qr-dialog .el-dialog__body { padding: 8px 28px 28px; }
|
||
.detail-page /deep/ .source-qr-dialog .el-dialog__headerbtn { top: 18px; right: 20px; }
|
||
.detail-page /deep/ .source-qr-dialog .el-dialog__close { color: #6e7886; font-size: 20px; }
|
||
|
||
.source-qr-content { text-align: center; }
|
||
.source-qr-kicker { color: #ef6a3a; font: 700 9px/1 Consolas, monospace; letter-spacing: .18em; }
|
||
.source-qr-content h2 { margin: 10px 0 7px; color: #17273c; font-size: 24px; line-height: 1.35; }
|
||
.source-qr-content > p { margin: 0 auto 20px; max-width: 390px; color: #788291; font-size: 12px; line-height: 1.7; }
|
||
|
||
.source-qr-image {
|
||
width: 300px;
|
||
height: 300px;
|
||
margin: 0 auto;
|
||
overflow: hidden;
|
||
border: 1px solid #e9e2d8;
|
||
border-radius: 14px;
|
||
background: #f8f5ef;
|
||
}
|
||
|
||
.source-qr-image img { width: 100%; height: 100%; display: block; object-fit: contain; }
|
||
|
||
.source-qr-project {
|
||
margin-top: 15px;
|
||
padding: 11px 13px;
|
||
display: grid;
|
||
grid-template-columns: auto minmax(0, 1fr);
|
||
align-items: center;
|
||
gap: 12px;
|
||
border-radius: 10px;
|
||
color: #25384e;
|
||
background: #edf4f2;
|
||
text-align: left;
|
||
}
|
||
|
||
.source-qr-project span { color: #74808d; font-size: 10px; }
|
||
.source-qr-project strong { overflow: hidden; font-size: 11px; text-align: right; text-overflow: ellipsis; white-space: nowrap; }
|
||
|
||
@media (max-width: 920px) {
|
||
.project-detail-grid { grid-template-columns: 1fr; }
|
||
.source-panel { position: static; }
|
||
}
|
||
|
||
@media (max-width: 820px) {
|
||
.article-hero .breadcrumbs,
|
||
.article-hero .hero-layout,
|
||
.article-wrap { width: min(100% - 28px, 1180px); }
|
||
}
|
||
|
||
@media (max-width: 560px) {
|
||
.overview-grid { grid-template-columns: 1fr; }
|
||
.delivery-strip { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
|
||
.source-panel { padding: 21px; }
|
||
.detail-page /deep/ .source-qr-dialog .el-dialog__body { padding: 8px 20px 22px; }
|
||
.source-qr-content h2 { font-size: 20px; }
|
||
.source-qr-image { width: 236px; height: 236px; margin: 0 auto; }
|
||
.source-qr-image img { width: auto; max-width: none; height: 100%; }
|
||
.source-qr-project { grid-template-columns: 1fr; gap: 5px; text-align: center; }
|
||
.source-qr-project strong { text-align: center; }
|
||
}
|
||
</style>
|