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