标签页与里程碑页面的网络请求

dev_forge
dingyongkang 5 years ago
parent 8a83b053c5
commit e2550b9d74

@ -32,7 +32,7 @@ module.exports = {
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
// devtool: "cheap-module-eval-source-map",
// 开启调试
//devtool: "source-map", // 开启调试
devtool: "source-map", // 开启调试
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS.

@ -94,10 +94,10 @@
"react-transition-group": "^1.2.1"
}
},
"@types/anymatch": {
"version": "1.3.1",
"resolved": "https://registry.npm.taobao.org/@types/anymatch/download/@types/anymatch-1.3.1.tgz?cache=0&sync_timestamp=1563089138491&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fanymatch%2Fdownload%2F%40types%2Fanymatch-1.3.1.tgz",
"integrity": "sha1-M2utwb7sudrMOL6izzKt9ieoQho="
"@icons/material": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
},
"@types/jss": {
"version": "9.5.8",
@ -108,11 +108,6 @@
"indefinite-observable": "^1.0.1"
}
},
"@types/node": {
"version": "12.6.3",
"resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-12.6.3.tgz",
"integrity": "sha1-RNUHxWNPhecWRwfKNruiG1IT1Ic="
},
"@types/prop-types": {
"version": "15.7.0",
"resolved": "http://registry.npm.taobao.org/@types/prop-types/download/@types/prop-types-15.7.0.tgz",
@ -135,30 +130,6 @@
"@types/react": "*"
}
},
"@types/tapable": {
"version": "1.0.4",
"resolved": "https://registry.npm.taobao.org/@types/tapable/download/@types/tapable-1.0.4.tgz"
},
"@types/uglify-js": {
"version": "3.0.4",
"resolved": "https://registry.npm.taobao.org/@types/uglify-js/download/@types/uglify-js-3.0.4.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fuglify-js%2Fdownload%2F%40types%2Fuglify-js-3.0.4.tgz",
"integrity": "sha1-lr6uI99vVhhiqDC0KIpJ6GuqwII=",
"requires": {
"source-map": "^0.6.1"
}
},
"@types/webpack": {
"version": "4.4.35",
"resolved": "https://registry.npm.taobao.org/@types/webpack/download/@types/webpack-4.4.35.tgz",
"integrity": "sha1-twiOstRx1WReVQPScng8r6dTWDs=",
"requires": {
"@types/anymatch": "*",
"@types/node": "*",
"@types/tapable": "*",
"@types/uglify-js": "*",
"source-map": "^0.6.0"
}
},
"abab": {
"version": "1.0.4",
"resolved": "http://registry.npm.taobao.org/abab/download/abab-1.0.4.tgz",
@ -500,8 +471,7 @@
},
"async-validator": {
"version": "1.12.2",
"resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-1.12.2.tgz",
"integrity": "sha1-vq5nHnF00pOLe0tp0vt+cit/1yw="
"resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-1.12.2.tgz"
},
"asynckit": {
"version": "0.4.0",
@ -6988,6 +6958,11 @@
"object-visit": "^1.0.0"
}
},
"material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
},
"material-ui": {
"version": "1.0.0-beta.46",
"resolved": "http://registry.npm.taobao.org/material-ui/download/material-ui-1.0.0-beta.46.tgz",
@ -7260,19 +7235,6 @@
"resolved": "http://registry.npm.taobao.org/moment/download/moment-2.24.0.tgz",
"integrity": "sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s="
},
"monaco-editor": {
"version": "0.15.6",
"resolved": "http://registry.npm.taobao.org/monaco-editor/download/monaco-editor-0.15.6.tgz",
"integrity": "sha1-1js7BvhvgDRk8AOyUmJ8PrSglIM="
},
"monaco-editor-webpack-plugin": {
"version": "1.7.0",
"resolved": "http://registry.npm.taobao.org/monaco-editor-webpack-plugin/download/monaco-editor-webpack-plugin-1.7.0.tgz",
"integrity": "sha1-kgy+7Mol8V1w1Win4RsLpNrxroM=",
"requires": {
"@types/webpack": "^4.4.19"
}
},
"ms": {
"version": "2.1.1",
"resolved": "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz",
@ -9595,6 +9557,19 @@
"prop-types": "^15.5.4"
}
},
"react-color": {
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.18.0.tgz",
"integrity": "sha512-FyVeU1kQiSokWc8NPz22azl1ezLpJdUyTbWL0LPUpcuuYDrZ/Y1veOk9rRK5B3pMlyDGvTk4f4KJhlkIQNRjEA==",
"requires": {
"@icons/material": "^0.2.4",
"lodash": "^4.17.11",
"material-colors": "^1.2.1",
"prop-types": "^15.5.10",
"reactcss": "^1.2.0",
"tinycolor2": "^1.4.1"
}
},
"react-content-loader": {
"version": "3.4.2",
"resolved": "http://registry.npm.taobao.org/react-content-loader/download/react-content-loader-3.4.2.tgz",
@ -9834,6 +9809,14 @@
"query-string": "^4.2.3"
}
},
"reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
"integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
"requires": {
"lodash": "^4.0.1"
}
},
"read-pkg": {
"version": "1.1.0",
"resolved": "http://registry.npm.taobao.org/read-pkg/download/read-pkg-1.1.0.tgz",
@ -10456,7 +10439,8 @@
"reqwest": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/reqwest/-/reqwest-2.0.5.tgz",
"integrity": "sha1-APsVrEkYxBnKgrQ/JMeIguZgOaE="
"integrity": "sha1-APsVrEkYxBnKgrQ/JMeIguZgOaE=",
"dev": true
},
"resize-observer-polyfill": {
"version": "1.5.1",
@ -11554,6 +11538,11 @@
"resolved": "http://registry.npm.taobao.org/tiny-warning/download/tiny-warning-1.0.2.tgz",
"integrity": "sha1-Hfrnce4aBDlr394no63OvGtkiyg="
},
"tinycolor2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz",
"integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g="
},
"tmp": {
"version": "0.0.33",
"resolved": "http://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz",

@ -73,6 +73,7 @@
"react-beautiful-dnd": "^10.0.4",
"react-codemirror": "^1.0.0",
"react-codemirror2": "^6.0.0",
"react-color": "^2.18.0",
"react-content-loader": "^3.1.1",
"react-dev-utils": "^5.0.0",
"react-dom": "^16.9.0",

@ -45,15 +45,16 @@ export function initAxiosInterceptors(props) {
// https://github.com/axios/axios/issues/1497
// TODO 读取到package.json中的配置
var proxy = "http://localhost:3000"
// proxy = "http://testbdweb.trustie.net"
// proxy = "http://testbdweb.educoder.net"
var //proxy = "http://localhost:3000"
//proxy = "http://testbdweb.trustie.net"
//proxy = "http://testbdweb.educoder.net"
// proxy = "https://testeduplus2.educoder.net"
//proxy="http://47.96.87.25:48080"
// proxy="https://pre-newweb.educoder.net"
// proxy="https://test-newweb.educoder.net"
//proxy="https://test-jupyterweb.educoder.net"
//proxy="http://192.168.2.63:3001"
//proxy="http://192.168.2.63:3001"
proxy="http://123.59.135.93:56666"
// 在这里使用requestMap控制避免用户通过双击等操作发出重复的请求
// 如果需要支持重复的请求考虑config里面自定义一个allowRepeat参考来控制

@ -1,6 +1,6 @@
import React , { Component } from 'react';
import {Route,Switch} from 'react-router-dom';
import {Route,Switch,Link} from 'react-router-dom';
import { SnackbarHOC } from 'educoder';
@ -14,6 +14,8 @@ import Loading from '../Loading';
import axios from 'axios';
const ProjectNew = Loadable({
loader: () => import('./New/Index'),
loading: Loading,
@ -28,11 +30,12 @@ const ProjectDetail = Loadable({
loading: Loading,
})
class Index extends Component{
constructor(props){
super(props);
this.state={
current_user:undefined
current_user:undefined,
}
}
componentDidMount=()=>{
@ -53,8 +56,9 @@ class Index extends Component{
console.log(error)
})
}
render(){
const {current_user} = this.state;
const { current_user } = this.state;
return(
<Switch {...this.props}>
<Route path="/projects/:projectsType/new"
@ -67,13 +71,14 @@ class Index extends Component{
(props) => (<ProjectDetail {...this.props} {...props} {...this.state} current_user={current_user}/>)
}
></Route>
<Route exact path="/projects"
<Route exact path="/projects"
render={
(props) => (<ProjectIndex {...this.props} {...props} {...this.state} current_user={current_user}/>)
}
></Route>
</Switch>
)
}
}
export default CNotificationHOC() ( SnackbarHOC() ( Index ));

@ -47,10 +47,9 @@ class CoderRootDirectory extends Component{
// 获取根目录
getProjectRoot=(branch)=>{
const { login } = this.props.current_user;
//const { login } = this.props.current_user;
const { projectsId } = this.props.match.params;
const url = `/${login}/${projectsId}/entries.json`;
const url = `/${this.props&&this.props.current_user}/${projectsId}/entries.json`;
axios.get((url),{
params:{
branch
@ -103,11 +102,12 @@ class CoderRootDirectory extends Component{
// 获取子目录
getFileDetail=(arr)=>{
const { current_user } = this.props;
const { projectsId } = this.props.match.params;
const { branch } = this.state;
const url =`/${current_user.login}/${projectsId}/sub_entries.json`;
const url =`/${this.props&&current_user.login}/${projectsId}/sub_entries.json`;
axios.get(url,{
params:{

@ -32,6 +32,21 @@ const CoderRootIndex = Loadable({
loader: () => import('./CoderRootIndex'),
loading: Loading,
})
const OrderMilepost = Loadable({
loader: () => import('../Order/Milepost'),
loading: Loading,
})
const OrdernewMilepost = Loadable({
loader: () => import('../Order/newMilepost'),
loading: Loading,
})
const OrderupdateMilepost = Loadable({
loader: () => import('../Order/UpdateMilepost'),
loading: Loading,
})
/**
* permissionManager:管理员Reporter报告人员(只有读取权限)Developer开发人员除不能设置仓库信息外
*/
@ -46,12 +61,29 @@ class Detail extends Component{
project_id:undefined,
watchers_count:undefined ,
praises_count:undefined ,
forked_count:undefined
forked_count:undefined,
current_user:undefined,
}
}
getUserInfo=()=>{
const url = `/users/me.json`;
axios.get(url).then(result=>{
if(result && result.data.login){
this.setState({
current_user:result.data
})
this.getDetail();
}
}).catch(error=>{
console.log(error)
})
}
componentDidMount=()=>{
this.getDetail();
this.getUserInfo();
}
componentDidUpdate=(provState)=>{
@ -60,10 +92,14 @@ class Detail extends Component{
}
}
getDetail=()=>{
const { login } = this.props.current_user;
// const { login } = this.props.current_user;
const { current_user } = this.state;
const { projectsId } = this.props.match.params;
const url = `/${login}/${projectsId}.json`;
const url = `/${current_user&&current_user.login}/${projectsId}.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
@ -216,6 +252,26 @@ class Detail extends Component{
(props) => (<OrderDetail {...this.props} {...props} {...this.state}/>)
}
></Route>
{/* 里程碑 */}
<Route path="/projects/:projectsId/orders/Milepost"
render={
(props) => (<OrderMilepost {...this.props} {...props} {...this.state}/>)
}
></Route>
{/* 新建里程碑 */}
<Route path="/projects/:projectsId/orders/meilpost"
render={
(props) => (<OrdernewMilepost {...this.props} {...props} {...this.state}/>)
}
></Route>
{/*修改里程碑*/}
<Route path="/projects/:projectsId/orders/:meilid/meilpost"
render={
(props) => (<OrderupdateMilepost {...this.props} {...props} {...this.state}/>)
}
></Route>
{/* 新建工单 */}
@ -225,6 +281,9 @@ class Detail extends Component{
}
></Route>
{/* 代码Index */}
<Route path="/projects/:projectsId/orders"
render={

@ -64,7 +64,6 @@ class Index extends Component{
// 获取类型
getType=()=>{
const url = `/projects/group_type_list.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
@ -220,7 +219,8 @@ class Index extends Component{
</a>
</Dropdown>
<Dropdown overlay={newItem} trigger={["click"]} placement='bottomRight'>
<a className="createBtn"> + 新建</a>
<a className="createBtn"> + 新建
</a>
</Dropdown>
</div>
</div>

@ -16,7 +16,7 @@ class IndexItem extends Component{
<img className="p-r-photo" alt="" src={getImageUrl(`images/${item.author && item.author.image_url}`)} ></img>
<div className="p-r-Infos">
<div className="p-r-name">
<Link to={`/projects/${item.id}/coder`} className="hide-1 font-16 color-grey-3" style={{whiteSpace:"wrap"}}>{item.name}</Link>
<Link to={`/projects/${item.id}/coder`} className="hide-1 font-16 color-grey-3" style={{whiteSpace:"wrap"}}>{item.name}</Link>
<span className="p-r-tags">
{ item.forked_count ? <span><label>Fork</label><span>{ item.forked_count}</span></span>:"" }
<span><label>Start</label><span>{ item.praises_count }</span></span>

@ -0,0 +1,47 @@
import React , { Component } from 'react';
import { Link } from 'react-router-dom';
class MergeItem extends Component{
render(){
const { issues , search_count , page , limit } = this.props;
const { projectsId } = this.props.match.params;
const renderList =()=>{
if(issues && issues.length > 0){
return(
issues.map((item,key)=>{
return(
<div className="issueItem">
<div className="flex-1">
<p className="mb15 df">
<span className="issueNo"># {search_count - (key + (page-1) * limit)}</span>
<Link to={`/projects/${projectsId}/orders/${item.id}/detail`} className="flex-1 hide-1 font-16 color-grey-3 lineh-30">{item.name}</Link>
</p>
<p className="color-grey-6">
<span>{item.created_at}</span>
{ item.journals_count ? <span className="ml20"><i className="iconfont icon-pinglun1 mr3 font-16"></i>{item.journals_count}</span> : "" }
</p>
</div>
<ul className="topWrapper_select">
<li>{item.issue_tags || "--"}</li>
<li>{item.issue_type || "--"}</li>
<li>{item.tracker || "--"}</li>
<li>{item.author_name || "--"}</li>
<li>{item.assign_user_name || "--"}</li>
<li>{item.priority || "--"}</li>
<li>{item.done_ratio || "--"}</li>
</ul>
</div>
)
})
)
}
}
return(
<div>
{renderList()}
</div>
)
}
}
export default MergeItem;

@ -0,0 +1,254 @@
import React , { Component } from "react";
import {Link} from 'react-router-dom';
import { Input ,Dropdown , Menu , Icon , Pagination , Spin } from 'antd';
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import Nav from '../Order/Nav';
import MergeItem from './MergeItem';
import axios from 'axios';
const Search = Input.Search;
/**
* issue_chosen:下拉的筛选列表,
* data:列表接口返回的所有数据,
* issues:列表数组,
* isSpin:加载中,
* search:搜索关键字,
* author_id:发布者id,
* assigned_to_id:指派给的id
* limit:每页条数,
* page:当前页,
* search_count:列表总条数
* issue_type:搜索条件
*/
class merge extends Component{
constructor(props){
super(props);
this.state={
issue_chosen:undefined,
data:undefined,
issues:undefined,
isSpin:false,
search:undefined,
author_id:undefined,
assigned_to_id:undefined,
limit:15,
page:1,
search_count:undefined,
issue_type:undefined
}
}
componentDidMount=()=>{
this.getSelectList();
this.getIssueList();
}
getSelectList=()=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/issues/index_chosen.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
issue_chosen:result.data.issue_chosen
})
}
}).catch((error)=>{
console.log(error);
})
}
// 获取列表数据
getIssueList=(page,limit,search,author_id,assigned_to_id,id,value)=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/issues.json`;
axios.get(url,{
params:{
page,limit,search,author_id,assigned_to_id,
[id]:value
}
}).then((result)=>{
if(result){
this.setState({
data:result.data,
issues:result.data.issues,
search_count:result.data.search_count,
isSpin:false
})
}
}).catch((error)=>{
console.log(error);
})
}
getOption=(e,id)=>{
this.setState({
[id]:e.key
})
const { page,limit,search,author_id,assigned_to_id } = this.state;
this.getIssueList(page,limit,search,author_id,assigned_to_id,id,e.key);
}
renderMenu =(array,name,id)=>{
return(
<Menu>
<Menu.Item key={undefined} onClick={(e)=>this.getOption(e,id)}>{name}</Menu.Item>
{
array && array.length > 0 && array.map((item,key)=>{
return(
<Menu.Item key={item.id} onClick={(e)=>this.getOption(e,id)}>{item.name}</Menu.Item>
)
})
}
</Menu>
)
}
// 翻页
ChangePage=(page)=>{
this.setState({
page,
isSpin:true
})
const {limit,search} = this.state;
this.getIssueList(page,limit,search);
}
// 搜索
searchFunc=(value)=>{
this.setState({
search:value,
isSpin:true
})
const {page,limit} = this.state;
this.getIssueList(page,limit,value);
}
// 筛选:全部、指派给我、由我创建
ChangeAssign=(type)=>{
const { limit, search} = this.state;
this.setState({
isSpin:true
})
if(type){
const { current_user } = this.props;
if(type===1){
this.setState({
page:1,
author_id:current_user.user_id,
assigned_to_id:undefined
})
this.getIssueList(1,limit,search,current_user.user_id,undefined);
}else{
this.setState({
page:1,
author_id:undefined,
assigned_to_id:current_user.user_id
})
this.getIssueList(1,limit,search,undefined,current_user.user_id);
}
}else{
this.setState({
page:1,
author_id:undefined,
assigned_to_id:undefined
})
this.getIssueList(1,limit,search,undefined,undefined);
}
}
render(){
const { issue_chosen , issues , limit , page , search_count , data , assigned_to_id , author_id , isSpin } = this.state;
const { projectsId } = this.props.match.params;
const Paginations = (
<React.Fragment>
{
search_count > limit ?
<div className="mt30 mb50 edu-txt-center">
<Pagination simple defaultCurrent={page} total={search_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div>:""
}
</React.Fragment>
)
return(
<div className="main">
<div className="topWrapper">
<Nav {...this.props} {...this.state}/>
<Link to={`/projects/${projectsId}/orders/new`} className="topWrapper_btn">创建合并请求</Link>
</div>
<div className="topWrapper" style={{borderBottom:"none"}}>
<p className="topWrapper_nav">
<span>{data && data.open_count}个开启中</span>
<span>{data && data.close_count}个已关闭</span>
</p>
<div>
<Search
placeholder="搜索"
enterButton
onSearch={this.searchFunc}
style={{ width: 300 }}
/>
</div>
</div>
<Spin spinning={isSpin}>
<div className="f-wrap-between mb20">
<div>
</div>
<ul className="topWrapper_select">
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.issue_tag,'标签','issue_tag_id')} trigger={['click']} placement="bottomCenter">
<span>标签<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.issue_type,'所有类型','issue_type')} trigger={['click']} placement="bottomCenter">
<span>类型<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.tracker,'所有分类','tracker_id')} trigger={['click']} placement="bottomCenter">
<span>分类<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.assign_user,'发布人','author_id')} trigger={['click']} placement="bottomCenter">
<span>发布人<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.assign_user,'指派人','assigned_to_id')} trigger={['click']} placement="bottomCenter">
<span>指派人<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.priority,'优先度','priority_id')} trigger={['click']} placement="bottomCenter">
<span>优先度<Icon type="caret-down" className="ml5"/></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.done_ratio,'完成度','done_ratio')} trigger={['click']} placement="bottomCenter">
<span>完成度<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
</ul>
</div>
{
search_count === 0 ?
<NoneData></NoneData>
:
<MergeItem issues={issues} search_count={search_count} page={page} limit={limit} {...this.props} {...this.state}></MergeItem>
}
{ Paginations }
</Spin>
</div>
)
}
}
export default merge;

@ -3,13 +3,22 @@ import {Link} from 'react-router-dom';
import axios from 'axios';
import Nav from './Nav';
import UploadComponent from '../Upload/Index';
import{ Modal,List,Form,Input,Tooltip } from 'antd'
const TextArea = Input.TextArea;
class Detail extends Component{
constructor(props){
super(props);
this.state={
data:undefined
data:undefined,
isShow:false,
imgsrc:'',
//图片区域是否显示 none 隐藏 block 显示
display:'none'
}
}
@ -31,53 +40,193 @@ class Detail extends Component{
})
}
handleok=() => {
this.setState({
isShow:false
});
};
handleCancel=()=>{
this.setState({
isShow:false
});
}
imgshow=()=>{
this.setState({
isShow:true
});
};
render(){
const { projectsId } = this.props.match.params;
const { data } = this.state;
const numbers = [1, 2, 3, 4, 5];
const valuse = [
{
title: 'Title 1',
},
{
title: 'Title 2',
},
{
title: 'Title 3',
},
{
title: 'Title 4',
},
{
title: 'Title 1',
},
{
title: 'Title 2',
},
{
title: 'Title 3',
},
{
title: 'Title 4',
},
{
title: 'Title 1',
},
{
title: 'Title 2',
},
{
title: 'Title 3',
},
{
title: 'Title 4',
},
];
const listTowItems = numbers.map((numbers) =>
<li>
<div className="order_line">
<div className="rectangle"></div>
<img class="comment_img" src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/>
<p className="commit_p">张三
<Tooltip title="2020.1.1 08.08.08" placement="bottom">
<span className="commenttitle">于12日前评论</span>
</Tooltip>
评论 <a type="submit" onClick={this.handleSubmit}>relase</a>
</p>
</div>
</li>
);
const listItems = numbers.map((numbers) =>
<li>
<div className="df">
<Link to={``}><img class="user_img" src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/></Link>
<div className="detail_context" >
<div className="topWrapper_detali"><p className="detail_p">张三
<Tooltip title="2020.1.1 08.08.08" placement="bottom">
<span className="commenttitle">于12日前评论</span>
</Tooltip>
评论</p> <a className="fr" type="submit" onClick={this.handleSubmit}>Issue</a> <a className="fr" type="submit" onClick={this.handleSubmit}>Issue</a> <a className="fr" type="submit" onClick={this.handleSubmit}>Issue</a></div>
<div className="detail_ptitlecount"><p>哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈</p> </div>
<div style={{display: this.state.display}}>
<div className="div_line" ></div>
<List
grid={{ gutter: 16, column: 6 }}
dataSource={valuse}
renderItem={obj => (
<List.Item>
<img class="list_img" onClick={this.imgshow} src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/>
</List.Item>
)}
/>
</div>
</div>
</div>
<div className="listTowItems">
{listTowItems}
</div>
</li>
);
return(
<div className="main">
<div className="topWrapper">
<Nav {...this.props} {...this.state}/>
<Link to={`/projects/${projectsId}/orders/new`} className="topWrapper_btn">创建工单</Link>
<div className="topWrapper">
<Nav {...this.props} {...this.state}/>
<Link to={`/projects/${projectsId}/orders/new`} className="topWrapper_btn">创建工单</Link>
</div>
<div>
<div className="detailContent">
<p>
<span className="font-16">{ data && data.subject }</span>
<a onClick={this.editOrder} className="color-blue fr">编辑</a>
</p>
<p className="mt15">{ data && data.description }</p>
<p className="mt10 color-grey-c">
{ data && data.author_name} { data && data.created_at }创建{ data && data.journals_count && data.journals_count > 0 ?` · ${data.journals_count} 条评论`:""}
</p>
</div>
<div>
<div className="detailContent">
<div className="f-wrap-between mt20" style={{alignItems:"flex-start"}}>
<div className="list-right df divwidth" >
<ul className="ul_width">
{listItems}
<li>
<div className="list-right df">
<Link to={``}><img class="user_img" onClick={this.imgshow} src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/> </Link>
<div className="new_context">
<Form.Item>
<Input placeholder="标题"/>
</Form.Item>
<Form.Item>
<TextArea placeholder="添加一个可选的扩展描述。。。" style={{height:"150px"}}/>
</Form.Item>
<UploadComponent load={this.UploadFunc}></UploadComponent>
<p className="clearfix mt15">
<a className="topWrapper_btn fr" type="submit" onClick={this.handleSubmit}>评论</a>
<a className="Closeor_btn fr" type="submit" onClick={this.handleSubmit}>关闭工单</a>
</p>
</div>
</div>
</li>
</ul>
</div>
<div className="list-left DetailRight">
<p>
<span className="font-16">{ data && data.subject }</span>
<a onClick={this.editOrder} className="color-blue fr">编辑</a>
<span className="span_title">当前状态</span>
<span>已解决</span>
</p>
<p className="mt15">{ data && data.description }</p>
<p className="mt10 color-grey-c">
{ data && data.author_name} { data && data.created_at }创建{ data && data.journals_count && data.journals_count > 0 ?` · ${data.journals_count} 条评论`:""}
<p>
<span className="span_title">优先级</span>
<span></span>
</p>
<p>
<span className="span_title">指派给</span>
<span>蔡世</span>
</p>
<p>
<span className="span_title">里程碑</span>
<span>20200131前上线</span>
</p>
<p>
<span className="span_title">里程碑</span>
<span>20200131前上线</span>
</p>
</div>
<div className="f-wrap-between mt20" style={{alignItems:"flex-start"}}>
<div className="list-right df"></div>
<div className="list-left DetailRight">
<p>
<span className="span_title">当前状态</span>
<span>已解决</span>
</p>
<p>
<span className="span_title">优先级</span>
<span></span>
</p>
<p>
<span className="span_title">指派给</span>
<span>蔡世</span>
</p>
<p>
<span className="span_title">里程碑</span>
<span>20200131前上线</span>
</p>
<p>
<span className="span_title">里程碑</span>
<span>20200131前上线</span>
</p>
</div>
</div>
</div>
</div>
<Modal
onCancel={this.handleCancel}
visible={this.state.isShow}
width="400px"
footer={
[]
}
bodyStyle={{textAlign:'center'}}
>
<img class="list_img" src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1608431072,669449145&fm=27&gp=0.jpg" alt=""/>
</Modal>
</div>
)
}
}

@ -0,0 +1,244 @@
import React , {Component} from 'react';
import { Link } from 'react-router-dom';
import { Dropdown , Icon , Menu , Pagination,Typography} from 'antd';
import Nav from './Nav';
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import reactCSS from 'reactcss'
import axios from 'axios';
const { Text } = Typography;
class Milepost extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
limit:15,
page:1,
order_type:undefined,
//新建标签区域是否显示 none 隐藏 block 显示
display:'none',
status:'open'
}
}
componentDidMount=()=>{
this.getList(1,this.state.status,'desc');
}
getList=(page,status,order_type)=>{
const { projectsId } = this.props.match.params;
const { limit } = this.state;
const url = `/projects/${projectsId}/versions.json`;
axios.get(url,{
params:{
projectsId,page,limit,status,order_type
}
}).then((result)=>{
if(result){
this.setState({
data:result.data
})
}
}).catch((error)=>{
console.log(error);
})
}
opneMilelist=()=>{
this.setState({
status:'open'
})
this.getList(1,'open','desc');
}
closeMilelist=()=>{
this.setState({
status:'closed'
})
this.getList(1,'closed','desc');
}
updatestatusemile=(status,arr)=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/versions/${arr.id}/update_status`;
axios.post(url,{
project_id:projectsId,
id:arr.id,
status:status
}).then(result=>{
if(result){
this.getList(1,'open','desc')
}
}).catch(error=>{
console.log(error);
})
}
closemile=(arr)=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/versions/${arr.id}`;
axios.delete(url,{ data: {
project_id: projectsId,
id: arr.id
}
}).then((result)=>{
if(result){
this.getList(1,this.state.status,'desc')
}
}).catch((error)=>{
console.log(error);
})
}
ChangePage=(page)=>{
this.setState({
page
})
this.getList(page);
}
// 排序
arrayList=(e)=>{
this.setState({
order_name:e.key,
order_type:e.item.props.value
})
this.getList(1,this.state.status,e.item.props.value);
}
//控制新建标签页是否显示
newshow=()=>{
this.setState({
display:'block'
});
};
newclose=()=>{
this.setState({
display:'none'
});
};
render(){
const { data , limit , page } = this.state;
const { projectsId } = this.props.match.params;
const menu = (
<Menu onClick={this.arrayList}>
<Menu.Item key={'created_at'} value="desc">到期日从近到远</Menu.Item>
<Menu.Item key={'created_at'} value="asc">到期日从远到近</Menu.Item>
<Menu.Item key={'issues_count'} value="desc">完成度从低到高</Menu.Item>
<Menu.Item key={'issues_count'} value="asc">完成度从高到低</Menu.Item>
<Menu.Item key={'issues_count'} value="asc">工单从多到少</Menu.Item>
<Menu.Item key={'issues_count'} value="asc">工单从少到多</Menu.Item>
</Menu>
)
const Paginations = (
<React.Fragment>
{
data && data.issue_tags_count > limit ?
<div className="mt30 mb50 edu-txt-center">
<Pagination simple defaultCurrent={page} total={data && data.issue_tags_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div>:""
}
</React.Fragment>
)
const renderList =()=>{
if(data && data.versions && data.versions.length>0 ){
return(
<div className="tagList">
{
data.versions.map((item,key)=>{
return(
<div style={{display:'block'}}>
<div className="milepostdiv">
<div className="milepostwidth">
<p style={{background:'red',width:20}}></p>
<p>{item.name}</p>
</div>
<div className="mileposwidth">
</div>
</div>
<div className="milepostdiv" style={{marginTop:5}}>
<div className="milepostrighe">
<p style={{background:'red',width:20}}></p>
<p>{item.effective_date}</p>
<p style={{background:'red',width:20}}></p>
<p>{item.open_issues_count}个开启</p>
<p style={{background:'red',width:20}}></p>
<p>{item.close_issues_count}个关闭</p>
</div>
<div className="milepostleft">
<p style={{background:'red',width:20}}></p>
<p><Link to={`/projects/${projectsId}/orders/${item.id}/meilpost`} >编辑</Link></p>
<p style={{background:'red',width:20}}></p>
<p onClick={()=>this.updatestatusemile('closed',item)}>关闭</p>
<p style={{background:'red',width:20}}></p>
<p onClick={()=>this.closemile(item)} >删除</p>
</div>
</div>
<div className="milepostdiv"style={{marginTop:5}}>
<div className="textwidth">
<Text
type="secondary"
ellipsis={{rows: 30, expandable: false, onExpand: Function}}
>
{item.description}</Text>
</div>
</div>
</div>
)
})
}
</div>
)
}else{
return(
<NoneData />
)
}
}
return(
<div className="main">
<div>
<div className="topWrapper">
<Nav {...this.props} {...this.state} />
{/* <a onClick={this.newshow} className="topWrapper_btn" >新建里程碑</a> */}
<Link to={`/projects/${projectsId}/orders/meilpost`} className="topWrapper_btn">新的里程碑</Link>
</div>
<div style={{display: this.state.display}}>
<div className="tagdiv" >
<span>里程碑{ data && data.issue_tags_count }已创建</span>
</div>
</div>
<div className="topWrapper">
<div className="topWrapper_nav">
<span onClick={this.opneMilelist}>{ data && data.open_count }开启中</span>
<span onClick={this.closeMilelist}>{ data && data.closed_count }已关闭</span>
</div>
<ul className="topWrapper_select">
<li>
<Dropdown className="topWrapperSelect" overlay={menu} trigger={['click']} placement="bottomCenter">
<span>排序<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
</ul>
</div>
{ renderList()}
{ Paginations }
</div>
</div>
)
}
}
export default Milepost;

@ -7,7 +7,8 @@ class Nav extends Component{
return(
<p className="topWrapper_nav">
<Link to={`/projects/${projectsId}/orders/tags`} >标签</Link>
<Link to={``}>里程碑</Link>
<Link to={`/projects/${projectsId}/orders/Milepost`}>里程碑</Link>
</p>
)
}

@ -19,12 +19,12 @@ class New extends Component{
branch_name:"",
issue_tag_ids:"",
fixed_version_id:"",
tracker_id:"",
issue_type:"",
status_id:'',
tracker_id:"缺陷",
issue_type:"普通",
status_id:'新增',
assigned_to_id:"",
priority_id:"",
done_ratio:"",
priority_id:"正常",
done_ratio:"0%",
issue_chosen:undefined,
branches:undefined,
fileList:undefined
@ -62,7 +62,7 @@ class New extends Component{
return(
list.map((item,key)=>{
return(
<Option key={key+1} value={item.id}>{item.name}</Option>
<Option key={key+1} value={item.id+""}>{item.name}</Option>
)
})
)
@ -76,6 +76,22 @@ class New extends Component{
const { projectsId } = this.props.match.params;
const { fileList } = this.state;
const url = `/projects/${projectsId}/issues.json`;
if(values.status_id==="新增"){
values.status_id="1"
}
// if(values.issue_type==="普通"){
// values.issue_type="1"
// }
if(values.tracker_id==="缺陷"){
values.tracker_id="1"
}
if(values.priority_id==="正常"){
values.priority_id="2"
}
if(values.done_ratio==="0%"){
values.done_ratio="0"
}
axios.post(url,{
...values,
attachment_ids:fileList
@ -87,6 +103,7 @@ class New extends Component{
}).catch(error=>{
console.log(error);
})
}
})
}
@ -187,12 +204,11 @@ class New extends Component{
}],
})(
<Select value={status_id}>
<Option value={""}>未选择完成状态</Option>
{ this.renderSelect(issue_chosen && issue_chosen.issue_status) }
</Select>
)}
</Form.Item>
<Form.Item
{/* <Form.Item
label="类型"
>
{getFieldDecorator('issue_type', {
@ -200,12 +216,11 @@ class New extends Component{
required: true, message: '请选择类型'
}],
})(
<Select value={issue_type}>
<Option value={""}>未选择类型</Option>
<Select value={issue_type}>
{ this.renderSelect(issue_chosen && issue_chosen.issue_type) }
</Select>
)}
</Form.Item>
</Form.Item> */}
<Form.Item
label="分类"
>
@ -215,7 +230,6 @@ class New extends Component{
}],
})(
<Select value={tracker_id}>
<Option value={""}>未选择分类</Option>
{ this.renderSelect(issue_chosen && issue_chosen.tracker) }
</Select>
)}
@ -224,7 +238,8 @@ class New extends Component{
label="指派成员"
>
{getFieldDecorator('assigned_to_id', {
rules: [],
rules: [{
}],
})(
<Select value={assigned_to_id}>
<Option value={""}>未指派成员</Option>
@ -241,7 +256,6 @@ class New extends Component{
}],
})(
<Select value={priority_id}>
<Option value={""}>未选择优先度</Option>
{ this.renderSelect(issue_chosen && issue_chosen.priority) }
</Select>
)}
@ -255,7 +269,6 @@ class New extends Component{
}],
})(
<Select value={done_ratio}>
<Option value={""}>未选择完成度</Option>
{ this.renderSelect(issue_chosen && issue_chosen.done_ratio) }
</Select>
)}

@ -1,9 +1,10 @@
import React , {Component} from 'react';
import { Dropdown , Icon , Menu , Pagination } from 'antd';
import { Dropdown , Icon , Menu , Pagination, Modal,Input,Popconfirm,Form } from 'antd';
import { Link } from 'react-router-dom';
import Nav from './Nav';
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import { SketchPicker } from 'react-color'
import reactCSS from 'reactcss'
import axios from 'axios';
class Tags extends Component{
constructor(props){
@ -13,7 +14,24 @@ class Tags extends Component{
limit:15,
page:1,
order_name:undefined,
order_type:undefined
order_type:undefined,
//新建标签区域是否显示 none 隐藏 block 显示
display:'none',
//调色盘颜色
displayColorPicker: false,
color: {
r: '241',
g: '112',
b: '19',
a: '1',
},
textcolor:'#F17013',
isShow:false,
newcolor:'',
name:'',
description:'',
id:'',
modelname:''
}
}
@ -21,6 +39,7 @@ class Tags extends Component{
this.getList();
}
getList=(page,order_name,order_type)=>{
const { projectsId } = this.props.match.params;
const { limit } = this.state;
@ -40,6 +59,29 @@ class Tags extends Component{
})
}
createtagpost=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/issue_tags`;
axios.post(url,{
...values,
project_id:projectsId,
color:this.state.textcolor
}).then(result=>{
if(result){
this.setState({
display:'none'
});
this.getList()
}
}).catch(error=>{
console.log(error);
})
}
})
}
ChangePage=(page)=>{
this.setState({
page
@ -58,9 +100,113 @@ class Tags extends Component{
this.getList(1,e.key,e.item.props.value);
}
handleClick = () => {
this.setState({ displayColorPicker: !this.state.displayColorPicker })
};
handleClose = () => {
this.setState({ displayColorPicker: false })
};
handleChange = (color) => {
this.setState({
color: color.rgb,
textcolor:color.hex,
newcolor:color.hex,
})
};
//控制新建标签页是否显示
newshow=()=>{
this.setState({
display:'block'
});
};
newclose=()=>{
this.setState({
display:'none'
});
};
handleok=()=>{
this.updatetag();
}
updatetag=()=>{
const { projectsId } = this.props.match.params;
let id=this.state.id;
const url = `/projects/${projectsId}/issue_tags/${id}.json`;
let name=this.state.name;
let description=this.state.description;
let modalcolor=this.state.newcolor
axios.put(url,{
project_id:projectsId,
id:id,
name:name,
description:description,
color:modalcolor
}).then((result)=>{
if(result){
this.setState({
isShow:false
});
this.getList()
}
}).catch((error)=>{
console.log(error);
})
}
deletetag=(id)=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/issue_tags/${id}.json`;
axios.delete(url,{ data: {
project_id: projectsId,
id: id
}
}).then((result)=>{
if(result){
this.getList()
}
}).catch((error)=>{
console.log(error);
})
}
handleCancel=()=>{
this.setState({
isShow:false
});
}
changmodelname=(e)=>{
this.setState({
name:e.target.value
})
}
changdescription=(e)=>{
this.setState({
description:e.target.value
})
}
editshow=(arr)=>{
this.setState({
isShow:true,
newcolor:arr.color,
name:arr.name,
description:arr.description,
id:arr.id
});
};
render(){
const { data , limit , page } = this.state;
const { projectsId } = this.props.match.params;
const { getFieldDecorator } = this.props.form;
const menu = (
<Menu onClick={this.arrayList}>
<Menu.Item key={'created_at'} value="desc">按创建时间降序排序</Menu.Item>
@ -69,6 +215,46 @@ class Tags extends Component{
<Menu.Item key={'issues_count'} value="asc">按issue个数升序排序</Menu.Item>
</Menu>
)
const styles = reactCSS({
'default': {
color: {
width: '20px',
height: '20px',
borderRadius: '2px',
background: `rgba(${ this.state.color.r }, ${ this.state.color.g }, ${ this.state.color.b }, ${ this.state.color.a })`,
},
swatch: {
padding: '5px',
background: '#fff',
borderRadius: '1px',
width:'100px',
marginTop:'5px',
height:'28px',
boxShadow: '0 0 0 1px rgba(0,0,0,.1)',
display: 'flex',
cursor: 'pointer',
},
popover: {
position: 'absolute',
zIndex: '2',
},
cover: {
position: 'fixed',
top: '0px',
right: '0px',
bottom: '0px',
left: '0px',
},
modalcolor:{
width: '20px',
height: '20px',
borderRadius: '2px',
background: this.state.newcolor,
}
},
});
const Paginations = (
<React.Fragment>
{
@ -94,6 +280,12 @@ class Tags extends Component{
</span>
<span className="hide-1">{item.description}</span>
<span>{item.issues_count}个开启的工单</span>
<div>
<Popconfirm placement="bottom" title={'删除标签会将其从所有问题中删除。继续?'} okText="Yes" cancelText="No" onConfirm={()=>this.deletetag(item.id)}>
<a className="Closeor_btn fr" >删除</a>
</Popconfirm>
<a onClick={()=>this.editshow(item)} className="Closeor_btn fr" >编辑</a>
</div>
</div>
)
})
@ -106,12 +298,64 @@ class Tags extends Component{
)
}
}
return(
<div className="main">
<div>
<div className="topWrapper">
<Nav {...this.props} {...this.state} />
<Link to={`/projects/${projectsId}/orders/new`} className="topWrapper_btn">新建标签</Link>
<a onClick={this.newshow} className="topWrapper_btn" >创建标签</a>
{/* <Link to={`/projects/${projectsId}/orders/new`} className="topWrapper_btn" >新建标签</Link> */}
</div>
<div style={{display: this.state.display}}>
<Form>
<div className="tagdiv" >
<Form.Item
className="inptwidth"
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请填写标签名字'
}],
})(
<Input placeholder="标签名字"/>
)}
</Form.Item>
<Form.Item
className="inputcount"
>
{getFieldDecorator('description', {
rules: [{
required: true, message: '描述不能为空'
}],
})(
<Input placeholder="描述"/>
)}
</Form.Item>
<div>
<div style={ styles.swatch } onClick={ this.handleClick }>
<div style={ styles.color }>
<p style={{paddingLeft:25}}>{this.state.textcolor}</p>
</div>
</div>
{ this.state.displayColorPicker ? <div style={ styles.popover }>
<div style={ styles.cover } onClick={ this.handleClose }/>
<SketchPicker color={ this.state.color } onChange={ this.handleChange } />
</div> :
null }
</div>
<div className="fr" style={{marginTop:5}}>
<a onClick={this.createtagpost} className="topWrapper_btn fr" >创建标签</a>
<a onClick={this.newclose} className="Closeor_btn fr" >取消</a>
</div>
</div>
</Form>
</div>
<div className="topWrapper">
<span>{ data && data.issue_tags_count }个标签</span>
@ -123,12 +367,39 @@ class Tags extends Component{
</li>
</ul>
</div>
{ renderList() }
{ Paginations }
</div>
<Modal
title="编辑标签"
onCancel={this.handleCancel}
visible={this.state.isShow}
onOk={this.handleok}
mask={true}
width="60%"
>
<div className="dialogdiv">
<Input placeholder="标签名字" className="inptwidth" value={this.state.name} onChange={this.changmodelname}/>
<Input placeholder="描述" className="inputcount" value={this.state.description} onChange={this.changdescription}/>
<div>
<div style={ styles.swatch } onClick={ this.handleClick }>
<div style={ styles.modalcolor }>
<p style={{paddingLeft:25,width:100}}>{this.state.newcolor}</p>
</div>
</div>
{ this.state.displayColorPicker ? <div style={ styles.popover }>
<div style={ styles.cover } onClick={ this.handleClose }/>
<SketchPicker color={ this.state.color } onChange={ this.handleChange } />
</div> :
null }
</div>
</div>
</Modal>
</div>
)
}
}
export default Tags;
const WrappedTags = Form.create({ name: 'tageFrom' })(Tags);
export default WrappedTags;

@ -0,0 +1,231 @@
import React , {Component} from 'react';
import { Link } from 'react-router-dom';
import { Calendar, Select, Radio, Col, Row,Divider,Input,Form} from 'antd';
import Nav from './Nav';
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import reactCSS from 'reactcss'
import axios from 'axios';
import moment from 'moment'
const TextArea = Input.TextArea;
const { Group, Button } = Radio;
class UpdateMilepost extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
value: moment('2017-01-25'),
selectedValue: moment('2020-2-12'),
}
}
componentDidMount=()=>{
this.getmeil();
}
onPanelChange=(time, mode)=>{
this.setState({
value:time
});
}
onSelect=(time)=>{
this.setState({
value:time,
selectedValue: time,
});
}
getmeil=()=>{
const { projectsId } = this.props.match.params;
const { meilid } = this.props.match.params;
const url = `/projects/${projectsId}/versions/${meilid}/edit.json`;
axios.get(url,{
params:{
projectsId,meilid
}
}).then((result)=>{
if(result){
this.setState({
data:result.data,
selectedValue:moment(result.data.effective_date)
})
this.props.form.setFieldsValue({
name:result.data.name,
description:result.data.description
});
}
}).catch((error)=>{
console.log(error);
})
}
submit=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { projectsId } = this.props.match.params;
const { meilid } = this.props.match.params;
const url = `/projects/${projectsId}/versions/${meilid}.json`;
let time=this.state.selectedValue.format("YYYY-MM-DD")
axios.put(url,{
...values,
project_id:projectsId,
id:meilid,
effective_date:time,
status:'open'
}).then(result=>{
}).catch(error=>{
console.log(error);
})
}
})
}
render(){
const { getFieldDecorator } = this.props.form;
const { data } = this.state;
const { projectsId } = this.props.match.params;
return(
<div className="main">
<Form>
<div className="topWrapper">
<Nav {...this.props} {...this.state} />
{/* <a onClick={this.newshow} className="topWrapper_btn" >新建里程碑</a> */}
</div>
<h1 style={{marginLeft:15}}>编辑里程碑</h1>
<h3 style={{marginLeft:15}}>里程碑组织工单合并请求和跟踪进度.</h3>
<Divider/>
<div style={{display:'flex'}}>
<div className="newmilepostleft">
标题
<div>
<Form.Item>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入标题'
}],
})(
<Input placeholder="标题" />
)}
</Form.Item>
</div>
描述
<Form.Item>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入描述内容'
}],
})(
<TextArea placeholder="添加一个可选的扩展描述。。。" style={{height:"300px"}} />
)}
</Form.Item>
</div>
<div className="newmilepostrighe" >
截止日期(可选) <a style={{color:'red'}}>清除</a>
<div>
<Input style={{width:"120px"}} value={this.state.selectedValue && this.state.selectedValue.format('YYYY-MM-DD')}/>
</div>
<div style={{ width: 300, border: '1px solid #d9d9d9', borderRadius: 4 ,marginTop:5}}>
<Calendar
fullscreen={false}
headerRender={({ value, type, onChange, onTypeChange }) => {
const start = 0;
const end = 12;
const monthOptions = [];
const current = value.clone();
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
}
for (let index = start; index < end; index++) {
monthOptions.push(
<Select.Option className="month-item" key={`${index}`}>
{months[index]}
</Select.Option>,
);
}
const month = value.month();
const year = value.year();
const options = [];
for (let i = year - 10; i < year + 10; i += 1) {
options.push(
<Select.Option key={i} value={i} className="year-item">
{i}
</Select.Option>,
);
}
return (
<div style={{ padding: 10 }}>
<div style={{ marginBottom: '10px' }}>Custom header </div>
<Row type="flex" justify="space-between">
<Col>
<Group size="small" onChange={e => onTypeChange(e.target.value)} value={type}>
<Button value="month">Month</Button>
<Button value="year">Year</Button>
</Group>
</Col>
<Col>
<Select
size="small"
dropdownMatchSelectWidth={false}
className="my-year-select"
style={{width:80}}
onChange={newYear => {
const now = value.clone().year(newYear);
onChange(now);
}}
value={String(year)}
>
{options}
</Select>
</Col>
<Col>
<Select
size="small"
dropdownMatchSelectWidth={false}
value={String(month)}
onChange={selectedMonth => {
const newValue = value.clone();
newValue.month(parseInt(selectedMonth, 10));
onChange(newValue);
}}
>
{monthOptions}
</Select>
</Col>
</Row>
</div>
);
}}
onPanelChange={this.onPanelChange}
onSelect={this.onSelect}
/>
</div>
</div>
</div>
<Divider/>
<div className="clearfix mt15" onClick={this.submit}>
<Link to={`/projects/${projectsId}/orders/Milepost`} className="topWrapper_btn fr" >更新里程碑</Link>
</div>
</Form>
</div>
)
}
}
const WrappedUpdatemile = Form.create({ name: 'UpdatemileFrom' })(UpdateMilepost);
export default WrappedUpdatemile;

@ -0,0 +1,199 @@
import React , {Component} from 'react';
import { Link } from 'react-router-dom';
import { Calendar, Select, Radio, Col, Row,Divider,Input,Form} from 'antd';
import Nav from './Nav';
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import reactCSS from 'reactcss'
import axios from 'axios';
import moment from 'moment'
const TextArea = Input.TextArea;
const { Group, Button } = Radio;
class NewMilepost extends Component{
constructor(props){
super(props);
this.state={
data:undefined,
value: moment('2017-01-25'),
selectedValue: moment('2020-2-12'),
}
}
componentDidMount=()=>{
}
onPanelChange=(time, mode)=>{
this.setState({
value:time
});
}
onSelect=(time)=>{
this.setState({
value:time,
selectedValue: time,
});
}
submit=()=>{
this.props.form.validateFieldsAndScroll((err, values) => {
if(!err){
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/versions`;
let time=this.state.selectedValue.format("YYYY-MM-DD")
axios.post(url,{
...values,
project_id:projectsId,
effective_date:time,
status:'open'
}).then(result=>{
}).catch(error=>{
console.log(error);
})
}
})
}
render(){
const { getFieldDecorator } = this.props.form;
const { projectsId } = this.props.match.params;
return(
<div className="main">
<Form>
<div className="topWrapper">
<Nav {...this.props} {...this.state} />
{/* <a onClick={this.newshow} className="topWrapper_btn" >新建里程碑</a> */}
</div>
<h1 style={{marginLeft:15}}>新的里程碑</h1>
<h3 style={{marginLeft:15}}>里程碑组织工单合并请求和跟踪进度.</h3>
<Divider/>
<div style={{display:'flex'}}>
<div className="newmilepostleft">
标题
<div>
<Form.Item>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入标题'
}],
})(
<Input placeholder="标题"/>
)}
</Form.Item>
</div>
描述
<Form.Item>
{getFieldDecorator('description', {
rules: [{
required: true, message: '请输入描述内容'
}],
})(
<TextArea placeholder="添加一个可选的扩展描述。。。" style={{height:"300px"}}/>
)}
</Form.Item>
</div>
<div className="newmilepostrighe" >
截止日期(可选) <a style={{color:'red'}}>清除</a>
<div>
<Input style={{width:"120px"}} value={this.state.selectedValue && this.state.selectedValue.format('YYYY-MM-DD')}/>
</div>
<div style={{ width: 300, border: '1px solid #d9d9d9', borderRadius: 4 ,marginTop:5}}>
<Calendar
fullscreen={false}
headerRender={({ value, type, onChange, onTypeChange }) => {
const start = 0;
const end = 12;
const monthOptions = [];
const current = value.clone();
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i++) {
current.month(i);
months.push(localeData.monthsShort(current));
}
for (let index = start; index < end; index++) {
monthOptions.push(
<Select.Option className="month-item" key={`${index}`}>
{months[index]}
</Select.Option>,
);
}
const month = value.month();
const year = value.year();
const options = [];
for (let i = year - 10; i < year + 10; i += 1) {
options.push(
<Select.Option key={i} value={i} className="year-item">
{i}
</Select.Option>,
);
}
return (
<div style={{ padding: 10 }}>
<div style={{ marginBottom: '10px' }}>Custom header </div>
<Row type="flex" justify="space-between">
<Col>
<Group size="small" onChange={e => onTypeChange(e.target.value)} value={type}>
<Button value="month">Month</Button>
<Button value="year">Year</Button>
</Group>
</Col>
<Col>
<Select
size="small"
dropdownMatchSelectWidth={false}
className="my-year-select"
style={{width:80}}
onChange={newYear => {
const now = value.clone().year(newYear);
onChange(now);
}}
value={String(year)}
>
{options}
</Select>
</Col>
<Col>
<Select
size="small"
dropdownMatchSelectWidth={false}
value={String(month)}
onChange={selectedMonth => {
const newValue = value.clone();
newValue.month(parseInt(selectedMonth, 10));
onChange(newValue);
}}
>
{monthOptions}
</Select>
</Col>
</Row>
</div>
);
}}
onPanelChange={this.onPanelChange}
onSelect={this.onSelect}
/>
</div>
</div>
</div>
<Divider/>
<div className="clearfix mt15" onClick={this.submit}>
<Link to={`/projects/${projectsId}/orders/Milepost`} className="topWrapper_btn fr" >创建里程碑</Link>
</div>
</Form>
</div>
)
}
}
const WrappedNewMile = Form.create({ name: 'NewMilepostFrom' })(NewMilepost);
export default WrappedNewMile;

