首页
This commit is contained in:
parent
64073f7e9c
commit
a79b0d9135
@ -2,6 +2,11 @@ import request from '@/utils/request'
|
|||||||
|
|
||||||
const suffix = '.dspy'
|
const suffix = '.dspy'
|
||||||
|
|
||||||
|
const withDomainName = (params = {}) => ({
|
||||||
|
...params,
|
||||||
|
domain_name: window.location.hostname
|
||||||
|
})
|
||||||
|
|
||||||
//注册新用户
|
//注册新用户
|
||||||
export function registerUserAPI(params) {
|
export function registerUserAPI(params) {
|
||||||
return request({
|
return request({
|
||||||
@ -47,7 +52,7 @@ export function getCodeAPI(params) {
|
|||||||
return request({
|
return request({
|
||||||
url: `/user/mobilecode${suffix}`,
|
url: `/user/mobilecode${suffix}`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: params
|
params: withDomainName(params)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +70,7 @@ export function retrieveCodeAPI(data) {
|
|||||||
url: `/user/mobilecode.dspy`,
|
url: `/user/mobilecode.dspy`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
data
|
data: withDomainName(data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +274,7 @@ export function sendCode(data) {
|
|||||||
return request({
|
return request({
|
||||||
url: `/user/mobilecode.dspy`,
|
url: `/user/mobilecode.dspy`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data: withDomainName(data),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 注册
|
// 注册
|
||||||
|
|||||||
@ -23,29 +23,24 @@ export const reqNewsDetail = (data) => {
|
|||||||
url: '/news/front_news_detail.dspy',
|
url: '/news/front_news_detail.dspy',
|
||||||
// 详情接口使用 GET 查询。
|
// 详情接口使用 GET 查询。
|
||||||
method: 'get',
|
method: 'get',
|
||||||
// 传入文章 id 和当前页面 url_link 等查询参数。
|
// 传入文章 id 。
|
||||||
params: data
|
params: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 添加新闻
|
// 添加新闻
|
||||||
export const reqAddNews = (data) => {
|
export const reqAddNews = (data) => {
|
||||||
const isFormData = data instanceof FormData
|
|
||||||
return request({
|
return request({
|
||||||
url: '/news/news_article_add.dspy',
|
url: '/news/news_article_add.dspy',
|
||||||
method: isFormData ? 'post' : 'get',
|
method: 'post',
|
||||||
params: isFormData ? undefined : data,
|
data
|
||||||
data: isFormData ? data : undefined,
|
|
||||||
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : undefined
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 编辑新闻
|
// 编辑新闻
|
||||||
export const reqEditNews = (data) => {
|
export const reqEditNews = (data) => {
|
||||||
const isFormData = data instanceof FormData
|
|
||||||
return request({
|
return request({
|
||||||
url: '/news/news_article_update.dspy',
|
url: '/news/news_article_update.dspy',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data
|
||||||
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : undefined
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 删除新闻
|
// 删除新闻
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
@click="handleSearch"
|
@click="handleSearch"
|
||||||
></el-button>
|
></el-button>
|
||||||
</el-input-group>
|
</el-input-group>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="search-label">创建日期:</span>
|
<span class="search-label">创建日期:</span>
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
|
|||||||
@ -25,7 +25,7 @@ export default {
|
|||||||
contactSalesBtn: 'Contact Sales',
|
contactSalesBtn: 'Contact Sales',
|
||||||
aiSolutionsTitle: 'AI + Solutions',
|
aiSolutionsTitle: 'AI + Solutions',
|
||||||
successCasesTitle: 'Use Cases',
|
successCasesTitle: 'Use Cases',
|
||||||
moreCases: 'View All Use Cases →',
|
moreCases: 'View All Use Cases',
|
||||||
ctaTitle: 'How Do These Solutions Work in Practice?',
|
ctaTitle: 'How Do These Solutions Work in Practice?',
|
||||||
ctaDesc: 'Get industry-specific AI solutions.',
|
ctaDesc: 'Get industry-specific AI solutions.',
|
||||||
contactUsArrow: 'Contact Us →',
|
contactUsArrow: 'Contact Us →',
|
||||||
@ -70,19 +70,22 @@ export default {
|
|||||||
},
|
},
|
||||||
cases: {
|
cases: {
|
||||||
railway: {
|
railway: {
|
||||||
name: 'China Railway Group · AI Industry Bidding Agent Engine',
|
name: 'China Railway Group · Huitobid',
|
||||||
title: 'Smart Engineering',
|
title: 'Smart Engineering',
|
||||||
desc: 'AI-Powered Bidding Process'
|
desc: 'AI-driven full-stack bidding process - from bid document analysis to pricing compilation, delivering a significant improvement in win rates',
|
||||||
|
summary: 'Project Overview: Built the Huitobid and HuiTu Large Model for China Railway Group, establishing a Joint Innovation Center and an AI Application Innovation Platform. Covering the full bidding lifecycle - intelligent document analysis, automatic qualification matching, pricing decision support, and smart bid compilation - the solution enables a step-change transformation from manpower-heavy manual workflows to AI-powered bidding operations.'
|
||||||
},
|
},
|
||||||
forestry: {
|
forestry: {
|
||||||
name: 'Nanning Forestry Bureau · Smart Harvesting',
|
name: 'Nanning Forestry Bureau',
|
||||||
title: 'Smart Harvesting',
|
title: 'Smart Harvesting',
|
||||||
desc: 'AI-Powered Forestry Spatial Intelligence Review'
|
desc: 'From harvesting approval to scientific oversight - spatial intelligence integration, enabling data-driven forest governance.',
|
||||||
|
summary: 'Project Overview: Developed an Intelligent Forest Harvesting Spatial Review System for Nanning Forestry Bureau, integrating GIS spatial analysis, satellite remote sensing, and multi-source data from Unmanned Aerial Vehicles (UAVs) and sensors to achieve unified intelligent review of spatial and attribute data. Harvesting boundaries are automatically verified for compliance, review reports are generated with one click, and the approval cycle is compressed from days to minutes - human-machine collaboration ensures every decision is evidence-based.'
|
||||||
},
|
},
|
||||||
beigang: {
|
beigang: {
|
||||||
name: 'AI Empowerment · Beibu Gulf Big Data',
|
name: 'Beibu Gulf Port Big Data',
|
||||||
title: 'Digital & Intelligent Upgrade',
|
title: 'AI-Powered Digital & Intelligent Transformation',
|
||||||
desc: 'Three Core AI Agent Platforms'
|
desc: 'From bidding to decision-making, from contracts to management - a full-stack AI agent solution that keeps your business one step ahead.',
|
||||||
|
summary: 'Project Overview: Developed a full-stack AI agent solution for Beibu Gulf Port Big Data, covering bidding & tendering, investment decision-making, and contract review. The Bid Agent Engine enables bid document generation in seconds with a significantly improved win rate; the Investment Strategy Agent Engine compresses weeks of research reports into minutes, supporting precise investment decisions; and the Contract Review Agent boosts review efficiency by over 60% while reducing the risk oversight rate to below 3%. The three products are seamlessly integrated, truly closing the digital loop from business acquisition to risk management.'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
news: {
|
news: {
|
||||||
|
|||||||
@ -72,17 +72,20 @@ export default {
|
|||||||
railway: {
|
railway: {
|
||||||
name: '中国中铁 · 慧投标智能体',
|
name: '中国中铁 · 慧投标智能体',
|
||||||
title: '智慧工程',
|
title: '智慧工程',
|
||||||
desc: 'AI驱动投标全流程,从标书解读到报价编制,中标率提升显著'
|
desc: 'AI驱动投标全流程,从标书解读到报价编制,中标率提升显著',
|
||||||
|
summary: '项目概况:为中国中铁打造慧投标智能体+慧途大模型,建立联合创新中心与AI应用创新平台。覆盖投标全流程——标书智能解读、资审自动匹配、报价辅助决策、标书智能编制,实现投标工作从人海战术到AI赋能的跨越式升级。'
|
||||||
},
|
},
|
||||||
forestry: {
|
forestry: {
|
||||||
name: '南宁林业局',
|
name: '南宁林业局',
|
||||||
title: '智慧采伐',
|
title: '智慧采伐',
|
||||||
desc: '从采伐审批到科学监管——空间智能融合,让数据真正服务林区治理。'
|
desc: '从采伐审批到科学监管——空间智能融合,让数据真正服务林区治理',
|
||||||
|
summary: '项目概况:为南宁林业局打造林业空间采伐智审系统,融合GIS空间分析、卫星遥感、无人机与传感器多源数据,实现空间与属性数据的一体化智能审核。采伐范围自动核验合规性,审查报告一键生成,审批周期从数天压缩至分钟级,人机协同让每一步决策都有据可依。'
|
||||||
},
|
},
|
||||||
beigang: {
|
beigang: {
|
||||||
name: '北港大数据',
|
name: '北港大数据',
|
||||||
title: 'AI赋能,数智升级',
|
title: 'AI赋能,数智升级',
|
||||||
desc: '从投标到决策,从合同到管理——全链路AI智能体,让业务快人一步'
|
desc: '从投标到决策,从合同到管理——全链路AI智能体,让业务快人一步',
|
||||||
|
summary: '项目概况:为北港大数据打造覆盖招投标、投研分析、合同审查的全链路AI智能体解决方案。以投标智能体引擎实现标书秒级生成、中标率显著提升;以投策智能体引擎将数周研报压缩至分钟级,支撑精准投资决策;以合同智能审查将审查效率提升60%以上,风险漏检率降至3%以下。三款产品无缝衔接,真正打通企业从业务承接到风险管控的数字化闭环。'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
news: {
|
news: {
|
||||||
|
|||||||
@ -730,11 +730,6 @@ export default {
|
|||||||
this.editUserInfoDialog = false;
|
this.editUserInfoDialog = false;
|
||||||
},
|
},
|
||||||
async logout() {
|
async logout() {
|
||||||
let redirectPath = ''
|
|
||||||
if (this.$route && this.$route.fullPath && !this.$route.fullPath.includes('/login')) {
|
|
||||||
redirectPath = this.$route.fullPath
|
|
||||||
sessionStorage.setItem('loginRedirectPath', redirectPath)
|
|
||||||
}
|
|
||||||
store.commit('tagsView/resetBreadcrumbState');
|
store.commit('tagsView/resetBreadcrumbState');
|
||||||
store.commit('permission/RESET_ROUTES');
|
store.commit('permission/RESET_ROUTES');
|
||||||
sessionStorage.removeItem("auths");
|
sessionStorage.removeItem("auths");
|
||||||
@ -755,16 +750,12 @@ export default {
|
|||||||
localStorage.removeItem("org_type")
|
localStorage.removeItem("org_type")
|
||||||
sessionStorage.removeItem('userId')
|
sessionStorage.removeItem('userId')
|
||||||
this.$store.commit('setLoginState', false)
|
this.$store.commit('setLoginState', false)
|
||||||
await this.$router.push({
|
await this.$router.replace(getHomePath()).catch(() => {});
|
||||||
path: '/login',
|
|
||||||
query: redirectPath ? { redirect: redirectPath } : {}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
async logout1() {
|
async logout1() {
|
||||||
logoutAPI().then((res) => {
|
logoutAPI().then((res) => {
|
||||||
});
|
});
|
||||||
let url = window.location.href;
|
await this.$router.replace(getHomePath()).catch(() => {});
|
||||||
await this.$router.push(`/login`);
|
|
||||||
store.commit('tagsView/resetBreadcrumbState');
|
store.commit('tagsView/resetBreadcrumbState');
|
||||||
store.commit('permission/RESET_ROUTES');
|
store.commit('permission/RESET_ROUTES');
|
||||||
sessionStorage.removeItem("auths");
|
sessionStorage.removeItem("auths");
|
||||||
|
|||||||
@ -414,6 +414,13 @@ export const constantRoutes = [
|
|||||||
hidden: true,
|
hidden: true,
|
||||||
meta: { title: "企业动态", onCache: true },
|
meta: { title: "企业动态", onCache: true },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "news/detail/:id",
|
||||||
|
component: () => import("@/views/homePage/news/NewsDetail.vue"),
|
||||||
|
name: "homePageNewsDetail",
|
||||||
|
hidden: true,
|
||||||
|
meta: { title: "新闻详情", onCache: true },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "new",
|
path: "new",
|
||||||
component: () => import("@/views/homePage/components/topBox/new/index.vue"),
|
component: () => import("@/views/homePage/components/topBox/new/index.vue"),
|
||||||
|
|||||||
@ -575,10 +575,10 @@ export default {
|
|||||||
height: 46px;
|
height: 46px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
border: 1px solid rgba(15, 23, 42, 0.72);
|
border: 1px solid #cbd5e1;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
background: rgba(255, 255, 255, 0.66);
|
background: rgba(255, 255, 255, 0.66);
|
||||||
color: #1f2937;
|
color: #94a3b8;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@ -143,12 +143,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<Talk></Talk>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Talk from '@/views/homePage/dialog/talk/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DecisionCase',
|
name: 'DecisionCase',
|
||||||
|
components: { Talk },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeTab: 'scenarios',
|
activeTab: 'scenarios',
|
||||||
@ -301,7 +305,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleContact() {
|
handleContact() {
|
||||||
this.$message.info('感谢您的关注,我们将尽快与您联系')
|
this.$store.commit('setShowTalk', true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,30 +75,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="page-section">
|
|
||||||
<div class="section-inner">
|
|
||||||
<div class="cta-panel">
|
|
||||||
<h2 class="cta-panel__title">需要定制智能体?</h2>
|
|
||||||
<p class="cta-panel__desc">告诉我们您的业务场景,我们将为您打造专属的AI智能体解决方案</p>
|
|
||||||
<button type="button" class="use-btn btn-primary" @click="handleContact">
|
|
||||||
联系我们
|
|
||||||
<svg class="icon-svg--sm" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Talk></Talk>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Talk from '@/views/homePage/dialog/talk/index.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AgentStore',
|
name: 'AgentStore',
|
||||||
|
components: { Talk },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeMainTab: 'general',
|
activeMainTab: 'general',
|
||||||
@ -161,7 +153,7 @@ export default {
|
|||||||
this.$message.info(`即将使用智能体:${app.name}`)
|
this.$message.info(`即将使用智能体:${app.name}`)
|
||||||
},
|
},
|
||||||
handleContact() {
|
handleContact() {
|
||||||
this.$message.info('感谢您的关注,我们将尽快与您联系')
|
this.$store.commit('setShowTalk', true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -198,7 +198,22 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
'$route.fullPath'() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scrollHomeToTop()
|
||||||
|
window.setTimeout(this.scrollHomeToTop, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
scrollHomeToTop() {
|
||||||
|
const container = this.$el
|
||||||
|
if (container) container.scrollTop = 0
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
document.documentElement.scrollTop = 0
|
||||||
|
document.body.scrollTop = 0
|
||||||
|
},
|
||||||
goOut(url){
|
goOut(url){
|
||||||
window.open(url)
|
window.open(url)
|
||||||
},
|
},
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 581 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
@ -71,15 +71,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<!-- 成功案例 -->
|
<!-- 成功案例 -->
|
||||||
<section id="cases-section" class="case-section">
|
<section id="cases-section" class="case-section">
|
||||||
<div class="case-inner">
|
<div class="case-inner">
|
||||||
<div class="case-head">
|
<div class="case-head">
|
||||||
<h2 class="section-title">{{ $t('home.successCasesTitle') }}</h2>
|
<h2 class="section-title">{{ $t('home.successCasesTitle') }}</h2>
|
||||||
<button type="button" class="case-more" @click="goCases">
|
<!-- <button type="button" class="case-more" @click="goCases">
|
||||||
{{ $t('home.moreCases') }}
|
{{ $t('home.moreCases') }}
|
||||||
<i class="el-icon-right"></i>
|
<i class="el-icon-right"></i>
|
||||||
</button>
|
</button> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="case-grid">
|
<div class="case-grid">
|
||||||
@ -101,7 +101,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="case-cta" :style="{ backgroundImage: `url(${caseCtaBg})` }">
|
<div class="case-cta" :style="{ backgroundImage: `url(${caseCtaBg})` }">
|
||||||
@ -114,7 +114,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</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--left"></div>
|
||||||
<div class="news-glow news-glow--right"></div>
|
<div class="news-glow news-glow--right"></div>
|
||||||
<div class="news-glow news-glow--center"></div>
|
<div class="news-glow news-glow--center"></div>
|
||||||
@ -148,7 +149,7 @@
|
|||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section> -->
|
||||||
|
|
||||||
<Talk></Talk>
|
<Talk></Talk>
|
||||||
</div>
|
</div>
|
||||||
@ -177,21 +178,24 @@ export default {
|
|||||||
title: '智慧工程',
|
title: '智慧工程',
|
||||||
desc: 'AI驱动投标全流程,从标书解读到报价编制,中标率提升显著',
|
desc: 'AI驱动投标全流程,从标书解读到报价编制,中标率提升显著',
|
||||||
summary: '项目概况:为中国中铁打造慧投标智能体+慧途大模型,建立联合创新中心与AI应用创新平台。覆盖投标全流程——标书智能解读、资审自动匹配、报价辅助决策、标书智能编制,实现投标工作从人海战术到AI赋能的跨越式升级。',
|
summary: '项目概况:为中国中铁打造慧投标智能体+慧途大模型,建立联合创新中心与AI应用创新平台。覆盖投标全流程——标书智能解读、资审自动匹配、报价辅助决策、标书智能编制,实现投标工作从人海战术到AI赋能的跨越式升级。',
|
||||||
image: require('./img/case/china-railway-bidding-case.jpg')
|
image: require('./img/case/china-railway-bidding-case.jpg'),
|
||||||
|
imageEn: require('./img/case/china-railway-huitobid-case-en.png')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '南宁林业局',
|
name: '南宁林业局',
|
||||||
title: '智慧采伐',
|
title: '智慧采伐',
|
||||||
desc: '从采伐审批到科学监管——空间智能融合,让数据真正服务林区治理。',
|
desc: '从采伐审批到科学监管——空间智能融合,让数据真正服务林区治理。',
|
||||||
summary: '项目概况:为南宁林业局打造林业空间采伐智审系统,融合GIS空间分析、卫星遥感、无人机与传感器多源数据,实现空间与属性数据的一体化智能审核。采伐范围自动核验合规性,审查报告一键生成,审批周期从数天压缩至分钟级,人机协同让每一步决策都有据可依。',
|
summary: '项目概况:为南宁林业局打造林业空间采伐智审系统,融合GIS空间分析、卫星遥感、无人机与传感器多源数据,实现空间与属性数据的一体化智能审核。采伐范围自动核验合规性,审查报告一键生成,审批周期从数天压缩至分钟级,人机协同让每一步决策都有据可依。',
|
||||||
image: require('./img/case/nanning-forestry-case.jpg')
|
image: require('./img/case/nanning-forestry-case.jpg'),
|
||||||
|
imageEn: require('./img/case/nanning-forestry-smart-harvesting-case-en.png')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '北港大数据',
|
name: '北港大数据',
|
||||||
title: 'AI赋能,数智升级',
|
title: 'AI赋能,数智升级',
|
||||||
desc: '从投标到决策,从合同到管理——全链路AI智能体,让业务快人一步',
|
desc: '从投标到决策,从合同到管理——全链路AI智能体,让业务快人一步',
|
||||||
summary: '项目概况:为北港大数据打造覆盖招投标、投研分析、合同审查的全链路AI智能体解决方案。以投标智能体引擎实现标书秒级生成、中标率显著提升;以投策智能体引擎将数周研报压缩至分钟级,支撑精准投资决策;以合同智能审查将审查效率提升60%以上,风险漏检率降至3%以下。三款产品无缝衔接,真正打通企业从业务承接到风险管控的数字化闭环',
|
summary: '项目概况:为北港大数据打造覆盖招投标、投研分析、合同审查的全链路AI智能体解决方案。以投标智能体引擎实现标书秒级生成、中标率显著提升;以投策智能体引擎将数周研报压缩至分钟级,支撑精准投资决策;以合同智能审查将审查效率提升60%以上,风险漏检率降至3%以下。三款产品无缝衔接,真正打通企业从业务承接到风险管控的数字化闭环',
|
||||||
image: require('./img/case/beigang-big-data-case.jpg')
|
image: require('./img/case/beigang-big-data-case.jpg'),
|
||||||
|
imageEn: require('./img/case/beibu-gulf-port-big-data-case-en.png')
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
newsList: [],
|
newsList: [],
|
||||||
@ -346,6 +350,7 @@ export default {
|
|||||||
},
|
},
|
||||||
localizedCaseCards() {
|
localizedCaseCards() {
|
||||||
const keys = ['railway', 'forestry', 'beigang']
|
const keys = ['railway', 'forestry', 'beigang']
|
||||||
|
const isEn = this.$i18n && this.$i18n.locale === 'en-US'
|
||||||
return this.caseCards.map((card, index) => {
|
return this.caseCards.map((card, index) => {
|
||||||
const key = keys[index]
|
const key = keys[index]
|
||||||
if (!key) return card
|
if (!key) return card
|
||||||
@ -353,7 +358,9 @@ export default {
|
|||||||
...card,
|
...card,
|
||||||
name: this.$t(`home.cases.${key}.name`),
|
name: this.$t(`home.cases.${key}.name`),
|
||||||
title: this.$t(`home.cases.${key}.title`),
|
title: this.$t(`home.cases.${key}.title`),
|
||||||
desc: this.$t(`home.cases.${key}.desc`)
|
desc: this.$t(`home.cases.${key}.desc`),
|
||||||
|
summary: this.$t(`home.cases.${key}.summary`),
|
||||||
|
image: isEn && card.imageEn ? card.imageEn : card.image
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -1066,7 +1073,7 @@ body.dark-theme .bg-orb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.case-card {
|
.case-card {
|
||||||
min-height: 520px;
|
min-height: 620px;
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
perspective: 1400px;
|
perspective: 1400px;
|
||||||
}
|
}
|
||||||
@ -1131,38 +1138,51 @@ body.dark-theme .bg-orb {
|
|||||||
.case-card__content {
|
.case-card__content {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
min-height: 100%;
|
width: 100%;
|
||||||
padding: 34px 30px;
|
height: 100%;
|
||||||
|
padding: 40px 38px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: flex-start;
|
||||||
|
overflow-y: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(255, 255, 255, 0.28);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin: 0 0 12px;
|
margin: 0 0 16px;
|
||||||
font-size: 32px;
|
font-size: 36px;
|
||||||
line-height: 1.18;
|
line-height: 1.2;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
margin: 0 0 18px;
|
margin: 0 0 22px;
|
||||||
color: #e0f2fe;
|
color: #e0f2fe;
|
||||||
font-size: 21px;
|
font-size: 25px;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 0 0 16px;
|
margin: 0 0 20px;
|
||||||
color: rgba(255, 255, 255, 0.9);
|
color: rgba(255, 255, 255, 0.9);
|
||||||
font-size: 16px;
|
font-size: 18px;
|
||||||
line-height: 1.75;
|
line-height: 1.72;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.case-card__summary {
|
.case-card__summary {
|
||||||
opacity: 0.82;
|
opacity: 0.82;
|
||||||
font-size: 14px !important;
|
font-size: 16px !important;
|
||||||
|
line-height: 1.68 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.case-cta {
|
.case-cta {
|
||||||
|
|||||||
@ -122,6 +122,36 @@ const normalizeImageUrl = (url) => {
|
|||||||
return `${window.location.origin}/idfile?path=${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 {
|
export default {
|
||||||
name: 'ArticleEditorDialog',
|
name: 'ArticleEditorDialog',
|
||||||
components: { Editor, Toolbar },
|
components: { Editor, Toolbar },
|
||||||
@ -150,12 +180,18 @@ export default {
|
|||||||
placeholder: '请输入文章内容...',
|
placeholder: '请输入文章内容...',
|
||||||
MENU_CONF: {
|
MENU_CONF: {
|
||||||
uploadImage: {
|
uploadImage: {
|
||||||
customUpload: (file, insertFn) => {
|
customUpload: async (file, insertFn) => {
|
||||||
// 正文图片参考商品上传做法:先保存 File,提交时随文章 FormData 一起传。
|
try {
|
||||||
this.form.contentFiles.push(file)
|
// 正文图片先压缩再转 Base64,降低接口请求体积。
|
||||||
// 本地生成预览地址,插入到编辑器内容中。
|
const url = await compressImageToBase64(file, {
|
||||||
const url = URL.createObjectURL(file)
|
maxWidth: 900,
|
||||||
insertFn(url, file.name, url)
|
maxHeight: 900,
|
||||||
|
quality: 0.65
|
||||||
|
})
|
||||||
|
insertFn(url, file.name, url)
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('正文图片读取失败')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,9 +268,7 @@ export default {
|
|||||||
publishTime: '',
|
publishTime: '',
|
||||||
views: 0,
|
views: 0,
|
||||||
content: '',
|
content: '',
|
||||||
contentFiles: [],
|
|
||||||
coverUrl: '',
|
coverUrl: '',
|
||||||
coverFile: null,
|
|
||||||
coverName: ''
|
coverName: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -246,8 +280,8 @@ export default {
|
|||||||
}
|
}
|
||||||
// 没有发布时间时默认使用当天日期。
|
// 没有发布时间时默认使用当天日期。
|
||||||
if (!this.form.publishTime) this.form.publishTime = this.today
|
if (!this.form.publishTime) this.form.publishTime = this.today
|
||||||
// 初始化封面预览,新上传前优先显示接口返回的封面地址。
|
// 初始化封面预览。
|
||||||
this.coverPreview = ''
|
this.coverPreview = this.form.coverUrl || ''
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
// 表单初始化完成后重置未保存状态。
|
// 表单初始化完成后重置未保存状态。
|
||||||
this.dirty = false
|
this.dirty = false
|
||||||
@ -257,23 +291,31 @@ export default {
|
|||||||
// 保存编辑器实例,后续销毁时使用。
|
// 保存编辑器实例,后续销毁时使用。
|
||||||
this.editor = Object.seal(editor)
|
this.editor = Object.seal(editor)
|
||||||
},
|
},
|
||||||
handleCoverUpload(event) {
|
async handleCoverUpload(event) {
|
||||||
// 读取用户选择的封面文件。
|
// 读取用户选择的封面文件。
|
||||||
const file = event.target.files && event.target.files[0]
|
const file = event.target.files && event.target.files[0]
|
||||||
if (!file) return
|
if (!file) return
|
||||||
// 保存文件名用于页面提示。
|
// 保存文件名用于页面提示。
|
||||||
this.form.coverName = file.name
|
this.form.coverName = file.name
|
||||||
// 保存原始文件,父组件提交时会放入 FormData 的 cover_img。
|
try {
|
||||||
this.form.coverFile = file
|
// 封面图片先压缩再转 Base64,直接保存到 coverUrl / cover_img。
|
||||||
// 生成本地预览地址,注意这个地址只用于预览,不提交给接口。
|
const base64 = await compressImageToBase64(file, {
|
||||||
this.coverPreview = URL.createObjectURL(file)
|
maxWidth: 900,
|
||||||
// 清空 input 值,保证重复选择同一文件也能触发 change。
|
maxHeight: 900,
|
||||||
event.target.value = ''
|
quality: 0.68
|
||||||
|
})
|
||||||
|
this.coverPreview = base64
|
||||||
|
this.form.coverUrl = base64
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('封面图片读取失败')
|
||||||
|
} finally {
|
||||||
|
// 清空 input 值,保证重复选择同一文件也能触发 change。
|
||||||
|
event.target.value = ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleCoverUrlInput() {
|
handleCoverUrlInput() {
|
||||||
// 用户手动输入图片路径时,清空本地上传预览状态。
|
// 用户手动输入图片路径时,清空本地上传预览状态。
|
||||||
this.coverPreview = ''
|
this.coverPreview = ''
|
||||||
this.form.coverFile = null
|
|
||||||
this.form.coverName = ''
|
this.form.coverName = ''
|
||||||
},
|
},
|
||||||
startResize(event) {
|
startResize(event) {
|
||||||
@ -333,8 +375,8 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 第四步:校验封面图片,确保提交接口时有 cover_img。
|
// 第四步:校验封面图片,确保提交接口时有 cover_img。
|
||||||
if (!this.form.coverFile && !this.form.coverUrl) {
|
if (!this.form.coverUrl) {
|
||||||
this.$message.warning('请上传封面图片或填写图片地址')
|
this.$message.warning('请输入封面图片')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 第五步:校验文章正文。
|
// 第五步:校验文章正文。
|
||||||
|
|||||||
247
f/web-kboss/src/views/homePage/news/NewsDetail.vue
Normal file
247
f/web-kboss/src/views/homePage/news/NewsDetail.vue
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
<template>
|
||||||
|
<div class="news-detail-page">
|
||||||
|
<div class="news-detail-shell">
|
||||||
|
<button type="button" class="back-btn" @click="goBack">
|
||||||
|
<i class="el-icon-arrow-left"></i>
|
||||||
|
返回动态
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<div v-else-if="!loading" class="empty-state">
|
||||||
|
<i class="el-icon-document"></i>
|
||||||
|
<p>暂无新闻详情</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reqNewsDetail } from '@/api/newsapi/newsapi'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NewsDetail',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
article: {
|
||||||
|
id: '',
|
||||||
|
title: '',
|
||||||
|
summary: '',
|
||||||
|
articleType: '',
|
||||||
|
publishTime: '',
|
||||||
|
coverImg: '',
|
||||||
|
content: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getNewsDetail()
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scrollToTop()
|
||||||
|
window.setTimeout(this.scrollToTop, 0)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
scrollToTop() {
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
document.documentElement.scrollTop = 0
|
||||||
|
document.body.scrollTop = 0
|
||||||
|
const scrollContainers = [
|
||||||
|
document.querySelector('.homeOut'),
|
||||||
|
document.querySelector('.home-router-view'),
|
||||||
|
document.querySelector('#app')
|
||||||
|
].filter(Boolean)
|
||||||
|
scrollContainers.forEach((container) => {
|
||||||
|
container.scrollTop = 0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
goBack() {
|
||||||
|
this.$router.push('/homePage/news')
|
||||||
|
},
|
||||||
|
normalizeImageUrl(url) {
|
||||||
|
if (!url) return ''
|
||||||
|
if (/^(https?:|blob:|data:|\/\/)/.test(url)) return url
|
||||||
|
return `${window.location.origin}/idfile?path=${url}`
|
||||||
|
},
|
||||||
|
getResponseDetail(res) {
|
||||||
|
if (res.data && res.data.data && !Array.isArray(res.data.data)) return res.data.data
|
||||||
|
if (res.data && !Array.isArray(res.data)) return res.data
|
||||||
|
if (Array.isArray(res.data) && res.data[0]) return res.data[0]
|
||||||
|
if (res.detail) return res.detail
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
normalizeArticle(row) {
|
||||||
|
return {
|
||||||
|
id: row.id || this.$route.params.id,
|
||||||
|
title: row.title || '未命名文章',
|
||||||
|
summary: row.summary || '',
|
||||||
|
articleType: row.article_type || row.type || '企业动态',
|
||||||
|
publishTime: row.publish_time || row.publishTime || '',
|
||||||
|
coverImg: this.normalizeImageUrl(row.cover_img || row.coverImg || ''),
|
||||||
|
content: row.content || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getNewsDetail() {
|
||||||
|
const id = this.$route.params.id || this.$route.query.id
|
||||||
|
if (!id) {
|
||||||
|
this.$message.warning('缺少新闻ID')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await reqNewsDetail({
|
||||||
|
id,
|
||||||
|
url_link: window.location.href
|
||||||
|
})
|
||||||
|
if (res && (res.status === true || res.status === 'true')) {
|
||||||
|
this.article = this.normalizeArticle(this.getResponseDetail(res))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$message.error((res && (res.message || res.msg)) || '新闻详情加载失败')
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('新闻详情加载失败')
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.news-detail-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 96px 24px 64px;
|
||||||
|
background: linear-gradient(180deg, #eff6ff 0%, #fff 55%, #f8fbff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-detail-shell {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1080px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 9px 14px;
|
||||||
|
color: #2563eb;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid rgba(37, 99, 235, 0.16);
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-tag {
|
||||||
|
padding: 4px 10px;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(135deg, #2563eb, #14b8a6);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0;
|
||||||
|
color: #0f172a;
|
||||||
|
font-size: 38px;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary {
|
||||||
|
margin: 18px 0 0;
|
||||||
|
color: #475569;
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 1.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-wrap {
|
||||||
|
margin: 32px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-wrap img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body {
|
||||||
|
color: #334155;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.95;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-body ::v-deep img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
min-height: 320px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #94a3b8;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state i {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.news-detail-page {
|
||||||
|
padding: 80px 14px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -315,38 +315,17 @@ export default {
|
|||||||
},
|
},
|
||||||
buildArticlePayload(article) {
|
buildArticlePayload(article) {
|
||||||
// 将编辑弹窗字段转换成新增/编辑接口需要的字段。
|
// 将编辑弹窗字段转换成新增/编辑接口需要的字段。
|
||||||
const payload = {
|
return {
|
||||||
...(article.id ? { id: article.id } : {}),
|
...(article.id ? { id: article.id } : {}),
|
||||||
url_link: window.location.href,
|
url_link: window.location.href,
|
||||||
title: article.title,
|
title: article.title,
|
||||||
article_type: article.type,
|
article_type: article.type,
|
||||||
summary: article.summary,
|
summary: article.summary,
|
||||||
publish_time: article.publish_time || article.publishTime,
|
publish_time: article.publish_time || article.publishTime,
|
||||||
|
cover_img: article.coverUrl,
|
||||||
content: article.content,
|
content: article.content,
|
||||||
status: this.getApiStatus(article.status)
|
status: this.getApiStatus(article.status)
|
||||||
}
|
}
|
||||||
const hasContentFiles = Array.isArray(article.contentFiles) && article.contentFiles.length > 0
|
|
||||||
if (article.coverFile || hasContentFiles) {
|
|
||||||
const formData = new FormData()
|
|
||||||
Object.keys(payload).forEach(key => {
|
|
||||||
formData.append(key, payload[key])
|
|
||||||
})
|
|
||||||
if (article.coverFile) {
|
|
||||||
formData.append('cover_img', article.coverFile)
|
|
||||||
} else {
|
|
||||||
formData.append('cover_img', article.coverUrl)
|
|
||||||
}
|
|
||||||
if (hasContentFiles) {
|
|
||||||
article.contentFiles.forEach(file => {
|
|
||||||
formData.append('content_images', file)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return formData
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...payload,
|
|
||||||
cover_img: article.coverUrl
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async confirmAction(title, message, type = 'warning') {
|
async confirmAction(title, message, type = 'warning') {
|
||||||
// 操作前弹出二次确认,用户取消时直接终止后续请求。
|
// 操作前弹出二次确认,用户取消时直接终止后续请求。
|
||||||
|
|||||||
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
<section class="featured-section">
|
<section class="featured-section">
|
||||||
<div class="news-shell">
|
<div class="news-shell">
|
||||||
<article v-if="featuredNews" class="news-featured">
|
<article v-if="featuredNews" class="news-featured" @click="goNewsDetail(featuredNews)">
|
||||||
<div class="news-item-glow"></div>
|
<div class="news-item-glow"></div>
|
||||||
<span class="hover-detail">详情 <i class="el-icon-arrow-right"></i></span>
|
<span class="hover-detail">详情 <i class="el-icon-arrow-right"></i></span>
|
||||||
<div class="news-featured-inner">
|
<div class="news-featured-inner">
|
||||||
@ -66,6 +66,7 @@
|
|||||||
:key="item.id"
|
:key="item.id"
|
||||||
class="news-item"
|
class="news-item"
|
||||||
:style="{ animationDelay: `${(index + 1) * 0.08}s` }"
|
:style="{ animationDelay: `${(index + 1) * 0.08}s` }"
|
||||||
|
@click="goNewsDetail(item)"
|
||||||
>
|
>
|
||||||
<div class="news-item-glow"></div>
|
<div class="news-item-glow"></div>
|
||||||
<span class="hover-detail">详情 <i class="el-icon-arrow-right"></i></span>
|
<span class="hover-detail">详情 <i class="el-icon-arrow-right"></i></span>
|
||||||
@ -100,7 +101,7 @@
|
|||||||
<i class="el-icon-arrow-right"></i>
|
<i class="el-icon-arrow-right"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -147,6 +148,10 @@ export default {
|
|||||||
goAbout() {
|
goAbout() {
|
||||||
this.$router.push('/homePage/about')
|
this.$router.push('/homePage/about')
|
||||||
},
|
},
|
||||||
|
goNewsDetail(item) {
|
||||||
|
if (!item || !item.id) return
|
||||||
|
this.$router.push(`/homePage/news/detail/${item.id}`)
|
||||||
|
},
|
||||||
handleCategoryChange(value) {
|
handleCategoryChange(value) {
|
||||||
this.activeCategory = value
|
this.activeCategory = value
|
||||||
this.page = 1
|
this.page = 1
|
||||||
|
|||||||
@ -18,10 +18,7 @@
|
|||||||
<p class="hero-description animate-fade-in-up animate-delay-200">
|
<p class="hero-description animate-fade-in-up animate-delay-200">
|
||||||
一站式云端AI开发平台,通过对话即可快速构建智能体、工作流、网页与移动应用,依托强大的云端基础设施实现开箱即用的环境和一键部署服务
|
一站式云端AI开发平台,通过对话即可快速构建智能体、工作流、网页与移动应用,依托强大的云端基础设施实现开箱即用的环境和一键部署服务
|
||||||
</p>
|
</p>
|
||||||
<div class="hero-actions animate-fade-in-up animate-delay-300">
|
|
||||||
<button type="button" class="use-btn btn-primary" @click="handleStart">开始使用</button>
|
|
||||||
<button type="button" class="btn-secondary" @click="handleVisit">访问平台</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="hero-blur hero-blur--blue floating"></div>
|
<div class="hero-blur hero-blur--blue floating"></div>
|
||||||
<div class="hero-blur hero-blur--indigo hero-blur--indigo-delay floating"></div>
|
<div class="hero-blur hero-blur--indigo hero-blur--indigo-delay floating"></div>
|
||||||
@ -97,17 +94,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="page-section">
|
|
||||||
<div class="section-inner cta-panel">
|
|
||||||
<h2 class="cta-panel__title cta-panel__title--lg">告别部署烦恼</h2>
|
|
||||||
<p class="cta-panel__desc cta-panel__desc--lg">
|
|
||||||
无论你是零基础小白还是资深开发者,训推平台都能帮你实现从想法到产品上线的丝滑体验
|
|
||||||
</p>
|
|
||||||
<div class="hero-actions">
|
|
||||||
<button type="button" class="use-btn btn-primary" @click="handleLearnMore">了解更多</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
:loading="isGettingCode"
|
:loading="isGettingCode"
|
||||||
@click="debouncedGetCode"
|
@click="debouncedGetCode"
|
||||||
>
|
>
|
||||||
{{ sendCodeText }}
|
{{ sendCodeText }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user