change req data, date show, styles

VRTKSSUP-229
Осьмаков Денис 5 years ago
parent c6ed7fc57e
commit 0efb9f66e4
  1. 87
      package-lock.json
  2. 5
      package.json
  3. 3
      src/webparts/summaryWebPart/SummaryWebPartWebPart.manifest.json
  4. 12
      src/webparts/summaryWebPart/SummaryWebPartWebPart.ts
  5. 1
      src/webparts/summaryWebPart/components/ISummaryWebPartProps.ts
  6. 161
      src/webparts/summaryWebPart/components/SummaryContainer/SummaryContainer.tsx
  7. 8
      src/webparts/summaryWebPart/components/SummaryGlobalComponent/SummaryGlobalComponent.module.scss
  8. 23
      src/webparts/summaryWebPart/components/SummaryGlobalComponent/SummaryGlobalComponent.tsx
  9. 30
      src/webparts/summaryWebPart/components/SummaryWebPart.tsx
  10. 32
      src/webparts/summaryWebPart/components/TrafficLight/TrafficLight.tsx

87
package-lock.json generated

@ -347,6 +347,11 @@
"superagent": "^3.5.2" "superagent": "^3.5.2"
} }
}, },
"@microsoft/microsoft-graph-types": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@microsoft/microsoft-graph-types/-/microsoft-graph-types-1.7.0.tgz",
"integrity": "sha512-Mxu5H+69F8T5NzV4+U8FkTvpIYYWHsmRZzfAuOlIO0zJJGlVyRIVqpq4NmOdUXGC00vZ73ONgCuzuaksxqDm/Q=="
},
"@microsoft/node-core-library": { "@microsoft/node-core-library": {
"version": "0.3.16", "version": "0.3.16",
"resolved": "https://registry.npmjs.org/@microsoft/node-core-library/-/node-core-library-0.3.16.tgz", "resolved": "https://registry.npmjs.org/@microsoft/node-core-library/-/node-core-library-0.3.16.tgz",
@ -1123,6 +1128,88 @@
} }
} }
}, },
"@pnp/common": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/@pnp/common/-/common-1.3.8.tgz",
"integrity": "sha512-VYdShvkeOeOzXB3Lg/BqS+0WaHFSCd4n/8huBt7b63ormLLBrHX9aFRy457GiqHbnfEflHNBsVfwPj11z5wktg==",
"requires": {
"adal-angular": "1.0.17",
"tslib": "1.10.0"
},
"dependencies": {
"adal-angular": {
"version": "1.0.17",
"resolved": "https://registry.npmjs.org/adal-angular/-/adal-angular-1.0.17.tgz",
"integrity": "sha1-bpNuDkH5HTsqiOf/ypwvb29WLMQ="
},
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}
}
},
"@pnp/graph": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/@pnp/graph/-/graph-1.3.8.tgz",
"integrity": "sha512-uBBDrpWNILGBfTxtHqFrdv3YkJZm+jgXOLBp3KR8ocBrTt+yQmkCEwztawYqUhSys6SoDkcFE/DqLIjhyHiBDA==",
"requires": {
"@microsoft/microsoft-graph-types": "1.7.0",
"tslib": "1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}
}
},
"@pnp/logging": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/@pnp/logging/-/logging-1.3.8.tgz",
"integrity": "sha512-5uA+03Q9TCigpf3yJqqms0BCDzvm8Ko0bmX1TM4hjNGh2MEqE3OlQ99uPSz4jQGmEQ/93ReGvzD5S+JL9qd8EA==",
"requires": {
"tslib": "1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}
}
},
"@pnp/odata": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/@pnp/odata/-/odata-1.3.8.tgz",
"integrity": "sha512-uGcV+Dx59W/yO6xOlMoObF8IYWZJnUqCsbuH/KI4BQ+izcPXi4N2tnj2i2OOEso0dobduoADR8q8XK7+SpXjOQ==",
"requires": {
"tslib": "1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}
}
},
"@pnp/sp": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/@pnp/sp/-/sp-1.3.8.tgz",
"integrity": "sha512-x85cQL/L5fBYJWqWvDL3e2sHdYZIqUeWifFndsGRk6iLFHTq2DsxNNzTnCpP7JCKUwK6jHpu0JzIuK98E8Hl9w==",
"requires": {
"tslib": "1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
}
}
},
"@types/adal": { "@types/adal": {
"version": "1.0.27", "version": "1.0.27",
"resolved": "https://registry.npmjs.org/@types/adal/-/adal-1.0.27.tgz", "resolved": "https://registry.npmjs.org/@types/adal/-/adal-1.0.27.tgz",

@ -16,6 +16,11 @@
"@microsoft/sp-lodash-subset": "~1.4.0", "@microsoft/sp-lodash-subset": "~1.4.0",
"@microsoft/sp-office-ui-fabric-core": "~1.4.0", "@microsoft/sp-office-ui-fabric-core": "~1.4.0",
"@microsoft/sp-webpart-base": "~1.4.0", "@microsoft/sp-webpart-base": "~1.4.0",
"@pnp/common": "^1.3.8",
"@pnp/graph": "^1.3.8",
"@pnp/logging": "^1.3.8",
"@pnp/odata": "^1.3.8",
"@pnp/sp": "^1.3.8",
"@types/es6-promise": "0.0.33", "@types/es6-promise": "0.0.33",
"@types/react": "15.6.6", "@types/react": "15.6.6",
"@types/react-dom": "15.5.6", "@types/react-dom": "15.5.6",

@ -21,7 +21,8 @@
"officeFabricIconFontName": "Page", "officeFabricIconFontName": "Page",
"properties": { "properties": {
"description": "Сводка", "description": "Сводка",
"requestUrl": "http://logics.portal.vertex.spb.ru/api/Project/GetSummaryProject?projCode=" "requestUrl": "http://logics.portal.vertex.spb.ru/api/Project/GetSummaryProject?projCode=",
"rowsOrder": "Manager_Project; Status_Project; Code_project; pmis_ProjectPortfolio; Type_Project; Objective_Project; Tasks_Project; Customer_Project; Curator_Project; Coordinator_Project"
} }
}] }]
} }

@ -14,6 +14,7 @@ import { ISummaryWebPartProps } from './components/ISummaryWebPartProps';
export interface ISummaryWebPartWebPartProps { export interface ISummaryWebPartWebPartProps {
description: string; description: string;
requestUrl: string; requestUrl: string;
rowsOrder: string;
context: any; context: any;
} }
@ -25,7 +26,8 @@ export default class SummaryWebPartWebPart extends BaseClientSideWebPart<ISummar
{ {
description: this.properties.description, description: this.properties.description,
requestUrl: this.properties.requestUrl ? this.properties.requestUrl : 'http://logics.portal.vertex.spb.ru/api/Project/GetSummaryProject?projCode=', requestUrl: this.properties.requestUrl ? this.properties.requestUrl : 'http://logics.portal.vertex.spb.ru/api/Project/GetSummaryProject?projCode=',
context: this.context context: this.context,
rowsOrder: this.properties.rowsOrder
} }
); );
@ -55,6 +57,14 @@ export default class SummaryWebPartWebPart extends BaseClientSideWebPart<ISummar
label: 'URL' label: 'URL'
}) })
] ]
},
{
groupName: 'Отображение и порядок строк',
groupFields: [
PropertyPaneTextField('rowsOrder', {
label: "Строки(разделитель - ';')"
})
]
} }
], ],

@ -2,4 +2,5 @@ export interface ISummaryWebPartProps {
description: string; description: string;
requestUrl: string; requestUrl: string;
context: any; context: any;
rowsOrder: string;
} }

@ -1,10 +1,18 @@
import * as React from 'react'; import * as React from 'react';
import { ISummaryProjectData } from '../../interfaces/ISummaryProjectData'; import { ISummaryProjectData } from '../../interfaces/ISummaryProjectData';
import { DetailsList, SelectionMode, DetailsListLayoutMode } from 'office-ui-fabric-react/lib/DetailsList'; import {
DetailsList,
SelectionMode,
DetailsListLayoutMode,
ConstrainMode,
DetailsRow
} from "office-ui-fabric-react/lib/DetailsList";
import { values } from '@uifabric/utilities/lib'; import { values } from '@uifabric/utilities/lib';
import { sp, Web, Field } from "@pnp/sp";
export interface IComponentProps{ export interface IComponentProps {
projectInfo: ISummaryProjectData order: string;
context: any;
} }
export interface IComponentState { export interface IComponentState {
@ -16,108 +24,99 @@ export interface IComponentState {
} }
export default class SummaryContainer extends React.Component<IComponentProps, IComponentState> { export default class SummaryContainer extends React.Component<IComponentProps,IComponentState> {
public state = { public state = {
items: null items: []
}; };
componentDidMount(){ componentDidMount() {
const {projectInfo} =this.props; const { order, context } = this.props;
let missCount = 0; let relUrl = context.pageContext.web.serverRelativeUrl;
let rows = [ let prjCode = relUrl ? relUrl.split("/")[relUrl.split("/").length - 1] : "";
{
key: 1, let web = new Web("http://portal.vertex.spb.ru/PMIS");
fieldName: 'Руководитель проекта', let webMDM = new Web("http://portal.vertex.spb.ru/sites/mdm");
value: projectInfo.chief, let dispItems = webMDM.lists.getById("35b69b82-eb54-46fb-a8b4-2c763b11e10f").items.select("Title, Order0").get();
}, let fields = web.lists.getById("eeba7db6-4c28-41a2-a54e-82a2aaf0ca15").fields.get();
{
key: 2, Promise.all([dispItems, fields]).then(result=>{
fieldName: 'Статус', let sortedDispItems = result[0].sort((a, b) => a.Order0 - b.Order0);
value: projectInfo.status, let allFields = result[1];
}, return sortedDispItems.map(dispItem => {
{ let item = allFields.filter(e => dispItem.Title == e.StaticName);
key: 3, return {
fieldName: 'Код проекта', key: dispItem.Order0,
value: projectInfo.code, fieldName: item[0].LookupField
}, ? `${dispItem.Title}/Title`
{ : dispItem.Title,
key: 4, fieldRuTitle: item[0].Title,
fieldName: 'Портфель проектов', LookupField: item[0].LookupField ? dispItem.Title : ""
value: projectInfo.portfolio, };
},
{
key: 5,
fieldName: 'Программа проектов',
value: projectInfo.programm,
},
{
key: 6,
fieldName: 'Тип проекта',
value: projectInfo.type,
},
{
key: 7,
fieldName: 'Цель проекта',
value: projectInfo.target,
},
{
key: 8,
fieldName: 'Задачи проекта',
value: projectInfo.task,
},
{
key: 9,
fieldName: 'Заказчик проекта',
value: projectInfo.customer,
},
{
key: 10,
fieldName: 'Куратор проекта',
value: projectInfo.curator,
},
{
key: 11,
fieldName: 'Координатор проекта',
value: projectInfo.coordinator,
},
].filter(e=>{
return e.value !== ""
}); });
}).then(res=>{
let selectedFields = res.map(e=>e.fieldName).join(', ');
let lookupFields = res.filter(e=> e.LookupField !== "").map(e=>e.LookupField).join(', ');
this.setState({items: rows}); let toState = [];
web.lists
.getById("eeba7db6-4c28-41a2-a54e-82a2aaf0ca15")
.items.filter(
"Code_project eq '" + prjCode + "'"
)
.select(selectedFields)
.expand(lookupFields)
.get()
.then(currentProject => {
res.forEach(e=>{
let fieldValue = !e.fieldName.match(/\/Title/gi)?currentProject[0][e.fieldName] : currentProject[0][e.fieldName.split('/')[0]]? currentProject[0][e.fieldName.split('/')[0]]['Title'] : ''
if (fieldValue){
toState.push({
key: e.key,
fieldName: e.fieldRuTitle,
value: fieldValue
});
}
});
this.setState({ items: toState });
});
})
} }
public columns = [ public columns = [
{ {
key: 'column1', key: "column1",
name: 'Название', name: "Название",
fieldName: 'fieldName', fieldName: "fieldName",
minWidth: 16, minWidth: 16,
maxWidth: 150 maxWidth: 150,
canResizeColumns: true,
isMultiline: true
}, },
{ {
key: 'column2', key: "column2",
name: 'Значение', name: "Значение",
fieldName: 'value', fieldName: "value",
minWidth: 16, minWidth: 16,
maxWidth: 100 canResizeColumns: true,
}, isMultiline: true
] }
];
public render(): React.ReactElement<IComponentProps> { public render(): React.ReactElement<IComponentProps> {
const {items} = this.state; const { items } = this.state;
return ( return (
<div> <div>
<DetailsList <DetailsList
setKey="items"
items={items} items={items}
columns={this.columns} columns={this.columns}
compact={true} compact={true}
isHeaderVisible={false} isHeaderVisible={false}
selectionMode={SelectionMode.none}
layoutMode={DetailsListLayoutMode.justified} layoutMode={DetailsListLayoutMode.justified}
selectionMode={SelectionMode.none}
constrainMode={ConstrainMode.horizontalConstrained}
/> />
</div> </div>
); );
} }
} }

@ -3,9 +3,11 @@
grid-template-columns: 34% 34% 30%; grid-template-columns: 34% 34% 30%;
column-gap: 30px; column-gap: 30px;
.SummaryPageRowOne{ .SummaryPageRowOne{
display: grid; display: flex;
grid-template-rows: 1fr 1fr; flex-direction: column;
column-gap: 30px; canvas{
height: 100% !important;
}
} }
.SummaryPageRowTwo{ .SummaryPageRowTwo{
width: 100%; width: 100%;

@ -7,26 +7,35 @@ import Structure from '../Structure/Structure';
import { IPageData } from '../../interfaces/IPageData'; import { IPageData } from '../../interfaces/IPageData';
export interface IComponentProps{ export interface IComponentProps {
data: IPageData data: IPageData;
rowsOrder: string;
context: any
} }
export default class SummaryGlobalComponent extends React.Component<IComponentProps, {}> { export default class SummaryGlobalComponent extends React.Component<IComponentProps, {}> {
public render(): React.ReactElement<IComponentProps> { public render(): React.ReactElement<IComponentProps> {
const { data } = this.props; const { data, rowsOrder, context } = this.props;
return ( return (
<div className={styles.SummaryPageContainer}> <div className={styles.SummaryPageContainer}>
<SummaryContainer projectInfo={data.PrjInfo} /> <SummaryContainer
order={rowsOrder}
context={context}
/>
<div className={styles.SummaryPageRowOne}> <div className={styles.SummaryPageRowOne}>
<TrafficLight statuses={data.Status} taskStats={data.TaskStats} dateInfo={data.HighLvlPrjInfo}/> <TrafficLight
<TaskStatusesChart taskStats={data.TaskStats}/> statuses={data.Status}
taskStats={data.TaskStats}
dateInfo={data.HighLvlPrjInfo}
/>
<TaskStatusesChart taskStats={data.TaskStats} />
</div> </div>
<Structure structureData={data.MainExec}/> <Structure structureData={data.MainExec} />
</div> </div>
); );
} }

@ -23,7 +23,7 @@ export default class SummaryWebPart extends React.Component<ISummaryWebPartProps
let relUrl = context.pageContext.web.serverRelativeUrl let relUrl = context.pageContext.web.serverRelativeUrl
let projectCode = relUrl ? relUrl.split('/')[relUrl.split('/').length - 1] : ''; let projectCode = relUrl ? relUrl.split('/')[relUrl.split('/').length - 1] : '';
fetch(requestUrl + projectCode) fetch(requestUrl + /* 'test01_test02_001' */projectCode)
.then((response)=>{ .then((response)=>{
return response.json() return response.json()
}).then(result=>{ }).then(result=>{
@ -38,12 +38,28 @@ export default class SummaryWebPart extends React.Component<ISummaryWebPartProps
public render(): React.ReactElement<ISummaryWebPartProps> { public render(): React.ReactElement<ISummaryWebPartProps> {
const { pageData, isLoaded, isBlank } = this.state; const { pageData, isLoaded, isBlank } = this.state;
return (isLoaded ? return isLoaded ? (
<div style={{display: 'flex', flexDirection: 'column'}}> <div style={{ display: "flex", flexDirection: "column" }}>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}><PrimaryButton text="Изменение карточки проекта" onClick={this.relocate} /></div> <div style={{ display: "flex", justifyContent: "flex-end" }}>
<SummaryGlobalComponent data={pageData} /> <PrimaryButton
text="Изменение карточки проекта"
onClick={this.relocate}
/>
</div> </div>
: <SummaryGlobalComponent
isBlank ? <div></div> : <Spinner label="Подождите, идёт загрузка" ariaLive="assertive" size={SpinnerSize.large} />) data={pageData}
rowsOrder={this.props.rowsOrder}
context={this.props.context}
/>
</div>
) : isBlank ? (
<div></div>
) : (
<Spinner
label="Подождите, идёт загрузка"
ariaLive="assertive"
size={SpinnerSize.large}
/>
);
} }
} }

@ -1,6 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import styles from '../SummaryGlobalComponent/SummaryGlobalComponent.module.scss' import styles from '../SummaryGlobalComponent/SummaryGlobalComponent.module.scss'
import Moment from "react-moment";
import moment from "moment/min/moment-with-locales"; import moment from "moment/min/moment-with-locales";
import { DetailsList, SelectionMode, DetailsListLayoutMode } from 'office-ui-fabric-react/lib/DetailsList'; import { DetailsList, SelectionMode, DetailsListLayoutMode } from 'office-ui-fabric-react/lib/DetailsList';
@ -30,15 +29,15 @@ export default class TrafficLight extends React.Component<IComponentProps, {}> {
const { statuses, taskStats, dateInfo} = this.props; const { statuses, taskStats, dateInfo} = this.props;
let procent = (taskStats.compl/(taskStats.plan + taskStats.compl + taskStats.exec))* 100; let procent = (taskStats.compl/(taskStats.plan + taskStats.compl + taskStats.exec))* 100;
let startDate = moment(dateInfo.dateStart).format("DD.MM.YY"); let startDate = moment(dateInfo.dateStart).format("DD.MM.YYYY");
let finDate = moment(dateInfo.dateFinish).format("DD.MM.YY"); let finDate = moment(dateInfo.dateFinish).format("DD.MM.YYYY");
let totalDays = new moment.duration((new Date(dateInfo.dateFinish) as any) -(new Date(dateInfo.dateStart) as any)).asDays(); let totalDays = new moment.duration((new Date(dateInfo.dateFinish ? dateInfo.dateFinish.split('T')[0] : dateInfo.dateFinish) as any) - (new Date(dateInfo.dateStart ? dateInfo.dateStart.split('T')[0] : dateInfo.dateStart) as any)).asDays();
return ( return (
<div className={styles.statusesContainer}> <div className={styles.statusesContainer}>
<DetailsList <DetailsList
onRenderItemColumn={this.renderItemColumn} onRenderItemColumn={this.renderItemColumn}
items={[ items= {statuses.budget !== 'none'?[
{ {
key: 1, key: 1,
fieldName: "Статус по сроку", fieldName: "Статус по сроку",
@ -54,7 +53,20 @@ export default class TrafficLight extends React.Component<IComponentProps, {}> {
fieldName: "Статус по % выполнения", fieldName: "Статус по % выполнения",
status: statuses.percCompl status: statuses.percCompl
} }
]} ] :
[
{
key: 1,
fieldName: "Статус по сроку",
status: statuses.term
},
{
key: 2,
fieldName: "Статус по % выполнения",
status: statuses.percCompl
}
]
}
columns={[ columns={[
{ {
key: "column1", key: "column1",
@ -79,9 +91,9 @@ export default class TrafficLight extends React.Component<IComponentProps, {}> {
items={[ items={[
{ {
key: 1, key: 1,
start: startDate, start: startDate !== 'Invalid date' ? startDate : '',
end: finDate, end: finDate !== 'Invalid date' ? finDate : '',
time: totalDays, time: totalDays ? totalDays : '',
allTasks: taskStats.plan + taskStats.compl + taskStats.exec allTasks: taskStats.plan + taskStats.compl + taskStats.exec
} }
]} ]}
@ -127,7 +139,7 @@ export default class TrafficLight extends React.Component<IComponentProps, {}> {
marginTop: 15, marginTop: 15,
marginBottom: 15 marginBottom: 15
}} }}
>{`Актуальный статус выполнения ${procent.toFixed(2)}%`}</div> >{`Актуальный статус выполнения ${!isNaN(+procent.toFixed(2)) ? procent.toFixed(2) + '%' : ' -' }`}</div>
</div> </div>
); );
} }

Loading…
Cancel
Save