new buttons with perm and disp

VRTKSSUP-229
Осьмаков Денис 5 years ago
parent 1d7ea3c156
commit 40a53f7d99
  1. 105
      src/webparts/summaryWebPart/components/RejectTasks/RejectTasks.module.scss
  2. 193
      src/webparts/summaryWebPart/components/RejectTasks/RejectTasks.tsx
  3. 3
      src/webparts/summaryWebPart/components/SummaryContainer/SummaryContainer.scss
  4. 11
      src/webparts/summaryWebPart/components/SummaryContainer/SummaryContainer.tsx
  5. 10
      src/webparts/summaryWebPart/components/SummaryGlobalComponent/SummaryGlobalComponent.module.scss
  6. 47
      src/webparts/summaryWebPart/components/SummaryWebPart.tsx
  7. 2
      src/webparts/summaryWebPart/components/TaskStatusesChart/TaskStatusesChart.tsx

@ -1,123 +1,64 @@
.commonTable { .commonTable {
/* min-width: 361px;
max-width: 361px;
width: 361px; */
width: 100%; width: 100%;
border-bottom: 1px solid #c8c8c8; min-width: 350px;
.thead { border-collapse:collapse;
display: flex; caption-side:bottom;
.th { table-layout: fixed;
overflow: hidden;
white-space: nowrap;
thead {
tr {
th{
padding: 6px; padding: 6px;
border-top: 1px solid #c8c8c8; border: 1px solid #c8c8c8;
border-left: 1px solid #c8c8c8;
font-family: "Segoe UI Web (West European)",Segoe UI,-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,sans-serif; font-family: "Segoe UI Web (West European)",Segoe UI,-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,sans-serif;
width: 100%;
color: #767676; color: #767676;
font-size: 13px; font-size: 13px;
font-weight: bold; font-weight: bold;
transition: 0.5s; transition: 0.5s;
white-space: normal;
word-break: break-all;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background: #f4f4f4; background: #f4f4f4;
color: #666666; color: #666666;
transition: 0.5s; transition: 0.5s;
} }
} }
.Departments {
min-width: 123px !important;
} }
.Managers {
min-width: 116px !important;
} }
.Members { .commonTbody {
min-width: 116px !important; tr {
} td {
.count { padding: 6px;
min-width: 46px !important; border: 1px solid #c8c8c8;
max-width: 46px !important; font-family: "Segoe UI Web (West European)",Segoe UI,-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,sans-serif;
border-right: 1px solid #c8c8c8;
}
}
.tbody {
display: flex;
.td {
border-top: 1px solid #c8c8c8;
border-left: 1px solid #c8c8c8;
color: #767676; color: #767676;
background: #ffffff;
font-size: 13px; font-size: 13px;
width: 100%;
font-family: "Segoe UI Web (West European)",Segoe UI,-apple-system,BlinkMacSystemFont,Roboto,Helvetica Neue,sans-serif;
transition: 0.5s; transition: 0.5s;
cursor: pointer; cursor: pointer;
.cell {
padding: 3px 5px;
color: #767676;
border-bottom: 1px solid #c8c8c8;
display: flex;
align-items: center;
justify-content: center;
/* max-width: 100px; */
&:hover { &:hover {
background: #f4f4f4; background: #f4f4f4;
color: #666666; color: #666666;
transition: 0.5s; transition: 0.5s;
} }
span { div {
/* white-space: nowrap; */ width: 99%;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
display: block;
}
}
.Departments {
width: 124px !important;
margin-left: 1px;
} }
.Managers {
min-width: 106px !important;
}
.Members {
min-width: 106px !important;
} }
.isCrit { .isCrit {
background: #ff000042; background: #ff000042;
&:hover { &:hover {
background: #ff0000ab; background: #ff0000ab;
color: #4b4b4b; color: #4b4b4b;
transition: 0.5s; transition: .5s;
} }
} }
.count {
min-width: 47px !important;
} }
.cell:last-child {
border-bottom: none;
} }
div {
text-align: center;
vertical-align: center;
}
.dividingLine{
border-bottom: 1px solid #c8c8c8;
}
}
.MembersTaskCount {
width: 58px;
max-width: 58px !important;
min-width: 58px !important;
border-right: 1px solid #c8c8c8;
}
}
}
.dividingLine{
border-bottom: 1px solid #c8c8c8;
} }