@ -8,7 +8,58 @@
}
.topWrapper_nav{
display: flex;
}
.detail_p{
display: flex;
width: 80%;
padding-left: 15px;
margin: auto;
}
.commit_p{
font-size: 12px;
padding-top: 10px;
padding-left: 5px;
}
.ul_width{
width: 100%;
}
.Closeor_btn{
border:1px solid red;
color: red;
height: 32px;
text-align: center;
border-radius:4px;
padding:0px 12px;
margin-right: 15px;
margin-right: 15px;
text-align: center;
line-height: 32px;
}
.rectangle {
width: 8px;
height: 8px;
border-radius: 100%;
margin-top: 15px;
margin-left: -4px;
margin-bottom: 10px;
background: green;
}
.order_line{
display: flex;
height: 32px;
margin: auto;
border-left:1px solid green;
}
.comment_img{
height: 25px;
width: 25px;
margin-top: 5px;
border-radius: 100%;
}
.topWrapper_nav a,.topWrapper_nav span{
border:1px solid #f4f4f4;
border-radius: 5px 0px 0px 5px;
@ -150,6 +201,75 @@
margin-bottom: 0px;
}
/*编辑工单*/
.editingsheet{
background: #ffffff;
color: #21ba45!important;
padding:0px 12px;
text-align: center;
height: 32px;
line-height: 32px;
}
.commenttitle{
color: #21ba45!important;
}
.topWrapper_detali{
display: flex;
height: 35px;
background-color: #4CACFF;
}
.towwrapper_img_detali{
display: flex;
padding-left: 80px;
margin-left: 80px;
margin-right: 20px;
border: 1px solid #4CACFF;
}
.div_line{
width: 100%;
border: 1px solid #4CACFF;
}
.list_img{
height: 145px;
padding: 15px;
width: 145px;
}
.detail_context {
flex: 1;
border: 1px solid #dededf;
margin-left: 15px;
padding-top: 0px;
padding-left: 0px;
margin-right: 15px;
position: relative;
background: #FFFFFF;
}
.detail_context:before {
position: absolute;
content: "";
height: 0;
width: 0;
border: solid transparent;
border-right-color: #dededf;
border-width: 9px;
top: 12px;
right: 100%;
}
.detail_context::after {
position: absolute;
content: "";
height: 0;
width: 0;
border: solid transparent;
border-right-color: #fff;
border-width: 7px;
top: 14px;
right: 100%;
}
/* 工单标签列表 */
.tagList > div{
border-bottom: 1px dashed #f4f4f4;
@ -157,6 +277,17 @@
justify-content: space-around;
padding:15px 0px;
}
.divwidth{
width: 80%;
}
.listTowItems{
width: 80%;
padding-left: 80px;
}
.detail_ptitlecount{
padding: 15px;
}
.tagList > div:last-child{
border-bottom: none;
}
@ -173,6 +304,45 @@
border-radius: 4px;
margin-right: 5px;
}
/*里程碑*/
.milepostdiv{
display: flex;
}
.milepostwidth{
display: flex;
width: 60%;
}
.mileposwidth{
background: #21ba45;
border-radius: 4px;
width: 40%;
}
.milepostrighe{
display: flex;
width: 85%;
}
.milepostleft{
text-align: right;
display: flex;
justify-content: right;
width: 15%;
}
.textwidth{
display: flex;
width: 100%;
}
.newmilepostleft{
padding: 15px;
margin-right: 50px;
width: 60%;
}
.newmilepostrighe{
margin-left: 50px;
padding: 15px;
width: 30%;
}
/* 工单详情 */
.detailContent{
padding:15px 0px;
@ -187,12 +357,40 @@
height: 30px;
line-height:30px;
}
.inptwidth{
width: 20%;
}
.inputcount{
width: 40%;
}
.tagdiv{
padding: 15px;
height: 70px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
border: 1px solid #EEEEEE;
flex-wrap: wrap;
}
.dialogdiv{
padding: 5px;
height: 45px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.DetailRight > p >span:nth-child(1){
min-width: 90px;
margin-right: 15px;
text-align: right;
}
@media screen and (max-width: 700px){
.topWrapper_select li{
width:auto;

@ -0,0 +1,14 @@
import React , { Component } from 'react';
import { Link } from 'react-router-dom';
class VersionItem extends Component{
render(){
return(
<div>
1111111111
</div>
)
}
}
export default VersionItem;

@ -0,0 +1,187 @@
import React , { Component } from "react";
import {Link} from 'react-router-dom';
import { Input ,Dropdown , Menu , Icon , Pagination , Spin } from 'antd';
import NoneData from '../../modules/courses/coursesPublic/NoneData';
import Nav from '../Order/Nav';
import VersionItem from './VersionItem';
import axios from 'axios';
const Search = Input.Search;
/**
* issue_chosen:下拉的筛选列表,
* data:列表接口返回的所有数据,
* issues:列表数组,
* isSpin:加载中,
* search:搜索关键字,
* author_id:发布者id,
* assigned_to_id:指派给的id
* limit:每页条数,
* page:当前页,
* search_count:列表总条数
* issue_type:搜索条件
*/
class version extends Component{
constructor(props){
super(props);
this.state={
issue_chosen:undefined,
data:undefined,
issues:undefined,
isSpin:false,
search:undefined,
author_id:undefined,
assigned_to_id:undefined,
limit:15,
page:1,
search_count:undefined,
issue_type:undefined
}
}
componentDidMount=()=>{
this.getSelectList();
this.getIssueList();
}
getSelectList=()=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/issues/index_chosen.json`;
axios.get(url).then((result)=>{
if(result){
this.setState({
issue_chosen:result.data.issue_chosen
})
}
}).catch((error)=>{
console.log(error);
})
}
// 获取列表数据
getIssueList=(page,limit,search,author_id,assigned_to_id,id,value)=>{
const { projectsId } = this.props.match.params;
const url = `/projects/${projectsId}/issues.json`;
axios.get(url,{
params:{
page,limit,search,author_id,assigned_to_id,
[id]:value
}
}).then((result)=>{
if(result){
this.setState({
data:result.data,
issues:result.data.issues,
search_count:result.data.search_count,
isSpin:false
})
}
}).catch((error)=>{
console.log(error);
})
}
getOption=(e,id)=>{
this.setState({
[id]:e.key
})
const { page,limit,search,author_id,assigned_to_id } = this.state;
this.getIssueList(page,limit,search,author_id,assigned_to_id,id,e.key);
}
renderMenu =(array,name,id)=>{
return(
<Menu>
<Menu.Item key={undefined} onClick={(e)=>this.getOption(e,id)}>{name}</Menu.Item>
{
array && array.length > 0 && array.map((item,key)=>{
return(
<Menu.Item key={item.id} onClick={(e)=>this.getOption(e,id)}>{item.name}</Menu.Item>
)
})
}
</Menu>
)
}
// 翻页
ChangePage=(page)=>{
this.setState({
page,
isSpin:true
})
const {limit,search} = this.state;
this.getIssueList(page,limit,search);
}
// 搜索
searchFunc=(value)=>{
this.setState({
search:value,
isSpin:true
})
const {page,limit} = this.state;
this.getIssueList(page,limit,value);
}
// 筛选:全部、指派给我、由我创建
ChangeAssign=(type)=>{
const { limit, search} = this.state;
this.setState({
isSpin:true
})
if(type){
const { current_user } = this.props;
if(type===1){
this.setState({
page:1,
author_id:current_user.user_id,
assigned_to_id:undefined
})
this.getIssueList(1,limit,search,current_user.user_id,undefined);
}else{
this.setState({
page:1,
author_id:undefined,
assigned_to_id:current_user.user_id
})
this.getIssueList(1,limit,search,undefined,current_user.user_id);
}
}else{
this.setState({
page:1,
author_id:undefined,
assigned_to_id:undefined
})
this.getIssueList(1,limit,search,undefined,undefined);
}
}
render(){
const { projectsId } = this.props.match.params;
return(
<div className="main">
<div className="topWrapper">
<h1>版本发布</h1>
<Link to={`/projects/${projectsId}/orders/new`} className="topWrapper_btn">发布新版</Link>
</div>
<div>
1
1
1
1
1
{VersionItem}
</div>
</div>
)
}
}
export default version;
Loading…
Cancel
Save