This commit is contained in:
caishi 2020-07-31 20:15:28 +08:00
parent cefd974498
commit dfbcc09e5b
8 changed files with 565 additions and 295 deletions

View File

@ -3,15 +3,15 @@ import './Component.scss';
export const Tags = (status)=>{
switch(status){
case 1:
case "running":
return(
<span className="statusColor running">运行中</span>
);
case 2:
case "failure":
return (
<span className="statusColor failed">未通过</span>
);
case 3:
case "success":
return (
<span className="statusColor pass">已通过</span>
);

View File

@ -1,27 +1,33 @@
import React , { forwardRef , useCallback } from 'react';
import activate from '../Images/activate.png';
import { Blueback } from '../Component/layout';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { Form , Input } from 'antd';
import axios from 'axios';
import React, { forwardRef, useCallback, useState , useEffect } from "react";
import activate from "../Images/activate.png";
import { Blueback } from "../Component/layout";
import styled from "styled-components";
import { Link } from "react-router-dom";
import { Form, Input, Modal, Button } from "antd";
import axios from "axios";
const P = styled.p`
{
width: 200px;
line-height: 30px;
font-size: 16px;
color: #333;
text-align: center;
margin-top: 30px;
margin-bottom: 30px !important;
}
`;
function About(props, ref) {
const { form: { getFieldDecorator, validateFields } } = props;
const [step, setStep] = useState(1);
const [visible, setVisible] = useState(false);
const [firstCompleted, setFirstCompleted] = useState(false);
const P = styled.p`{
width:200px;
line-height:30px;
font-size:16px;
color:#333;
text-align:center;
margin-top:30px;
margin-bottom:30px!important;
}`;
function About( props , ref){
const { form: { getFieldDecorator , validateFields } } = props;
const helper = useCallback(
(label, name, rules, widget, isRequired) => (
<React.Fragment>
<span className={isRequired?"required":""}>{label}</span>
<span className={isRequired ? "required" : ""}>{label}</span>
<Form.Item>
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
</Form.Item>
@ -29,52 +35,140 @@ function About( props , ref){
),
[]
);
//
function goStep() {
if (!firstCompleted) {
let projectsId = props.match.params.projectsId;
validateFields((error, values) => {
if (!error) {
const url = `/dev_ops/cloud_accounts.json`;
axios.post(url, {
...values,
project_id: projectsId,
})
.then((result) => {
if (result && result.data.redirect_url) {
setVisible(true);
setFirstCompleted(true);
// window.location.href = result.data.redirect_url;
}
})
.catch((error) => {
console.log(error);
});
}
});
} else {
setStep(2);
}
}
//
function sure(){
setVisible(false)
setStep(2);
}
//
function startActive(){
let projectsId = props.match.params.projectsId;
validateFields((error,values)=>{
if(!error){
const url = `/dev_ops/cloud_accounts.json`;
axios.post(url,{
...values,
project_id:projectsId
}).then(result=>{
if(result && result.data.redirect_url){
window.location.href = result.data.redirect_url;
}
}).catch(error=>{
console.log(error);
})
validateFields((error, values) => {
if(!values){
}
})
}
return(
return (
<div className="activatePanel">
<img src={activate} alt="" width="250px"/>
<Modal
title="提示"
visible={visible}
closable={true}
onCancel={() => setVisible(false)}
footer={
<React.Fragment>
<Button onClick={() => setVisible(false)}>取消</Button>
<Button
onClick={sure}
type={"primary"}
className="ml20"
>
确定
</Button>
</React.Fragment>
}
>
<div style={{ display: "flex", justifyContent: "center" }}>
<p style={{ maxWidth: "260px" }}>
初始化配置已完成请前往:
<br />
<a
target="_blank"
href="http://ip:80/login/oauth/authorize"
className="color-blue"
>
http://ip:80/login/oauth/authorize
</a>
<br />
进入认证
</p>
</div>
</Modal>
<img src={activate} alt="" width="250px" />
<P>定义DevOps工作流帮助您检测bug发布代码</P>
<Link to={""} style={{color:"#5091FF",marginBottom:"20px"}}>了解什么是DevOps</Link>
<Form>
{helper(
"服务器IP地址",
"ip_num",
[{ required: true, message: "请输入服务器IP地址" }],
<Input placeholder="请输入服务器IP地址" style={{width:"368px"}} size="large" />,true
)}
{helper(
"服务器用户名:",
"account",
[{ required: true, message: "请输入服务器用户名" }],
<Input placeholder="请输入服务器用户名" size="large" />,true
)}
{helper(
"服务器密码:",
"secret",
[{ required: true, message: "请输入服务器密码" }],
<Input.Password placeholder="请输入服务器密码" size="large" />,true
)}
</Form>
<Blueback onClick={startActive}>开始激活</Blueback>
<Link to={""} style={{ color: "#5091FF", marginBottom: "20px" }}>
了解什么是DevOps
</Link>
{step === 1 ? (
<React.Fragment>
<Form>
<p className="mb20" style={{width:"370px"}}>请仔细核对您的服务器信息一旦确认提交将无法修改</p>
{helper(
"服务器IP地址",
"ip_num",
[{ required: true, message: "请输入服务器IP地址" }],
<Input
placeholder="请输入服务器IP地址"
style={{ width: "368px" }}
size="large"
disabled={firstCompleted}
/>,
true
)}
{helper(
"服务器用户名:",
"account",
[{ required: true, message: "请输入服务器用户名" }],
<Input placeholder="请输入服务器用户名" size="large" disabled={firstCompleted} />,
true
)}
{helper(
"服务器密码:",
"secret",
[{ required: true, message: "请输入服务器密码" }],
<Input.Password placeholder="请输入服务器密码" size="large" disabled={firstCompleted}/>,
true
)}
</Form>
<Blueback onClick={goStep}>下一步</Blueback>
</React.Fragment>
) : (
<div>
<Form>
<p className="mb20" style={{width:"370px"}}>认证成功后请前往<a target="_blank" href="http://ip:80/account" className="color-blue">http://ip:80/account</a>tokentoken</p>
{helper(
"token值",
"token",
[{ required: true, message: "请输入token值" }],
<Input placeholder="请输入token值" size="large" />,
true
)}
<div style={{ display: "flex", justifyContent: "center" }}>
<Button onClick={()=>setStep(1)}>返回上一步</Button>
<Blueback onClick={startActive} className="ml20">开始激活</Blueback>
</div>
</Form>
</div>
)}
</div>
)
);
}
export default Form.create()(forwardRef(About));
export default Form.create()(forwardRef(About));

View File

@ -1,42 +1,80 @@
import React from 'react';
import { FlexAJ , Blueline , AlignCenter } from '../Component/layout';
import styled from 'styled-components';
import { Menu } from 'antd';
import { TagsLine } from '../Component/OpsStatus';
import React, { useEffect ,useState } from "react";
import { FlexAJ, Blueline, AlignCenter } from "../Component/layout";
import styled from "styled-components";
import { Menu , Popconfirm } from "antd";
import { TagsLine } from "../Component/OpsStatus";
import { Time } from "../Utils/Time";
import { truncateCommitId } from "../common/util";
const SubMenu = Menu.SubMenu;
const Img = styled.img`{
width:25px;
height:25px;
border-radius:50%;
margin-right:10px;
}`
export default (()=>{
return(
const Img = styled.img`
{
width: 25px;
height: 25px;
border-radius: 50%;
margin-right: 10px;
}
`;
export default ({ data , repeatSet }) => {
const [ tamp , setTamp ] = useState(undefined);
const [ sha , setSha ] = useState(undefined);
useEffect(()=>{
if(data && data.started){
let t = parseInt(data.started) * 1000;
let time = Time(t);
setTamp(time);
}
if(data && data.after){
setSha(truncateCommitId(data.after));
}
},[data])
return (
<div>
<FlexAJ className="leftheader">
<AlignCenter>
<Img src="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2091711702,2468700162&fm=111&gp=0.jpg"/>
<span className="nest">开始时间<span>2020.07.10 15:30</span></span>
<span className="nest">运行时间<span>20s</span></span>
<Img src={data && data.author_avatar} />
{data && data.started && (
<span className="nest">
开始时间<span> {tamp}</span>
</span>
)}
{data && data.timestamp && (
<span className="nest">
运行时间<span>{data && data.timestamp}s</span>
</span>
)}
</AlignCenter>
<Blueline>重新创建</Blueline>
<Popconfirm title="是否重新创建?" okText="确定" cancelText="取消" onConfirm={repeatSet}>
<Blueline>重新创建</Blueline>
</Popconfirm>
</FlexAJ>
<div className="leftMainContent">
<AlignCenter className="contentBranch">
<i className="iconfont icon-fenzhi1"></i>
<span>分支</span>
<span className="branchname">master</span>
<span className="branchsha">8b3476f5</span>
<span className="branchname">{data && data.source}</span>
<span className="branchsha">{sha}</span>
</AlignCenter>
</div>
<Menu mode='inline' className="leftMenu">
<SubMenu title={<div><i className="iconfont icon-gongzuoliu font-14 mr4"></i><span>CI</span></div>}>
<Menu mode="inline" className="leftMenu">
<SubMenu
title={
<div>
<i className="iconfont icon-gongzuoliu font-14 mr4"></i>
<span>CI</span>
</div>
}
>
<Menu.Item>
<FlexAJ><span>Build setup 01 {TagsLine(1)}</span><span>20s</span></FlexAJ>
<FlexAJ>
<span>Build setup 01 {TagsLine(1)}</span>
<span>20s</span>
</FlexAJ>
</Menu.Item>
</SubMenu>
</Menu>
</div>
)
})
);
};

View File

@ -1,240 +1,318 @@
import React , { useState , useEffect } from 'react';
import { FlexAJ , AlignCenter , Blueback } from '../Component/layout';
import { Table , Pagination } from 'antd';
import { truncateCommitId } from '../common/util';
import styled from 'styled-components';
import axios from 'axios';
import React, { useState, useEffect } from "react";
import { FlexAJ, AlignCenter, Blueback } from "../Component/layout";
import { Table, Pagination, Popconfirm } from "antd";
import { truncateCommitId } from "../common/util";
import styled from "styled-components";
import axios from "axios";
import { Time } from "../Utils/Time";
const STATUS = [
{name:"所有",value:"1"},
{name:"准备中",value:"2"},
{name:"运行中",value:"3"},
{name:"已完成",value:"4"}
]
const LIMIT = 15;
const datasource = [
{
status:2,
author:"caishi",
message:{
branch:"master",
sha:"8b3476f5",
image:"https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2034740944,4251903193&fm=26&gp=0.jpg",
message:"将分支“ 221063-improve-buy-ci-minutes-link”"
},
begin:"2020-07-08",
run:"20s"
},
{
status:1,
author:"caishi",
message:{
branch:"master",
sha:"8b3476f5",
image:"https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2034740944,4251903193&fm=26&gp=0.jpg",
message:"将分支“ 221063-improve-buy-ci-minutes-link”"
},
begin:"2020-07-08",
run:""
}
{ name: "所有", value: "1" },
{ name: "准备中", value: "2" },
{ name: "运行中", value: "3" },
{ name: "已完成", value: "4" },
];
const LIMIT = 15;
const Img = styled.img`
{
border-radius: 50%;
margin-rigth: 10px;
width: 25px;
height: 25px;
}
`;
export default (props) => {
const [status, setStatus] = useState("1");
const [page, setPage] = useState(1);
const [total, setTotal] = useState(10);
const [data, setData] = useState(undefined);
const [tableLoading, setTableLoading] = useState(true);
const Img = styled.img`{
border-radius:50%;
margin-rigth:10px;
width:25px;
height:25px;
}`
export default ((props)=>{
const [ status ,setStatus ] = useState("1");
const [ page ,setPage ] = useState(1);
const [ total ,setTotal ] = useState(10);
const [ data , setData ] = useState(undefined);
let projectsId = props.match.params.projectsId;
useEffect(()=>{
if(projectsId){
const url ='/dev_ops/builds.json';
axios.get(url,{
params:{
project_id:projectsId
}
}).then(result=>{
if(result){
let list = result.data && result.data.map((item,key)=>{
return {
status:item.status,
author:item.sender,
message:{
branch:item.source,
image:item.author_avatar,
message:item.message,
sha:truncateCommitId(item.after)
},
started:item.started,
timestamp:item.timestamp
}
})
setData(list);
}
}).catch(error=>{
console.log(error);
})
let projectsId = props.match.params.projectsId;
useEffect(() => {
if (projectsId) {
Init();
}
},[])
}, []);
function ChangeStatus(value){
setStatus(value)
function Init() {
const url = "/dev_ops/builds.json";
axios
.get(url, {
params: {
project_id: projectsId,
},
})
.then((result) => {
if (result) {
let list =
result.data &&
result.data.map((item, key) => {
return {
status: item.status,
author: item.sender,
message: {
branch: item.source,
image: item.author_avatar,
message: item.message,
sha: truncateCommitId(item.after),
},
started: item.started
? Time(parseInt(item.started) * 1000)
: "--",
timestamp: item.timestamp,
number: item.number,
id:item.id
};
});
setData(list);
setTableLoading(false);
}
})
.catch((error) => {
console.log(error);
});
}
function ChangeStatus(value) {
setStatus(value);
}
//
function ChangePage(page){
setPage(page)
function ChangePage(page) {
setPage(page);
}
function renderStatus() {
return(
return (
<ul className="listNav">
{
STATUS.map((item,key)=>{
return <li onClick={()=>ChangeStatus(item.value)} className={ status === item.value ? "active":""}>{item.name}</li>
})
}
{STATUS.map((item, key) => {
return (
<li
onClick={() => ChangeStatus(item.value)}
className={status === item.value ? "active" : ""}
>
{item.name}
</li>
);
})}
</ul>
)
);
}
function renderStatusBtn(status){
if(status === "failure" || status ==="success"){
return(
<a className="color-blue">重新构建</a>
)
}else{
return(
<a className="color-red">撤销构建</a>
)
function renderStatusBtn(status, number) {
if (status === "failure" || status === "success") {
return (
<Popconfirm
title="确认重新构建?"
onConfirm={(e) => repeatSet(e,number)}
onCancel={(e)=>{e.stopPropagation()}}
cancelText="取消"
okText="确定"
>
<a className="color-blue" onClick={(e)=>{e.stopPropagation()}}>重新构建</a>
</Popconfirm>
);
} else {
return (
<Popconfirm
title="确认撤销构建?"
onConfirm={(e) => cancelSet(e,number)}
onCancel={(e)=>{e.stopPropagation()}}
cancelText="取消"
okText="确定"
>
<a className="color-red" onClick={(e)=>{e.stopPropagation()}}>撤销构建</a>
</Popconfirm>
);
}
}
function renderTableStatus (status){
switch (status){
//
function repeatSet(e,number) {
e.stopPropagation();
setTableLoading(true);
const url = `/dev_ops/builds/${number}.json`;
axios.post(url, { project_id: projectsId })
.then((result) => {
if (result) {
props.showNotification("工作流正在重新构建!");
Init();
}
})
.catch((error) => {
console.log(error);
});
}
//
function cancelSet(e,number) {
e.stopPropagation();
setTableLoading(true);
const url = `/dev_ops/builds/${number}.json`;
axios.delete(url, {
params:{project_id: projectsId}
})
.then((result) => {
if (result) {
props.showNotification("撤销构建成功!");
Init(projectsId);
}
})
.catch((error) => {
console.log(error);
});
}
function renderTableStatus(status) {
switch (status) {
case "running":
return(
<span className="statusTag running"><i className="iconfont icon-yunhangzhong"></i>运行中</span>
return (
<span className="statusTag running">
<i className="iconfont icon-yunhangzhong"></i>运行中
</span>
);
case "failure":
return (
<span className="statusTag failed"><i className="iconfont icon-weitongguo"></i>未通过</span>
<span className="statusTag failed">
<i className="iconfont icon-weitongguo"></i>未通过
</span>
);
case "success":
return (
<span className="statusTag pass"><i className="iconfont icon-yitongguo"></i>已通过</span>
<span className="statusTag pass">
<i className="iconfont icon-yitongguo"></i>已通过
</span>
);
default:
return (
<span className="statusTag Preparing"><i className="iconfont icon-zhunbeizhong"></i>准备中</span>
<span className="statusTag Preparing">
<i className="iconfont icon-zhunbeizhong"></i>准备中
</span>
);
}
}
function clickRows(event,e){
props.history.push(`/projects/${projectsId}/ops/${e.number}/detail`);
}
const column = [
{
title:'序号',
dataIndex:"No",
key:"No",
width:"8%",
render:(item,value,key)=>{
return(
<span>#{key+1}</span>
)
}
title: "序号",
dataIndex: "number",
key: "number",
width: "8%",
render: ( value, item, key) => {
return <span>#{value}</span>;
},
},
{
title:'状态',
dataIndex:"status",
key:"status",
width:"12%",
render:(value,item,key)=>{
return(renderTableStatus(value))
}
title: "状态",
dataIndex: "status",
key: "status",
width: "12%",
render: (value, item, key) => {
return renderTableStatus(value);
},
},
{
title:'构建人',
dataIndex:"author",
key:"author",
width:"12%",
align:"center"
title: "构建人",
dataIndex: "author",
key: "author",
width: "12%",
align: "center",
},
{
title:'提交信息',
dataIndex:"message",
key:"message",
width:"30%",
render:(value,item,key)=>{
title: "提交信息",
dataIndex: "message",
key: "message",
width: "30%",
render: (value, item, key) => {
let meg = item.message;
return (
return (
<React.Fragment>
<div>
{ meg.branch && <span className="mr10 color-grey-8"><i className="iconfont icon-fenzhi1 font-16 mr5"></i>分支{meg.branch}</span>}
{ meg.sha && <span className="color-orange">{meg.sha}</span>}
{meg.branch && (
<span className="mr10 color-grey-8">
<i className="iconfont icon-fenzhi1 font-16 mr5"></i>分支
{meg.branch}
</span>
)}
{meg.sha && <span className="color-orange">{meg.sha}</span>}
</div>
<AlignCenter>
<Img src={meg.image} />
<div className="task-hide ml5" style={{maxWidth:"300px"}}>{meg.message}</div>
<div className="task-hide ml5" style={{ maxWidth: "300px" }}>
{meg.message}
</div>
</AlignCenter>
</React.Fragment>
)
}
);
},
},
{
title:'开始时间',
dataIndex:"started",
key:"started",
width:"15%",
render:(value,item,key)=>{
return (
<span>{value || "--"}</span>
)
}
title: "开始时间",
dataIndex: "started",
key: "started",
width: "15%",
render: (value, item, key) => {
return <span>{value || "--"}</span>;
},
},
{
title:'运行时间',
dataIndex:"timestamp",
key:"timestamp",
width:"15%",
render:(value,item,key)=>{
return (
<span>{value || value === 0 ? `${value}s` : "--"}</span>
)
}
title: "运行时间",
dataIndex: "timestamp",
key: "timestamp",
width: "15%",
render: (value, item, key) => {
return <span>{value || value === 0 ? `${value}s` : "--"}</span>;
},
},
{
title:'操作',
dataIndex:"operation",
key:"operation",
render:(value,item,key)=>{
return(renderStatusBtn(item.status));
}
}
]
return(
title: "操作",
dataIndex: "operation",
key: "operation",
render: (value, item, key) => {
return renderStatusBtn(item.status, item.number);
},
},
];
return (
<div className="listPart">
<FlexAJ>
{renderStatus()}
<span>
<Blueback className="mr30">手动创建</Blueback>
<span className="mr30"><i className="iconfont icon-fenzhi1 font-16 mr5 color-blue"></i>分支</span>
<span><i className="iconfont icon-biaoqian3 font-16 mr5 color-blue"></i>标签</span>
<span className="mr30">
<i className="iconfont icon-fenzhi1 font-16 mr5 color-blue"></i>分支
</span>
<span>
<i className="iconfont icon-biaoqian3 font-16 mr5 color-blue"></i>
标签
</span>
</span>
</FlexAJ>
<Table
onRow={(record,index)=>{
return{
onClick:(event)=>clickRows(event,record)
}
}}
columns={column}
className="normalTable"
dataSource={data}
pagination={false}
loading={tableLoading}
></Table>
{
total > LIMIT ?
<div style={{textAlign:'center',margin:"30px 50px"}}>
<Pagination showQuickJumper defaultCurrent={page} total={total} pageSize={LIMIT} onChange={ChangePage}></Pagination>
</div>:""
}
{total > LIMIT ? (
<div style={{ textAlign: "center", margin: "30px 50px" }}>
<Pagination
showQuickJumper
defaultCurrent={page}
total={total}
pageSize={LIMIT}
onChange={ChangePage}
></Pagination>
</div>
) : (
""
)}
</div>
)
})
);
};

View File

@ -70,6 +70,9 @@
}
}
}
.ant-modal-close{
top:7px;
}
// 列表
.listPart{
.statusTag{

View File

@ -1,33 +1,90 @@
import React from 'react';
import './ops.scss';
import { FlexAJ, AlignCenter } from '../Component/layout';
import { Tags } from '../Component/OpsStatus';
import SplitPane from 'react-split-pane';
import LeftPanel from './OpsDetailLeftpanel';
import RightPanel from './OpsDetailRightpanel';
import React, { useEffect, useState , useRef , useContext } from "react";
import "./ops.scss";
import { FlexAJ, AlignCenter } from "../Component/layout";
import { Tags } from "../Component/OpsStatus";
import SplitPane from "react-split-pane";
import LeftPanel from "./OpsDetailLeftpanel";
import RightPanel from "./OpsDetailRightpanel";
import axios from "axios";
import { Spin } from "antd";
import { Link } from 'react-router-dom';
export default (props) => {
const [data, setData] = useState(undefined);
const [stages, setStages] = useState(undefined);
const [spinning, setSpinning] = useState(true);
export default (()=>{
return(
<div className="opsDetailPanel">
<FlexAJ className="opsInfos">
<AlignCenter>
<span>#1</span>
<span className="ml10">将分支221063-improve-buy-ci-minutes-link合并到221063-improve-buy-ci-minutes-link"</span>
{Tags(1)}
</AlignCenter>
<a style={{color:"#ddd"}}><i className="iconfont icon-yiguanbi font-15 mr5"></i>退出</a>
</FlexAJ>
<div className="opsSection">
<SplitPane className="outer-split-pane" split="vertical" minSize={468} maxSize={-350} defaultSize="40%">
<section className="leftSection">
<LeftPanel />
</section>
<section className="rightSection">
<RightPanel />
</section>
</SplitPane>
let projectId = props.match.params.projectId;
let opsId = props.match.params.opsId;
useEffect(() => {
if (opsId && projectId) {
Init();
}
}, [opsId]);
function Init(){
const url = `/dev_ops/builds/${opsId}.json`;
axios.get(url, {
params: {
project_id: projectId,
},
})
.then((result) => {
if (result && result.data) {
setSpinning(false);
setData(result.data);
setStages(result.data.stages);
}
})
.catch((error) => {
console.log(error);
});
}
//
function repeatSet() {
const url = `/dev_ops/builds/${data && data.number}.json`;
axios.post(url, { project_id: projectId })
.then((result) => {
if (result) {
Init();
}
})
.catch((error) => {
console.log(error);
});
}
return (
<Spin spinning={spinning}>
<div className="opsDetailPanel">
<FlexAJ className="opsInfos">
<AlignCenter>
<span>#{data && data.number}</span>
<span className="ml10">{data && data.message}</span>
{Tags(`${data && data.status}`)}
</AlignCenter>
<Link style={{ color: "#ddd" }} to={`/projects/${projectId}/ops/list`}>
<i className="iconfont icon-yiguanbi font-15 mr5"></i>退出
</Link>
</FlexAJ>
<div className="opsSection">
<SplitPane
className="outer-split-pane"
split="vertical"
minSize={468}
maxSize={-350}
defaultSize="40%"
>
<section className="leftSection">
<LeftPanel data={data} repeatSet={repeatSet}/>
</section>
<section className="rightSection">
<RightPanel data={data} />
</section>
</SplitPane>
</div>
</div>
</div>
)
});
</Spin>
);
};

View File

@ -438,12 +438,12 @@ class Detail extends Component {
</Link>
</li>
}
{/* <li className={url.indexOf("/ops") > -1 ? "active" : ""}>
<li className={url.indexOf("/ops") > -1 ? "active" : ""}>
<Link to={{ pathname: `/projects/${projectsId}/ops`, state }}>
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
</Link>
</li> */}
</li>
<li className={(url.indexOf("/Milepost") > -1 || url.indexOf("meilpost") > -1) ? "active" : ""}>
<Link to={{ pathname: `/projects/${projectsId}/orders/Milepost`, state }}>
<img alt="" src={img_milepost} width="16" />里程碑

View File

@ -26,7 +26,7 @@ export function getDateTime(value, dataformat) {
return date.format(dataformat);
}
export default function Time(UTCtiem) {
export function Time(UTCtiem) {
var dateTime = new Date(UTCtiem);
var year = dateTime.getFullYear();