@ -1,129 +1,112 @@
import * as React from 'react'; import * as React from 'react';
/* import styles from '../SummaryGlobalComponent/SummaryGlobalComponent.module.scss' */
import { DetailsList, SelectionMode, DetailsListLayoutMode } from 'office-ui-fabric-react/lib/DetailsList';
import { DeviationTasks } from '../../interfaces/IDeviationTasks'; import { DeviationTasks } from '../../interfaces/IDeviationTasks';
import styles from '../RejectTasks/RejectTasks.module.scss' import styles from '../RejectTasks/RejectTasks.module.scss'
export interface IComponentProps { export interface IComponentProps {
structureData: DeviationTasks[] structureData: DeviationTasks[]
} }
export interface IComponentState { export interface IComponentState {
} }
export default class TrafficLight extends React.Component<IComponentProps, IComponentState> { export default class DeviationTaskTable extends React.Component<IComponentProps, IComponentState> {
private _renderHeaderCell(): JSX.Element {
private _renderHeaderTable(): JSX.Element {
return ( return (
<div className={styles.thead}> <thead>
<div className={styles.th + ' ' + styles.Departments}> <tr>
<th>
Подразделение Подразделение
</div> </th>
<div className={styles.th + ' ' + styles.Managers}> <th>
Руководитель Руководитель
</div> </th>
<div className={styles.th + ' ' + styles.Members}> <th>
Участник Участник
</div> </th>
<div className={styles.count + ' ' + styles.th}> <th style={{width:"50px"}}>
Кол-во задач Кол-во задач
</div> </th>
</div> </tr>
</thead>
) )
} }
private _cell(value:string,length:any,className:string,crit?:boolean,): JSX.Element { private _renderBodyTable(structureData:any): JSX.Element {
// 7 px это 1px border и padding 3px
var height = 'calc('+ 100/length + '% - 7px)' var structureTable = [] //В этом массив пушиться вся структура таблицы (tr td)
var critClassName = ''
if(crit) {
critClassName = 'isCrit'
}
return (
<div className={styles.cell + ' ' + styles[className] + ' ' + styles[critClassName]} style={{height}}><span>{value}</span></div>
)
}
// Прохожусь по всему приходящему массиву. Через функции _cell() и _customCell пушу ячеейки в structureTable. Так же в этой фунции определяться rowSpan и сокращаеться value до ФИО
if(structureData){
if(structureData.Departments.length){
private _renderCell(structureData:any,i:number): JSX.Element { for (let i = 0; i < structureData.Departments.length; i++) {
// Формула rowSpan
let rowSpan = 0;
var Departments = [] //Подразделения structureData.Departments[i].Managers.forEach(function(e) {
var Managers = [] //Руководители rowSpan = rowSpan + (e.Members.length+1);
var Members = [] //Участники })
var MembersTaskCount = [] //Кол-во задач
if(structureData){ // Конец формуле
if(structureData.Departments.length){ structureTable.push(this._cell(structureData.Departments[i].Name, rowSpan+1 , 'Departments',true))
// пушу в массив Departments ячейки
Departments.push(this._cell(structureData.Departments[i].Name,1 , 'Departments'))
if(structureData.Departments[i].Managers){ if(structureData.Departments[i].Managers){
for (let index = 0; index < structureData.Departments[i].Managers.length; index++) { for (let index = 0; index < structureData.Departments[i].Managers.length; index++) {
let menagers = structureData.Departments[i].Managers[index].Name
let menagers = structureData.Departments[i].Managers[index].Name;
if(menagers){ if(menagers){
//Сокращаю Имена и Отчества Пример Масловский Артем Андреевич Масловский А.А. //Сокращаю Имена и Отчества Пример Масловский Артем Андреевич Масловский А.А.
let ManagersName = structureData.Departments[i].Managers[index].Name.split(' ') let ManagersName = structureData.Departments[i].Managers[index].Name.split(' ');
let name = ManagersName[1].split('')[0] + '.' let name = ManagersName[1].split('')[0] + '.';
let surname = ManagersName[0] let surname = ManagersName[0];
if(ManagersName[2]){ if(ManagersName[2]){
let patronymic = ManagersName[1].split('')[0] + '.';
let patronymic = ManagersName[1].split('')[0] + '.' ManagersName = surname + ' ' + name + ' ' + patronymic;
ManagersName = surname + ' ' + name + ' ' + patronymic
} else { } else {
ManagersName = surname + ' ' + name ManagersName = surname + ' ' + name;
} }
let maxLength = 0 let maxLength = 0;
structureData.Departments[i].Managers.forEach(function(e) { structureData.Departments[i].Managers.forEach(function(e) {
maxLength = maxLength + e.Members.length maxLength = maxLength + e.Members.length;
}) })
structureTable.push(
//Переменная для расчета высоты ячейки менеджеров. this._cell( ManagersName ,structureData.Departments[i].Managers[index].Members.length+1,'Managers')
let length = maxLength/structureData.Departments[i].Managers[index].Members.length )
//Пушу ячейки
Managers.push(this._cell( ManagersName ,length,'Managers'))
} else { } else {
Managers.push(this._cell( '' ,structureData.Departments[i].Managers[index].length,'Managers')) structureTable.push(
this._cell( ' ' ,structureData.Departments[i].Managers[index].Members.length+1,'Managers')
)
} }
if(structureData.Departments[i].Managers[index].Members.length){ if(structureData.Departments[i].Managers[index].Members.length){
for (let counter = 0; counter < structureData.Departments[i].Managers[index].Members.length; counter++) { for (let counter = 0; counter < structureData.Departments[i].Managers[index].Members.length; counter++) {
let MembersName = structureData.Departments[i].Managers[index].Members[counter].Name let MembersName = structureData.Departments[i].Managers[index].Members[counter].Name
if(MembersName) { if(MembersName) {
//Сокращаю Имена и Отчества Пример Масловский Артем Андреевич Масловский А.А. //Сокращаю Имена и Отчества Пример Масловский Артем Андреевич Масловский А.А.
MembersName = MembersName.split(' '); MembersName = MembersName.split(' ');
let name = MembersName[1].split('')[0] + '.'; let name = MembersName[1].split('')[0] + '.';
let surname = MembersName[0]; let surname = MembersName[0];
if(MembersName[2]){ if(MembersName[2]){
MembersName[2].split('')[0]; MembersName[2].split('')[0];
let patronymic = MembersName[2].split('')[0] + '.'; let patronymic = MembersName[2].split('')[0] + '.';
MembersName = surname + ' ' + name + ' ' + patronymic; MembersName = surname + ' ' + name + ' ' + patronymic;
} else { } else {
MembersName = surname + ' ' + name MembersName = surname + ' ' + name
} }
} }
//Пушу ячейки
Members.push( let isCrit = structureData.Departments[i].Managers[index].Members[counter].Crit
this._cell( MembersName ,structureData.Departments[i].Managers[index].length,'Members',
structureData.Departments[i].Managers[index].Members[counter].Crit) structureTable.push(
) this._customCell( MembersName , structureData.Departments[i].Managers[index].Members[counter].TaskCount,isCrit)
//Пушу ячейки
MembersTaskCount.push(
this._cell(structureData.Departments[i].Managers[index].Members[counter].TaskCount ,structureData.Departments[i].Managers[index].length,'count',
structureData.Departments[i].Managers[index].Members[counter].Crit)
) )
} }
} }
@ -131,73 +114,47 @@ export default class TrafficLight extends React.Component<IComponentProps, IComp
} }
} }
} }
return (
<div className={styles.tbody}>
<div className={styles.td}>
{
Departments
} }
</div> return (
<div className={styles.td}> <tbody className={styles.commonTbody} >
{ {structureTable}
Managers </tbody>
}
</div>
<div className={styles.td}>
{
Members
}
</div>
<div className={styles.MembersTaskCount + ' ' + styles.td}>
{
MembersTaskCount
}
</div>
</div>
) )
} }
private _renderBodyTable(structureData:any,): JSX.Element {
var body = []
for (let i = 0; i < structureData.Departments.length; i++) { private _cell(value:string,length:any,className:string,row?:boolean,): JSX.Element {
body.push(this._renderCell(structureData, i))
}
return ( return (
<div>{body}</div> <tr><td rowSpan={length} ><div><span>{value}</span></div></td></tr>
) )
} }
componentDidMount(){
private _customCell(membersValue:string,countValue:string,crit?:boolean): JSX.Element {
let critClassName = '';
if(crit) {
critClassName = 'isCrit';
} }
public onRenderFooter = () =>{ return (
<tr style={ {height:"25px"}}>
<td className={styles[critClassName]}><div><span>{membersValue}</span></div></td >
<td className={styles[critClassName]} style={{textAlign:"center"}}><div><span>{countValue}</span></div></td >
</tr>
)
} }
public render(): React.ReactElement<IComponentProps> { public render(): React.ReactElement<IComponentProps> {
return ( return (
<div style={{display: 'flex', justifyContent: 'center',minWidth:' 360px'}}> <table className={styles.commonTable}>
<div> {this._renderHeaderTable()}
{this._renderBodyTable(this.props.structureData)}
<div className={styles.commonTable}> </table>
<div>
{this._renderHeaderCell()}
</div>
<div>
{
this._renderBodyTable(this.props.structureData)
}
</div>
</div>
</div>
</div>
); );
} }
} }

@ -0,0 +1,3 @@
.ms-DetailsRow-cell {
white-space: pre-line;
}

@ -1,6 +1,7 @@
import * as React from 'react'; import * as React from 'react';
import { ISummaryProjectData } from '../../interfaces/ISummaryProjectData'; import { ISummaryProjectData } from '../../interfaces/ISummaryProjectData';
import styles from '../SummaryWebPart.module.scss' import styles from '../SummaryWebPart.module.scss';
import '../SummaryContainer/SummaryContainer.scss'
import { import {
DetailsList, DetailsList,
SelectionMode, SelectionMode,
@ -149,7 +150,13 @@ export default class SummaryContainer extends React.Component<IComponentProps,IC
items.forEach(function(e) { items.forEach(function(e) {
if(e.fieldName == 'Внешний исполнитель') { if(e.fieldName == 'Внешний исполнитель') {
e.value = e.value.split(';#').join(' ') let value = []
e.value.split(';#').forEach(function(item) {
if(item) {
value.push(item)
}
})
e.value = value.join('\n')
} }
}) })
return ( return (

@ -1,7 +1,7 @@
.SummaryPageContainer{ .SummaryPageContainer{
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
min-width: 1159px; min-width: 1060px;
div{ div{
.Title { .Title {
text-align: center; text-align: center;
@ -11,14 +11,14 @@
} }
.SummaryPageColumnOne{ .SummaryPageColumnOne{
width: 100%; width: calc(33% - 15px);
} }
.SummaryPageColumnTwo{ .SummaryPageColumnTwo{
width: 100%; width: calc(33% - 10px);
margin: 0 25px; margin: 0 20px;
} }
.SummaryPageColumnThree{ .SummaryPageColumnThree{
width: 100%; width: calc(33% - 15px);
} }
.SummaryPageRowOne{ .SummaryPageRowOne{

@ -12,6 +12,7 @@ export interface IComponentState{
isBlank: boolean; isBlank: boolean;
prjID: string | number; prjID: string | number;
isPerm: boolean; isPerm: boolean;
isPermConfigButton: boolean;
noPermDiv: any; noPermDiv: any;
} }
@ -22,6 +23,7 @@ export default class SummaryWebPart extends React.Component<ISummaryWebPartProps
isBlank: false, isBlank: false,
prjID: '', prjID: '',
isPerm: false, isPerm: false,
isPermConfigButton: false,
noPermDiv: <div></div> noPermDiv: <div></div>
} }
@ -49,20 +51,26 @@ export default class SummaryWebPart extends React.Component<ISummaryWebPartProps
document.body.appendChild(scripts); document.body.appendChild(scripts);
let relUrl = context.pageContext.web.serverRelativeUrl; let relUrl = context.pageContext.web.serverRelativeUrl;
let projectCode = relUrl ? relUrl.split('/')[relUrl.split('/').length - 1] : ''; /* 'UNI_UNI_018' */ let projectCode = relUrl ? relUrl.split('/')[relUrl.split('/').length - 1] : ''; /* 'NEW_UNI_002' */
let web = new Web('http://portal.vertex.spb.ru/PMIS'); let web = new Web('http://portal.vertex.spb.ru/PMIS');
let thisWeb = new Web('http://portal.vertex.spb.ru/PMIS/' + projectCode); let thisWeb = new Web('http://portal.vertex.spb.ru/PMIS/' + projectCode);
thisWeb.lists.getByTitle('CustomPerm').items.get().then(e => { thisWeb.lists.getByTitle('CustomPerm').items.get().then((e:any) => {
if(e.length){ let permWP = null;
this.setState({ isPerm: true }) e.forEach(el=>{
}else{ if (el.Title == 'PermEdit') this.setState({isPermConfigButton: true})
if (el.Title == 'WPSummary') this.setState({ isPerm: true }); permWP = true;
})
if (!permWP){
this.setState({ this.setState({
noPermDiv: <MessageBar messageBarType={MessageBarType.error} isMultiline={false} dismissButtonAriaLabel="Close"> noPermDiv: <MessageBar messageBarType={MessageBarType.error} isMultiline={false} dismissButtonAriaLabel="Close">
{'Отсутствует доступ к странице'} {'Отсутствует доступ к странице'}
</MessageBar>}) </MessageBar>})
} }
}) })
web.lists.getById('eeba7db6-4c28-41a2-a54e-82a2aaf0ca15').items.filter("Code_project eq '" + projectCode +"'").select('ID').get().then(e=>{ web.lists.getById('eeba7db6-4c28-41a2-a54e-82a2aaf0ca15').items.filter("Code_project eq '" + projectCode +"'").select('ID').get().then(e=>{
@ -77,28 +85,41 @@ export default class SummaryWebPart extends React.Component<ISummaryWebPartProps
}) })
} }
public relocate = () => { public relocate = (loc:string) => {
const { prjID } = this.state; const { prjID } = this.state;
location.href = 'http://portal.vertex.spb.ru/PMIS/SitePages/EditForm.aspx?itemId=' + prjID; location.href = `http://portal.vertex.spb.ru/PMIS/SitePages/${loc}.aspx?itemId=${prjID}`;
} }
public render(): React.ReactElement<ISummaryWebPartProps> { public render(): React.ReactElement<ISummaryWebPartProps> {
const { pageData, isLoaded, isBlank, isPerm, noPermDiv } = this.state; const { pageData, isLoaded, isBlank, isPerm, noPermDiv, isPermConfigButton } = this.state;
return isPerm ? isLoaded ? ( return isPerm || isPermConfigButton ? isLoaded ? (
<div style={{ display: "flex", flexDirection: "column", overflowX: 'auto' }}> <div style={{ display: "flex", flexDirection: "column", overflowX: 'auto' }}>
<div style={{ display: "flex", justifyContent: "flex-end" }}> <div style={{ display: "flex", justifyContent: "flex-end" }}>
<PrimaryButton <div>
{isPermConfigButton ? <PrimaryButton
text="Настройка прав проекта"
onClick={()=>this.relocate('PermForm')}
style={{fontSize: '13px'}}
/> : null}
{isPerm && <PrimaryButton
text="Изменение карточки проекта" text="Изменение карточки проекта"
onClick={this.relocate} onClick={()=>this.relocate('EditForm')}
style={{ fontSize: '13px', marginRight: '10px', marginLeft: '10px'}}
/>}
<PrimaryButton
text="Просмотреть все свойства"
onClick={() => this.relocate('DispForm')}
style={{ fontSize: '13px' }} style={{ fontSize: '13px' }}
/> />
</div> </div>
<SummaryGlobalComponent </div>
{isPerm && <SummaryGlobalComponent
data={pageData} data={pageData}
rowsOrder={this.props.rowsOrder} rowsOrder={this.props.rowsOrder}
context={this.props.context} context={this.props.context}
/> />}
</div> </div>
) : isBlank ? ( ) : isBlank ? (
<div></div> <div></div>

@ -27,7 +27,7 @@ export default class TaskStatusesChart extends React.Component<IComponentProps,
} }
public render(): React.ReactElement<IComponentProps> { public render(): React.ReactElement<IComponentProps> {
const { taskStats } = this.props; const { taskStats } = this.props;
let chartTitle = 'Текущee состояние проекта (выполняемых задач: '+( Number(taskStats.exec) + Number(taskStats.plan) + Number(taskStats.compl))+' шт.)' let chartTitle = 'Текущee состояние проекта (всего задач: '+( Number(taskStats.exec) + Number(taskStats.plan) + Number(taskStats.compl))+' шт.)'
return ( return (
<div > <div >
<div><h1 style={{textAlign: 'center', fontSize: '13px', color: '#666',textTransform: 'uppercase'}}>{chartTitle}</h1></div> <div><h1 style={{textAlign: 'center', fontSize: '13px', color: '#666',textTransform: 'uppercase'}}>{chartTitle}</h1></div>

Loading…
Cancel
Save