Merge branch 'main' of https://git.opencomputing.cn/yumoqing/kboss
This commit is contained in:
commit
7f483fa246
@ -313,10 +313,193 @@ body {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.news-confirm-box {
|
||||
position: relative;
|
||||
width: 460px !important;
|
||||
padding: 28px 32px 24px;
|
||||
border: 0;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 20px 56px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__header {
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
width: 100%;
|
||||
padding-left: 0;
|
||||
text-align: left;
|
||||
color: #1f2937;
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__title span {
|
||||
display: block;
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__status {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__title::before {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
flex: 0 0 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.news-confirm-box--warning .el-message-box__title::before {
|
||||
content: '!';
|
||||
color: #f59e0b;
|
||||
background: #fff7ed;
|
||||
}
|
||||
|
||||
.news-confirm-box--danger .el-message-box__title::before {
|
||||
content: '×';
|
||||
color: #ef4444;
|
||||
background: #fef2f2;
|
||||
}
|
||||
|
||||
.news-confirm-box--success .el-message-box__title::before {
|
||||
content: '✓';
|
||||
color: #22c55e;
|
||||
background: #f0fdf4;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__headerbtn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__content {
|
||||
position: static;
|
||||
padding: 16px 0 0 58px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__message {
|
||||
margin-left: 0 !important;
|
||||
padding-left: 0 !important;
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
color: #64748b;
|
||||
font-size: 16px;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__message p {
|
||||
margin: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__btns {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
padding: 24px 0 0;
|
||||
}
|
||||
|
||||
.news-confirm-btn {
|
||||
min-width: 88px;
|
||||
height: 42px;
|
||||
margin-left: 0 !important;
|
||||
padding: 0 22px;
|
||||
border-radius: 10px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.news-confirm-btn--cancel {
|
||||
color: #64748b;
|
||||
background: #fff;
|
||||
border-color: #d8e0ec;
|
||||
}
|
||||
|
||||
.news-confirm-btn--cancel:hover,
|
||||
.news-confirm-btn--cancel:focus {
|
||||
color: #334155;
|
||||
background: #f8fafc;
|
||||
border-color: #cbd5e1;
|
||||
}
|
||||
|
||||
.news-confirm-btn--confirm {
|
||||
color: #fff;
|
||||
background: #3b82f6;
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
.news-confirm-btn--confirm:hover,
|
||||
.news-confirm-btn--confirm:focus {
|
||||
color: #fff;
|
||||
background: #2563eb;
|
||||
border-color: #2563eb;
|
||||
}
|
||||
|
||||
.news-confirm-btn--confirm.is-danger {
|
||||
background: #ef4444;
|
||||
border-color: #ef4444;
|
||||
}
|
||||
|
||||
.news-confirm-btn--confirm.is-danger:hover,
|
||||
.news-confirm-btn--confirm.is-danger:focus {
|
||||
background: #dc2626;
|
||||
border-color: #dc2626;
|
||||
}
|
||||
|
||||
.news-confirm-btn--confirm.is-success {
|
||||
background: #22c55e;
|
||||
border-color: #22c55e;
|
||||
}
|
||||
|
||||
.news-confirm-btn--confirm.is-success:hover,
|
||||
.news-confirm-btn--confirm.is-success:focus {
|
||||
background: #16a34a;
|
||||
border-color: #16a34a;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 760px) {
|
||||
.el-message-box {
|
||||
width: 320px !important;
|
||||
}
|
||||
|
||||
.news-confirm-box {
|
||||
width: calc(100vw - 32px) !important;
|
||||
padding: 24px 20px 22px;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__title {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__title::before {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
flex-basis: 40px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__content {
|
||||
padding-left: 52px;
|
||||
}
|
||||
|
||||
.news-confirm-box .el-message-box__message {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
|
||||
@ -66,4 +66,14 @@ export const reqUnpublishNews = (data) => {
|
||||
method: 'get',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
|
||||
// 新闻图片上传
|
||||
export const reqUploadNewsImage = (data) => {
|
||||
return request({
|
||||
url: '/docs/upload_file.dspy',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
})
|
||||
}
|
||||
@ -37,35 +37,99 @@ export default {
|
||||
solutionCards: {
|
||||
collaboration: {
|
||||
title: 'Collaborative Intelligence',
|
||||
subtitle: 'Multi-Agent Coordination'
|
||||
subtitle: 'Multi-Agent Collaboration',
|
||||
detailTitle: 'Collective Intelligence',
|
||||
detailSubTitle: 'Multi-Agent Collaboration',
|
||||
detailDesc: 'Multiple AI agents collaborate autonomously based on role specialization, completing the full workflow of information gathering, data analysis, logical reasoning, and conclusion generation. With dynamic task allocation and shared context, complex business decisions shift from human sequential workflows to parallel agent execution, significantly reducing cycle times for high-knowledge-density work.',
|
||||
metrics: {
|
||||
first: { value: '10x+', label: 'Knowledge work efficiency improvement' },
|
||||
second: { value: 'Real-time', label: 'Multi-source information fusion' },
|
||||
third: { value: 'High complexity', label: 'Decision scenario adaptability' }
|
||||
}
|
||||
},
|
||||
spatial: {
|
||||
title: 'Spatial Intelligence',
|
||||
subtitle: 'GIS Smart Analysis'
|
||||
subtitle: 'GIS Intelligent Analysis',
|
||||
detailTitle: 'Spatial Awakening',
|
||||
detailSubTitle: 'GIS Intelligent Analysis',
|
||||
detailDesc: 'Integrating Geographic Information Systems, satellite remote sensing imagery, and drone aerial photography, AI automatically identifies land feature boundaries, analyzes spatial relationships through overlay analysis, and verifies compliance constraints. Geographic spatial judgments that once required manual layer-by-layer comparison are now upgraded to automated spatial intelligence decisions delivered in minutes.',
|
||||
metrics: {
|
||||
first: { value: 'Days to minutes', label: 'Spatial analysis' },
|
||||
second: { value: '90%+', label: 'Violation detection accuracy' },
|
||||
third: { value: '70%', label: 'Labor cost savings' }
|
||||
}
|
||||
},
|
||||
predictive: {
|
||||
title: 'Predictive Insight',
|
||||
subtitle: 'Intelligent Forecasting Engine'
|
||||
subtitle: 'Intelligent Prediction Engine',
|
||||
detailTitle: 'One Step Ahead',
|
||||
detailSubTitle: 'Intelligent Prediction Engine',
|
||||
detailDesc: 'Integrating physics-based models with data-driven approaches, the system collects real-time equipment operating parameters to autonomously identify early anomaly characteristics and accurately predict remaining useful life. Warnings are issued 72 hours before actual failure occurs, transforming maintenance from reactive repair to proactive defense and maximizing production continuity.',
|
||||
metrics: {
|
||||
first: { value: '95%+', label: 'Fault warning accuracy' },
|
||||
second: { value: '60%', label: 'Unplanned downtime reduction' },
|
||||
third: { value: '72 hours', label: 'Advance prediction lead time' }
|
||||
}
|
||||
},
|
||||
vision: {
|
||||
title: 'Microscopic Insight',
|
||||
subtitle: 'Machine Vision Inspection'
|
||||
title: 'Insight into the Microscopic',
|
||||
subtitle: 'Machine Vision Inspection',
|
||||
detailTitle: 'Insight into the Microscopic',
|
||||
detailSubTitle: 'Machine Vision Inspection',
|
||||
detailDesc: 'Deep learning-based high-speed full-coverage defect detection for production lines, covering the entire quality inspection process including surface treatment, coating spraying, and welding assembly. This is not sampling inspection; every inch of product undergoes AI pixel-by-pixel comparison, completing defect identification and classification in milliseconds, ensuring zero compromise on product quality.',
|
||||
metrics: {
|
||||
first: { value: 'Milliseconds', label: 'Inspection speed' },
|
||||
second: { value: '95%', label: 'Missed detection rate reduction' },
|
||||
third: { value: '99.5%+', label: 'Identification accuracy' }
|
||||
}
|
||||
},
|
||||
qa: {
|
||||
title: 'Instant Answers',
|
||||
subtitle: 'Intelligent Q&A Knowledge Base'
|
||||
subtitle: 'Intelligent Q&A Knowledge Base',
|
||||
detailTitle: 'Instant Answers',
|
||||
detailSubTitle: 'Intelligent Q&A Knowledge Base',
|
||||
detailDesc: 'An AI-powered Q&A engine built on enterprise private knowledge bases, supporting natural language queries for business data, technical specifications, and policy documents. Every answer is automatically annotated with authoritative sources, ensuring information is traceable and verifiable. Expert-level knowledge is no longer locked in documents but available on demand, like asking a colleague.',
|
||||
metrics: {
|
||||
first: { value: '<3 sec', label: 'Response time' },
|
||||
second: { value: '90%', label: 'Expert knowledge coverage' },
|
||||
third: { value: '5x', label: 'Decision-making efficiency improvement' }
|
||||
}
|
||||
},
|
||||
protection: {
|
||||
title: 'Continuous Protection',
|
||||
subtitle: 'Intelligent Device Monitoring'
|
||||
title: 'Full Protection',
|
||||
subtitle: 'Intelligent Device Monitoring',
|
||||
detailTitle: 'Full Protection',
|
||||
detailSubTitle: 'Intelligent Equipment Monitoring',
|
||||
detailDesc: 'Building independent monitoring strategies for each device, with 3D visualization presenting real-time operating status. AI automatically identifies anomalies and highlights fault locations, while synchronously outputting detailed diagnostic recommendations and troubleshooting steps. Operations staff are liberated from being glued to screens hunting for issues; the system proactively tells you where the issue is and how to fix it.',
|
||||
metrics: {
|
||||
first: { value: '1000+', label: 'Monitoring points supported' },
|
||||
second: { value: '<1 sec', label: 'Alert response' },
|
||||
third: { value: '40%', label: 'Maintenance cost reduction' }
|
||||
}
|
||||
},
|
||||
document: {
|
||||
title: 'Document Intelligence',
|
||||
subtitle: 'Smart Document Parsing'
|
||||
title: 'Read and Comprehend',
|
||||
subtitle: 'Intelligent Document Parsing',
|
||||
detailTitle: 'Read and Comprehend',
|
||||
detailSubTitle: 'Intelligent Document Parsing',
|
||||
detailDesc: 'Supporting one-click parsing of multiple formats including PDF, Word, and scanned documents. AI automatically extracts key clauses, qualification requirements, scoring criteria, and other core information for structured presentation. This is not simple OCR text recognition; it understands document semantics, judges information importance, and highlights risk points, making the core content of lengthy documents clear at a glance.',
|
||||
metrics: {
|
||||
first: { value: '98%+', label: 'Parsing accuracy' },
|
||||
second: { value: '85%', label: 'Manual review time reduction' },
|
||||
third: { value: 'Zero omission', label: 'Key information' }
|
||||
}
|
||||
},
|
||||
edge: {
|
||||
title: 'Edge Intelligence',
|
||||
subtitle: 'Edge AI Inference'
|
||||
title: 'On-Site Intelligence',
|
||||
subtitle: 'Edge AI Inference',
|
||||
detailTitle: 'On-Site Intelligence',
|
||||
detailSubTitle: 'Edge AI Inference',
|
||||
detailDesc: 'Deploying AI inference capabilities at the edge of production sites, achieving millisecond-level real-time decisions through lightweight algorithms. Data does not need to be transmitted back to the cloud; sensing to judgment is completed locally, ensuring data never leaves the facility and zero-latency response. Redundant architecture guarantees 7x24 continuous operation with uninterrupted production line inspection.',
|
||||
metrics: {
|
||||
first: { value: '<50ms', label: 'Inference latency' },
|
||||
second: { value: 'Local', label: 'Data processed on site' },
|
||||
third: { value: '7x24h', label: 'Continuous operation' }
|
||||
}
|
||||
}
|
||||
},
|
||||
cases: {
|
||||
|
||||
@ -37,35 +37,99 @@ export default {
|
||||
solutionCards: {
|
||||
collaboration: {
|
||||
title: '群智协作',
|
||||
subtitle: '多智能体协同'
|
||||
subtitle: '多智能体协同',
|
||||
detailTitle: '群智协作',
|
||||
detailSubTitle: '多智能体协同',
|
||||
detailDesc: '多个AI智能体按角色分工,自主完成信息采集、数据分析、逻辑推理与结论生成的全流程协作。支持动态任务分配与上下文共享,将复杂业务决策从"人串联"变为"智能体并行",大幅压缩高知识密度工作的完成周期。',
|
||||
metrics: {
|
||||
first: { value: '10倍+', label: '知识工作效率提升' },
|
||||
second: { value: '多源', label: '信息实时融合' },
|
||||
third: { value: '高复杂度', label: '决策场景适配' }
|
||||
}
|
||||
},
|
||||
spatial: {
|
||||
title: '空间觉醒',
|
||||
subtitle: 'GIS智能分析'
|
||||
subtitle: 'GIS智能分析',
|
||||
detailTitle: '空间觉醒',
|
||||
detailSubTitle: 'GIS智能分析',
|
||||
detailDesc: '融合地理信息系统、卫星遥感影像、无人机航拍等多维空间数据,AI自动识别地物边界、叠加分析空间关系、校验合规约束。将传统需要人工逐层比对的地理空间判断,升级为分钟级自动完成的空间智能决策。',
|
||||
metrics: {
|
||||
first: { value: '分钟级', label: '空间分析' },
|
||||
second: { value: '90%+', label: '违规识别准确率' },
|
||||
third: { value: '70%', label: '人力成本节省' }
|
||||
}
|
||||
},
|
||||
predictive: {
|
||||
title: '先见一步',
|
||||
subtitle: '智能预测引擎'
|
||||
subtitle: '智能预测引擎',
|
||||
detailTitle: '先见一步',
|
||||
detailSubTitle: '智能预测引擎',
|
||||
detailDesc: '融合机理模型与数据驱动模型,通过实时采集设备运行参数,AI自主识别早期异常特征并精准预测剩余使用寿命。在故障真正发生前72小时发出预警,让运维从"事后抢修"转变为"事前防御",最大化保障生产连续性。',
|
||||
metrics: {
|
||||
first: { value: '95%+', label: '故障预警准确率' },
|
||||
second: { value: '60%', label: '非计划停机减少' },
|
||||
third: { value: '72小时', label: '预测提前量' }
|
||||
}
|
||||
},
|
||||
vision: {
|
||||
title: '洞察入微',
|
||||
subtitle: '机器视觉检测'
|
||||
subtitle: '机器视觉检测',
|
||||
detailTitle: '洞察入微',
|
||||
detailSubTitle: '机器视觉检测',
|
||||
detailDesc: '基于深度学习的高速产线全幅面缺陷检测能力,覆盖表面处理、涂层喷涂、焊接装配等全流程质检环节。不是抽样检查,而是每一寸产品都经过AI逐像素比对,在毫秒级时间内完成缺陷识别与分类,确保出厂品质零妥协。',
|
||||
metrics: {
|
||||
first: { value: '毫秒级', label: '检测速度' },
|
||||
second: { value: '95%', label: '漏检率降低' },
|
||||
third: { value: '99.5%+', label: '识别准确率' }
|
||||
}
|
||||
},
|
||||
qa: {
|
||||
title: '一问即达',
|
||||
subtitle: '智能问答知识库'
|
||||
subtitle: '智能问答知识库',
|
||||
detailTitle: '一问即达',
|
||||
detailSubTitle: '智能问答知识库',
|
||||
detailDesc: '基于企业私有知识库构建的AI问答引擎,支持自然语言直接查询业务数据、技术规范、制度文件。每条回答自动标注权威来源,信息可追溯、可验证。让专家级知识不再锁在文档里,而是像问同事一样即问即答。',
|
||||
metrics: {
|
||||
first: { value: '<3秒', label: '响应速度' },
|
||||
second: { value: '90%', label: '专家知识覆盖率' },
|
||||
third: { value: '5倍', label: '决策效率提升' }
|
||||
}
|
||||
},
|
||||
protection: {
|
||||
title: '全程守护',
|
||||
subtitle: '设备智能监控'
|
||||
subtitle: '设备智能监控',
|
||||
detailTitle: '全程守护',
|
||||
detailSubTitle: '设备智能监控',
|
||||
detailDesc: '为每台设备构建独立监控策略,通过三维可视化实时呈现运行状态。AI自动识别异常并高亮定位故障点,同步输出详细诊断建议和排查步骤。将运维人员从"盯屏找问题"解放出来,让系统主动告诉你问题在哪、怎么修。',
|
||||
metrics: {
|
||||
first: { value: '1000+', label: '监控点位支持' },
|
||||
second: { value: '<1秒', label: '告警响应' },
|
||||
third: { value: '40%', label: '运维成本降低' }
|
||||
}
|
||||
},
|
||||
document: {
|
||||
title: '触文即懂',
|
||||
subtitle: '智能文档解析'
|
||||
subtitle: '智能文档解析',
|
||||
detailTitle: '触文即懂',
|
||||
detailSubTitle: '智能文档解析',
|
||||
detailDesc: '支持PDF、Word、扫描件等多种格式一键解析,AI自动提取关键条款、资质要求、评分细则等核心信息并结构化呈现。不是简单的OCR文字识别,而是理解文档语义、判断信息重要性、标注风险点,让冗长文档的核心内容一目了然。',
|
||||
metrics: {
|
||||
first: { value: '98%+', label: '解析准确率' },
|
||||
second: { value: '85%', label: '人工核查时间减少' },
|
||||
third: { value: '零遗漏', label: '关键信息' }
|
||||
}
|
||||
},
|
||||
edge: {
|
||||
title: '端侧即算',
|
||||
subtitle: '边缘AI推理'
|
||||
subtitle: '边缘AI推理',
|
||||
detailTitle: '端侧即算',
|
||||
detailSubTitle: '边缘AI推理',
|
||||
detailDesc: '将AI推理能力部署在生产现场边缘侧,通过轻量化算法实现毫秒级实时决策。数据无需回传云端,在本地即可完成从感知到判断的全流程,确保数据不出厂、响应零延迟。冗余架构设计保障7×24小时持续运行,产线检测永不中断。',
|
||||
metrics: {
|
||||
first: { value: '<50ms', label: '推理延迟' },
|
||||
second: { value: '本地', label: '数据处理不出厂' },
|
||||
third: { value: '7×24h', label: '持续运行' }
|
||||
}
|
||||
}
|
||||
},
|
||||
cases: {
|
||||
|
||||
@ -391,7 +391,7 @@ export default {
|
||||
const userId = sessionStorage.getItem('userId');
|
||||
if (!userId) {
|
||||
this.$message.warning('请先登录');
|
||||
this.$router.push('/login');
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'));
|
||||
return;
|
||||
}
|
||||
this.messageCenterVisible = true;
|
||||
|
||||
@ -122,6 +122,27 @@ export default {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .happy-scroll-strip,
|
||||
::v-deep .happy-scroll-bar,
|
||||
::v-deep .happy-scroll-rail {
|
||||
display: none !important;
|
||||
opacity: 0 !important;
|
||||
width: 0 !important;
|
||||
}
|
||||
|
||||
::v-deep .happy-scroll-content,
|
||||
::v-deep .happy-scroll-container {
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
::v-deep .happy-scroll-content::-webkit-scrollbar,
|
||||
::v-deep .happy-scroll-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-collapse-btn {
|
||||
|
||||
@ -610,7 +610,7 @@ export const asyncRoutes = [
|
||||
path: "/newsLog",
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: "新闻动态",
|
||||
title: "企业动态",
|
||||
fullPath: "/newsLog",
|
||||
noCache: true,
|
||||
icon: "el-icon-document",
|
||||
@ -622,7 +622,7 @@ export const asyncRoutes = [
|
||||
component: () => import('@/views/homePage/news/newsLog.vue'),
|
||||
name: 'NewsLog',
|
||||
meta: {
|
||||
title: "新闻动态",
|
||||
title: "企业动态",
|
||||
fullPath: "/newsLog",
|
||||
noCache: true,
|
||||
roles: ["运营"]
|
||||
@ -855,6 +855,18 @@ export const asyncRoutes = [
|
||||
name: "detail",
|
||||
hidden: true,
|
||||
meta: { title: "详情", cache: true },
|
||||
}, {
|
||||
path: "news",
|
||||
component: () => import("@/views/homePage/news/newsView.vue"),
|
||||
name: "homePageNewsLegacy",
|
||||
hidden: true,
|
||||
meta: { title: "企业动态", cache: true },
|
||||
}, {
|
||||
path: "news/detail/:id",
|
||||
component: () => import("@/views/homePage/news/NewsDetail.vue"),
|
||||
name: "homePageNewsDetailLegacy",
|
||||
hidden: true,
|
||||
meta: { title: "新闻详情", cache: true },
|
||||
}, {
|
||||
path: "hospital",
|
||||
component: () => import("@/views/homePage/solve/hospital/index.vue"),
|
||||
|
||||
@ -165,9 +165,16 @@ service.interceptors.response.use(
|
||||
isRedirectingToLogin = true
|
||||
saveLoginRedirectPath()
|
||||
showErrorMessage('登录已过期,请重新登录')
|
||||
router.push({path: '/login'}).finally(() => {
|
||||
const currentPath = (router.currentRoute && router.currentRoute.path) || ''
|
||||
const isHomePage = currentPath.includes('/homePage') || currentPath.includes('/ncmatchHome')
|
||||
if (isHomePage) {
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
isRedirectingToLogin = false
|
||||
})
|
||||
} else {
|
||||
router.push({path: '/login'}).finally(() => {
|
||||
isRedirectingToLogin = false
|
||||
})
|
||||
}
|
||||
}
|
||||
// window.location.href = 'https://www.opencomputing.cn/'
|
||||
} else if (code == 403) {
|
||||
|
||||
@ -13,8 +13,7 @@
|
||||
<div class="brand-area">
|
||||
|
||||
<div class="brand-text">
|
||||
<h2>{{ activeTab === 'login' ? '欢迎回来' : '创建账号' }}</h2>
|
||||
<p>{{ activeTab === 'login' ? '登录后继续使用智能服务' : '注册开启全新体验' }}</p>
|
||||
<h2>{{ activeTab === 'login' ? '欢迎登录' : '创建账号' }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
goLoginPage() {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
},
|
||||
goRegisterPage() {
|
||||
this.$router.push('/register')
|
||||
|
||||
@ -407,7 +407,7 @@ export default {
|
||||
window.open('http://tmpweb.opencomputing.cn/col.jsp?id=136')
|
||||
},
|
||||
login() {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
},
|
||||
register() {
|
||||
this.$router.push('/registrationPage')
|
||||
|
||||
@ -367,9 +367,11 @@ export default Vue.extend({
|
||||
mounted() {
|
||||
this.nick_name = sessionStorage.getItem('username') || ''
|
||||
window.addEventListener('kboss-open-ai-chat', this.handleExternalAIOpen)
|
||||
window.addEventListener('kboss-open-login-dialog', this.handleExternalLoginOpen)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('kboss-open-ai-chat', this.handleExternalAIOpen)
|
||||
window.removeEventListener('kboss-open-login-dialog', this.handleExternalLoginOpen)
|
||||
this.stopAIPanelDrag()
|
||||
},
|
||||
methods: {
|
||||
@ -519,17 +521,10 @@ export default Vue.extend({
|
||||
this.userId = sessionStorage.getItem('userId')
|
||||
},
|
||||
goLogin() {
|
||||
this.closeProductPanelImmediate()
|
||||
if (this.$route && this.$route.fullPath && !this.$route.fullPath.includes('/login')) {
|
||||
sessionStorage.setItem('loginRedirectPath', this.$route.fullPath)
|
||||
}
|
||||
const fallback = `${window.location.origin}${window.location.pathname}#/login?fromPath=homePage`
|
||||
this.$router.replace({ path: '/login', query: { fromPath: 'homePage' } }).catch(() => {})
|
||||
window.setTimeout(() => {
|
||||
if (!window.location.hash.includes('/login')) {
|
||||
window.location.href = fallback
|
||||
}
|
||||
}, 220)
|
||||
this.openLoginDialog()
|
||||
},
|
||||
handleExternalLoginOpen() {
|
||||
this.openLoginDialog()
|
||||
},
|
||||
handleMessageClick() {
|
||||
if (this.loginState) {
|
||||
|
||||
@ -255,13 +255,7 @@ export default {
|
||||
submitCreate() {
|
||||
if (!this.loginState) {
|
||||
this.$message.warning('请先登录后再创建实例')
|
||||
this.$router.push({
|
||||
path: '/login',
|
||||
query: {
|
||||
fromPath: 'computeMarketCreateInstance',
|
||||
redirect: this.$route.fullPath
|
||||
}
|
||||
})
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -455,7 +455,7 @@ export default {
|
||||
window.open('http://tmpweb.opencomputing.cn/col.jsp?id=136')
|
||||
},
|
||||
login() {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
},
|
||||
register() {
|
||||
this.$router.push('/registrationPage')
|
||||
|
||||
@ -359,7 +359,7 @@ export default Vue.extend({
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
@ -418,14 +418,14 @@ export default Vue.extend({
|
||||
if (this.loginState) {
|
||||
this.$router.push('/ncmatchHome/favoriteBox')
|
||||
} else {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
}
|
||||
},
|
||||
goHistory() {
|
||||
if (this.loginState) {
|
||||
this.$router.push('/ncmatchHome/historyBox')
|
||||
} else {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@
|
||||
</section>
|
||||
<!-- 企业动态 -->
|
||||
|
||||
<!-- <section id="news" class="news-section">
|
||||
<section id="news" class="news-section">
|
||||
<div class="news-glow news-glow--left"></div>
|
||||
<div class="news-glow news-glow--right"></div>
|
||||
<div class="news-glow news-glow--center"></div>
|
||||
@ -149,7 +149,7 @@
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section> -->
|
||||
</section>
|
||||
|
||||
<Talk></Talk>
|
||||
</div>
|
||||
@ -338,13 +338,26 @@ export default {
|
||||
'触文即懂': 'document',
|
||||
'端侧即算': 'edge'
|
||||
}
|
||||
const metricKeys = ['first', 'second', 'third']
|
||||
return this.solutionCards.map((card) => {
|
||||
const key = keyMap[card.title]
|
||||
if (!key) return card
|
||||
return {
|
||||
...card,
|
||||
title: this.$t(`home.solutionCards.${key}.title`),
|
||||
subtitle: this.$t(`home.solutionCards.${key}.subtitle`)
|
||||
subtitle: this.$t(`home.solutionCards.${key}.subtitle`),
|
||||
detailTitle: this.$t(`home.solutionCards.${key}.detailTitle`),
|
||||
detailSubTitle: this.$t(`home.solutionCards.${key}.detailSubTitle`),
|
||||
detailDesc: this.$t(`home.solutionCards.${key}.detailDesc`),
|
||||
metrics: card.metrics.map((metric, index) => {
|
||||
const metricKey = metricKeys[index]
|
||||
if (!metricKey) return metric
|
||||
return {
|
||||
...metric,
|
||||
value: this.$t(`home.solutionCards.${key}.metrics.${metricKey}.value`),
|
||||
label: this.$t(`home.solutionCards.${key}.metrics.${metricKey}.label`)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -840,7 +853,7 @@ body.dark-theme .bg-orb {
|
||||
border-radius: inherit;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
color: #1f2937;
|
||||
text-align: left;
|
||||
background: transparent;
|
||||
@ -850,6 +863,18 @@ body.dark-theme .bg-orb {
|
||||
pointer-events: none;
|
||||
transform: translateY(16px);
|
||||
transition: all 0.25s ease;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(37, 99, 235, 0.18);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
strong {
|
||||
margin-bottom: 8px;
|
||||
@ -872,23 +897,24 @@ body.dark-theme .bg-orb {
|
||||
p {
|
||||
margin: 0;
|
||||
color: #475569;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
font-size: 12px;
|
||||
line-height: 1.62;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 18px 0 0;
|
||||
margin: 16px 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
li {
|
||||
min-height: 72px;
|
||||
padding: 10px 6px 9px;
|
||||
min-width: 0;
|
||||
min-height: 74px;
|
||||
padding: 9px 6px 8px;
|
||||
border: 1px solid rgba(186, 220, 255, 0.72);
|
||||
border-radius: 14px;
|
||||
display: flex;
|
||||
@ -901,21 +927,26 @@ body.dark-theme .bg-orb {
|
||||
|
||||
b {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
color: #2563eb;
|
||||
font-size: 26px;
|
||||
line-height: 1.1;
|
||||
font-size: 22px;
|
||||
line-height: 1.12;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.01em;
|
||||
white-space: nowrap;
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
small {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
margin-top: 7px;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 1.25;
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
font-weight: 700;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
&::before {
|
||||
|
||||
@ -191,7 +191,7 @@ export default Vue.extend({
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -359,7 +359,7 @@ export default Vue.extend({
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
@ -418,14 +418,14 @@ export default Vue.extend({
|
||||
if (this.loginState) {
|
||||
this.$router.push('/ncmatchHome/favoriteBox')
|
||||
} else {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
}
|
||||
},
|
||||
goHistory() {
|
||||
if (this.loginState) {
|
||||
this.$router.push('/ncmatchHome/historyBox')
|
||||
} else {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,7 +454,7 @@ export default {
|
||||
},
|
||||
sendInfo(type) {
|
||||
if (!this.loginState) {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -1,21 +1,32 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
:fullscreen="true"
|
||||
append-to-body
|
||||
custom-class="article-editor-dialog"
|
||||
:close-on-click-modal="false"
|
||||
:before-close="handleBeforeClose"
|
||||
@open="handleOpen"
|
||||
@close="handleDialogClose"
|
||||
>
|
||||
<div class="article-editor">
|
||||
<div slot="title" class="article-dialog-title">
|
||||
<button type="button" class="dialog-back-btn" @click="requestClose">
|
||||
<i class="el-icon-arrow-left"></i>
|
||||
返回
|
||||
</button>
|
||||
<span>{{ dialogTitle }}</span>
|
||||
</div>
|
||||
|
||||
<div class="article-editor" :class="{ 'is-editor-fullscreen': editorFullscreen }">
|
||||
<div class="article-editor__left">
|
||||
<div class="article-editor__form">
|
||||
<el-form :model="form" label-width="76px" size="small">
|
||||
<el-form-item label="文章标题">
|
||||
<el-form-item>
|
||||
<template slot="label"><span class="required-star">*</span>文章标题</template>
|
||||
<el-input v-model.trim="form.title" placeholder="请输入文章标题" />
|
||||
</el-form-item>
|
||||
<el-form-item label="文章摘要">
|
||||
<el-form-item>
|
||||
<template slot="label"><span class="required-star">*</span>文章摘要</template>
|
||||
<el-input
|
||||
v-model.trim="form.summary"
|
||||
type="textarea"
|
||||
@ -26,7 +37,8 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="article-editor__inline">
|
||||
<el-form-item label="文章类型">
|
||||
<el-form-item>
|
||||
<template slot="label"><span class="required-star">*</span>文章类型</template>
|
||||
<el-select v-model="form.type" placeholder="请选择文章类型">
|
||||
<el-option label="企业动态" value="企业动态" />
|
||||
<el-option label="产品动态" value="产品动态" />
|
||||
@ -34,7 +46,8 @@
|
||||
<el-option label="活动资讯" value="活动资讯" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="发布时间">
|
||||
<el-form-item>
|
||||
<template slot="label"><span class="required-star">*</span>发布时间</template>
|
||||
<el-date-picker
|
||||
v-model="form.publishTime"
|
||||
type="date"
|
||||
@ -43,7 +56,8 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label="封面配图">
|
||||
<el-form-item>
|
||||
<template slot="label"><span class="required-star">*</span>封面配图</template>
|
||||
<div class="cover-row">
|
||||
<el-button type="primary" size="small" @click="$refs.coverInput.click()">上传图片</el-button>
|
||||
<el-input
|
||||
@ -61,6 +75,7 @@
|
||||
|
||||
|
||||
<div v-if="dialogVisible" class="wang-editor-wrap">
|
||||
|
||||
<Toolbar
|
||||
class="wang-toolbar"
|
||||
:editor="editor"
|
||||
@ -104,9 +119,9 @@
|
||||
<div slot="footer" class="article-editor-footer">
|
||||
<span class="editor-status">{{ dirty ? '未保存' : '已同步' }}</span>
|
||||
<div>
|
||||
<el-button size="small" @click="dialogVisible = false">取消</el-button>
|
||||
<el-button size="small" @click="handleSave('draft')">保存草稿</el-button>
|
||||
<el-button type="primary" size="small" @click="handleSave('published')">发布文章</el-button>
|
||||
<el-button size="small" @click="requestClose">取消</el-button>
|
||||
<el-button size="small" @click="handleSave('0')">保存草稿</el-button>
|
||||
<el-button type="primary" size="small" @click="handlePublishConfirm">保存并发布</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@ -115,6 +130,7 @@
|
||||
<script>
|
||||
import '@wangeditor/editor/dist/css/style.css'
|
||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||
import { reqUploadNewsImage } from '@/api/newsapi/newsapi'
|
||||
|
||||
const normalizeImageUrl = (url) => {
|
||||
if (!url) return ''
|
||||
@ -122,36 +138,6 @@ const normalizeImageUrl = (url) => {
|
||||
return `${window.location.origin}/idfile?path=${url}`
|
||||
}
|
||||
|
||||
const compressImageToBase64 = (file, options = {}) => {
|
||||
const maxWidth = options.maxWidth || 900
|
||||
const maxHeight = options.maxHeight || 900
|
||||
const quality = options.quality || 0.65
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => {
|
||||
const image = new Image()
|
||||
image.onload = () => {
|
||||
const ratio = Math.min(maxWidth / image.width, maxHeight / image.height, 1)
|
||||
const width = Math.round(image.width * ratio)
|
||||
const height = Math.round(image.height * ratio)
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
ctx.fillStyle = '#fff'
|
||||
ctx.fillRect(0, 0, width, height)
|
||||
ctx.drawImage(image, 0, 0, width, height)
|
||||
resolve(canvas.toDataURL('image/jpeg', quality))
|
||||
}
|
||||
image.onerror = reject
|
||||
image.src = reader.result
|
||||
}
|
||||
reader.onerror = reject
|
||||
reader.readAsDataURL(file)
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'ArticleEditorDialog',
|
||||
components: { Editor, Toolbar },
|
||||
@ -182,15 +168,11 @@ export default {
|
||||
uploadImage: {
|
||||
customUpload: async (file, insertFn) => {
|
||||
try {
|
||||
// 正文图片先压缩再转 Base64,降低接口请求体积。
|
||||
const url = await compressImageToBase64(file, {
|
||||
maxWidth: 900,
|
||||
maxHeight: 900,
|
||||
quality: 0.65
|
||||
})
|
||||
insertFn(url, file.name, url)
|
||||
// 正文图片上传到文件接口,正文中保存可回显的图片地址。
|
||||
const url = await this.uploadNewsImage(file)
|
||||
insertFn(normalizeImageUrl(url), file.name, normalizeImageUrl(url))
|
||||
} catch (error) {
|
||||
this.$message.error('正文图片读取失败')
|
||||
this.$message.error('正文图片上传失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,6 +180,9 @@ export default {
|
||||
},
|
||||
// 上传封面的本地预览地址,只用于页面显示,不提交给接口。
|
||||
coverPreview: '',
|
||||
imageUploading: false,
|
||||
editorFullscreen: false,
|
||||
editorFullscreenObserver: null,
|
||||
// 右侧预览区域宽度。
|
||||
previewWidth: 400,
|
||||
// 标记预览区域是否正在拖拽调整宽度。
|
||||
@ -255,6 +240,8 @@ export default {
|
||||
}
|
||||
// 清理拖拽监听事件。
|
||||
this.removeResizeListeners()
|
||||
this.stopObserveEditorFullscreen()
|
||||
this.editorFullscreen = false
|
||||
},
|
||||
methods: {
|
||||
createEmptyForm() {
|
||||
@ -282,33 +269,131 @@ export default {
|
||||
if (!this.form.publishTime) this.form.publishTime = this.today
|
||||
// 初始化封面预览。
|
||||
this.coverPreview = this.form.coverUrl || ''
|
||||
this.editorFullscreen = false
|
||||
this.$nextTick(() => {
|
||||
// 表单初始化完成后重置未保存状态。
|
||||
this.dirty = false
|
||||
this.startObserveEditorFullscreen()
|
||||
})
|
||||
},
|
||||
handleEditorCreated(editor) {
|
||||
// 保存编辑器实例,后续销毁时使用。
|
||||
this.editor = Object.seal(editor)
|
||||
},
|
||||
handleDialogClose() {
|
||||
this.stopObserveEditorFullscreen()
|
||||
this.editorFullscreen = false
|
||||
},
|
||||
requestClose() {
|
||||
this.handleBeforeClose(() => {
|
||||
this.dialogVisible = false
|
||||
})
|
||||
},
|
||||
handleBeforeClose(done) {
|
||||
if (!this.dirty) {
|
||||
done()
|
||||
return
|
||||
}
|
||||
this.$confirm('当前编辑内容尚未保存,是否保存为草稿?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
customClass: 'news-confirm-box news-confirm-box--warning',
|
||||
confirmButtonClass: 'news-confirm-btn news-confirm-btn--confirm',
|
||||
cancelButtonClass: 'news-confirm-btn news-confirm-btn--cancel'
|
||||
}).then(() => {
|
||||
this.handleSave('0')
|
||||
}).catch(() => {
|
||||
done()
|
||||
})
|
||||
},
|
||||
handlePublishConfirm() {
|
||||
this.$confirm('请确认该文章不包含敏感词汇。', '确认发布企业动态文章?', {
|
||||
confirmButtonText: '确定发布',
|
||||
cancelButtonText: '取消',
|
||||
type: 'success',
|
||||
customClass: 'news-confirm-box news-confirm-box--success',
|
||||
confirmButtonClass: 'news-confirm-btn news-confirm-btn--confirm is-success',
|
||||
cancelButtonClass: 'news-confirm-btn news-confirm-btn--cancel'
|
||||
}).then(() => {
|
||||
this.handleSave('1')
|
||||
}).catch(() => {})
|
||||
},
|
||||
isEditorFullscreenActive() {
|
||||
const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement
|
||||
if (fullscreenElement) return true
|
||||
return !!document.querySelector('.w-e-full-screen-container, .w-e-full-screen, .w-e-text-container-full-screen')
|
||||
},
|
||||
updateEditorFullscreenState() {
|
||||
this.editorFullscreen = this.isEditorFullscreenActive()
|
||||
},
|
||||
startObserveEditorFullscreen() {
|
||||
this.stopObserveEditorFullscreen()
|
||||
this.updateEditorFullscreenState()
|
||||
this.editorFullscreenObserver = new MutationObserver(() => {
|
||||
this.updateEditorFullscreenState()
|
||||
})
|
||||
this.editorFullscreenObserver.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
attributeFilter: ['class', 'style']
|
||||
})
|
||||
},
|
||||
stopObserveEditorFullscreen() {
|
||||
if (this.editorFullscreenObserver) {
|
||||
this.editorFullscreenObserver.disconnect()
|
||||
this.editorFullscreenObserver = null
|
||||
}
|
||||
},
|
||||
getUploadUrl(res) {
|
||||
const pickUrl = (data) => {
|
||||
if (!data) return ''
|
||||
if (typeof data === 'string') return data
|
||||
if (typeof data === 'object') {
|
||||
return data.file_path ||
|
||||
data.file_url ||
|
||||
data.save_url ||
|
||||
data.url ||
|
||||
data.path ||
|
||||
data.filePath ||
|
||||
data.fileUrl ||
|
||||
data.saveUrl ||
|
||||
pickUrl(data.data)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
return pickUrl(res && (res.data || res))
|
||||
},
|
||||
async uploadNewsImage(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file_data', file)
|
||||
formData.append('domain_name', window.location.host)
|
||||
const res = await reqUploadNewsImage(formData)
|
||||
if (res && (res.status === true || res.status === 'true')) {
|
||||
const url = this.getUploadUrl(res)
|
||||
if (url) return url
|
||||
}
|
||||
throw new Error((res && (res.msg || res.message)) || '图片上传失败')
|
||||
},
|
||||
async handleCoverUpload(event) {
|
||||
// 读取用户选择的封面文件。
|
||||
const file = event.target.files && event.target.files[0]
|
||||
if (!file) return
|
||||
// 保存文件名用于页面提示。
|
||||
this.form.coverName = file.name
|
||||
this.imageUploading = true
|
||||
try {
|
||||
// 封面图片先压缩再转 Base64,直接保存到 coverUrl / cover_img。
|
||||
const base64 = await compressImageToBase64(file, {
|
||||
maxWidth: 900,
|
||||
maxHeight: 900,
|
||||
quality: 0.68
|
||||
})
|
||||
this.coverPreview = base64
|
||||
this.form.coverUrl = base64
|
||||
// 封面图片上传后保存接口返回路径,提交文章时作为 cover_img。
|
||||
const url = await this.uploadNewsImage(file)
|
||||
this.form.coverUrl = url
|
||||
this.coverPreview = normalizeImageUrl(url)
|
||||
this.$message.success('封面图片上传成功')
|
||||
} catch (error) {
|
||||
this.$message.error('封面图片读取失败')
|
||||
this.form.coverName = ''
|
||||
this.$message.error('封面图片上传失败')
|
||||
} finally {
|
||||
this.imageUploading = false
|
||||
// 清空 input 值,保证重复选择同一文件也能触发 change。
|
||||
event.target.value = ''
|
||||
}
|
||||
@ -384,6 +469,10 @@ export default {
|
||||
this.$message.warning('请输入文章正文')
|
||||
return
|
||||
}
|
||||
if (this.imageUploading) {
|
||||
this.$message.warning('图片上传中,请稍后保存')
|
||||
return
|
||||
}
|
||||
// 第六步:组装保存参数,status 由按钮决定是草稿还是发布。
|
||||
const payload = {
|
||||
...this.form,
|
||||
@ -402,6 +491,19 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep .el-form-item__content{
|
||||
/* width: 100% !important; */
|
||||
margin-left: 88px !important;
|
||||
}
|
||||
::v-deep .el-form-item__label{
|
||||
width: auto !important;
|
||||
}
|
||||
.required-star{
|
||||
color: #ff0000;
|
||||
font-size: 16px;
|
||||
/* font-weight: 700; */
|
||||
margin-right: 4px;
|
||||
}
|
||||
::v-deep .article-editor-dialog {
|
||||
margin: 0 !important;
|
||||
height: 100vh;
|
||||
@ -415,6 +517,35 @@ export default {
|
||||
border-bottom: 1px solid #edf0f5;
|
||||
}
|
||||
|
||||
.article-dialog-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dialog-back-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 5px 10px;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
background: #fff;
|
||||
border: 1px solid #d8e0ec;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.dialog-back-btn:hover {
|
||||
color: #2563eb;
|
||||
border-color: #bfdbfe;
|
||||
background: #eff6ff;
|
||||
}
|
||||
|
||||
::v-deep .article-editor-dialog .el-dialog__body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
@ -474,6 +605,10 @@ export default {
|
||||
background: #3b82f6;
|
||||
}
|
||||
|
||||
.article-editor.is-editor-fullscreen .resize-handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.article-editor__form {
|
||||
padding: 16px 18px 4px 0;
|
||||
border-bottom: 1px solid #edf0f5;
|
||||
|
||||
@ -1,33 +1,34 @@
|
||||
<template>
|
||||
<div class="news-detail-page">
|
||||
<div class="news-detail-shell">
|
||||
<div class="news-detail-layout">
|
||||
<button type="button" class="back-btn" @click="goBack">
|
||||
<i class="el-icon-arrow-left"></i>
|
||||
返回动态
|
||||
</button>
|
||||
<div class="news-detail-shell">
|
||||
<article v-loading="loading" class="detail-card">
|
||||
<div v-if="article.id" class="detail-content">
|
||||
<div class="detail-meta">
|
||||
<span class="detail-tag">{{ article.articleType }}</span>
|
||||
<time>{{ article.publishTime }}</time>
|
||||
</div>
|
||||
|
||||
<article v-loading="loading" class="detail-card">
|
||||
<div v-if="article.id" class="detail-content">
|
||||
<div class="detail-meta">
|
||||
<span class="detail-tag">{{ article.articleType }}</span>
|
||||
<time>{{ article.publishTime }}</time>
|
||||
<h1>{{ article.title }}</h1>
|
||||
<!-- <p v-if="article.summary" class="summary">{{ article.summary }}</p> -->
|
||||
<!--
|
||||
<div v-if="article.coverImg" class="cover-wrap">
|
||||
<img :src="article.coverImg" :alt="article.title">
|
||||
</div> -->
|
||||
|
||||
<div class="article-body" v-html="article.content"></div>
|
||||
</div>
|
||||
|
||||
<h1>{{ article.title }}</h1>
|
||||
<p v-if="article.summary" class="summary">{{ article.summary }}</p>
|
||||
|
||||
<div v-if="article.coverImg" class="cover-wrap">
|
||||
<img :src="article.coverImg" :alt="article.title">
|
||||
<div v-else-if="!loading" class="empty-state">
|
||||
<i class="el-icon-document"></i>
|
||||
<p>暂无新闻详情</p>
|
||||
</div>
|
||||
|
||||
<div class="article-body" v-html="article.content"></div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="!loading" class="empty-state">
|
||||
<i class="el-icon-document"></i>
|
||||
<p>暂无新闻详情</p>
|
||||
</div>
|
||||
</article>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -40,6 +41,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
fallbackNewsImage: require('@/assets/image/news.jpg'),
|
||||
article: {
|
||||
id: '',
|
||||
title: '',
|
||||
@ -115,6 +117,9 @@ export default {
|
||||
})
|
||||
if (res && (res.status === true || res.status === 'true')) {
|
||||
this.article = this.normalizeArticle(this.getResponseDetail(res))
|
||||
this.$nextTick(() => {
|
||||
this.bindArticleImageFallback()
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$message.error((res && (res.message || res.msg)) || '新闻详情加载失败')
|
||||
@ -123,6 +128,16 @@ export default {
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
bindArticleImageFallback() {
|
||||
const images = this.$el.querySelectorAll('.article-body img, .cover-wrap img')
|
||||
images.forEach((image) => {
|
||||
image.onerror = () => {
|
||||
if (image.src !== this.fallbackNewsImage) {
|
||||
image.src = this.fallbackNewsImage
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -135,32 +150,49 @@ export default {
|
||||
background: linear-gradient(180deg, #eff6ff 0%, #fff 55%, #f8fbff 100%);
|
||||
}
|
||||
|
||||
.news-detail-layout {
|
||||
width: 100%;
|
||||
max-width: 1000px;
|
||||
display: grid;
|
||||
grid-template-columns: 132px minmax(0, 677px);
|
||||
column-gap: 12px;
|
||||
align-items: start;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.news-detail-shell {
|
||||
width: 100%;
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
max-width: 677px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 20px;
|
||||
padding: 9px 14px;
|
||||
justify-content: flex-start;
|
||||
margin-top: 0;
|
||||
padding: 5px 8px;
|
||||
color: #2563eb;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(37, 99, 235, 0.16);
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
// background: #fff;
|
||||
// border: 1px solid rgba(37, 99, 235, 0.16);
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
min-height: 420px;
|
||||
padding: 44px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid rgba(226, 232, 240, 0.9);
|
||||
border-radius: 24px;
|
||||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.08);
|
||||
padding-left: 44px;
|
||||
padding-right: 44px;
|
||||
padding-bottom: 44px;
|
||||
// background: rgba(255, 255, 255, 0.92);
|
||||
// border: 1px solid rgba(226, 232, 240, 0.9);
|
||||
// border-radius: 24px;
|
||||
// box-shadow: 0 24px 70px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
.detail-meta {
|
||||
@ -211,9 +243,13 @@ h1 {
|
||||
}
|
||||
|
||||
.article-body ::v-deep img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
width: auto !important;
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
margin: 18px auto;
|
||||
border-radius: 12px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
@ -236,6 +272,14 @@ h1 {
|
||||
padding: 80px 14px 40px;
|
||||
}
|
||||
|
||||
.news-detail-layout {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.detail-card {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="article-admin-page">
|
||||
<div class="page-title-wrap">
|
||||
<h1>企业文章</h1>
|
||||
<h1>企业动态</h1>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
@ -66,7 +66,16 @@
|
||||
{{ getRowNo(scope.$index) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="title" label="标题" min-width="260" show-overflow-tooltip>
|
||||
<el-table-column
|
||||
prop="title"
|
||||
label="标题"
|
||||
min-width="240"
|
||||
align="left"
|
||||
header-align="left"
|
||||
class-name="title-column"
|
||||
label-class-name="title-column-header"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span class="article-title">{{ scope.row.title }}</span>
|
||||
</template>
|
||||
@ -83,6 +92,7 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="updateTime" label="创建时间" width="170" />
|
||||
<el-table-column prop="publishTime" label="发布时间" width="140" />
|
||||
<el-table-column label="阅读数据" width="130">
|
||||
<template slot-scope="scope">
|
||||
@ -118,7 +128,7 @@
|
||||
class="success-text"
|
||||
@click="publishArticle(scope.row)"
|
||||
>
|
||||
上架
|
||||
发布
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
@ -228,7 +238,7 @@ export default {
|
||||
// 按文章类型返回对应的标签样式类。
|
||||
const classMap = {
|
||||
企业动态: 'type-blue',
|
||||
产品动态: 'type-purple',
|
||||
产品动态: 'type-green',
|
||||
行业洞察: 'type-amber',
|
||||
活动资讯: 'type-violet'
|
||||
}
|
||||
@ -256,7 +266,7 @@ export default {
|
||||
},
|
||||
getApiStatus(status) {
|
||||
// 页面状态转成接口需要的状态值:1 上架,0 草稿/下架。
|
||||
return status === 'published' ? '1' : '0'
|
||||
return String(status) === '1' || status === 'published' ? '1' : '0'
|
||||
},
|
||||
getViewStatus(status) {
|
||||
// 接口状态转成页面使用的状态枚举。
|
||||
@ -286,6 +296,7 @@ export default {
|
||||
type: row.article_type || row.type || '企业动态',
|
||||
status: this.getViewStatus(row.status),
|
||||
publishTime: row.publish_time || row.publishTime || '',
|
||||
updateTime: row.update_time || row.updateTime || '',
|
||||
views: row.read_count || row.views || 0,
|
||||
content: row.content || '',
|
||||
coverUrl: row.cover_img || row.coverUrl || '',
|
||||
@ -321,19 +332,25 @@ export default {
|
||||
title: article.title,
|
||||
article_type: article.type,
|
||||
summary: article.summary,
|
||||
update_time: article.update_time || article.updateTime,
|
||||
publish_time: article.publish_time || article.publishTime,
|
||||
cover_img: article.coverUrl,
|
||||
content: article.content,
|
||||
status: this.getApiStatus(article.status)
|
||||
}
|
||||
},
|
||||
async confirmAction(title, message, type = 'warning') {
|
||||
async confirmAction(title, message, type = 'warning', confirmButtonText = '确定') {
|
||||
// 操作前弹出二次确认,用户取消时直接终止后续请求。
|
||||
const isDanger = type === 'error'
|
||||
const isSuccess = type === 'success'
|
||||
try {
|
||||
await this.$confirm(message, title, {
|
||||
confirmButtonText: '确定',
|
||||
confirmButtonText,
|
||||
cancelButtonText: '取消',
|
||||
type
|
||||
type,
|
||||
customClass: `news-confirm-box ${isDanger ? 'news-confirm-box--danger' : isSuccess ? 'news-confirm-box--success' : 'news-confirm-box--warning'}`,
|
||||
confirmButtonClass: `news-confirm-btn news-confirm-btn--confirm ${isDanger ? 'is-danger' : isSuccess ? 'is-success' : ''}`,
|
||||
cancelButtonClass: 'news-confirm-btn news-confirm-btn--cancel'
|
||||
})
|
||||
return true
|
||||
} catch (error) {
|
||||
@ -380,7 +397,7 @@ export default {
|
||||
return
|
||||
}
|
||||
// 保存成功后提示,并刷新列表展示最新数据。
|
||||
this.$message.success(article.status === 'published' ? '发布成功' : '草稿已保存')
|
||||
this.$message.success(this.getApiStatus(article.status) === '1' ? '发布成功' : '草稿已保存')
|
||||
this.getArticleList()
|
||||
} catch (error) {
|
||||
// 网络或程序异常时提示保存失败。
|
||||
@ -389,7 +406,7 @@ export default {
|
||||
},
|
||||
async publishArticle(row) {
|
||||
// 上架前先二次确认,避免误操作。
|
||||
const confirmed = await this.confirmAction('确认上架', `确定要上架「${row.title}」吗?`)
|
||||
const confirmed = await this.confirmAction('确认发布企业动态文章?', '请确认该文章不包含敏感词汇。', 'success', '确定发布')
|
||||
if (!confirmed) return
|
||||
try {
|
||||
// 调用上架接口。
|
||||
@ -400,16 +417,16 @@ export default {
|
||||
return
|
||||
}
|
||||
// 上架成功后刷新列表。
|
||||
this.$message.success('上架成功')
|
||||
this.$message.success('发布成功')
|
||||
this.getArticleList()
|
||||
} catch (error) {
|
||||
// 请求异常时提示用户。
|
||||
this.$message.error('上架失败')
|
||||
this.$message.error('发布失败')
|
||||
}
|
||||
},
|
||||
async unpublishArticle(row) {
|
||||
// 下架前先二次确认,避免误操作。
|
||||
const confirmed = await this.confirmAction('确认下架', `确定要下架「${row.title}」吗?`)
|
||||
const confirmed = await this.confirmAction('确定要下架这篇文章吗?', '下架后将在企业动态页面隐藏。')
|
||||
if (!confirmed) return
|
||||
try {
|
||||
// 调用下架接口。
|
||||
@ -563,6 +580,11 @@ export default {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.filter-form ::v-deep .el-button--small {
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.table-card {
|
||||
overflow: hidden;
|
||||
}
|
||||
@ -574,9 +596,18 @@ export default {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.article-table ::v-deep .title-column .cell,
|
||||
.article-table ::v-deep .title-column-header .cell {
|
||||
justify-content: flex-start;
|
||||
/* text-align: left !important; */
|
||||
}
|
||||
|
||||
.article-title {
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: #1f2937;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.type-tag {
|
||||
@ -592,9 +623,9 @@ export default {
|
||||
background: #eff6ff;
|
||||
}
|
||||
|
||||
.type-purple {
|
||||
color: #7c3aed;
|
||||
background: #f5f3ff;
|
||||
.type-green {
|
||||
color: #059669;
|
||||
background: #ecfdf5;
|
||||
}
|
||||
|
||||
.type-amber {
|
||||
@ -603,8 +634,8 @@ export default {
|
||||
}
|
||||
|
||||
.type-violet {
|
||||
color: #8b5cf6;
|
||||
background: #f5f3ff;
|
||||
color: #db2777;
|
||||
background: #fdf2f8;
|
||||
}
|
||||
|
||||
.status-tag {
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
<span class="hover-detail">详情 <i class="el-icon-arrow-right"></i></span>
|
||||
<div class="news-featured-inner">
|
||||
<div class="news-featured-img">
|
||||
<img :src="featuredNews.img || fallbackNewsImage" :alt="featuredNews.title">
|
||||
<img :src="featuredNews.img || fallbackNewsImage" :alt="featuredNews.title" @error="handleImageError">
|
||||
</div>
|
||||
<div class="news-featured-body">
|
||||
<div class="news-featured-date">
|
||||
@ -71,7 +71,7 @@
|
||||
<div class="news-item-glow"></div>
|
||||
<span class="hover-detail">详情 <i class="el-icon-arrow-right"></i></span>
|
||||
<div class="news-item-img">
|
||||
<img :src="item.img || fallbackNewsImage" :alt="item.title">
|
||||
<img :src="item.img || fallbackNewsImage" :alt="item.title" @error="handleImageError">
|
||||
<div class="news-item-img-overlay"></div>
|
||||
<span class="news-item-tag" :style="{ background: item.tagColor }">{{ item.tag }}</span>
|
||||
</div>
|
||||
@ -115,6 +115,7 @@ export default {
|
||||
fallbackNewsImage: require('@/assets/image/news.jpg'),
|
||||
activeCategory: 'all',
|
||||
page: 1,
|
||||
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
filterTabs: [
|
||||
@ -150,7 +151,17 @@ export default {
|
||||
},
|
||||
goNewsDetail(item) {
|
||||
if (!item || !item.id) return
|
||||
this.$router.push(`/homePage/news/detail/${item.id}`)
|
||||
this.$router.push({
|
||||
name: 'homePageNewsDetail',
|
||||
params: { id: item.id }
|
||||
}).catch(() => {
|
||||
this.$router.push(`/homePage/news/detail/${item.id}`)
|
||||
})
|
||||
},
|
||||
handleImageError(event) {
|
||||
if (event && event.target && event.target.src !== this.fallbackNewsImage) {
|
||||
event.target.src = this.fallbackNewsImage
|
||||
}
|
||||
},
|
||||
handleCategoryChange(value) {
|
||||
this.activeCategory = value
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="train-page">
|
||||
<div class="grid-bg min-h-screen">
|
||||
<main>
|
||||
<div class="page-shell">
|
||||
<div class="page-shell">
|
||||
<section class="hero-section">
|
||||
<div class="hero-content">
|
||||
<div class="hero-eyebrow animate-fade-in-up">
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="mainBox">
|
||||
<div class="header">
|
||||
<div class="logowx"><img src="../../assets/kyy/simple_logonew.png" alt=""></div>
|
||||
<div class="btnStyle" @click="$router.push('/login')"> 登录/注册</div>
|
||||
<div class="btnStyle" @click="openLoginDialog"> 登录/注册</div>
|
||||
</div>
|
||||
<div class="banner" style="margin-top: 60px">
|
||||
{{ $route.query.productType === '0' ? "供给详情" : "需求详情" }}
|
||||
@ -87,7 +87,7 @@
|
||||
</li>
|
||||
<li>
|
||||
<span style="margin-right: 15px" class="tag">产品单价:</span>
|
||||
<span style="font-weight: 700;color: blue" @click="$router.push('/login')">登录后查看</span></li>
|
||||
<span style="font-weight: 700;color: blue" @click="openLoginDialog">登录后查看</span></li>
|
||||
</ul>
|
||||
<ul v-else-if="$route.query.productType=='1'" class="detail-ul">
|
||||
<li><span style="margin-right: 15px" class="tag">需求说明:</span>{{ dataObj.demanddesc }}</li>
|
||||
@ -127,6 +127,9 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openLoginDialog() {
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
},
|
||||
computedWord(type) {
|
||||
if (type === '1') {
|
||||
return '机柜'
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="mainBox">
|
||||
<div class="header">
|
||||
<div class="logowx"><img src="../../assets/kyy/simple_logonew.png" alt=""></div>
|
||||
<div class="btnStyle" @click="$router.push('/login')"> 登录/注册</div>
|
||||
<div class="btnStyle" @click="openLoginDialog"> 登录/注册</div>
|
||||
</div>
|
||||
<div class="banner" style="background: #f8f9fe">
|
||||
<div class="block">
|
||||
@ -39,7 +39,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div style="background: #f8f9fe" class="lookMore">
|
||||
<span class="word" @click="$router.push('/login')"> 查看更多</span>
|
||||
<span class="word" @click="openLoginDialog"> 查看更多</span>
|
||||
</div>
|
||||
<div class="apS">
|
||||
模型广场
|
||||
@ -73,7 +73,7 @@
|
||||
</ul>
|
||||
|
||||
<div class="lookMore">
|
||||
<span class="word" @click="$router.push('/login')"> 查看更多</span>
|
||||
<span class="word" @click="openLoginDialog"> 查看更多</span>
|
||||
</div>
|
||||
<div class="footerBox">
|
||||
<!-- <div>-->
|
||||
@ -147,6 +147,9 @@ export default {
|
||||
|
||||
},
|
||||
methods: {
|
||||
openLoginDialog() {
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
},
|
||||
goDetail(item) {
|
||||
this.$router.push({
|
||||
path: "/wxDetailPage",
|
||||
|
||||
@ -439,7 +439,7 @@
|
||||
window.open('http://tmpweb.opencomputing.cn/col.jsp?id=136')
|
||||
},
|
||||
login() {
|
||||
this.$router.push('/login')
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'))
|
||||
},
|
||||
register() {
|
||||
this.$router.push('/registrationPage')
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<el-dialog
|
||||
custom-class="forgot-password-dialog"
|
||||
:visible="visible"
|
||||
width="420px"
|
||||
width="540px"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
@ -45,7 +45,7 @@
|
||||
|
||||
<div slot="footer" class="forgot-footer">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">确认重置</el-button>
|
||||
<el-button class="confirm-btn" type="primary" :loading="submitting" @click="handleSubmit">确认重置</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -205,21 +205,21 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
.forgot-password-dialog {
|
||||
border-radius: 16px;
|
||||
border-radius: 30px;
|
||||
overflow: hidden;
|
||||
|
||||
.el-dialog__header {
|
||||
padding: 24px 28px 18px;
|
||||
background: linear-gradient(135deg, #f4f8ff 0%, #ffffff 70%);
|
||||
border-bottom: 1px solid #eef2f7;
|
||||
padding: 40px 44px 20px;
|
||||
background: #fff;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 24px 28px 8px;
|
||||
padding: 10px 44px 8px;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding: 14px 28px 24px;
|
||||
padding: 12px 44px 36px;
|
||||
}
|
||||
|
||||
.el-dialog__headerbtn {
|
||||
@ -261,7 +261,7 @@ export default {
|
||||
|
||||
.forgot-form {
|
||||
.el-form-item {
|
||||
margin-bottom: 18px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.el-form-item__label {
|
||||
@ -272,9 +272,10 @@ export default {
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
height: 42px;
|
||||
border-color: #dfe5ef;
|
||||
border-radius: 8px;
|
||||
height: 48px;
|
||||
border-color: #c8d3e2;
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.94);
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,11 +289,11 @@ export default {
|
||||
|
||||
.code-btn {
|
||||
width: 118px;
|
||||
height: 42px;
|
||||
height: 48px;
|
||||
color: #2f6bff;
|
||||
background: #eef4ff;
|
||||
border-color: #cfe0ff;
|
||||
border-radius: 8px;
|
||||
border-radius: 14px;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
@ -305,12 +306,30 @@ export default {
|
||||
|
||||
.forgot-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
|
||||
.el-button {
|
||||
min-width: 90px;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
height: 52px;
|
||||
margin-left: 0;
|
||||
border-radius: 999px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
color: #fff;
|
||||
background: #020617;
|
||||
border-color: #020617;
|
||||
box-shadow: 0 16px 34px rgba(2, 6, 23, 0.22);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #fff;
|
||||
background: #020617;
|
||||
border-color: #020617;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -542,6 +542,8 @@
|
||||
}
|
||||
}
|
||||
.model-table {
|
||||
border-radius: 12px;
|
||||
border
|
||||
/deep/ .el-table__header th {
|
||||
color: #475467;
|
||||
background: #f8fbff;
|
||||
|
||||
@ -303,6 +303,7 @@ export default {
|
||||
.config-table {
|
||||
margin-top: 10px;
|
||||
color: #344054;
|
||||
border-radius: 12px;
|
||||
|
||||
/deep/ th {
|
||||
color: #475467;
|
||||
|
||||
@ -847,41 +847,21 @@ export default {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$router.push({
|
||||
path: "/login",
|
||||
query: {
|
||||
fromPath: 'productService',
|
||||
type: 'bd',
|
||||
listUrl: product.listUrl,
|
||||
url: product.url
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'));
|
||||
}
|
||||
} else if (product.type === '阿里云') {
|
||||
|
||||
if (userId) {
|
||||
await this.handleAliyunProductClick();
|
||||
} else {
|
||||
this.$router.push({
|
||||
path: "/login",
|
||||
query: {
|
||||
fromPath: 'productService',
|
||||
type: 'ali',
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'));
|
||||
}
|
||||
} else if (product.type === '智算' || product.type === '算力网络') {
|
||||
if (product.name === '容器云') {
|
||||
if (userId) {
|
||||
this.$router.push('/product/productHome/k8s/createK8s');
|
||||
} else {
|
||||
this.$router.push({
|
||||
path: "/login",
|
||||
query: {
|
||||
fromPath: 'productService',
|
||||
type: 'rqy',
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(new Event('kboss-open-login-dialog'));
|
||||
}
|
||||
} else {
|
||||
this.$router.push({
|
||||
@ -904,7 +884,7 @@ export default {
|
||||
<style lang="less" scoped>
|
||||
.product-service-page {
|
||||
margin: 0 auto;
|
||||
padding: 82px 24px 24px;
|
||||
padding: 0px 24px 24px;
|
||||
background: #fff;
|
||||
min-height: calc(100vh - 100px);
|
||||
|
||||
|
||||
@ -587,6 +587,7 @@ export default {
|
||||
}
|
||||
|
||||
.api-key-table {
|
||||
border-radius: 12px;
|
||||
color: #606266;
|
||||
background: transparent;
|
||||
|
||||
|
||||
@ -467,17 +467,17 @@ export default {
|
||||
min-height: 100vh;
|
||||
padding: 24px;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(64, 158, 255, 0.16), transparent 34%),
|
||||
// radial-gradient(circle at top left, rgba(64, 158, 255, 0.16), transparent 34%),
|
||||
linear-gradient(180deg, #f3f7ff 0%, #f7f9fc 48%, #ffffff 100%);
|
||||
}
|
||||
|
||||
.usage-shell {
|
||||
min-height: calc(100vh - 48px);
|
||||
padding: 24px;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid #edf1f7;
|
||||
// padding: 24px;
|
||||
// background: rgba(255, 255, 255, 0.92);
|
||||
// border: 1px solid #edf1f7;
|
||||
border-radius: 18px;
|
||||
box-shadow: 0 12px 30px rgba(31, 45, 61, 0.06);
|
||||
// box-shadow: 0 12px 30px rgba(31, 45, 61, 0.06);
|
||||
}
|
||||
|
||||
.page-header,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user