老师反馈修改

This commit is contained in:
黄心宇 2026-01-05 10:13:27 +08:00
parent 58b026776d
commit a93ae524bb
38 changed files with 1864 additions and 297 deletions

View File

@ -204,7 +204,7 @@
"eslintConfig": {
"extends": "react-app"
},
"proxy": "https://testforgeplus.trustie.net/",
"proxy": "http://172.20.32.203:4000/",
"port": "3007",
"devDependencies": {
"@babel/core": "^7.23.6",

View File

@ -80,6 +80,11 @@ const SoftwareFactoryLessons = Loadable({
loading: Loading,
})
const SoftwareFactoryLessonsDetail = Loadable({
loader: () => import('./factory/lessons/detail/index'),
loading: Loading,
})
const SoftwareFactoryScene = Loadable({
@ -518,6 +523,15 @@ class App extends Component {
}
}>
</Route>
<Route
path={"/softwareFactory/lessons/:id"}
render={
(props) => {
return (<SoftwareFactoryLessonsDetail {...this.props} {...props} {...this.state} />)
}
}>
</Route>
<Route
path={"/softwareFactory/lessons"}

View File

@ -67,7 +67,7 @@ function News(props) {
return (
<div className={`factory-news factory-module ${isVisible ? 'animate-active' : ''}`} ref={contentRef}>
<h1 className="module-title">动态速递实时感知软件工厂业内新闻</h1>
<h1 className="module-title">创新引领软件工厂业界最新动态</h1>
<div className="circle-wrapper">
<div className="circle-item"></div>
<div className="circle-item"></div>

View File

@ -5,22 +5,24 @@ import { ScrollTrigger } from 'gsap/ScrollTrigger';
import KFIcon from '../../../components/KFIcon';
import { Link } from 'react-router-dom';
import { getProjectsLists, getSourceList, httpUrl } from '../../api';
import { factoryZoneId, lessonId, versionId, toolId } from '../../../constants/factory'
import { factoryZoneId, lessonId, versionId, toolId, commontoolId } from '../../../constants/factory'
import { downloadFunc } from '../../../forge/Utils/utils'
import '../../common.scss'
gsap.registerPlugin(ScrollTrigger);
const resourceInfo = [
{ name: '项目', title: '软件项目', icon: 'icon-xiangmu', desc: '汇聚用户需求,形成开发任务,设置质量门槛,提升软件质量,快速构建软件版本,高效应对市场变化。', path: '/softwareFactory/resource/softwareProject' },
{ name: '版本', title: '软件工厂基座', icon: 'icon-banben', desc: '按照敏捷开发快速迭代的思路形成解决微小问题的小版本提供长期支持版本LTS版。', path: '/softwareFactory/resource/factoryVersion' },
{ name: '工具', title: '开发工具', icon: 'icon-gongju', desc: '提供开发者所需的各类软件开发工具包括IDE、Git工具、命令行终端工具、数据库设计工具、图像编辑工具等。', path: '/softwareFactory/resource/developmentTools' },
{ name: '项目', title: '工厂开源项目', icon: 'icon-xiangmu', desc: '标准化生产线核心代码及软件工厂开发工具源码', path: '/softwareFactory/resource/softwareProject' },
{ name: '版本', title: '生产线安装包', icon: 'icon-banben', desc: '标准化生产线快速迭代版本和稳定支持版本', path: '/softwareFactory/resource/factoryVersion' },
{ name: '工具', title: '共建共用工具', icon: 'icon-gongju', desc: '由XX集团、科研院所、地方企业等提供可免费共用的工具', path: '/softwareFactory/resource/commonTools' },
{ name: '软件', title: '开源社区软件', icon: 'icon-gongju', desc: '来自开源社区,可按授权许可使用和复用的各类软件', path: '/softwareFactory/resource/developmentTools' },
]
const Resource = forwardRef(({ zoneId }, ref) => {
const r1Ref = useRef(null);
const r2Ref = useRef(null);
const r3Ref = useRef(null);
const r4Ref = useRef(null);
const containerRef = useRef(null);
const timelineRef = useRef(null);
@ -28,11 +30,13 @@ const Resource = forwardRef(({ zoneId }, ref) => {
const [resourceList1, setResourceList1] = useState([]);
const [resourceList2, setResourceList2] = useState([]);
const [resourceList3, setResourceList3] = useState([]);
const [resourceList4, setResourceList4] = useState([]);
useEffect(() => {
if (!zoneId) return;
getToolsList();
getVersionList();
getCommonToolsList();
getProjectsLists(zoneId, { isHomePage: 1 }).then(res => {
if (res.data && res.data.code === 200) {
setResourceList1(res.data.rows.slice(0, 6));
@ -59,7 +63,7 @@ const Resource = forwardRef(({ zoneId }, ref) => {
if (!containerRef.current) return;
//
const panels = [r1Ref.current, r2Ref.current, r3Ref.current];
const panels = [r1Ref.current, r2Ref.current, r3Ref.current, r4Ref.current];
//
timelineRef.current = gsap.timeline({
@ -76,13 +80,14 @@ const Resource = forwardRef(({ zoneId }, ref) => {
//
timelineRef.current.to(panels[0], {
y: "-5%",
scale: 0.85,
duration: 1
}, 0);
//
timelineRef.current.to(panels[1], {
y: "-175%",
y: "-50%",
scale: 0.9,
duration: 1
}, 0);
@ -91,7 +96,14 @@ const Resource = forwardRef(({ zoneId }, ref) => {
timelineRef.current.to(panels[2], {
y: "-150%",
scale: 0.95,
duration: 1.25
duration: 1
}, 0);
// v
timelineRef.current.to(panels[3], {
y: "-230%",
scale: 0.98,
duration: 1.5
}, 0);
//
@ -119,7 +131,7 @@ const Resource = forwardRef(({ zoneId }, ref) => {
const getVersionList = () => {
getSourceList({ id: factoryZoneId, keywords: versionId }).then(res => {
setResourceList2(res.data.rows.slice(0, 4));
setResourceList2(res.data.rows.slice(0, 2));
});
}
@ -134,6 +146,21 @@ const Resource = forwardRef(({ zoneId }, ref) => {
rows.push({ ...e, extendDataUrl: extendData.url, extendDataHeadImg: extendData.headImg })
});
setResourceList4(rows.slice(0, 6));
});
}
const getCommonToolsList = () => {
getSourceList({ id: factoryZoneId, keywords: commontoolId }).then(res => {
const rows = []
res.data.rows.forEach(e => {
let extendData = {}
if (e.extendData) {
extendData = JSON.parse(e.extendData)
}
rows.push({ ...e, extendDataUrl: extendData.url, extendDataHeadImg: extendData.headImg })
});
setResourceList3(rows.slice(0, 6));
});
}
@ -144,10 +171,30 @@ const Resource = forwardRef(({ zoneId }, ref) => {
ref={ref}
>
<div className="resource-container" ref={containerRef}>
<h1 className="module-title">资源中枢共享复用释放生态力量</h1>
<h1 className="module-title">共建共用共享为软件工厂赋能</h1>
<div className="panels-stack">
<div ref={r1Ref} className="resource-1">
<div className="panel-content">
{
getLeftContent(1)
}
<div className="content-right">
{
resourceList2.length > 0 && resourceList2.map((item, index) => {
return <div className="content-item2" key={index}>
<div className="item-name">{item.name}</div>
<div className="item-desc">{item.summary}</div>
<button onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`) }}>下载</button>
</div>
})
}
</div>
</div>
</div>
<div ref={r2Ref} className="resource-2">
<div className="panel-content">
{
getLeftContent(0)
@ -187,25 +234,6 @@ const Resource = forwardRef(({ zoneId }, ref) => {
</div>
</div>
<div ref={r2Ref} className="resource-2">
<div className="panel-content">
{
getLeftContent(1)
}
<div className="content-right">
{
resourceList2.length > 0 && resourceList2.map((item, index) => {
return <div className="content-item2" key={index}>
<div className="item-name">{item.name}</div>
<div className="item-desc">{item.summary}</div>
<button onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`) }}>下载</button>
</div>
})
}
</div>
</div>
</div>
<div ref={r3Ref} className="resource-3">
<div className="panel-content">
{
@ -227,6 +255,27 @@ const Resource = forwardRef(({ zoneId }, ref) => {
</div>
</div>
</div>
<div ref={r4Ref} className="resource-4">
<div className="panel-content">
{
getLeftContent(3)
}
<div className="content-right">
{
resourceList4.length > 0 && resourceList4.map((item, index) => {
return <div className="content-item3" key={index}>
<div className="item-name">{item.name}</div>
<div className="item-desc">{item.summary}</div>
<div className="item-btn">
<Link to={`/softwareFactory/resource/developmentTools/${item.id}`}><button className="shiny-button">查看</button></Link>
<button onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`) }}>下载</button>
</div>
</div>
})
}
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
.factory-resource {
position: relative;
min-height: 2000px;
min-height: 2300px;
overflow: hidden;
margin-top: 56px;
@ -10,7 +10,7 @@
position: relative;
width: 100%;
background: linear-gradient(180deg, #ffffff 0%, #ffffff 84.87%, rgba(255, 255, 255, 0) 100%);
min-height: 800px;
min-height: 1000px;
border-top-left-radius: 36px;
border-top-right-radius: 36px;
}
@ -32,7 +32,7 @@
// 面板堆叠容器
.panels-stack {
position: relative;
height: 900px;
height: 1000px;
display: flex;
justify-content: center;
margin-top: 100px;
@ -41,7 +41,8 @@
// 面板基础样式
.resource-1,
.resource-2,
.resource-3 {
.resource-3,
.resource-4 {
position: absolute;
width: 1600px;
border-radius: 30px;
@ -52,11 +53,11 @@
// transform-origin: center center;
}
.resource-1 {
top: 0;
.resource-2 {
top: 430px;
height: 663px;
background: #d3ecfc;
z-index: 1;
z-index: 2;
.panel-content .content-right {
.content-item1 {
@ -140,11 +141,11 @@
}
}
.resource-2 {
top: 742px;
.resource-1 {
top: 0;
height: 350px;
background: #e6ecff;
z-index: 2;
z-index: 1;
.panel-content .content-right {
.content-item2 {
@ -223,6 +224,51 @@
}
}
}
.resource-4 {
top: 1810px;
height: 622px;
background: #DFF0EC;
z-index: 4;
.content-item3 {
width: 385px;
height: 246px;
background: #ffffff;
border-radius: 16px;
box-shadow: 0px 0px 18px rgba(0, 74, 168, 0.05);
padding: 48px 35px 35px 35px;
display: flex;
flex-direction: column;
margin-right: 15px;
.item-desc {
margin-top: 27px;
}
.item-btn {
margin-top: auto;
button {
margin-right: 20px;
background-color: #ffffff;
color: #091221;
&:nth-child(1) {
background-color: #091221;
color: #ffffff;
border: none;
}
&:nth-child(2) {
&:hover {
border-color: #164ce4;
color: #164ce4;
}
}
}
}
}
}
// 面板内容样式
.panel-content {

View File

@ -1,20 +1,26 @@
import React, { useEffect, useRef, useState, forwardRef } from 'react';
import './index.scss';
import lessonsRight1 from '../../../images/factory/lessons-right-1.webp'
import lessonsStandard1 from '../../../images/factory/lessons-standard-1.webp'
import lessonsStandard2 from '../../../images/factory/lessons-standard-2.webp'
import lessonsStandard3 from '../../../images/factory/lessons-standard-3.webp'
import { Link } from 'react-router-dom';
import KFIcon from '../../../components/KFIcon';
import back1 from '../../../images/factory/back1.png'
import tagIcon from '../../../images/factory/lessons-tag-icon.webp'
import '../../common.scss'
import { getSourceList, httpUrl } from '../../api';
import { factoryZoneId, manualId, standardId, lessonId } from '../../../constants/factory'
import { factoryZoneId, manualId, standardId, lessonId } from '../../../constants/factory'
import { downloadFunc } from '../../../forge/Utils/utils'
import { Carousel } from 'antd';
const iconList = [lessonsStandard1, lessonsStandard2, lessonsStandard3]
const Resource2 = forwardRef(({ zoneId }, ref) => {
const [isVisible, setIsVisible] = useState(false);
const [standard, setStandard] = useState({});
const [standardList, setStandardList] = useState([]);
const [manualList, setManualList] = useState([]);
const [chapterList, setChapterList] = useState([]);
const carouselEL = useRef(null);
const [current, setCurrent] = useState(0);
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
@ -43,7 +49,7 @@ const Resource2 = forwardRef(({ zoneId }, ref) => {
}
rows.push({ ...e, extendDataUrl: extendData.url, extendDataHeadImg: extendData.headImg })
});
setStandard(rows[0]);
setStandardList(rows.slice(0, 3));
});
}
@ -102,13 +108,13 @@ const Resource2 = forwardRef(({ zoneId }, ref) => {
<p>全景智治贯通需求到交付敏捷可视管控风险打造高效可信软件生产新范式赋能研发跃迁</p>
<div className="left-content">
{
chapterList.slice(0,2).map((item, index) => {
chapterList.slice(0, 2).map((item, index) => {
return <div className="left-item" key={index}>
<img src={ item.extendDataHeadImg || back1} alt="" />
<img src={item.extendDataHeadImg || back1} alt="" />
<div className="item-info">
<h4>{ item.name }</h4>
<h4>{item.name}</h4>
<p>{item.summary}</p>
<button className="shiny-button" onClick={() => { window.open(standard.extendDataUrl) }}>查看详情</button>
<button className="shiny-button" onClick={() => { window.open(item.extendDataUrl) }}>查看详情</button>
</div>
</div>
})
@ -118,40 +124,57 @@ const Resource2 = forwardRef(({ zoneId }, ref) => {
</div>
<div className="resource2-content-right">
<div className="standard">
<div className="standard-info">
<div className="standard-tags">
<span><img src={tagIcon} alt="" />最新规范</span>
<span>自动合规</span>
<span>行业对齐</span>
</div>
{
standard && standard.name && <>
<h3>{standard.name}</h3>
<p>{standard.summary}</p>
<button className="shiny-button" onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`) }}>立即下载</button>
</>
}
</div>
<img className="standard-img" src={lessonsRight1} alt="" />
<Carousel autoplay ref={carouselEL} dots={false}>
{manualList.map(item => {
return <div className="standard-item">
<div className="standard-info">
<h3>{item.name}</h3>
<p>{item.summary}</p>
<button className="shiny-button" onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`) }}>立即下载</button>
</div>
<img className="standard-img" src={item.extendDataHeadImg} alt="" />
</div>
})}
</Carousel>
</div>
<div className="manual">
<div className="manual-tags">
<span><img src={tagIcon} alt="" />用户手册</span>
</div>
<h3>软件工厂用户手册</h3>
<h3>文档资料</h3>
<div className="manual-content">
{
manualList.map((item, index) => {
return <div key={ index }>
<Link to="/softwareFactory/lessons" ><h4>{ item.name }</h4> <KFIcon type="icon-icon_blackarrow_hover" font={40} /></Link>
<p>{ item.summary }</p>
<ul>
{manualList.map((item, index) => (
<li key={index} className={`activity-item-v2 df activity-section-item ${current === index ? 'activity-section-item-active' : ''}`} onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`) }}>
<span className="title-border-to-right-icon">{item.name}</span>
</li>
))}
</ul>
<Carousel autoplay ref={carouselEL} dots={false} afterChange={setCurrent}>
{manualList.map(item => {
return <div className="manual-item">
<img className="manual-img" src={item.extendDataHeadImg} alt="" />
</div>
})
}
})}
</Carousel>
</div>
</div>
</div>
</div>
<div className="standard2">
<h3>标准规范</h3>
<div className="standard2-content">
{
standardList.map((item,index) => {
return <div className="standard-item" key={index}>
<img src={ iconList[index] } alt="" />
<div className="standard-item-head">
<Link to={`/softwareFactory/lessons/${ item.id }`}><h4 title={ item.name }>{item.name}</h4><KFIcon type="icon-icon_blackarrow_hover" font={40} /></Link>
</div>
<p title={ item.summary }>{item.summary}</p>
</div>
})
}
</div>
</div>
<Link to="/softwareFactory/lessons" className="resource2-more">探索更多资源<KFIcon type="icon-icon_blackarrow_hover" font={40} /></Link>
</div>
);

View File

@ -1,20 +1,19 @@
.factory-resource2 {
margin-top: 78px;
h3 {
line-height: 35px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 26px;
}
.resource2-content {
display: flex;
width: 1600px;
margin-top: 46px;
h3 {
line-height: 35px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 26px;
}
p {
line-height: 28px;
font-family: alibabareg;
@ -101,7 +100,8 @@
text-align: center;
margin-top: auto;
// background: #ffffff !important;
background-image: linear-gradient(#ffffff, #ffffff) ;
background-image: linear-gradient(#ffffff, #ffffff);
&:hover {
background-color: #091221 !important;
color: #ffffff;
@ -115,15 +115,11 @@
&-right {
opacity: 0;
.standard,
.manual {
background-repeat: no-repeat;
background-size: 100% 100%;
h3 {
margin-top: 24px;
}
background-color: #ffffff;
border: 1px solid;
border-color: rgba(19, 53, 91, 0.08);
@ -168,12 +164,16 @@
height: 286.5px;
background-image: url('../../../images/factory/lessons-right-1-bg.webp');
&-img {
width: 256px;
height: 266px;
.standard-item {
display: flex !important;
padding: 54px 30px 30px 35px;
}
display: flex;
&-img {
width: 178px;
height: 178px;
margin-left: auto;
}
&-tags {
margin-top: 32px;
@ -193,6 +193,7 @@
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
width: 295px;
}
button {
@ -210,6 +211,7 @@
font-size: 14px;
background-color: transparent;
background-image: none;
&:hover {
background-color: #091221 !important;
color: #ffffff;
@ -220,7 +222,6 @@
p,
button {
cursor: pointer;
margin-left: 35px;
}
}
@ -234,95 +235,23 @@
&-content {
display: flex;
width: 100%;
margin-top: 32px;
margin-top: 18px;
justify-content: space-between;
ul {
width: 300px;
}
div {
width: 240px;
width: 178px;
}
a {
display: flex;
align-items: center;
.manual-item {
height: 178px;
h4 {
line-height: 25px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 18px;
}
i {
margin-left: auto;
height: 25px;
width: 25px;
position: relative;
display: inline-block;
svg {
display: none;
position: absolute;
left: -17px;
top: 5px;
transition: all .2s ease-out;
}
overflow: hidden;
}
&:hover {
h4 {
color: #164ce4;
}
svg {
left: 3px;
top: -15px;
display: inline-block;
}
}
}
p {
margin-top: 18px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
&:nth-child(1) {
h4 {
&::before {
content: "";
background-image: url('../../../images/factory/lessons-icon-1.webp');
width: 12.85px;
height: 13.88px;
background-repeat: no-repeat;
background-size: 100% 100%;
display: inline-block;
margin-right: 9px;
}
}
}
&:nth-child(2) {
h4 {
&::before {
content: "";
background-image: url('../../../images/factory/lessons-icon-2.webp');
width: 15px;
height: 13.85px;
background-repeat: no-repeat;
background-size: 100% 100%;
display: inline-block;
margin-right: 8px;
}
}
img {
width: 178px;
height: 178px;
}
}
@ -367,4 +296,182 @@
}
}
}
.standard2 {
margin-top: 25px;
width: 1600px;
height: 321px;
background-image: url('../../../images/factory/lessons-bottom-bg.webp');
background-repeat: no-repeat;
background-size: 100% 100%;
padding: 40px 50px;
.standard2-content {
width: 1513px;
margin-top: 22px;
background: #ffffff;
border-radius: 16px;
display: flex;
padding: 18px 30px;
}
.standard-item {
width: 430px;
flex-shrink: 0;
img {
width: 48px;
}
&:not(:last-child) {
border-right: 1px dashed rgba(9, 18, 33, 0.22);
}
&:not(:first-child) {
margin-left: 87px;
}
&-head {
display: flex;
a {
display: flex;
width: 400px;
align-items: center;
i {
opacity: 0;
margin-left: auto;
height: 25px;
width: 25px;
position: relative;
display: inline-block;
overflow: hidden;
svg {
position: absolute;
left: 2px;
top: -16px;
}
}
&:hover {
h4 {
color: #164ce4;
}
i {
opacity: 1;
}
}
h4 {
width: 360px;
line-height: 33px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 20px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
cursor: pointer;
}
}
}
p {
-webkit-line-clamp: 1;
width: 400px;
margin-top: 15px;
}
&-img {
margin-top: 21px;
width: 287px;
height: 189px;
overflow: hidden;
border-radius: 16px;
img {
width: 287px;
height: 189px;
transition: transform .4s cubic-bezier(.25, .46, .45, .94);
}
}
}
}
}
.activity-item-v2 {
justify-content: space-between;
align-items: center;
padding: 10px 0 6px;
height: 65px;
cursor: pointer;
&:not(:last-child) {
border-bottom: 1px dashed #8284a457;
}
}
.activity-section-item {
position: relative;
&::after {
position: absolute;
bottom: -1px;
left: 0;
content: '';
width: 0;
height: 1px;
background-color: #2149d4;
}
&-active::after {
animation: bottomflowLight 3s forwards;
}
}
.activity-section-item-active .title-border-to-right-icon {
padding-right: 20px;
color: #2149d4;
&::before {
content: "\e794";
font-family: 'iconfont-factory';
font-weight: normal;
font-size: 12px;
position: absolute;
right: 0px;
top: 4px;
}
}
.title-border-to-right-icon {
width: 100%;
position: relative;
&:hover {
padding-right: 20px;
&+.hot-tag {
display: none;
}
}
&:hover::before {
content: "\e794";
font-family: 'iconfont-factory';
font-weight: normal;
font-size: 12px;
position: absolute;
right: 0;
top: 4px;
}
}

View File

@ -0,0 +1,80 @@
import React, { useEffect, useState, useRef } from 'react';
import './index.scss';
import { TPMIndexHOC } from '../../../modules/tpm/TPMIndexHOC';
import imageBack1 from '../../../images/factory/resource/tools-detail-head-left.webp'
import imageGif from '../../../images/factory/resource/tools-detail-head-left2.webp'
import { Link } from 'react-router-dom';
import RenderHtml from '../../../components/render-html';
import { Breadcrumb } from 'antd';
import { getSourceDetail, httpUrl, getSourceList } from '../../api';
import { downloadFunc } from '../../../forge/Utils/utils'
import { factoryZoneId, } from '../../../constants/factory'
import '../../common.scss'
import { Base64 } from 'js-base64';
function Index(props) {
const id = props.match.params.id
const [detail, setDetail] = useState({})
const [content, setContent] = useState();
useEffect(() => {
document.title = '规范详情-软件工厂专区';
}, []);
useEffect(() => {
if (id !== detail.id) {
getDetail()
}
}, [id]);
const getDetail = () => {
getSourceDetail(id).then(response => {
if (response) {
let extendData = {}
if (response.data.data.extendData) {
extendData = JSON.parse(response.data.data.extendData)
}
document.title = response.data.data.name
if (extendData.content) {
setContent(Base64.decode(extendData.content))
}
setDetail({...response.data.data, ...extendData});
}
}).catch(error => { })
}
return (
<div className="news-detail">
<div className="news-detail-header">
<Breadcrumb separator=">">
<Breadcrumb.Item href={`/softwareFactory`}>首页</Breadcrumb.Item>
<Breadcrumb.Item href={`/softwareFactory/lessons`}>学习资源</Breadcrumb.Item>
<Breadcrumb.Item> <span className="breacrumb-name">{detail.name}</span> </Breadcrumb.Item>
</Breadcrumb>
<div className="header-content">
<h3 title={ detail.name }>{detail.name}</h3>
<p title={ detail.summary }>{detail.summary}</p>
<button className="shiny-button" onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${detail.fileIds}`) }}>立即下载</button>
<div className="header-img">
<div className="header-img-wrapper">
<img src={detail.headImg || imageBack1} alt="" />
{!detail.headImg && <img src={imageGif} alt="" />}
</div>
</div>
</div>
</div>
<div className="news-detail-content">
<div className="news-detail-content-wrapper">
{
content && <RenderHtml className="informations_detail imageLayerParent" value={content} url={props.history.location} />
}
</div>
</div>
</div>
)
}
export default TPMIndexHOC(Index)

View File

@ -0,0 +1,276 @@
.news-detail {
min-height: calc(100vh - 58px);
.news-detail-header {
height: 752px;
width: 100%;
background-image: url("../../../images/factory/resource/tools-detail-head.webp");
background-repeat: no-repeat;
background-size: 100% 100%;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
justify-content: flex-start;
.ant-breadcrumb {
align-self: flex-start;
margin-top: 30px;
margin-left: calc((100vw - 1600px) / 2);
a {
color: #1b58df;
}
span {
color: #091221;
.breacrumb-name {
max-width: 200px;
display: inline-block;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
vertical-align: middle;
}
}
}
.header-content {
margin-top: 30px;
width: 1600px;
height: 481px;
position: relative;
border-radius: 16px;
padding: 60px 45px;
background: linear-gradient(106.16deg, #f7fbff 2.47%, #f5faff 95.98%);
border: 2px solid;
border-color: #ffffff;
h3 {
line-height: 47px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 34px;
max-width: 650px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
p {
margin-top: 25px;
max-width: 650px;
line-height: 22px;
font-family: alibabareg;
color: #5d6a80;
font-size: 16px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.tools-info {
display: flex;
margin-top: 35px;
div {
display: flex;
flex-direction: column;
position: relative;
margin-right: 78px;
span:nth-child(1) {
line-height: 32px;
font-family: alibabaBold;
font-weight: 700;
color: #164ce4;
font-size: 24px;
}
span:nth-child(2) {
line-height: 20px;
font-family: alibabareg;
color: #5d6a80;
font-size: 14px;
margin-top: 8px;
}
&:not(:last-child) {
&::after {
position: absolute;
content: "";
width: 0px;
height: 60px;
right: -39px;
border-right: 1px dashed;
border-color: rgba(22, 76, 228, 0.15);
}
}
}
}
button {
margin-top: 30px;
width: 110px;
height: 36px;
line-height: 36px;
cursor: pointer;
border-radius: 6px;
line-height: 20px;
font-family: alibaba;
font-weight: 500;
color: #ffffff;
font-size: 14px;
text-align: center;
background-color: #091221;
}
h6 {
margin-top: 34px;
line-height: 22px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 16px;
}
.more-tools {
display: flex;
margin-top: 20px;
span {
max-width: 200px;
cursor: pointer;
display: inline-block;
background: #e9f2ff;
border-radius: 4px;
padding: 13px 12px;
margin-right: 15px;
line-height: 19px;
font-family: alibaba;
color: #091221;
font-size: 15px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
img {
width: 19px;
height: 19px;
margin-right: 15px;
}
}
}
.header-img {
position: absolute;
top: 60px;
right: 60px;
width: 600px;
height: 360px;
background: linear-gradient(180deg, #ffffff 0%, #ffffff 100%);
border-radius: 14px;
box-shadow: 0px 0px 18px rgba(0, 74, 168, 0.05);
display: flex;
align-items: center;
justify-content: center;
&-wrapper {
width: 526px;
height: 300px;
border-radius: 10px;
overflow: hidden;
position: relative;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 10px;
&:nth-child(2) {
width: 120px;
height: 120px;
position: absolute;
right: 127px;
bottom: 15px;
}
}
}
}
&:hover {
.header-img .header-img-wrapper img {
&:nth-child(1) {
transform: scale(1.1);
transition: transform .4s cubic-bezier(.25, .46, .45, .94);
}
}
}
}
}
.news-detail-content {
width: 1600px;
height: 100%;
margin: 52px auto;
margin-top: -100px;
position: relative;
z-index: 1;
.ant-breadcrumb {
line-height: 20px;
font-family: alibaba;
font-size: 14px;
margin-bottom: 20px;
a {
color: #1b58df;
}
span {
color: #091221;
}
}
.news-detail-content-wrapper {
width: 1600px;
float: left;
padding-bottom: 60px;
}
.news-detail-content-others {
width: 300px;
float: right;
div {
background: #f2f6fa;
border-radius: 12px;
padding: 35px 30px;
h4 {
line-height: 22px;
font-family: alibaba;
font-weight: 500;
color: #091221;
font-size: 16px;
}
li {
line-height: 20px;
font-family: alibabareg;
color: #091221;
font-size: 14px;
margin-top: 20px;
}
}
}
}
}

View File

@ -29,6 +29,7 @@ function Index(props) {
const [standardList, setStandardList] = useState([]);
const [manualList, setManualList] = useState([]);
const [lesson, setLesson] = useState([])
const [docList, setDocList] = useState([])
useEffect(() => {
document.title = '学习专区-软件工厂专区';
@ -256,6 +257,31 @@ function Index(props) {
}
</div>
</div>
<div className="docs">
<h2>文档资料</h2>
<div className="docs-content">
{
docList.map((item, index) => {
return <div className="news-item" key={index}>
<div className="news-item-img">
<img src={item.headImg || getDefaultImage(item.id)} alt="" />
</div>
<div className="news-item-info">
<Link to={`/softwareFactory/news/${item.id}`}><h3>{item.name}</h3></Link>
<p>{item.summary}</p>
<div className="news-item-info-bottom">
<span>{item.publishTime}</span>
<Link to={`/softwareFactory/news/${item.id}`}>
<span>查看详情</span>
<KFIcon type="icon-icon_blackarrow_hover" font={40} />
</Link>
</div>
</div>
</div>
})
}
</div>
</div>
<div className="manual">
<h2>用户手册</h2>
<div className="manual-content">
@ -267,7 +293,7 @@ function Index(props) {
<p>持续迭代的权威指南随工厂进化同步更新的鲜活知识库</p>
</div>
{
manualList.slice(0, 3).map((item, index) => {
manualList.slice(0, 2).map((item, index) => {
const nameList = item.name.split('软件工厂')
return <div className={`manual-${index + 1}`}>
<img src={index === 0 ? manual1 : manual2} alt="" />
@ -278,7 +304,6 @@ function Index(props) {
})
}
</div>
</div>

View File

@ -117,9 +117,11 @@
.chapter-wrapper {
height: 387px;
overflow: hidden;
.chapter-list {
transition: all .4s cubic-bezier(.25, .46, .45, .94);
margin-left: 36px;
.chapter-item {
height: 88px;
width: 100%;
@ -782,4 +784,82 @@
}
}
}
.docs {
.news-item {
width: 48%;
&:hover {
h3 {
color: #164ce4;
}
svg {
left: 2px;
top: -20px;
}
}
&-title {
margin-top: 27px;
display: flex;
justify-content: space-between;
i {
flex-shrink: 0;
height: 28px;
width: 28px;
position: relative;
display: inline-block;
svg {
position: absolute;
left: -21px;
top: 4px;
transition: top .2s ease-out, left .2s ease-out;
}
overflow: hidden;
}
h3 {
line-height: 33px;
font-family: alibaba;
font-weight: 500;
color: #091221;
font-size: 22px;
max-width: 670px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
p {
margin-top: 22px;
line-height: 22px;
font-family: alibabareg;
color: #091221;
font-size: 16px;
max-width: 690px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
// 前两个
&:nth-child(-n+2) {
border-bottom: 1px solid #f0f0f0;
padding-bottom: 45px;
height: fit-content;
}
// 最后两个
&:nth-last-child(-n+2) {
display: flex;
justify-content: flex-end;
flex-direction: column;
}
}
}
}

View File

@ -88,11 +88,10 @@ function Index(props) {
setTotal(res.data.total)
})
}
return (
<div className={`news ${isVisible ? 'animate-active' : ''}`}>
<div className="news-header">
<h2><span>动态速递</span>实时感知软件工厂业内新闻</h2>
<h2><span>创新引领</span>软件工厂业界最新动态</h2>
<div className="header-content">
<div className="header-left">
<h3>{nowTop.name}</h3>
@ -217,7 +216,6 @@ function Index(props) {
hasMore={!loading && hasMore}
>
<div className="news-body-bottom">
{
newsList3.map((item, index) => {
return <div className="news-item" key={index}>

View File

@ -0,0 +1,119 @@
import React, { useEffect, useState, useRef } from 'react';
import './index.scss';
import { TPMIndexHOC } from '../../../../modules/tpm/TPMIndexHOC';
import imageBack1 from '../../../../images/factory/resource/tools-detail-head-left.webp'
import imageGif from '../../../../images/factory/resource/tools-detail-head-left2.webp'
import headIcon from '../../../../images/factory/resource/tools-detail-head-icon.webp'
import { Link } from 'react-router-dom';
import RenderHtml from '../../../../components/render-html';
import { Breadcrumb } from 'antd';
import { getSourceDetail, httpUrl, getSourceList } from '../../../api';
import { downloadFunc } from '../../../../forge/Utils/utils'
import { factoryZoneId, } from '../../../../constants/factory'
import '../../../common.scss'
import { Base64 } from 'js-base64';
function Index(props) {
const id = props.match.params.id
const [detail, setDetail] = useState({})
const [content, setContent] = useState();
const [otherList, setOtherList] = useState([]);
useEffect(() => {
document.title = '工具详情-软件工厂专区';
}, []);
useEffect(() => {
if (id !== detail.id) {
getDetail()
}
}, [id]);
useEffect(() => {
if (detail.id) {
getOtherList()
}
}, [detail])
const getDetail = () => {
getSourceDetail(id).then(response => {
if (response) {
let extendData = {}
if (response.data.data.extendData) {
extendData = JSON.parse(response.data.data.extendData)
}
document.title = response.data.data.name
if (extendData.content) {
setContent(Base64.decode(extendData.content))
}
setDetail({...response.data.data, ...extendData});
}
}).catch(error => { })
}
const getOtherList = () => {
getSourceList({ id: factoryZoneId, domainId: detail.domainId }).then(res => {
setOtherList(res.data.rows.filter(e => e.id !== detail.id).slice(0, 3));
});
}
return (
<div className="news-detail">
<div className="news-detail-header">
<Breadcrumb separator=">">
<Breadcrumb.Item href={`/softwareFactory`}>首页</Breadcrumb.Item>
<Breadcrumb.Item href={`/softwareFactory/resource/developmentTools`}>开发工具</Breadcrumb.Item>
<Breadcrumb.Item> <span className="breacrumb-name">{detail.name}</span> </Breadcrumb.Item>
</Breadcrumb>
<div className="header-content">
<h3>{detail.name}</h3>
<p title={ detail.summary }>{detail.summary}</p>
<div className="tools-info">
<div>
<span>{detail.downloadCount}</span>
<span>下载量</span>
</div>
<div>
<span>{detail.fileList && detail.fileList[0] && detail.fileList[0].fileSizeInfo}</span>
<span>文件大小</span>
</div>
<div>
<span>{detail.domainName}</span>
<span>工具类型</span>
</div>
</div>
<button className="shiny-button" onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${detail.fileIds}`) }}>立即下载</button>
<h6 className="more-title">更多热门工具</h6>
<div className="more-tools">
{
otherList.length > 0 && otherList.map((e, index) => {
return <Link to={`/softwareFactory/resource/developmentTools/${e.id}`} key={index}><span >
<img src={headIcon} alt="" />
{e.name}
</span>
</Link>
})
}
</div>
<div className="header-img">
<div className="header-img-wrapper">
<img src={detail.headImg || imageBack1} alt="" />
{!detail.headImg && <img src={imageGif} alt="" />}
</div>
</div>
</div>
</div>
<div className="news-detail-content">
<div className="news-detail-content-wrapper">
{
content && <RenderHtml className="informations_detail imageLayerParent" value={content} url={props.history.location} />
}
</div>
</div>
</div>
)
}
export default TPMIndexHOC(Index)

View File

@ -0,0 +1,276 @@
.news-detail {
min-height: calc(100vh - 58px);
.news-detail-header {
height: 752px;
width: 100%;
background-image: url("../../../../images/factory/resource/tools-detail-head.webp");
background-repeat: no-repeat;
background-size: 100% 100%;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
justify-content: flex-start;
.ant-breadcrumb {
align-self: flex-start;
margin-top: 30px;
margin-left: calc((100vw - 1600px) / 2);
a {
color: #1b58df;
}
span {
color: #091221;
.breacrumb-name {
max-width: 200px;
display: inline-block;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
vertical-align: middle;
}
}
}
.header-content {
margin-top: 30px;
width: 1600px;
height: 481px;
position: relative;
border-radius: 16px;
padding: 60px 45px;
background: linear-gradient(106.16deg, #f7fbff 2.47%, #f5faff 95.98%);
border: 2px solid;
border-color: #ffffff;
h3 {
line-height: 47px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 34px;
max-width: 650px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
p {
margin-top: 25px;
max-width: 650px;
line-height: 22px;
font-family: alibabareg;
color: #5d6a80;
font-size: 16px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.tools-info {
display: flex;
margin-top: 35px;
div {
display: flex;
flex-direction: column;
position: relative;
margin-right: 78px;
span:nth-child(1) {
line-height: 32px;
font-family: alibabaBold;
font-weight: 700;
color: #164ce4;
font-size: 24px;
}
span:nth-child(2) {
line-height: 20px;
font-family: alibabareg;
color: #5d6a80;
font-size: 14px;
margin-top: 8px;
}
&:not(:last-child) {
&::after {
position: absolute;
content: "";
width: 0px;
height: 60px;
right: -39px;
border-right: 1px dashed;
border-color: rgba(22, 76, 228, 0.15);
}
}
}
}
button {
margin-top: 30px;
width: 110px;
height: 36px;
line-height: 36px;
cursor: pointer;
border-radius: 6px;
line-height: 20px;
font-family: alibaba;
font-weight: 500;
color: #ffffff;
font-size: 14px;
text-align: center;
background-color: #091221;
}
h6 {
margin-top: 34px;
line-height: 22px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 16px;
}
.more-tools {
display: flex;
margin-top: 20px;
span {
max-width: 200px;
cursor: pointer;
display: inline-block;
background: #e9f2ff;
border-radius: 4px;
padding: 13px 12px;
margin-right: 15px;
line-height: 19px;
font-family: alibaba;
color: #091221;
font-size: 15px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
img {
width: 19px;
height: 19px;
margin-right: 15px;
}
}
}
.header-img {
position: absolute;
top: 60px;
right: 60px;
width: 600px;
height: 360px;
background: linear-gradient(180deg, #ffffff 0%, #ffffff 100%);
border-radius: 14px;
box-shadow: 0px 0px 18px rgba(0, 74, 168, 0.05);
display: flex;
align-items: center;
justify-content: center;
&-wrapper {
width: 526px;
height: 300px;
border-radius: 10px;
overflow: hidden;
position: relative;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 10px;
&:nth-child(2) {
width: 120px;
height: 120px;
position: absolute;
right: 127px;
bottom: 15px;
}
}
}
}
&:hover {
.header-img .header-img-wrapper img {
&:nth-child(1) {
transform: scale(1.1);
transition: transform .4s cubic-bezier(.25, .46, .45, .94);
}
}
}
}
}
.news-detail-content {
width: 1600px;
height: 100%;
margin: 52px auto;
margin-top: -100px;
position: relative;
z-index: 1;
.ant-breadcrumb {
line-height: 20px;
font-family: alibaba;
font-size: 14px;
margin-bottom: 20px;
a {
color: #1b58df;
}
span {
color: #091221;
}
}
.news-detail-content-wrapper {
width: 1600px;
float: left;
padding-bottom: 60px;
}
.news-detail-content-others {
width: 300px;
float: right;
div {
background: #f2f6fa;
border-radius: 12px;
padding: 35px 30px;
h4 {
line-height: 22px;
font-family: alibaba;
font-weight: 500;
color: #091221;
font-size: 16px;
}
li {
line-height: 20px;
font-family: alibabareg;
color: #091221;
font-size: 14px;
margin-top: 20px;
}
}
}
}
}

View File

@ -0,0 +1,125 @@
import React, { useEffect, useState, useRef } from 'react';
import './index.scss';
import { getSourceList, httpUrl } from '../../api'
import { factoryZoneId, commontoolId } from '../../../constants/factory'
import bg1 from '../../../images/factory/resource/tools-top-1.webp';
import bg2 from '../../../images/factory/resource/tools-top-2.webp';
import bg3 from '../../../images/factory/resource/tools-top-3.webp';
import bg4 from '../../../images/factory/resource/tools-bottom-1.webp';
import bg5 from '../../../images/factory/resource/tools-bottom-2.webp';
import defaultImg from '../../../images/factory/tools-default-1.png'
import ActionItem from '../components/ActionItem';
import '../../common.scss'
import { downloadFunc } from '../../../forge/Utils/utils'
import { Link } from "react-router-dom";
import InfiniteScroll from 'react-infinite-scroller';
const bgList = [bg1, bg2, bg3]
const bg2List = [bg4, bg5]
function Index(props) {
const [fullList, setFullList] = useState([]);
const [selectedType, setSelectedType] = useState(null);
const pageSize = 10
const [pageNum, setPageNum] = useState(1)
const [loading, setLoading] = useState(false)
const hasMore = useRef(true)
useEffect(() => {
}, []);
useEffect(() => {
setPageNum(1)
hasMore.current = true
getFullList()
}, [selectedType])
const getFullList = (isMore = false) => {
if (!hasMore.current) return
let params = {
id: factoryZoneId,
keywords: commontoolId,
pageNum: isMore ? isMore : pageNum,
pageSize
}
setLoading(true)
getSourceList(params).then(res => {
setLoading(false)
if (res.data.rows) {
const rows = []
res.data.rows.forEach(e => {
let extendData = {}
if (e.extendData) {
extendData = JSON.parse(e.extendData)
}
rows.push({ ...e, extendDataUrl: extendData.url, extendDataHeadImg: extendData.headImg, extendDataSharer: extendData.sharer})
});
if (isMore) {
setPageNum(isMore)
setFullList([...fullList, ...rows])
} else {
setFullList(rows);
}
hasMore.current = res.data.total > fullList.length
}
});
};
return (
<div className="commontools">
<div className="commontools-content">
<p>由XX集团科研院所地方企业等提供可免费共用的工具</p>
{
fullList.length > 0 && <InfiniteScroll
threshold={10}
initialLoad={false}
pageStart={1}
loadMore={(e) => { getFullList(e) }}
hasMore={!loading && hasMore.current}
><div className="tools-list">
{
fullList.map((item, index) => {
const createUser = item.createUser
return <ActionItem className="content-bottom-wrapper" key={index} backgroundColor="#fcfefe" padding="1px" borderRadius="23px">
<div className="content-bottom-item">
<div className="item-top">
<img src={item.extendDataHeadImg || defaultImg} alt="" className="item-img"></img>
<h5 className="item-title">{item.name}</h5>
</div>
<div className="item-tags">
<span>共建方</span> <div></div>{item.extendDataSharer}
</div>
<div className="item-desc" title={ item.summary }>
{item.summary}
</div>
<div className="item-data">
<span><i className="iconfont-factory icon-xiazai mr5 font-12" />{item.downloadCount}</span>
</div>
</div>
<div className="content-bottom-btn">
<Link to={`/softwareFactory/resource/developmentTools/${item.id}`}><button className="shiny-button">查看详情</button></Link>
</div>
</ActionItem>
})
}
</div>
</InfiniteScroll>
}
</div>
</div>
)
}
export default Index

View File

@ -0,0 +1,175 @@
.commontools {
display: flex;
flex-direction: column;
align-items: center;
margin-top: -50px;
padding-bottom: 100px;
.item-title {
line-height: 30px;
font-family: alibaba;
font-weight: 500;
color: #091221;
font-size: 24px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
margin: 0;
}
.item-desc {
margin-top: 18px;
line-height: 21px;
font-family: alibabareg;
color: #091221;
font-size: 15px;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
}
.commontools-content {
margin-top: 25px;
width: 1600px;
border-radius: 30px;
padding: 40px 30px;
background: url('../../../images/factory/resource/common-bg.webp'), linear-gradient(180deg, #164ce4 0%, #ffffff 100%);
background-repeat: no-repeat;
background-size: 100% auto;
p {
position: relative;
padding-left: 33px;
font-size: 18px;
font-family: alibaba;
color: #ffffff;
&::before {
position: absolute;
content: "";
width: 16.48px;
height: 16.48px;
background-image: url("../../../images/factory/resource/star2.webp");
background-repeat: no-repeat;
background-size: 100% 100%;
left: 0;
top: 50%;
transform: translate(0, -50%);
}
}
.tools-list {
display: flex;
flex-wrap: wrap;
margin-top: 40px;
}
.content-bottom-wrapper {
margin-bottom: 26px;
&:not(:nth-child(3n)) {
margin-right: 22px;
}
}
.content-bottom-item {
width: 483.3px;
height: 263px;
background: #fcfefe;
border-radius: 23px;
border: 1px solid;
border-color: #fcfefe21;
z-index: 1;
position: relative;
padding: 25px 35px;
display: flex;
flex-direction: column;
.item-tags {
// position: absolute;
display: flex;
justify-content: flex-start;
align-items: center;
margin-top: 16px;
width: fit-content;
background: #eaeff9;
border-radius: 4px;
height: 32px;
padding: 5px 9px;
line-height: 22px;
font-family: alibabareg;
color: #091221;
font-size: 13px;
img {
width: 15px;
margin-right: 5px;
height: 15px;
}
div {
width: 6px;
height: 6px;
background: #ffffff;
border-radius: 50%;
margin: 0 6px;
}
}
.item-top {
display: flex;
align-items: center;
img {
width: 53px;
height: 53px;
border-radius: 50%;
margin-right: 18px;
}
}
.item-desc {
-webkit-line-clamp: 2;
margin-top: 20px;
}
.item-data {
margin-top: auto;
span {
line-height: 18px;
font-family: alibabareg;
color: #5d6a80;
font-size: 13px;
position: relative;
}
}
}
.content-bottom-btn {
width: 483px;
height: 94px;
background: linear-gradient(180deg, rgba(248, 251, 255, 0) 0%, #f3f6ff 23.71%, #f8fbff 100%);
border-radius: 0px 0px 16px 16px;
display: flex;
align-items: center;
justify-content: center;
button {
cursor: pointer;
width: 413px;
height: 44px;
background-color: #091221;
border-radius: 9px;
line-height: 20px;
font-family: alibaba;
font-weight: 500;
color: #ffffff;
font-size: 14px;
text-align: center;
}
}
}
}

View File

@ -70,7 +70,7 @@ function Index(props) {
</Breadcrumb>
<div className="header-content">
<h3>{detail.name}</h3>
<p>{detail.summary}</p>
<p title={ detail.summary }>{detail.summary}</p>
<div className="tools-info">
<div>
<span>{detail.downloadCount}</span>

View File

@ -10,6 +10,8 @@ import bg3 from '../../../images/factory/resource/tools-top-3.webp';
import bg4 from '../../../images/factory/resource/tools-bottom-1.webp';
import bg5 from '../../../images/factory/resource/tools-bottom-2.webp';
import defaultImg from '../../../images/factory/tools-default-2.png'
import ActionItem from '../components/ActionItem';
import '../../common.scss'
import { downloadFunc } from '../../../forge/Utils/utils'
@ -184,7 +186,7 @@ function Index(props) {
<div className="tools-content-hot">
<div className="tools-content-hot-title">
<h5>热门工具</h5>
<span data-text="更强工具、更易落地、更高效率">更强工具更易落地更高效率</span>
<span data-text="来自开源社区,可按授权许可使用和复用的各类软件">来自开源社区可按授权许可使用和复用的各类软件</span>
</div>
<div className="tools-content-hot-list">
{
@ -192,7 +194,7 @@ function Index(props) {
const createUser = item.createUser
return <ActionItem className="hot-item-wrapper" key={index} padding="1px" borderRadius="16px">
<div className="hot-item">
<img src={ item.headImg || createUser.avatar} alt="" className="item-img"></img>
<img src={ item.extendDataHeadImg || defaultImg} alt="" className="item-img"></img>
<div className="item-info">
<h5 className="item-title">{item.name}</h5>
<p className="item-desc">
@ -220,7 +222,7 @@ function Index(props) {
newList.map((item, index) => {
const createUser = item.createUser
return <div className="new-item">
<img src={createUser.avatar} alt="" className="item-img"></img>
<img src={ item.extendDataHeadImg || defaultImg} alt="" className="item-img"></img>
<div className="item-info">
<Link to={`/softwareFactory/resource/developmentTools/${item.id}`}>
<h5 className="item-title">{item.name}</h5>
@ -253,7 +255,7 @@ function Index(props) {
<img src={getBackgroundImage(index)} alt="" className="item-bg" />
<div className="item-top">
<img src={createUser.avatar} alt="" className="item-img"></img>
<img src={ item.extendDataHeadImg || defaultImg} alt="" className="item-img"></img>
<h5 className="item-title">{item.name}</h5>
</div>
<div className="item-desc">

View File

@ -1,33 +1,57 @@
import React, { useEffect, useState, useRef } from 'react';
import './index.scss';
import { getSourceList, httpUrl } from '../../api'
import { factoryZoneId, versionId } from '../../../constants/factory'
import { factoryZoneId, versionId, manualId } from '../../../constants/factory'
import dot from '../../../images/factory/resource/version-dot.webp'
import versionNew from '../../../images/factory/resource/version-new.webp'
import '../../common.scss'
import { downloadFunc } from '../../../forge/Utils/utils'
import manual1 from '../../../images/factory/lessons/manual-1.webp'
import manual2 from '../../../images/factory/lessons/manual-2.webp'
const sourceCode = {
name: '软件工厂源码',
summary: '软件工厂源码即将开放,敬请期待',
id: 'code'
}
function Index(props) {
const [versionList, setVersionList] = useState([]);
const [manualList, setManualList] = useState([]);
useEffect(() => {
getFullList();
getManualList()
}, []);
const getFullList = () => {
getSourceList({ id: factoryZoneId, keywords: versionId }).then(res => {
setVersionList(res.data.rows.slice(0, 4));
setVersionList([res.data.rows[0], sourceCode]);
});
};
const getManualList = () => {
getSourceList({ id: factoryZoneId, keywords: manualId }).then(res => {
const rows = []
res.data.rows.forEach(e => {
let extendData = {}
if (e.extendData) {
extendData = JSON.parse(e.extendData)
}
rows.push({ ...e, extendDataUrl: extendData.url, extendDataHeadImg: extendData.headImg })
});
setManualList(rows);
});
}
return (
<div className="version">
<div className="version-top">
<h5>标准化生产线版本集</h5>
<p>存储与显示软件工厂历年来版本情况提供给用户下载</p>
<h5>生产线安装包</h5>
<p>标准化生产线快速迭代版本和稳定支持版本</p>
</div>
<div className="version-content">
{
@ -49,12 +73,35 @@ function Index(props) {
<span><i className="iconfont-factory icon-shijian mr5 font-12" />{item.createTime}</span>
</div>
</div>
<button onClick={() => {downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`)}} className={index === 0 ? "shiny-button" : "version-btn"}>立即下载</button>
<button onClick={() => { index === 0 && downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`)}} className={index === 0 ? "shiny-button" : "version-btn"}>{ index === 0 ? '立即下载' : '暂未开放'}</button>
</div>
</div>
})
}
</div>
<div className="manual">
<h2>用户手册</h2>
<div className="manual-content">
<div className="manual-left">
<h4>全面掌握软件工厂从理念到实践的全方位指南</h4>
<p>软件工厂白皮书系统阐释工厂理念架构与战略价值</p>
<p>软件工厂使用手册详解平台功能操作流程与最佳实践</p>
<p>从顶层设计到落地操作贯通方法论与工具链的完整知识体系</p>
<p>持续迭代的权威指南随工厂进化同步更新的鲜活知识库</p>
</div>
{
manualList.slice(0, 3).map((item, index) => {
const nameList = item.name.split('软件工厂')
return <div className={`manual-${index + 1}`}>
<img src={index === 0 ? manual1 : manual2} alt="" />
{index === 0 ? <div>{item.name}</div> : <div><span>软件工厂</span><div></div>{nameList[1]}</div>}
<p>{item.summary}</p>
<button onClick={() => { downloadFunc(`${httpUrl}/file/open/download/${item.fileIds}`) }} >下载</button>
</div>
})
}
</div>
</div>
</div>
)
}

View File

@ -34,12 +34,19 @@
width: 1600px;
display: flex;
margin-top: 59px;
justify-content: space-between;
justify-content: flex-start;
margin-bottom: 90px;
.version-item {
width: 348px;
width: 448px;
display: flex;
margin-right: 30px;
&:last-child {
.item-data {
opacity: 0;
}
}
&-left {
display: flex;
@ -96,7 +103,7 @@
p {
width: 100%;
height: 136px;
height: 92px;
line-height: 34px;
font-family: alibabareg;
color: #091221;
@ -108,64 +115,203 @@
text-overflow: ellipsis;
word-break: break-all;
}
.item-data {
margin-top: 10px;
span {
line-height: 18px;
font-family: alibabareg;
color: #5d6a80;
font-size: 13px;
position: relative;
}
span:not(:last-child) {
margin-right: 15px;
padding-right: 15px;
&::after {
position: absolute;
right: 0;
top: 50%;
transform: translate(0, -50%);
content: "";
width: 1px;
height: 9px;
background: rgba(9, 18, 33, 0.22);
.item-data {
margin-top: 10px;
span {
line-height: 18px;
font-family: alibabareg;
color: #5d6a80;
font-size: 13px;
position: relative;
}
span:not(:last-child) {
margin-right: 15px;
padding-right: 15px;
&::after {
position: absolute;
right: 0;
top: 50%;
transform: translate(0, -50%);
content: "";
width: 1px;
height: 9px;
background: rgba(9, 18, 33, 0.22);
}
}
}
}
}
button {
cursor: pointer;
margin-top: 20px;
width: 104px;
height: 36px;
background-color: rgba(255, 255, 255, 0.42);
border: 1px solid;
border-color: #091221;
border-color: gray;
border-radius: 9px;
line-height: 20px;
font-family: alibaba;
font-weight: 500;
color: #091221;
color: gray;
font-size: 14px;
}
.shiny-button {
cursor: pointer;
background-color: #091221;
color: #ffffff;
border: 2px solid transparent;
}
}
&:not(:first-child) {
button:hover {
border-color: #164ce4;
color: #164ce4;
// &:not(:first-child) {
// button:hover {
// border-color: #164ce4;
// color: #164ce4;
// }
// }
}
}
.manual {
width: 100%;
height: 512px;
display: flex;
flex-direction: column;
padding: 0 calc((100vw - 1600px) / 2);
h2 {
margin-bottom: 70px !important;
text-align: center;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 32px;
}
&-content {
display: flex;
}
&-left {
margin-right: 64px;
h4 {
line-height: 30px;
font-family: alibabaBold;
font-weight: 700;
color: #091221;
font-size: 22px;
margin-bottom: 30px !important;
}
p {
margin-bottom: 30px !important;
display: flex;
align-items: center;
&::before {
content: "";
background-image: url('../../../forge/Main/img/home/check.png');
background-repeat: no-repeat;
background-size: 100% 100%;
width: 26px;
height: 26px;
display: inline-block;
margin-right: 25px;
}
}
}
&-1,
&-2 {
padding: 48px;
width: 480px;
height: 263px;
margin-right: 52px;
display: flex;
flex-direction: column;
border-radius: 16px;
position: relative;
overflow: hidden;
z-index: 1;
img {
position: absolute;
width: 480px;
height: 263px;
transition: transform .4s cubic-bezier(.25, .46, .45, .94);
z-index: -1;
left: 0;
top: 0;
}
div {
line-height: 41px;
font-family: alibabaBold;
font-weight: 700;
font-size: 34px;
display: flex;
color: #000c77;
align-items: center;
span {
display: inline-block;
background: linear-gradient(91.39deg, #3f2ce7 3.54%, #7187f4 97.11%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
div {
margin: 0 18px;
width: 5px;
height: 22px;
background: rgba(0, 12, 119, 0.08);
}
}
p {
margin-top: 23px;
}
button {
cursor: pointer;
margin-top: auto;
width: 84px;
height: 36px;
border: 1px solid;
border-color: #ffffff;
border-radius: 9px;
line-height: 36px;
font-family: alibaba;
font-weight: 500;
color: #ffffff;
font-size: 14px;
background-color: transparent;
}
&:hover {
img {
transform: scale(1.1);
}
}
}
&-1 {
color: #ffffff;
div,
p {
color: #ffffff;
}
}
}
}

View File

@ -27,13 +27,18 @@ const DevelopmentTools = Loadable({
loading: Loading,
});
const CommonTools = Loadable({
loader: () => import("./commonTools/index"),
loading: Loading,
});
const zoneId = 199
const typeMap = [
{ name: '软件工厂基座', key: 'factoryVersion', icon: 'icon-gongchangbanben' },
{ name: '软件项目', key:'softwareProject', icon: 'icon-ruanjianxiangmu' },
{ name: '开发工具', key: 'developmentTools', icon: 'icon-kaifagongju' },
{ name: '生产线安装包', key: 'factoryVersion', icon: 'icon-gongchangbanben' },
{ name: '工厂开源项目', key:'softwareProject', icon: 'icon-ruanjianxiangmu' },
{ name: '共建共用工具', key: 'commonTools', icon: 'icon-kaifagongju' },
{ name: '开源社区软件', key: 'developmentTools', icon: 'icon-kaifagongju' },
]
function Index(props) {
@ -114,7 +119,7 @@ function Index(props) {
}
</div>
<h2><span>资源中枢</span>共享复用释放生态力量</h2>
<h2><span>共建共用共享</span>为软件工厂赋能</h2>
<div className="search-box">
<Input className="search-input" value={searchValue} placeholder="搜索资源" onKeyDown={kewDown} allowClear onChange={cleanSearch}></Input>
{/* <input className="search-input" type="text" placeholder="搜索资源" /> */}
@ -151,6 +156,11 @@ function Index(props) {
render={(p) => (
<DevelopmentTools {...props} {...p}/>
)} />
<Route
path="/softwareFactory/resource/commonTools"
render={(p) => (
<CommonTools {...props} {...p}/>
)} />
</Switch>
{
!selectedType && <Search ref={searchRef} searchValue={ searchValue }/>

View File

@ -208,7 +208,7 @@
font-family: alibaba;
font-weight: 500;
color: #091221;
font-size: 22px;
font-size: 20px;
margin-right: 44px;
cursor: pointer;

View File

@ -28,7 +28,6 @@ const contentBgList = [bg4, bg5, bg6, bg7]
function Index(props) {
const [topList, setTopList] = useState([]);
const [contentList, setContentList] = useState([]);
const [fullList, setFullList] = useState([]);
const pageSize = 10
@ -38,15 +37,8 @@ function Index(props) {
useEffect(() => {
getFullList();
getTopList();
}, []);
const getTopList = () => {
getProjectsLists(factoryZoneId, { isHomepage: 1 }).then(res => {
setTopList(res.data.rows.slice(0, 3)); // topList
});
};
const getFullList = (isMore = false) => {
if (!hasMore) return
setLoading(true)
@ -70,51 +62,11 @@ function Index(props) {
return (
<div className="project">
<div className="project-top">
{
topList.map((item, index) => {
const project = item.projectProperties
let imageUrl = project.authorImageUrl.split(':4000/') && project.authorImageUrl.split(':4000/')[1]
const authorImageUrl = imageUrl ? `${window.location.origin}/${imageUrl}` : project.authorImageUrl
// project.praisesCount = Math.floor(Math.random(0, 1) * 50)
// project.forkedCount = Math.floor(Math.random(0, 1) * 50)
return (
<Link to={`/${project.fullName}`}><div className="project-top-item" key={index}>
<img src={bgList[index]} alt="" className="item-bg" />
<img src={authorImageUrl} alt="" className="item-img"></img>
<div className="item-info">
<h5 className="item-title">{project.name.split('/')[1]}</h5>
<p className="item-desc">{project.description}</p>
<div className="item-bottom">
<div className="item-bottom-tags">
{/* {
project.topics && project.topics.split(',').splice(0, 3).map((topic, index) => {
return (
<span key={index} className="item-tag">{topic}</span>
)
})
} */}
<img src={user1} alt="" />
<span>捐赠者</span> <div></div>{project.name.split('/')[0]}
</div>
<div className="item-bottom-data">
<span><i className="iconfont-factory icon-guanzhu mr5 font-12" />{project.forkedCount}</span>
<span><i className="iconfont-factory icon-dianzan mr5 font-12" />{project.praisesCount}</span>
</div>
</div>
</div>
</div>
</Link>
)
})
}
</div>
<div className="project-content">
<h2>全部软件项目</h2>
<div className="project-content-top">
<div className="project-content-top-left">
<p>共创·共享·开放·共生携手共创软件工厂新生态</p>
<p>标准化生产线核心代码及软件工厂开发工具源码</p>
<div className="content-top-list">
{
contentList.map((item, index) => {
@ -137,8 +89,8 @@ function Index(props) {
)
})
} */}
<img src={user2} alt="" />
<span>捐赠者</span> <div></div>{project.name.split('/')[0]}
<img src={ index % 3 === 0 ? user1 : user2} alt="" />
<span>共建方</span> <div></div>{project.name.split('/')[0]}
</div>
<div className="item-desc">
{project.description}
@ -188,7 +140,7 @@ function Index(props) {
})
} */}
<img src={user1} alt="" />
<span>捐赠者</span> <div></div>{project.name.split('/')[0]}
<span>共建方</span> <div></div>{project.name.split('/')[0]}
</div>
<div className="item-desc">

View File

@ -164,13 +164,15 @@
}
&-content {
margin-top: 60px;
background: linear-gradient(180deg, #ffffff 0%, #ffffff 80.62%, rgba(255, 255, 255, 0.13) 100%);
border-radius: 80px 80px 0px 0px;
background: linear-gradient(180deg,#f4f8fd6c 0%,#f4f8fd6c 80.62%,#f4f8fd 100%), #ffffff;
border-radius:80px 80px 0px 0px;
padding-top: 28px;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
z-index: 20;
border-top: 2px solid #ffffff;
h2 {
line-height: 55px;
@ -260,7 +262,8 @@
p {
position: relative;
padding-left: 33px;
font-size: 16px;
font-size: 18px;
font-family: alibaba;
&::before {
position: absolute;
@ -315,15 +318,6 @@
justify-content: flex-start;
align-items: center;
margin-top: 20px;
// top: 150px;
// line-height: 21px;
// font-family: alibabareg;
// color: #091221;
// font-size: 15px;
// display: -webkit-box;
// -webkit-line-clamp: 1;
// -webkit-box-orient: vertical;
// overflow: hidden;
width: fit-content;
background: rgba(179, 190, 252, 0.18);
border: 1px solid;
@ -355,6 +349,27 @@
margin-right: 32px;
}
&:nth-child(1), &:nth-child(4) {
color: #ffffff;
h5, div {
color: #ffffff;
}
.item-data {
span {
color: #ffffff;
}
}
.item-tags {
width: 157px;
height: 32px;
background: rgba(179, 190, 252, 0.18);
border: 1px solid;
border-color: rgba(255, 255, 255, 0.22);
border-radius: 4px;
}
}
// 最后两个元素添加margin-bottom: 28px;
&:nth-last-child(-n+2) {
margin-bottom: 0;

View File

@ -6,6 +6,7 @@ import default5 from '../../images/factory/default/5.png'
import default6 from '../../images/factory/default/6.png'
import default7 from '../../images/factory/default/7.png'
import default8 from '../../images/factory/default/8.png'
import { message } from 'antd'
export function formatNumber(num) {
if (num === undefined || num === null) return
@ -44,6 +45,7 @@ export const downloadFunc = (url, name) => {
}
document.body.removeChild(link)
message.success('开始下载, 请稍后')
}, 50)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB