commit
5a65bde216
35 changed files with 18131 additions and 0 deletions
@ -0,0 +1,25 @@ |
||||
# EditorConfig helps developers define and maintain consistent |
||||
# coding styles between different editors and IDEs |
||||
# editorconfig.org |
||||
|
||||
root = true |
||||
|
||||
|
||||
[*] |
||||
|
||||
# change these settings to your own preference |
||||
indent_style = space |
||||
indent_size = 2 |
||||
|
||||
# we recommend you to keep these unchanged |
||||
end_of_line = lf |
||||
charset = utf-8 |
||||
trim_trailing_whitespace = true |
||||
insert_final_newline = true |
||||
|
||||
[*.md] |
||||
trim_trailing_whitespace = false |
||||
|
||||
[{package,bower}.json] |
||||
indent_style = space |
||||
indent_size = 2 |
@ -0,0 +1,32 @@ |
||||
# Logs |
||||
logs |
||||
*.log |
||||
npm-debug.log* |
||||
|
||||
# Dependency directories |
||||
node_modules |
||||
|
||||
# Build generated files |
||||
dist |
||||
lib |
||||
solution |
||||
temp |
||||
*.sppkg |
||||
|
||||
# Coverage directory used by tools like istanbul |
||||
coverage |
||||
|
||||
# OSX |
||||
.DS_Store |
||||
|
||||
# Visual Studio files |
||||
.ntvs_analysis.dat |
||||
.vs |
||||
bin |
||||
obj |
||||
|
||||
# Resx Generated Code |
||||
*.resx.ts |
||||
|
||||
# Styles Generated Code |
||||
*.scss.ts |
@ -0,0 +1,5 @@ |
||||
{ |
||||
"recommendations": [ |
||||
"msjsdiag.debugger-for-chrome" |
||||
] |
||||
} |
@ -0,0 +1,43 @@ |
||||
{ |
||||
/** |
||||
* Install Chrome Debugger Extension for Visual Studio Code to debug your components with the |
||||
* Chrome browser: https://aka.ms/spfx-debugger-extensions |
||||
*/ |
||||
"version": "0.2.0", |
||||
"configurations": [{ |
||||
"name": "Local workbench", |
||||
"type": "chrome", |
||||
"request": "launch", |
||||
"url": "https://localhost:4321/temp/workbench.html", |
||||
"webRoot": "${workspaceRoot}", |
||||
"sourceMaps": true, |
||||
"sourceMapPathOverrides": { |
||||
"webpack:///.././src/*": "${webRoot}/src/*", |
||||
"webpack:///../../../src/*": "${webRoot}/src/*", |
||||
"webpack:///../../../../src/*": "${webRoot}/src/*", |
||||
"webpack:///../../../../../src/*": "${webRoot}/src/*" |
||||
}, |
||||
"runtimeArgs": [ |
||||
"--remote-debugging-port=9222" |
||||
] |
||||
}, |
||||
{ |
||||
"name": "Hosted workbench", |
||||
"type": "chrome", |
||||
"request": "launch", |
||||
"url": "https://enter-your-SharePoint-site/_layouts/workbench.aspx", |
||||
"webRoot": "${workspaceRoot}", |
||||
"sourceMaps": true, |
||||
"sourceMapPathOverrides": { |
||||
"webpack:///.././src/*": "${webRoot}/src/*", |
||||
"webpack:///../../../src/*": "${webRoot}/src/*", |
||||
"webpack:///../../../../src/*": "${webRoot}/src/*", |
||||
"webpack:///../../../../../src/*": "${webRoot}/src/*" |
||||
}, |
||||
"runtimeArgs": [ |
||||
"--remote-debugging-port=9222", |
||||
"-incognito" |
||||
] |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,13 @@ |
||||
// Place your settings in this file to overwrite default and user settings. |
||||
{ |
||||
// Configure glob patterns for excluding files and folders in the file explorer. |
||||
"files.exclude": { |
||||
"**/.git": true, |
||||
"**/.DS_Store": true, |
||||
"**/bower_components": true, |
||||
"**/coverage": true, |
||||
"**/lib-amd": true, |
||||
"src/**/*.scss.ts": true |
||||
}, |
||||
"typescript.tsdk": ".\\node_modules\\typescript\\lib" |
||||
} |
@ -0,0 +1,11 @@ |
||||
{ |
||||
"@microsoft/generator-sharepoint": { |
||||
"isCreatingSolution": true, |
||||
"environment": "onprem19", |
||||
"version": "1.9.1", |
||||
"libraryName": "summary-web-part", |
||||
"libraryId": "08d4adf3-23e8-426b-b19c-afe95c0a61a4", |
||||
"packageManager": "npm", |
||||
"componentType": "webpart" |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
## summary-web-part |
||||
|
||||
This is where you include your WebPart documentation. |
||||
|
||||
### Building the code |
||||
|
||||
```bash |
||||
git clone the repo |
||||
npm i |
||||
npm i -g gulp |
||||
gulp |
||||
``` |
||||
|
||||
This package produces the following: |
||||
|
||||
* lib/* - intermediate-stage commonjs build artifacts |
||||
* dist/* - the bundled script, along with other resources |
||||
* deploy/* - all resources which should be uploaded to a CDN. |
||||
|
||||
### Build options |
||||
|
||||
gulp clean - TODO |
||||
gulp test - TODO |
||||
gulp serve - TODO |
||||
gulp bundle - TODO |
||||
gulp package-solution - TODO |
@ -0,0 +1,18 @@ |
||||
{ |
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json", |
||||
"version": "2.0", |
||||
"bundles": { |
||||
"summary-web-part-web-part": { |
||||
"components": [ |
||||
{ |
||||
"entrypoint": "./lib/webparts/summaryWebPart/SummaryWebPartWebPart.js", |
||||
"manifest": "./src/webparts/summaryWebPart/SummaryWebPartWebPart.manifest.json" |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
"externals": {}, |
||||
"localizedResources": { |
||||
"SummaryWebPartWebPartStrings": "lib/webparts/summaryWebPart/loc/{locale}.js" |
||||
} |
||||
} |
@ -0,0 +1,4 @@ |
||||
{ |
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json", |
||||
"deployCdnPath": "temp/deploy" |
||||
} |
@ -0,0 +1,7 @@ |
||||
{ |
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json", |
||||
"workingDir": "./temp/deploy/", |
||||
"account": "<!-- STORAGE ACCOUNT NAME -->", |
||||
"container": "summary-web-part", |
||||
"accessKey": "<!-- ACCESS KEY -->" |
||||
} |
@ -0,0 +1,13 @@ |
||||
{ |
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json", |
||||
"solution": { |
||||
"name": "summary-web-part-client-side-solution", |
||||
"id": "08d4adf3-23e8-426b-b19c-afe95c0a61a4", |
||||
"version": "1.0.0.0", |
||||
"includeClientSideAssets": true, |
||||
"skipFeatureDeployment": true |
||||
}, |
||||
"paths": { |
||||
"zippedPackage": "solution/summary-web-part.sppkg" |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
{ |
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json", |
||||
"port": 4321, |
||||
"https": true, |
||||
"initialPage": "https://localhost:5432/workbench", |
||||
"api": { |
||||
"port": 5432, |
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/" |
||||
} |
||||
} |
@ -0,0 +1,4 @@ |
||||
{ |
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json", |
||||
"cdnBasePath": "<!-- PATH TO CDN -->" |
||||
} |
@ -0,0 +1,7 @@ |
||||
'use strict'; |
||||
|
||||
const gulp = require('gulp'); |
||||
const build = require('@microsoft/sp-build-web'); |
||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`); |
||||
|
||||
build.initialize(gulp); |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,41 @@ |
||||
{ |
||||
"name": "summary-web-part", |
||||
"version": "0.0.1", |
||||
"private": true, |
||||
"main": "lib/index.js", |
||||
"engines": { |
||||
"node": ">=0.10.0" |
||||
}, |
||||
"scripts": { |
||||
"build": "gulp bundle", |
||||
"clean": "gulp clean", |
||||
"test": "gulp test" |
||||
}, |
||||
"dependencies": { |
||||
"@microsoft/sp-core-library": "~1.4.0", |
||||
"@microsoft/sp-lodash-subset": "~1.4.0", |
||||
"@microsoft/sp-office-ui-fabric-core": "~1.4.0", |
||||
"@microsoft/sp-webpart-base": "~1.4.0", |
||||
"@types/es6-promise": "0.0.33", |
||||
"@types/react": "15.6.6", |
||||
"@types/react-dom": "15.5.6", |
||||
"@types/webpack-env": "1.13.1", |
||||
"chart.js": "^2.9.2", |
||||
"chartjs-plugin-datalabels": "^0.7.0", |
||||
"react": "15.6.2", |
||||
"react-chartjs-2": "^2.8.0", |
||||
"react-dom": "15.6.2" |
||||
}, |
||||
"resolutions": { |
||||
"@types/react": "15.6.6" |
||||
}, |
||||
"devDependencies": { |
||||
"@microsoft/sp-build-web": "~1.4.1", |
||||
"@microsoft/sp-module-interfaces": "~1.4.1", |
||||
"@microsoft/sp-webpart-workbench": "~1.4.1", |
||||
"gulp": "~3.9.1", |
||||
"@types/chai": "3.4.34", |
||||
"@types/mocha": "2.2.38", |
||||
"ajv": "~5.2.2" |
||||
} |
||||
} |
@ -0,0 +1 @@ |
||||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
@ -0,0 +1,27 @@ |
||||
{ |
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json", |
||||
"id": "083aea7b-028e-4853-884d-0f0cac423575", |
||||
"alias": "SummaryWebPartWebPart", |
||||
"componentType": "WebPart", |
||||
|
||||
// The "*" signifies that the version should be taken from the package.json |
||||
"version": "*", |
||||
"manifestVersion": 2, |
||||
|
||||
// If true, the component can only be installed on sites where Custom Script is allowed. |
||||
// Components that allow authors to embed arbitrary script code should set this to true. |
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f |
||||
"requiresCustomScript": false, |
||||
|
||||
"preconfiguredEntries": [{ |
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other |
||||
"group": { "default": "Other" }, |
||||
"title": { "default": "Сводка" }, |
||||
"description": { "default": "Сводка" }, |
||||
"officeFabricIconFontName": "Page", |
||||
"properties": { |
||||
"description": "Сводка", |
||||
"requestUrl": "http://logics.portal.vertex.spb.ru/api/Project/GetSummaryProject?projCode=" |
||||
} |
||||
}] |
||||
} |
@ -0,0 +1,65 @@ |
||||
import * as React from 'react'; |
||||
import * as ReactDom from 'react-dom'; |
||||
import { Version } from '@microsoft/sp-core-library'; |
||||
import { |
||||
BaseClientSideWebPart, |
||||
IPropertyPaneConfiguration, |
||||
PropertyPaneTextField |
||||
} from '@microsoft/sp-webpart-base'; |
||||
|
||||
import * as strings from 'SummaryWebPartWebPartStrings'; |
||||
import SummaryWebPart from './components/SummaryWebPart'; |
||||
import { ISummaryWebPartProps } from './components/ISummaryWebPartProps'; |
||||
|
||||
export interface ISummaryWebPartWebPartProps { |
||||
description: string; |
||||
requestUrl: string; |
||||
context: any; |
||||
} |
||||
|
||||
export default class SummaryWebPartWebPart extends BaseClientSideWebPart<ISummaryWebPartWebPartProps> { |
||||
|
||||
public render(): void { |
||||
const element: React.ReactElement<ISummaryWebPartProps > = React.createElement( |
||||
SummaryWebPart, |
||||
{ |
||||
description: this.properties.description, |
||||
requestUrl: this.properties.requestUrl ? this.properties.requestUrl : 'http://logics.portal.vertex.spb.ru/api/Project/GetSummaryProject?projCode=', |
||||
context: this.context |
||||
} |
||||
); |
||||
|
||||
ReactDom.render(element, this.domElement); |
||||
} |
||||
|
||||
protected onDispose(): void { |
||||
ReactDom.unmountComponentAtNode(this.domElement); |
||||
} |
||||
|
||||
protected get dataVersion(): Version { |
||||
return Version.parse('1.0'); |
||||
} |
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { |
||||
return { |
||||
pages: [ |
||||
{ |
||||
header: { |
||||
description: 'Настройка' |
||||
}, |
||||
groups: [ |
||||
{ |
||||
groupName: 'Адрес запроса', |
||||
groupFields: [ |
||||
PropertyPaneTextField('requestUrl', { |
||||
label: 'URL' |
||||
}) |
||||
] |
||||
} |
||||
], |
||||
|
||||
} |
||||
] |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
export interface ISummaryWebPartProps { |
||||
description: string; |
||||
requestUrl: string; |
||||
context: any; |
||||
} |
@ -0,0 +1,70 @@ |
||||
import * as React from 'react'; |
||||
import styles from '../SummaryGlobalComponent/SummaryGlobalComponent.module.scss' |
||||
import { DetailsList, SelectionMode, DetailsListLayoutMode } from 'office-ui-fabric-react/lib/DetailsList'; |
||||
import { IMainExecItem } from '../../interfaces/IMainExecItem' |
||||
|
||||
export interface IComponentProps { |
||||
structureData: IMainExecItem[] |
||||
} |
||||
|
||||
export interface IComponentState { |
||||
items: { |
||||
key: number; |
||||
name: string; |
||||
department: number | string; |
||||
} [] | null |
||||
} |
||||
|
||||
export interface IComponentState { |
||||
} |
||||
export default class TrafficLight extends React.Component<IComponentProps, IComponentState> { |
||||
public state = { |
||||
items: null |
||||
} |
||||
componentDidMount(){ |
||||
const { structureData } = this.props; |
||||
let rows = []; |
||||
for (let i = 0; i < structureData.length; i++){ |
||||
rows.push({ |
||||
key: i, |
||||
name: structureData[i].name, |
||||
department: structureData[i].unit |
||||
}) |
||||
} |
||||
this.setState({items: rows}); |
||||
} |
||||
|
||||
public onRenderFooter = () =>{ |
||||
|
||||
} |
||||
|
||||
public render(): React.ReactElement<IComponentProps> { |
||||
const { items } = this.state; |
||||
return ( |
||||
<div style={{display: 'flex', flexDirection: 'column'}}> |
||||
<DetailsList |
||||
items={items} |
||||
columns={[ |
||||
{ |
||||
key: 'column1', |
||||
name: 'Название', |
||||
fieldName: 'name', |
||||
minWidth: 16, |
||||
maxWidth: 150 |
||||
}, |
||||
{ |
||||
key: 'column2', |
||||
name: 'Статус', |
||||
fieldName: 'department', |
||||
minWidth: 16, |
||||
maxWidth: 80 |
||||
} |
||||
]} |
||||
compact={true} |
||||
isHeaderVisible={true} |
||||
selectionMode={SelectionMode.none} |
||||
/> |
||||
</div> |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,119 @@ |
||||
import * as React from 'react'; |
||||
import { ISummaryProjectData } from '../../interfaces/ISummaryProjectData'; |
||||
import { DetailsList, SelectionMode, DetailsListLayoutMode } from 'office-ui-fabric-react/lib/DetailsList'; |
||||
|
||||
export interface IComponentProps{ |
||||
projectInfo: ISummaryProjectData |
||||
} |
||||
|
||||
export interface IComponentState { |
||||
items: { |
||||
key: number; |
||||
fieldName: string; |
||||
value: number | string; |
||||
}[] | null |
||||
} |
||||
|
||||
|
||||
export default class SummaryContainer extends React.Component<IComponentProps, IComponentState> { |
||||
public state = { |
||||
items: null |
||||
}; |
||||
|
||||
componentDidMount(){ |
||||
const {projectInfo} =this.props; |
||||
let rows = [ |
||||
{ |
||||
key: 1, |
||||
fieldName: 'Руководитель проекта', |
||||
value: projectInfo.chief, |
||||
}, |
||||
{ |
||||
key: 2, |
||||
fieldName: 'Статус', |
||||
value: projectInfo.status, |
||||
}, |
||||
{ |
||||
key: 3, |
||||
fieldName: 'Код проекта', |
||||
value: projectInfo.code, |
||||
}, |
||||
{ |
||||
key: 4, |
||||
fieldName: 'Портфель проектов', |
||||
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, |
||||
}, |
||||
] |
||||
|
||||
this.setState({items: rows}) |
||||
} |
||||
|
||||
|
||||
public columns = [ |
||||
{ |
||||
key: 'column1', |
||||
name: 'Название', |
||||
fieldName: 'fieldName', |
||||
minWidth: 16, |
||||
maxWidth: 150 |
||||
}, |
||||
{ |
||||
key: 'column2', |
||||
name: 'Значение', |
||||
fieldName: 'value', |
||||
minWidth: 16, |
||||
maxWidth: 100 |
||||
}, |
||||
] |
||||
|
||||
public render(): React.ReactElement<IComponentProps> { |
||||
const {items} = this.state; |
||||
return ( |
||||
<div> |
||||
<DetailsList |
||||
items={items} |
||||
columns={this.columns} |
||||
compact={true} |
||||
isHeaderVisible={false} |
||||
selectionMode={SelectionMode.none} |
||||
layoutMode={DetailsListLayoutMode.justified} |
||||
/> |
||||
</div> |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
.SummaryPageContainer{ |
||||
display: grid; |
||||
grid-template-columns: 34% 34% 30%; |
||||
column-gap: 30px; |
||||
.SummaryPageRowOne{ |
||||
display: grid; |
||||
grid-template-rows: 1fr 1fr; |
||||
column-gap: 30px; |
||||
} |
||||
.SummaryPageRowTwo{ |
||||
width: 100%; |
||||
} |
||||
} |
||||
|
||||
.statusesContainer{ |
||||
display: flex; |
||||
flex-direction: column; |
||||
} |
@ -0,0 +1,32 @@ |
||||
import * as React from 'react'; |
||||
import styles from './SummaryGlobalComponent.module.scss' |
||||
import SummaryContainer from '../SummaryContainer/SummaryContainer'; |
||||
import TrafficLight from '../TrafficLight/TrafficLight'; |
||||
import TaskStatusesChart from '../TaskStatusesChart/TaskStatusesChart'; |
||||
import Structure from '../Structure/Structure'; |
||||
import { IPageData } from '../../interfaces/IPageData'; |
||||
|
||||
|
||||
export interface IComponentProps{ |
||||
data: IPageData |
||||
} |
||||
|
||||
|
||||
|
||||
export default class SummaryGlobalComponent extends React.Component<IComponentProps, {}> { |
||||
public render(): React.ReactElement<IComponentProps> { |
||||
const { data } = this.props; |
||||
return ( |
||||
<div className={styles.SummaryPageContainer}> |
||||
<SummaryContainer projectInfo={data.PrjInfo} /> |
||||
|
||||
<div className={styles.SummaryPageRowOne}> |
||||
<TrafficLight statuses={data.Status} taskStats={data.TaskStats}/> |
||||
<TaskStatusesChart taskStats={data.TaskStats}/> |
||||
</div> |
||||
|
||||
<Structure structureData={data.MainExec}/> |
||||
</div> |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,74 @@ |
||||
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'; |
||||
|
||||
.summaryWebPart { |
||||
.container { |
||||
max-width: 700px; |
||||
margin: 0px auto; |
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1); |
||||
} |
||||
|
||||
.row { |
||||
@include ms-Grid-row; |
||||
@include ms-fontColor-white; |
||||
background-color: $ms-color-themeDark; |
||||
padding: 20px; |
||||
} |
||||
|
||||
.column { |
||||
@include ms-Grid-col; |
||||
@include ms-lg10; |
||||
@include ms-xl8; |
||||
@include ms-xlPush2; |
||||
@include ms-lgPush1; |
||||
} |
||||
|
||||
.title { |
||||
@include ms-font-xl; |
||||
@include ms-fontColor-white; |
||||
} |
||||
|
||||
.subTitle { |
||||
@include ms-font-l; |
||||
@include ms-fontColor-white; |
||||
} |
||||
|
||||
.description { |
||||
@include ms-font-l; |
||||
@include ms-fontColor-white; |
||||
} |
||||
|
||||
.button { |
||||
// Our button |
||||
text-decoration: none; |
||||
height: 32px; |
||||
|
||||
// Primary Button |
||||
min-width: 80px; |
||||
background-color: $ms-color-themePrimary; |
||||
border-color: $ms-color-themePrimary; |
||||
color: $ms-color-white; |
||||
|
||||
// Basic Button |
||||
outline: transparent; |
||||
position: relative; |
||||
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif; |
||||
-webkit-font-smoothing: antialiased; |
||||
font-size: $ms-font-size-m; |
||||
font-weight: $ms-font-weight-regular; |
||||
border-width: 0; |
||||
text-align: center; |
||||
cursor: pointer; |
||||
display: inline-block; |
||||
padding: 0 16px; |
||||
|
||||
.label { |
||||
font-weight: $ms-font-weight-semibold; |
||||
font-size: $ms-font-size-m; |
||||
height: 32px; |
||||
line-height: 32px; |
||||
margin: 0 4px; |
||||
vertical-align: top; |
||||
display: inline-block; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
import * as React from 'react'; |
||||
import { ISummaryWebPartProps } from './ISummaryWebPartProps'; |
||||
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner'; |
||||
import SummaryGlobalComponent from './SummaryGlobalComponent/SummaryGlobalComponent' |
||||
import { IPageData } from '../interfaces/IPageData'; |
||||
|
||||
export interface IComponentState{ |
||||
pageData: IPageData | null |
||||
isLoaded: boolean; |
||||
} |
||||
|
||||
export default class SummaryWebPart extends React.Component<ISummaryWebPartProps, IComponentState > { |
||||
public state = { |
||||
pageData: null, |
||||
isLoaded: false |
||||
} |
||||
|
||||
componentDidMount(){ |
||||
const {requestUrl,context} = this.props; |
||||
let relUrl = context.pageContext.web.serverRelativeUrl |
||||
let projectCode = relUrl ? relUrl.split('/')[relUrl.split('/').length - 1] : ''; |
||||
|
||||
fetch(requestUrl + projectCode) |
||||
.then((response)=>{ |
||||
return response.json() |
||||
}).then(result=>{ |
||||
this.setState({ pageData: result.data, isLoaded: true}) |
||||
}) |
||||
} |
||||
|
||||
public render(): React.ReactElement<ISummaryWebPartProps> { |
||||
const { pageData, isLoaded } = this.state; |
||||
return (isLoaded ? <SummaryGlobalComponent data={pageData} /> : <Spinner label="Подождите, идёт загрузка" ariaLive="assertive" size={SpinnerSize.large} />) |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
import * as React from 'react'; |
||||
import { Bar } from 'react-chartjs-2'; |
||||
import ChartDataLabels from 'chartjs-plugin-datalabels'; |
||||
|
||||
export interface IComponentProps{ |
||||
taskStats: {[key: string]: number;} |
||||
} |
||||
|
||||
|
||||
export default class TaskStatusesChart extends React.Component<IComponentProps, {}> { |
||||
|
||||
public getChartData = () =>{ |
||||
const { taskStats } = this.props; |
||||
return { |
||||
labels: ['Выполняемые', 'Планируемые', 'Завершенные', 'Всего задач'], |
||||
datasets: [ |
||||
{ |
||||
label: '', |
||||
backgroundColor: '#407855', |
||||
borderColor: '#407855', |
||||
borderWidth: 1, |
||||
data: [taskStats.exec, taskStats.plan, taskStats.compl, taskStats.plan + taskStats.compl + taskStats.exec] |
||||
} |
||||
] |
||||
}; |
||||
} |
||||
public render(): React.ReactElement<IComponentProps> { |
||||
const { taskStats } = this.props; |
||||
return ( |
||||
<div> |
||||
<Bar |
||||
data={this.getChartData} |
||||
plugins={ [ChartDataLabels]} |
||||
options={{ |
||||
maintainAspectRatio: false, |
||||
legend: { |
||||
display: false |
||||
}, |
||||
plugins: { |
||||
datalabels: { |
||||
color: '#000', |
||||
font: { |
||||
size: '10', |
||||
}, |
||||
anchor: 'end', |
||||
align: 'top', |
||||
}, |
||||
}, |
||||
title: { |
||||
display: true, |
||||
text: 'Текущие состояние проекта', |
||||
fontSize: 16 |
||||
}, |
||||
scales: { |
||||
yAxes: [{ |
||||
showGrid: false, |
||||
ticks: { |
||||
fontSize: 8, |
||||
suggestedMax: (taskStats.plan + taskStats.compl + taskStats.exec) + 20, |
||||
} |
||||
}], |
||||
xAxes: [{ |
||||
maxBarThickness: 30, |
||||
ticks: { |
||||
fontSize: 8 |
||||
} |
||||
}] |
||||
} |
||||
}} |
||||
/> |
||||
|
||||
</div> |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,114 @@ |
||||
import * as React from 'react'; |
||||
import styles from '../SummaryGlobalComponent/SummaryGlobalComponent.module.scss' |
||||
|
||||
import { DetailsList, SelectionMode, DetailsListLayoutMode } from 'office-ui-fabric-react/lib/DetailsList'; |
||||
|
||||
export interface IComponentProps{ |
||||
statuses: {[key: string]: string;}; |
||||
taskStats: {[key: string]: number;}; |
||||
} |
||||
export default class TrafficLight extends React.Component<IComponentProps, {}> { |
||||
public renderItemColumn = (item, index: number, column) => { |
||||
const fieldContent = item[column.fieldName] as string; |
||||
if (column.key === 'column2'){ |
||||
switch (item.status) { |
||||
case 'warning': |
||||
return <div style={{background: 'yellow', width: '10px', height: '10px', borderRadius: '50%', border: '1px solid #444', marginTop: '2px'}}></div> |
||||
case 'critical': |
||||
return <div style={{ background: 'red', width: '10px', height: '10px', borderRadius: '50%', border: '1px solid #444', marginTop: '2px'}}></div> |
||||
case 'normal': |
||||
return <div style={{ background: 'green', width: '10px', height: '10px', borderRadius: '50%', border: '1px solid #444', marginTop: '2px' }}></div> |
||||
} |
||||
}else{ |
||||
return <span>{fieldContent}</span>; |
||||
} |
||||
} |
||||
public render(): React.ReactElement<IComponentProps> { |
||||
const { statuses, taskStats} = this.props; |
||||
let procent = (taskStats.compl/(taskStats.plan + taskStats.compl + taskStats.exec))* 100; |
||||
|
||||
return ( |
||||
<div className={styles.statusesContainer}> |
||||
<DetailsList |
||||
onRenderItemColumn={this.renderItemColumn} |
||||
items={ |
||||
[ |
||||
{ |
||||
key: 1, |
||||
fieldName: 'Статус по сроку', |
||||
status: statuses.term, |
||||
}, |
||||
{ |
||||
key: 2, |
||||
fieldName: 'Статус по бюджету', |
||||
status: statuses.budget, |
||||
}, |
||||
{ |
||||
key: 3, |
||||
fieldName: 'Статус по % выполнения', |
||||
status: statuses.percCompl, |
||||
}, |
||||
] |
||||
} |
||||
columns={[ |
||||
{ |
||||
key: 'column1', |
||||
name: 'Название', |
||||
fieldName: 'fieldName', |
||||
minWidth: 16, |
||||
maxWidth: 150 |
||||
}, |
||||
{ |
||||
key: 'column2', |
||||
name: 'Статус', |
||||
fieldName: 'status', |
||||
minWidth: 16, |
||||
maxWidth: 80 |
||||
} |
||||
]} |
||||
compact={true} |
||||
isHeaderVisible={false} |
||||
selectionMode={SelectionMode.none} |
||||
/> |
||||
<DetailsList |
||||
items={ |
||||
[ |
||||
{ |
||||
key: 1, |
||||
start: '10.10.10', |
||||
end: '10.10.11', |
||||
time: '10.10.12' |
||||
}, |
||||
] |
||||
} |
||||
columns={[ |
||||
{ |
||||
key: 'column1', |
||||
name: 'Дата начала', |
||||
fieldName: 'start', |
||||
minWidth: 80, |
||||
}, |
||||
{ |
||||
key: 'column2', |
||||
name: 'Дата окончания', |
||||
fieldName: 'end', |
||||
minWidth: 80, |
||||
|
||||
}, |
||||
{ |
||||
key: 'column3', |
||||
name: 'Срок выполнения', |
||||
fieldName: 'time', |
||||
minWidth: 100, |
||||
} |
||||
]} |
||||
compact={true} |
||||
isHeaderVisible={true} |
||||
selectionMode={SelectionMode.none} |
||||
layoutMode={DetailsListLayoutMode.justified} |
||||
/> |
||||
<div style={{ marginLeft: '9', fontSize: '13px' }}>{`Актуальный статус выполнения ${procent.toFixed(2)}%`}</div> |
||||
</div> |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,4 @@ |
||||
export interface IMainExecItem { |
||||
name: string; |
||||
unit: string; |
||||
} |
@ -0,0 +1,9 @@ |
||||
import {ISummaryProjectData} from './ISummaryProjectData' |
||||
import { IMainExecItem } from './IMainExecItem' |
||||
|
||||
export interface IPageData { |
||||
PrjInfo: ISummaryProjectData; |
||||
Status: {[key: string]: string;}; |
||||
TaskStats: {[key: string]: number;}; |
||||
MainExec: IMainExecItem[] |
||||
} |
@ -0,0 +1,15 @@ |
||||
export interface ISummaryProjectData{ |
||||
spID: number
|
||||
status: string
|
||||
chief: string |
||||
code: string
|
||||
portfolio: string
|
||||
programm: string
|
||||
type: string |
||||
target: string |
||||
task: string |
||||
team: string[] |
||||
customer: string
|
||||
curator: string
|
||||
coordinator: string
|
||||
} |
@ -0,0 +1,7 @@ |
||||
define([], function() { |
||||
return { |
||||
"PropertyPaneDescription": "Description", |
||||
"BasicGroupName": "Group Name", |
||||
"DescriptionFieldLabel": "Description Field" |
||||
} |
||||
}); |
@ -0,0 +1,10 @@ |
||||
declare interface ISummaryWebPartWebPartStrings { |
||||
PropertyPaneDescription: string; |
||||
BasicGroupName: string; |
||||
DescriptionFieldLabel: string; |
||||
} |
||||
|
||||
declare module 'SummaryWebPartWebPartStrings' { |
||||
const strings: ISummaryWebPartWebPartStrings; |
||||
export = strings; |
||||
} |
@ -0,0 +1,26 @@ |
||||
{ |
||||
"compilerOptions": { |
||||
"target": "es5", |
||||
"forceConsistentCasingInFileNames": true, |
||||
"module": "esnext", |
||||
"moduleResolution": "node", |
||||
"jsx": "react", |
||||
"declaration": true, |
||||
"sourceMap": true, |
||||
"experimentalDecorators": true, |
||||
"skipLibCheck": true, |
||||
"typeRoots": [ |
||||
"./node_modules/@types", |
||||
"./node_modules/@microsoft" |
||||
], |
||||
"types": [ |
||||
"es6-promise", |
||||
"webpack-env" |
||||
], |
||||
"lib": [ |
||||
"es5", |
||||
"dom", |
||||
"es2015.collection" |
||||
] |
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
{ |
||||
"extends": "@microsoft/sp-tslint-rules/base-tslint.json", |
||||
"rules": { |
||||
"class-name": false, |
||||
"export-name": false, |
||||
"forin": false, |
||||
"label-position": false, |
||||
"member-access": true, |
||||
"no-arg": false, |
||||
"no-console": false, |
||||
"no-construct": false, |
||||
"no-duplicate-variable": true, |
||||
"no-eval": false, |
||||
"no-function-expression": true, |
||||
"no-internal-module": true, |
||||
"no-shadowed-variable": true, |
||||
"no-switch-case-fall-through": true, |
||||
"no-unnecessary-semicolons": true, |
||||
"no-unused-expression": true, |
||||
"no-use-before-declare": true, |
||||
"no-with-statement": true, |
||||
"semicolon": true, |
||||
"trailing-comma": false, |
||||
"typedef": false, |
||||
"typedef-whitespace": false, |
||||
"use-named-parameter": true, |
||||
"variable-name": false, |
||||
"whitespace": false |
||||
} |
||||
} |
Loading…
Reference in new issue