Create a gist now

Instantly share code, notes, and snippets.

docFlow
function doGet(e) {
return HtmlService.createTemplateFromFile('index').evaluate()
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
// пятиминутный триггер
function checkMail() {
checkComments();
}
// этот скрипт необходимо встроить в Google Документ, это меню для комментатора
function onOpen() {
var myDocUi=DocumentApp.getUi();
myDocUi.createMenu('Документооборот')
.addItem('Согласовать без замечаний', 'saveOK')
.addSeparator()
.addItem('Сохранить замечания', 'saveErrors')
.addToUi();
}
function saveErrors() {
var mail={
to: DriveApp.getFileById(DocumentApp.getActiveDocument().getId()).getOwner().getEmail(),
htmlBody: "<p>id="+DocumentApp.getActiveDocument().getId()+"СтатусЗамечанияКонец</p>",
subject: "Документооборот"
}
MailApp.sendEmail(mail);
}
function saveOK() {
var mail={
to: DriveApp.getFileById(DocumentApp.getActiveDocument().getId()).getOwner().getEmail(),
htmlBody: "<p>id="+DocumentApp.getActiveDocument().getId()+"СтатусСогласованоКонец</p>",
subject: "Документооборот"
}
MailApp.sendEmail(mail);
}
// справочник типов приложения docFlow
var TYPE_PROJECT="project"; // папка проекта
var TYPE_CONTRACT="contract"; // версия контракта
var TYPE_COMMENT="comment"; // замечания комментатора
var TYPE_OTHER_DOC="doc"; // сопутствующий документ
// справочник состояний проекта
var STATUS_NOT_FINISHED='false';
var STATUS_FINISHED='true';
var STATUS_CANCELLED='cancel';
Array.prototype.findByPropName = function(name){
for(var i = 0; i < this.length; i++){
if(this[i].key == name) return this[i]
}
return {value: undefined};
}
// Установка статуса папки
function setFolderStatus(folder, name, status) {
var currFolderId=folder.getId();
// документооборот
var property = {
key: 'docFlow',
value: TYPE_PROJECT,
visibility: 'PUBLIC'
}
Drive.Properties.insert(property, currFolderId);
// ответственный за проект
var property = {
key: 'senior',
value: name,
visibility: 'PRIVATE'
}
Drive.Properties.insert(property, currFolderId);
// закрыт или нет
var property = {
key: 'status',
value: status,
visibility: 'PRIVATE'
}
Drive.Properties.insert(property, currFolderId);
}
// Установка статуса файла согласования
function setFileStatus(file, name, status) {
var currFileId=file.getId();
// документооборот
var property = {
key: 'docFlow',
value: TYPE_COMMENT,
visibility: 'PUBLIC'
}
Drive.Properties.insert(property, currFileId);
// ответственный за проект
var property = {
key: 'senior',
value: name,
visibility: 'PRIVATE'
}
Drive.Properties.insert(property, currFileId);
// закрыт или нет
var property = {
key: 'status',
value: status,
visibility: 'PRIVATE'
}
Drive.Properties.insert(property, currFileId);
}
// Установка статуса контракта
function setContractStatus(file) {
var currFileId=file.getId();
// документооборот
var property = {
key: 'docFlow',
value: TYPE_CONTRACT,
visibility: 'PUBLIC'
}
Drive.Properties.insert(property, currFileId);
}
// Установка статуса документа
function setOtherDocStatus(file, status) {
var currFileId=file.getId();
// документооборот
var property = {
key: 'docFlow',
value: TYPE_OTHER_DOC,
visibility: 'PUBLIC'
}
Drive.Properties.insert(property, currFileId);
// наименование
var property = {
key: 'status',
value: status,
visibility: 'PRIVATE'
}
Drive.Properties.insert(property, currFileId);
}
// Удаление всех свойств
function delFileProperties(file) {
var currFileId=file.getId();
// документооборот
Drive.Properties.remove(currFileId, 'docFlow');
// ответственный за проект
Drive.Properties.remove(currFileId, 'senior');
// статус
Drive.Properties.remove(currFileId, 'status');
}
// Список проектов
function getPrjs() {
var query="properties has {key='docFlow' and value='"+TYPE_PROJECT+"' and visibility='PUBLIC'}";
query=query+" and properties has {key='senior' and value='"+Session.getActiveUser().getEmail()+"' and visibility='PRIVATE'}";
query=query+" and properties has {key='status' and value='"+STATUS_NOT_FINISHED+"' and visibility='PRIVATE'}";
var folders=Drive.Files.list({q: query});
var res=[];
for (var index=0; index<folders.items.length; index++) {
var folder=folders.items[index];
var element={
id: folder.id,
fname: folder.title,
link: folder.alternateLink,
senior: folder.properties.findByPropName('senior')
}
res.push(element);
}
return res;
}
// Список всех проектов для контролера
function getAllPrjs() {
var query="properties has {key='docFlow' and value='"+TYPE_PROJECT+"' and visibility='PUBLIC'}";
query=query+" and properties has {key='status' and value='"+STATUS_NOT_FINISHED+"' and visibility='PRIVATE'}";
var folders=Drive.Files.list({q: query});
var res=[];
for (var index=0; index<folders.items.length; index++) {
var folder=folders.items[index];
var element={
id: folder.id,
fname: folder.title,
link: folder.alternateLink,
senior: folder.properties.findByPropName('senior')
}
res.push(element);
}
return res;
}
// Список комментаторов
function getComments(id) {
var query="properties has {key='docFlow' and value='"+TYPE_COMMENT+"' and visibility='PUBLIC'} and '"+id+"' in parents";
var files=Drive.Files.list({q: query});
var res=[];
for (var index=0; index<files.items.length; index++) {
var file=files.items[index];
var element={
id: file.id,
fname: file.title,
link: file.alternateLink,
senior: file.properties.findByPropName('senior'),
status: file.properties.findByPropName('status')
}
res.push(element);
}
return res;
}
// Список файлов одного комментатора со статусом STATUS_COMMENTING
function getUserFiles(email) {
var query="properties has {key='docFlow' and value='"+TYPE_COMMENT+"' and visibility='PUBLIC'}";
query=query+" and properties has {key='senior' and value='"+email+"' and visibility='PRIVATE'}";
query=query+" and properties has {key='status' and value='"+STATUS_COMMENTING+"' and visibility='PRIVATE'}";
var files=Drive.Files.list({q: query});
var res=[];
for (var index=0; index<files.items.length; index++) {
var file=files.items[index];
var element={
id: file.id,
fname: file.title,
link: file.alternateLink,
senior: file.properties.findByPropName('senior'),
status: file.properties.findByPropName('status')
}
res.push(element);
}
return res;
}
// Список контрактов
function getContracts(id) {
var query="properties has {key='docFlow' and value='"+TYPE_CONTRACT+"' and visibility='PUBLIC'} and '"+id+"' in parents";
var files=Drive.Files.list({q: query});
var res=[];
for (var index=0; index<files.items.length; index++) {
var file=files.items[index];
var element={
id: file.id,
fname: file.title,
link: file.alternateLink,
date: file.createdDate
}
res.push(element);
}
return res;
}
// Список документов
function getOtherDocs(id) {
var query="properties has {key='docFlow' and value='"+TYPE_OTHER_DOC+"' and visibility='PUBLIC'} and '"+id+"' in parents";
var files=Drive.Files.list({q: query});
var res=[];
for (var index=0; index<files.items.length; index++) {
var file=files.items[index];
var element={
id: file.id,
fname: file.title,
link: file.alternateLink,
status: file.properties.findByPropName('status')
}
res.push(element);
}
return res;
}
// Получить описание файла
function getOtherDocStatus(id) {
var descr=Drive.Properties.get(id, 'status');
return descr;
}
// Получить ответственного по проекту
function getFolderSenior(id) {
var senior=Drive.Properties.get(id, 'senior');
return senior;
}
// Чтение статуса файла согласования
function getFileStatus(id) {
// закрыт или нет
var status=Drive.Properties.get(id, 'status');
// ответственный за проект
var senior=Drive.Properties.get(id, 'senior');
return {
status: status,
senior: senior
}
}
// список проектов
function getHtmlListPrj() {
// готовим список
var folders=[];
var isControler=isUserControl(Session.getActiveUser().getEmail());
if (isControler) folders=getAllPrjs()
else folders=getPrjs();
//заголовок
var listPrj='<table width=100% border=2>';
listPrj=listPrj+'<caption align="center"><b><h3>Текущие проекты</h3></b></caption>';
// форма добавления нового проекта
listPrj=listPrj+'<tr><td><form id="formCreateProject" class="form-new-object">';
listPrj=listPrj+'<label for="newPrjName">Новый проект: </label>';
listPrj=listPrj+'<input type="text" name="newPrjName" id="newPrjName"/>';
listPrj=listPrj+'<input type="button" id="createPrj" onclick="createProject()" value="+"/>';
listPrj=listPrj+'<input type="reset"/>';
listPrj=listPrj+'</form></td></tr>';
// шапка таблицы
listPrj=listPrj+"<tr><td><table width=100%>";
listPrj=listPrj+'<col width=60%><col width=40%>';
listPrj=listPrj+"<tr><th>Наименование проекта </th><th>Операции</th></tr>";
// список проектов
for (var i=0; i<folders.length; i++) {
listPrj=listPrj+'<tr><td><b>'+folders[i].fname+'</b></td>';
listPrj=listPrj+'<td><button class="share" value="'+folders[i].id+'" name="'+folders[i].fname+'" onclick="openPrj(this.value, this.name)"> ОТКРЫТЬ </button>';
listPrj=listPrj+'</td></tr>';
}
listPrj=listPrj+'</table></td></tr></table>';
if (isControler)
listPrj=listPrj+'<button class="share" onclick="report()">ВЫГРУЗИТЬ ОТЧЕТ В ТАБЛИЦУ</button>';
listPrj=listPrj+'<label for="curUser">Пользователь: </label>';
listPrj=listPrj+'<input type="text" id="curUser" name="curUser" value="'+Session.getActiveUser().getEmail()+'"/>';
listPrj=listPrj+'<button class="action" id="butShowPrj" onclick="loadCommentPrjList()">Показать</button>';
return listPrj;
}
// список проектов на согласовании
function getHtmlListCommentPrj(email) {
var listPrj='<table width=100% border=2>';
listPrj=listPrj+'<caption align="center"><b><h3>Проекты на согласовании</h3></b></caption>';
listPrj=listPrj+'<col width=80%><col width=20%>';
listPrj=listPrj+"<tr><th>Наименование проекта </th><th>Карточка</th></tr>";
var cards=getUserFiles(email);
for (var i=0; i<cards.length; i++) {
var folder=DriveApp.getFileById(cards[i].id).getParents().next();
var status=getOtherDocStatus(folder.getId()).value;
if (status==STATUS_NOT_FINISHED) { // отображаем только проекты в работе
var docFile=folder.getFilesByName("Карточка проекта").next();
listPrj=listPrj+'<tr><td><a href="'+cards[i].link+'">'+folder.getName()+'</a></td>';
listPrj=listPrj+'<td><a href="'+docFile.getUrl()+'">Посмотреть</a></td></tr>';
}
}
listPrj=listPrj+'</table>';
return listPrj;
}
// список комментаторов
function getHtmlEmailList(prjId) {
var prjFolder=DriveApp.getFolderById(prjId);
var prjHtml="";
//заголовок
prjHtml=prjHtml+"<table width=100% border=2>";
prjHtml=prjHtml+"<caption align='center'><b><h3>Список комментаторов:</h3></b></caption>";
// форма добавления комментатора
prjHtml=prjHtml+'<tr><td><form id="formNewComment" class="form-new-object">';
prjHtml=prjHtml+'<label for="email">Новый комментатор:</label>';
prjHtml=prjHtml+'<input type="text" name="email" id="email"/>';
prjHtml=prjHtml+'<input type="button" id="addEmail" onclick="newEmail()" value="+"/>';
prjHtml=prjHtml+'<input type="reset"/>';
prjHtml=prjHtml+'<input type="text" id="prjId" name="prjId" value="'+prjId+'" hidden/></form></td></tr>';
// список комментаторов
prjHtml=prjHtml+"<tr><td><table width=100%>";
prjHtml=prjHtml+'<col width=60%><col width=20%><col width=20%>';
prjHtml=prjHtml+"<tr><th>Емейл комментатора</th><th>Статус</th><th>Операции</th></tr>";
var comments=getComments(prjId);
for (var i=0; i<comments.length; i++) {
prjHtml=prjHtml+'<tr><td>'+comments[i].senior.value+'</td>';
if (comments[i].status.value==STATUS_OK)
prjHtml=prjHtml+'<td align="center"> Согласовано </td></tr>'
else if (comments[i].status.value==STATUS_ERRORS)
prjHtml=prjHtml+'<td align="center"> Замечания </td></tr>'
else
prjHtml=prjHtml+'<td align="center"> На рассмотрении </td></tr>';
}
prjHtml=prjHtml+'</table></td></tr></table>';
return prjHtml;
}
// список контрактов
function getHtmlContracts(prjId) {
var prjFolder=DriveApp.getFolderById(prjId);
var prjHtml="";
//заголовок
prjHtml=prjHtml+"<table width=100% border=2>";
prjHtml=prjHtml+"<caption align='center'><b><h3>Список версий:</h3></b></caption>";
// форма добавления версии контракта
prjHtml=prjHtml+'<tr><td><form id="formNewContract" class="form-new-object">';
prjHtml=prjHtml+'<label for="otherDocFile">Новая версия:</label>';
prjHtml=prjHtml+'<input type="file" name="contractFile" id="contractFile"/>';
prjHtml=prjHtml+'<input type="button" onclick="addNewContract()" id="uploadContract" value="+"/>';
prjHtml=prjHtml+'<input type="reset"/>';
prjHtml=prjHtml+'<input type="text" id="prjId" name="prjId" value="'+prjId+'" hidden/></form></td></tr>';
// список контрактов
prjHtml=prjHtml+"<tr><td><table width=100%>";
prjHtml=prjHtml+'<col width=60%><col width=40%>';
prjHtml=prjHtml+"<tr><th>Ссылка</th><th>Дата создания</th></tr>";
var contracts=getContracts(prjId);
for (var i=0; i<contracts.length; i++) {
prjHtml=prjHtml+'<tr><td><a href="'+contracts[i].link+'">'+contracts[i].fname+'</a></td>';
prjHtml=prjHtml+'<td align="center">'+transformDate(DriveApp.getFileById(contracts[i].id).getDateCreated())+'</td>';
}
prjHtml=prjHtml+'</table></td></tr></table>';
return prjHtml;
}
// список сопутствующих документов
function getHtmlOtherDocsList(prjId) {
var prjFolder=DriveApp.getFolderById(prjId);
var prjHtml="";
//заголовок
prjHtml=prjHtml+"<table width=100% border=2>";
prjHtml=prjHtml+"<caption align='center'><b><h3>Сопутствующие документы:</h3></b></caption>";
// форма добавления документа
prjHtml=prjHtml+'<tr><td><form id="formNewOtherDoc" class="form-new-object">';
prjHtml=prjHtml+'<label for="otherDocFile">Новый документ:</label>';
prjHtml=prjHtml+'<input type="file" name="otherDocFile" id="otherDocFile"/>';
prjHtml=prjHtml+'<input type="button" onclick="addOtherDoc()" id="uploadOtherDoc" value="+"/>';
prjHtml=prjHtml+'<input type="reset"/>';
prjHtml=prjHtml+'<input type="text" id="prjId" name="prjId" value="'+prjId+'" hidden/></form></td></tr>';
// список документов
prjHtml=prjHtml+"<tr><td><table width=100%>";
prjHtml=prjHtml+'<col width=40%><col width=30%><col width=15%><col width=15%>';
prjHtml=prjHtml+"<tr><th>Ссылка</th><th>Описание</th><th>Операции</th><th></th></tr>";
var otherDocs=getOtherDocs(prjId);
for (var i=0; i<otherDocs.length; i++) {
prjHtml=prjHtml+'<tr><td><a href="'+otherDocs[i].link+'">'+otherDocs[i].fname+'</a></td>';
prjHtml=prjHtml+'<td align="center"><input type="text" value="'+otherDocs[i].status.value+'" id="'+otherDocs[i].id+'"/></td>';
prjHtml=prjHtml+'<td><button class="share" value="'+otherDocs[i].id+'" onclick="setDescr(this.value)"> СОХРАНИТЬ </button></td>';
prjHtml=prjHtml+'<td><button class="create" value="'+otherDocs[i].id+'" onclick="delOtherDoc(this.value)"> УДАЛИТЬ </button></td>';
prjHtml=prjHtml+'</tr>';
}
prjHtml=prjHtml+'</table></td></tr></table>';
return prjHtml;
}
// панель проекта
function getHtmlPrj(prjId) {
var prjFolder=DriveApp.getFolderById(prjId);
// карточка проекта
try {
var docFile=prjFolder.getFilesByName("Карточка проекта").next();
var prjHtml="<b><h3><a href='"+docFile.getUrl()+"'> Посмотреть карточку проекта </a></h3></b>";
} catch(err) {
var prjHtml="<b><h3>Не найдена карточка проекта!</h3></b><br>Обратитесь к владельцу аккаунта "+Session.getEffectiveUser().getEmail()+" <br>";
return prjHtml;
}
// список комментаторов
prjHtml=prjHtml+getHtmlEmailList(prjId);
// список версий контракта
prjHtml=prjHtml+getHtmlContracts(prjId);
// список сопроводительных документов
prjHtml=prjHtml+getHtmlOtherDocsList(prjId);
return prjHtml;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<?!= include('styles'); ?>
<?!= include('scripts'); ?>
</head>
<body>
<!-- рабочая область -->
<div class="my-desktop">
<div class="app-form" id="Projects">
<div class="caption">Проекты</div>
<div id="prjList">Идет загрузка проектов!</div>
<div id="commentPrjList">Идет загрузка проектов на согласовании!</div> <br>
</div>
<div class="app-form" id="oneProject" hidden>
<div class="caption" id="prjName"></div>
<div class="form-element">
<button class="action" onclick="back()"> Назад </button>
<button class="action" onclick="refresh()"> Обновить карточку </button>
<button class="create" id="butCancelPrj" onclick="cancelPrj()"> Отменить проект </button>
<button class="share" id="butClosePrj" onclick="closePrj()"> Закрыть проект </button>
<input type="text" id="mainPrjId" value="" hidden/>
</div>
<div id="prjInfo">Идет загрузка информации по проекту!</div>
</div>
</div>
<script> Show()</script>
</body>
</html>
var DEFAULT_FOLDER='0B1pdx7gGZFcbdnJGNVF0Y0lCSGc'; // Папка для заливки договоров анонимами
var FILE_ID='1KbU9y30dm_uGCS6sddjERaYfU6ZUNJ7qhjDqymln0Ks'; // образец файла замечаний комментатора
var REPORT_ID='1fuDlS9FIImQ3PoK--CTqyY0Fae9byaZUCIPVKvBb284'; // таблица для отчета
// статусы файла комментатора
var STATUS_COMMENTING="На рассмотрении";
var STATUS_OK="Согласовано";
var STATUS_ERRORS="Замечания";
// парсер письма
function parseEmailBody(str) {
var startIdIndex=str.indexOf("id=")+"id=".length;
var endIdIndex=str.indexOf("Статус");
var startStatusIndex=str.indexOf("Статус")+"Статус".length;
var endStatusIndex=str.indexOf("Конец");
return {
id: str.substring(startIdIndex, endIdIndex),
status: str.substring(startStatusIndex, endStatusIndex)
}
}
// служебная функция преобразования даты
function transformDate(someDate) {
var res=" Дата: ";
if (someDate.getMonth()<9)
if (someDate.getDate()<10)
res=res+'0'+someDate.getDate()+'/0'+(someDate.getMonth()+1)+'/'+someDate.getFullYear();
else
res=res+someDate.getDate()+'/0'+(someDate.getMonth()+1)+'/'+someDate.getFullYear();
else
if (someDate.getDate()<10)
res=res+'0'+someDate.getDate()+'/'+(someDate.getMonth()+1)+'/'+someDate.getFullYear();
else
res=res+someDate.getDate()+'/'+(someDate.getMonth()+1)+'/'+someDate.getFullYear();
res=res+" Время: ";
res=res+someDate.getHours();
if (someDate.getMinutes()<10)
res=res+":0"+someDate.getMinutes();
else
res=res+":"+someDate.getMinutes();
return res;
}
// обновить карточку проекта
function docFileRefresh(prjId) {
try {
var folder=DriveApp.getFolderById(prjId);
var senior=getFolderSenior(prjId).value;
var docFile=folder.getFilesByName("Карточка проекта").next();
var body=DocumentApp.openById(docFile.getId()).getBody();
//наименование проекта (на всякий случая обновим)
var parPrjName=body.getParagraphs()[3];
parPrjName.setText("Наименование: "+folder.getName());
// ссылка на последнюю версию контракта
var parContract=body.getParagraphs()[4];
var contracts=getContracts(prjId);
if (contracts.length!=0) {
var maxDate=new Date(contracts[0]);
var curContract=0;
for (var i=1; i<contracts.length; i++) {
var curDate=new Date(contracts[i].date);
if (curDate>maxDate) {
curContract=i;
maxDate=curDate;
}
}
var file=DriveApp.getFileById(contracts[curContract].id);
parContract.setText("Последняя версия контракта "+file.getName());
var text=parContract.editAsText();
text.setLinkUrl(27, text.getText().length-1, file.getUrl());
} else parContract.setText("Последняя версия контракта не загружена");
// таблица комментаторов
var commentTable=body.getTables()[0];
while (1<commentTable.getNumRows())
commentTable.removeRow(1);
var comments=getComments(prjId);
for (var i=0; i<comments.length; i++) {
var row=commentTable.appendTableRow();
row.appendTableCell(comments[i].senior.value);
row.appendTableCell(comments[i].status.value);
}
// таблица сопутствующих доков
var otherDocTable=body.getTables()[1];
while (1<otherDocTable.getNumRows())
otherDocTable.removeRow(1);
var otherDocs=getOtherDocs(prjId);
for (var i=0; i<otherDocs.length; i++) {
var row=otherDocTable.appendTableRow();
row.appendTableCell(otherDocs[i].fname);
row.appendTableCell(otherDocs[i].status.value);
var text=row.getCell(0).editAsText();
text.setLinkUrl(otherDocs[i].link);
}
//ответственный проекта (на всякий случая обновим)
var parName=body.getParagraphs()[5];
parName.setText("Ответственный: "+senior);
} catch (err) {}
}
// добавление комментатора (передаем форму добавления комменатора)
function addEmail(form) {
var exampleFile=DriveApp.getFileById(FILE_ID);
var folder=DriveApp.getFolderById(form.prjId);
try {
var docFile=folder.getFilesByName("Карточка проекта").next();
DocumentApp.openById(docFile.getId()).addViewer(form.email);
var toDay=new Date();
var newFile=exampleFile.makeCopy(folder);
newFile.setName("Замечания комментатора "+form.email);
DocumentApp.openById(newFile.getId()).addEditor(form.email);
setFileStatus(newFile, form.email, STATUS_COMMENTING);
var body=DocumentApp.openById(docFile.getId()).getBody();
var tableRows=[[transformDate(toDay), "В проект добавлен комментатор "+form.email]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
var text=myTable.getCell(0, 1).editAsText();
text.setBold(30, text.getText().length-1, true);
body.appendParagraph("");
return true;
} catch (err) {
return err;
}
}
// загрузка версии контракта (передаем форму добавления контракта)
function uploadContract(form) {
var folder=DriveApp.getFolderById(form.prjId);
try {
var file=folder.createFile(form.contractFile);
setContractStatus(file);
var docFile=folder.getFilesByName("Карточка проекта").next();
var toDay=new Date();
var body=DocumentApp.openById(docFile.getId()).getBody();
var tableRows=[[transformDate(toDay), "В проект добавлена новая версия контракта "+file.getName()]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
var text=myTable.getCell(0, 1).editAsText();
text.setLinkUrl(42, text.getText().length-1, file.getUrl());
body.appendParagraph("");
// рассылаем всем комментаторам сообщение о новой версии контракта, сбрасываем статус файла согласования, добавляем всех комментаторов в редакторы
var comments=getComments(form.prjId);
for (var i=0; i<comments.length; i++) {
var email=comments[i].senior.value;
var htmlText="<p align='center'><b>Добрый день!</b></p><p></p><p>Вам на согласование представлена новая версия документа.</p>";
htmlText=htmlText+"<p>Проект: "+folder.getName()+"</p>";
htmlText=htmlText+"<p><a href='"+docFile.getUrl()+"'>Ссылка на карточку проекта</a></p>";
htmlText=htmlText+"<p><a href='"+comments[i].link+"'>Ссылка на файл, где Вы можете оставить свои замечания</a></p>";
var mail={
to: email,
htmlBody: htmlText,
subject: "Документооборот"
}
MailApp.sendEmail(mail);
var commentFile=DriveApp.getFileById(comments[i].id);
setFileStatus(commentFile, email, STATUS_COMMENTING);
file.addCommenter(email);
}
docFileRefresh(form.prjId);
return true;
} catch(err) {
return JSON.stringify(err);
}
}
// загрузка сопутствующего документа (передаем форму загрузки документа)
function uploadOtherDoc(form) {
var folder=DriveApp.getFolderById(form.prjId);
try {
var file=folder.createFile(form.otherDocFile);
setOtherDocStatus(file, "");
var docFile=folder.getFilesByName("Карточка проекта").next();
var toDay=new Date();
var body=DocumentApp.openById(docFile.getId()).getBody();
var tableRows=[[transformDate(toDay), "В проект добавлен сопутствующий документ "+file.getName()]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
var text=myTable.getCell(0, 1).editAsText();
text.setLinkUrl(40, text.getText().length-1, file.getUrl());
body.appendParagraph("");
return true;
} catch(err) {
return JSON.stringify(err);
}
}
// удаление сопутствующего документа (передаем ИД файла)
function delOtherDoc(id) {
var file=DriveApp.getFileById(id);
var fname=file.getName();
var descr=getOtherDocStatus(id).value;
var folders=file.getParents();
while (folders.hasNext()) {
var folder=folders.next();
folder.removeFile(file)
}
file.setTrashed(true);
delFileProperties(file);
var docFile=folder.getFilesByName("Карточка проекта").next();
var toDay=new Date();
var body=DocumentApp.openById(docFile.getId()).getBody();
var tableRows=[[transformDate(toDay), "Из проекта удален сопутствующий документ "+fname+" имеющий описание "+descr]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
var text=myTable.getCell(0, 1).editAsText();
text.setBold(text.getText().length-descr.length-1, text.getText().length-1, true);
body.appendParagraph("");
return true;
}
// добавление описания сопутствующего документа (передаем ИЛ файла и текст описания)
function setDescr(id, prjId, descr) {
var file=DriveApp.getFileById(id);
var folder=DriveApp.getFolderById(prjId);
setOtherDocStatus(file, descr);
var docFile=folder.getFilesByName("Карточка проекта").next();
var toDay=new Date();
var body=DocumentApp.openById(docFile.getId()).getBody();
var tableRows=[[transformDate(toDay), "Сопутствующему документу "+file.getName()+" установлено описание "+descr]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
var text=myTable.getCell(0, 1).editAsText();
text.setLinkUrl(text.getText().length-descr.length-1, text.getText().length-1, file.getUrl());
body.appendParagraph("");
}
// создание нового проекта (передаем форму создания проекта)
function createProject(form) {
var folder_id=getUserFolderId(Session.getActiveUser().getEmail());
if (folder_id==undefined) folder_id=DEFAULT_FOLDER;
var folder=DriveApp.getFolderById(folder_id);
var rootFolder=DriveApp.getRootFolder();
var newPrj=folder.createFolder(form.newPrjName);
var toDay=new Date();
// устанавливаем properties
setFolderStatus(newPrj, Session.getActiveUser().getEmail(), STATUS_NOT_FINISHED);
// формируем карточку проекта
var doc=DocumentApp.create("Карточка проекта");
doc.addEditor(Session.getActiveUser().getEmail());
var docFile=DriveApp.getFileById(doc.getId());
rootFolder.removeFile(docFile);
newPrj.addFile(docFile);
var body=doc.getBody();
var parTitle=body.appendParagraph("КАРТОЧКА ПРОЕКТА");
body.appendParagraph(" ");
body.appendParagraph("Наименование: "+form.newPrjName);
body.appendParagraph("Последняя версия контракта не загружена");
body.appendParagraph("Ответственный: "+Session.getActiveUser().getEmail());
body.appendParagraph("");
body.appendParagraph("Комментаторы");
var docTable=body.appendTable([["Комментатор", "Комментарий"], ["", ""]]);
docTable.setColumnWidth(0, 300);
docTable.setColumnWidth(1, 150);
body.appendParagraph("");
body.appendParagraph("Сопутствующие документы");
var docTable=body.appendTable([["Ссылка на документ", "Описание"], ["", ""]]);
docTable.setColumnWidth(0, 300);
docTable.setColumnWidth(1, 150);
body.appendPageBreak();
var parList=body.appendParagraph("ЛИСТ ВНЕСЕНИЯ ИЗМЕНЕНИЙ");
var tableRows=[[transformDate(toDay), "Проект создан пользователем "+Session.getActiveUser().getEmail()]]
var listTable=body.appendTable(tableRows);
listTable.setColumnWidth(0, 100);
listTable.setColumnWidth(1, 350);
var text=listTable.getCell(0, 1).editAsText();
text.setBold(28, text.getText().length-1, true);
body.appendParagraph("");
parTitle.setAlignment(DocumentApp.HorizontalAlignment.CENTER)
.editAsText().setBold(true)
.editAsText().setFontSize(14);
parList.setAlignment(DocumentApp.HorizontalAlignment.CENTER)
.editAsText().setBold(true)
.editAsText().setFontSize(14);
}
// отмена проекта ответственным
function prjCancel(prjId) {
try {
var folder=DriveApp.getFolderById(prjId);
var senior=getFolderSenior(prjId).value;
var docFile=folder.getFilesByName("Карточка проекта").next();
var toDay=new Date();
var body=DocumentApp.openById(docFile.getId()).getBody();
if (senior!=Session.getActiveUser().getEmail())
return false;
// устанавливаем properties
setFolderStatus(folder, Session.getActiveUser().getEmail(), STATUS_CANCELLED);
// записываем в лист изменений
var tableRows=[[transformDate(toDay), "Проект отменен ответственным"]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
body.appendParagraph("");
return true;
} catch(err) {
return err
}
}
// закрытие проекта контролером
function prjClose(prjId) {
try {
var folder=DriveApp.getFolderById(prjId);
var senior=getFolderSenior(prjId).value;
var docFile=folder.getFilesByName("Карточка проекта").next();
var toDay=new Date();
var body=DocumentApp.openById(docFile.getId()).getBody();
if (!isUserControl(Session.getActiveUser().getEmail()))
return false;
// устанавливаем properties
setFolderStatus(folder, senior, STATUS_FINISHED);
// записываем в лист изменений
var tableRows=[[transformDate(toDay), "Проект закрыт контролером "+Session.getActiveUser().getEmail()]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
var text=myTable.getCell(0, 1).editAsText();
text.setBold(26, text.getText().length-1, true);
body.appendParagraph("");
return true;
} catch(err) {
return err
}
}
// получение замечаний комментатора
function checkComments() {
var threads=GmailApp.search('is:unread subject:"Документооборот"');
for (var i=0; i<threads.length; i++) {
var messages=threads[i].getMessages();
for (var j=0; j<messages.length; j++) {
// получаем ид файла с замечаниями комментатора
messages[j].markRead();
var report=parseEmailBody(messages[j].getPlainBody());
var fileStatus=getFileStatus(report.id);
// далее работаем только если файл не закрыт
if (fileStatus.status.value==STATUS_COMMENTING) {
var folder=DriveApp.getFileById(report.id).getParents().next();
var comments=DocumentApp.openById(report.id).getBody().getText();
var senior=getFolderSenior(folder.getId());
// открываем карточку проекта
var docFile=folder.getFilesByName("Карточка проекта").next();
var toDay=new Date();
var body=DocumentApp.openById(docFile.getId()).getBody();
if (report.status=="Согласовано") {
// Вставляем в карточку замечания комментатора
var tableRows=[[transformDate(toDay), "Комментатор "+fileStatus.senior.value+" согласовал проект"]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
var text=myTable.getCell(0, 1).editAsText();
text.setBold(12, text.getText().length-19, true);
body.appendParagraph("");
// помечаем файл замечаний
setFileStatus(DriveApp.getFileById(report.id), fileStatus.senior.value, STATUS_OK);
} else {
// Вставляем в карточку замечания комментатора
var tableRows=[[transformDate(toDay), "Комментатор "+fileStatus.senior.value+" добавил замечания к проекту: "+comments]];
var myTable=body.appendTable(tableRows);
myTable.setColumnWidth(0, 100);
myTable.setColumnWidth(1, 350);
var text=myTable.getCell(0, 1).editAsText();
text.setBold(12, text.getText().length-31-comments.length, true);
body.appendParagraph("");
// помечаем файл замечаний
setFileStatus(DriveApp.getFileById(report.id), fileStatus.senior.value, STATUS_ERRORS);
}
try {
var mail={
to: senior.value,
htmlBody: "<p>Комментатор "+fileStatus.senior.value+" внес свои замечания в проект <b>"+folder.getName()+"</b></p>",
subject: "Документооборот"
}
MailApp.sendEmail(mail);
}
catch (err) {}
}
}
var label=GmailApp.getUserLabelByName('Приложения');
threads[i].moveToArchive();
threads[i].addLabel(label);
}
}
// выгрузка отчета
function report() {
var head=[['', 'Наименование проекта', 'Ответственный', 'Дата создания']];
var sh=SpreadsheetApp.openById(REPORT_ID).getSheets()[0];
sh.clear();
sh.getRange(1, 1).setValue("Отчет по договорам в работе");
sh.getRange(2, 1).setValue(transformDate(new Date()));
sh.getRange(3, 1, 1, 4).setValues(head);
var folders=getAllPrjs();
// список проектов
for (var i=0; i<folders.length; i++) {
var folder=DriveApp.getFolderById(folders[i].id);
var createDate=folder.getDateCreated();
sh.getRange(i+4, 1, 1, 4).setValues([[i+1, folders[i].fname, folders[i].senior.value, transformDate(createDate)]]);
}
}
var OPTION_ID='1a98ExhSi_eBFa4LCO9ckIloIagvQPGaARDssELjroIA';
function getUserFolderId(email) {
var doc=DocumentApp.openById(OPTION_ID);
var text=doc.getBody().getText();
var element=JSON.parse(text);
for (var i=0; i<element.folders.length; i++)
if (element.folders[i][0]==email)
return element.folders[i][1];
return undefined;
}
function isUserControl(email) {
var doc=DocumentApp.openById(OPTION_ID);
var text=doc.getBody().getText();
var element=JSON.parse(text);
for (var i=0; i<element.control.length; i++)
if (element.control[i]==email)
return true;
return false;
}
<script>
// отображение начальной страницы
function Show() {
google.script.run.withSuccessHandler(showListPrj).withFailureHandler(showListPrj).getHtmlListPrj();
}
function showListPrj(res) {
document.getElementById("prjList").innerHTML=res;
var t=document.getElementById("curUser").value;
google.script.run.withSuccessHandler(showListCommentPrj).withFailureHandler(showListCommentPrj).getHtmlListCommentPrj(t);
}
function showListCommentPrj(res) {
document.getElementById("commentPrjList").innerHTML=res;
document.getElementById("butShowPrj").hidden=false;
}
// загрузка проектов по выбранному емейлу
function loadCommentPrjList() {
var t=document.getElementById("curUser").value;
google.script.run.withSuccessHandler(showListCommentPrj).withFailureHandler(showListCommentPrj).getHtmlListCommentPrj(t);
document.getElementById("butShowPrj").hidden=true;
}
// создание нового проекта
function createProject() {
if (document.getElementById('newPrjName').value=='') {alert("Не задано имя проекта!");return}
document.getElementById("createPrj").hidden=true;
google.script.run.withSuccessHandler(onCreateSuccess).withFailureHandler(onCreateFailure).createProject(document.getElementById('formCreateProject'));
}
function onCreateSuccess() {
document.getElementById("createPrj").hidden=false;
Show();
}
function onCreateFailure() {
document.getElementById("createPrj").hidden=false;
}
// возврат к списку проектов
function back() {
document.getElementById("prjList").innerHTML="Идет загрузка проектов!";
document.getElementById("commentPrjList").innerHTML="Идет загрузка проектов на согласовании!";
document.getElementById("oneProject").hidden=true;
document.getElementById("Projects").hidden=false;
document.getElementById("prjInfo").innerHTML="Идет загрузка информации по проекту!";
Show();
}
// отобразить панель проекта
function showPrjPanel(id) {
google.script.run.withSuccessHandler(showPrj).withFailureHandler(showPrj).getHtmlPrj(id);
}
function showPrj(res) {
document.getElementById("prjInfo").innerHTML=res;
}
// переход к панели проекта
function openPrj(id, name) {
document.getElementById("Projects").hidden=true;
document.getElementById("oneProject").hidden=false;
document.getElementById("prjName").innerHTML="Проект: "+name;
document.getElementById("mainPrjId").value=id;
showPrjPanel(id);
}
// скрипты добавления комментатора
function newEmail() {
if (document.getElementById('email').value=='') {alert("Не задан емейл комментатора!");return}
document.getElementById("addEmail").hidden=true;
google.script.run.withSuccessHandler(onAddSuccess).withFailureHandler(onAddFailure).addEmail(document.getElementById('formNewComment'));
}
function onAddSuccess() {
document.getElementById("addEmail").hidden=false;
showPrjPanel(document.getElementById('mainPrjId').value);
refresh();
}
function onAddFailure(res) {
document.getElementById("addEmail").hidden=false;
showPrjPanel(document.getElementById('mainPrjId').value);
}
// скрипты добавления контракта
function addNewContract() {
document.getElementById("uploadContract").hidden=true;
google.script.run.withSuccessHandler(onUploadContractSuccess).withFailureHandler(onUploadContractFailure).uploadContract(document.getElementById('formNewContract'));
}
function onUploadContractSuccess() {
document.getElementById("uploadContract").hidden=false;
showPrjPanel(document.getElementById('mainPrjId').value);
refresh();
}
function onUploadContractFailure(res) {
document.getElementById("uploadContract").hidden=false;
showPrjPanel(document.getElementById('mainPrjId').value)
}
// скрипты добавления дополнительного документа
function addOtherDoc() {
document.getElementById("uploadOtherDoc").hidden=true;
google.script.run.withSuccessHandler(onUploadOtherDocSuccess).withFailureHandler(onUploadOtherDocFailure).uploadOtherDoc(document.getElementById('formNewOtherDoc'));
}
function onUploadOtherDocSuccess() {
document.getElementById("uploadOtherDoc").hidden=false;
showPrjPanel(document.getElementById('mainPrjId').value);
refresh();
}
function onUploadOtherDocFailure(res) {
document.getElementById("uploadOtherDoc").hidden=false;
showPrjPanel(document.getElementById('mainPrjId').value)
}
// описание сопутствующего документа
function setDescr(id) {
var descr=document.getElementById(id).value;
var prjId=document.getElementById('mainPrjId').value;
google.script.run.withSuccessHandler(onSetSuccess).withFailureHandler(onSetFailure).setDescr(id, prjId, descr);
}
function onSetSuccess() {
alert("Новое описание установлено!");
refresh();
}
function onSetFailure(err) {
alert("Произошла ошибка "+err);
}
// удаление сопутствующего документа
function delOtherDoc(id) {
google.script.run.withSuccessHandler(onDelSuccess).withFailureHandler(onDelFailure).delOtherDoc(id);
}
function onDelSuccess() {
alert("Файл успешно удален!");
showPrjPanel(document.getElementById('mainPrjId').value);
refresh();
}
function onDelFailure(err) {
alert("При удалении файла произошла ошибка "+err);
showPrjPanel(document.getElementById('mainPrjId').value);
}
// обновление карточки проекта
function refresh() {
var prjId=document.getElementById("mainPrjId").value;
google.script.run.docFileRefresh(prjId);
}
// отмена проекта
function cancelPrj() {
var prjId=document.getElementById("mainPrjId").value;
google.script.run.withSuccessHandler(onCancelSuccess).withFailureHandler(onCancelFailure).prjCancel(prjId);
document.getElementById("butCancelPrj").hidden=true;
}
function onCancelSuccess(res) {
if (res)
alert("Проект успешно отменен!")
else
alert("Проект не был отменен. Вероятно у Вас нет прав его отменять, либо произошла ошибка на Гугл Диске!");
document.getElementById("butCancelPrj").hidden=false;
}
function onCancelFailure(err) {
alert("Произошла ошибка "+err);
document.getElementById("butCancelPrj").hidden=false;
}
// закрытие проекта
function closePrj() {
var res=confirm("Вы уверены что проверили наличие всех необходимых документов и совпадение оригинала договора с последней версией контракта?");
if (!res) return;
var prjId=document.getElementById("mainPrjId").value;
google.script.run.withSuccessHandler(onCloseSuccess).withFailureHandler(onCloseFailure).prjClose(prjId);
document.getElementById("butClosePrj").hidden=true;
}
function onCloseSuccess(res) {
if (res)
alert("Проект успешно закрыт!")
else
alert("Проект не был закрыт. Вероятно у Вас нет прав его закрывать, либо произошла ошибка на Гугл Диске!");
document.getElementById("butClosePrj").hidden=false;
}
function onCloseFailure(err) {
alert("Произошла ошибка "+err);
document.getElementById("butClosePrj").hidden=false;
}
// выгрузка отчета
function report() {
google.script.run.report();
}
</script>
<style>
.grand-title {
color: blue;
background-color: lightgray;
font: bold 250% fantasy;
}
.my-sidebar {
width: 15%;
height: 95%;
background-color: #808080;
padding: 0;
border: 4px double #e8e8e8;
}
.mymenu-button {
margin: 1%;
width: 98%;
}
.my-desktop {
margin-left: 5%;
width: 90%;
}
.form-element {
margin: 3px 2% 3px 2%;
width: 96%;
}
#file {
background-color: silver;
width: 75%;
}
.caption {
color: white;
background-color: teal;
font: bold 110% sans-serif;
}
.app-form {
margin: 10px 10px;
width: 75%;
background-color: #e8e8e8;
}
.form-new-object{
background-color: #dddddd;
}
.table-header {
background-color: #808080;
color: white;
font: bold 100% arial;
padding: 3px;
}
table {
border-collapse: collapse;
border-spacing: 1;
}
th {
text-align: center;
margin: 0;
padding: 1px 0;
}
td {
margin: 0;
padding: 1px 0;
}
label {
font: bold 100% arial;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment