Как полученное фото передать в запись детали без костилей?
Сейчас там происходит загрузка файла, я заменил кнопку и хочу сделать так: При нажатии открывается веб камера и снимается фото.
Мне это фото нужно загрузить в деталь обратно как он делал при выборе файла.
Нравится
Здравствуйте Ислам!
После воспроизведения данного Вами кода, ошибка №1 не возникала (вероятно из-за разных версий продукта), но появлялась ошибка «Maximum call stack size exceeded error». Причина - обращение к AddRecordButton. Советую сделать замещение в diff на новую кнопку в FileDetailV2:
diff: /**SCHEMA_DIFF*/[
{
"operation": "insert",
"name": "CustomButton",
"parentName": "Detail",
"propertyName": "tools",
"values": {
"caption": "Click me",
"itemType": Terrasoft.ViewItemType.BUTTON,
"click": {"bindTo": "getWebCamClick"},
"visible": true
}
}
]/**SCHEMA_DIFF*/Добавление фотографий в деталь не выполнялось. Я внесла несколько изменений в ваш код, теперь функционал работает. При открытии модального окна вы можете несколько раз нажать на кнопку «Сделать фото» и после каждого клика будет добавлено новое фото. Прикрепляю обновленные методы CameraPageMixin:
takePhoto: function() {
var videoElement = document.querySelector("video");
if (videoElement.srcObject) {
var desiredWidth = 1000;
var desiredHeight = 1000;
var canvas = document.createElement("canvas");
canvas.width = desiredWidth;
canvas.height = desiredHeight;
var context = canvas.getContext("2d");
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
var photoData = canvas.toDataURL("image/jpeg");
var base64Part = photoData.split(",")[1];
var buffer = this.base64ToArrayBuffer(base64Part);
var mimeString = photoData.split(",")[0].split(":")[1].split(";")[0];
var blob = new Blob([buffer], {type: mimeString});
var files = new File([blob], "photo.jpeg", {type: "image/jpeg"});
return files;
}
return null;
},
base64ToArrayBuffer: function (base64) {
var binaryString = atob(base64);
var bytes = new Uint8Array(binaryString.length);
for (var i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
},Ошибка №2 возникает из-за потери контекста. В FileDetailV2 метод onFileSelect вызывает getIsNewRecord, а getIsNewRecord отправляет сокетное сообщение GetCardState на DetailModuleV2, хотя должен его отправлять в BasePageV2. Воспроизводится, если хотя бы раз открыть контейнер до перезахода на страницу. Поймать точный момент возникновения проблемы у меня не получилось, к сожалению.
Здравствуйте, Ислам!
Вы можете реализовать поставленную задачу с помощью пользовательского модуля:
https://academy.creatio.com/docs/developer/front_end_development/sandbox/overview
По нажатию на кнопку будет открываться модальное окно с необходимым функционалом. Пример загрузки модуля описан ниже: https://academy.creatio.com/docs/developer/front_end_development/sandbox/overview#case-2746
Так же хочу уточнить, что метод «CardStateV2.EDIT» актуален только до версии 7.7.0. Для всех следующих версий нужно будет делать его замену. Похожий пример реализации: https://community.creatio.com/articles/error-when-trying-add-new-activity-history-connecred-object?_gl=1*ol2aml*_gcl_au*MTYxNTAzNjkzMi4xNjkyOTU4NzI3
Полезная ссылка по решению загрузки пользовательского модуля с параметрами для конструктора объекта модуля:
https://community.terrasoft.ua/questions/loadmodule-s-parametrami-konstruktora-kak
В конце для загрузки фото с модуля нужно отладить загрузку файла во вложения и вызов ендпоинта /0/rest/FileApiService/UploadFile
С уважением,
Ангелина
Anhelina,
Благодарю за подробный ответ, мне не понятен последний момент. С отладкой загрузки файла. Мы можем реализовать этот кейс вызвав функцию upload(config), которая реализована в FileDetailV2? Если да, то подскажите где посмотреть примеры?
Ислам,
Вы можете вызвать функцию, передав нужное значение в config, так: this.Terrasoft.ConfigurationFileApi.upload(config, callback);
Модуль ConfigurationFileApi нужно добавить в зависимости: define(" ", [… " ConfigurationFileApi "], …
Так же могут быть полезными статьи:
https://academy.terrasoft.ua/docs/developer/ehlementy_interfejsa/strani…
https://community.terrasoft.ua/questions/vstavit-element-photocontainer…
Anhelina,
Я реализовал вызов Upload и у меня добавляется при нажатии на фотографировать фото в детали, но деталь ломается. Сразу после этого она перестает обновляться, то есть если я перехожу по другим записям деталь зависает и выводит две ошибки:
1) "Message DetailRendered is not defined in DetailModuleV2 (CardModuleV2_9d571769-06d3-44bf-a1bc-94c8fa686266_FinApplicationContactPage_detail_DocListInFinAppDetail_detail_nested_FilesDocListInFinAppFile) module"
2)

Я так понимаю ошибка происходит тут в файле FileDetailV2:

Для ясности оставлю код и детали и миксина, которые снимает фото с веб камеры:
ДЕТАЛЬ:
define("FileDetailV2", ["ModalBox", "CameraPageMixin","ConfigurationEnums","ConfigurationFileApi"],
function(ModalBox, ConfigurationEnums) {
return {
attributes: {},
messages: {},
mixins: {
CameraPageMixin: "Terrasoft.CameraPageMixin"
},
methods: {
getWebCamClick: function() {
var webCamModuleContainer = this.Ext.create("Terrasoft.Container", {
id: this.mixins.CameraPageMixin.containerId,
classes: {
wrapClassName: ["webcam-module-container-class"]
}
});
var photoContainerId = this.Ext.create("Terrasoft.Container", {
id: this.mixins.CameraPageMixin.photoContainerId,
classes: {
wrapClassName: ["photo-container-class"]
}
});
var captureButton = this.Ext.create("Terrasoft.Button", {
caption: "Сделать фото",
handler: function() {
this.onCapturePhotoClick();
}.bind(this)
});
var closeButton = this.Ext.create("Terrasoft.Button", {
caption: "Закрыть окно",
handler: function() {
this.closeModalBox();
}.bind(this)
});
var parentRecordId = this.get("MasterRecordId");
var modalBoxConfig = {
minHeight : "1",
minWidth : "1",
maxHeight : "100",
maxWidth : "100",
id: this.sandbox.id + "_CustomModalBox",
handler: this,
selector: "#CustomModalBox",
renderTo: Ext.getBody(),
instanceConfig: {
parentRecordId: parentRecordId
}
};
var modalBoxContainer = ModalBox.show(modalBoxConfig, this.destroy.bind(this));
ModalBox.setSize(510, 440);
modalBoxContainer.setStyle("background-color", "#FFFFFF");
webCamModuleContainer.render(modalBoxContainer);
photoContainerId.render(modalBoxContainer);
captureButton.render(modalBoxContainer);
closeButton.render(modalBoxContainer);
this.mixins.CameraPageMixin.openWebCamClick.apply(this, arguments);
},
onCapturePhotoClick: function(callback) {
var files = this.mixins.CameraPageMixin.takePhoto.apply(this, arguments);
var config = this.onFileSelect(files);
if (config) {
this.Terrasoft.ConfigurationFileApi.upload(config, callback);
}
},
closeModalBox: function() {
this.mixins.CameraPageMixin.closeWebCamAndRemoveContainer.apply(this, arguments);
ModalBox.close();
}
},
diff: /**SCHEMA_DIFF*/[
{
"operation": "merge",
"name": "AddRecordButton",
"parentName": "Detail",
"propertyName": "tools",
"values": {
"itemType": Terrasoft.ViewItemType.BUTTON,
"tag": "addFileButton",
"fileUpload": false,
// "filesSelected": {"bindTo": "onFileSelectOveridden"},
"click": {"bindTo": "getWebCamClick"},
// "visible": {"bindTo": "getAddRecordButtonVisible"},
"imageConfig": {"bindTo": "Resources.Images.AddButtonImage"}
}
}
]/**SCHEMA_DIFF*/
};
});
Миксин:
define("CameraPageMixin", [], function() {
Ext.define("Terrasoft.configuration.mixins.CameraPageMixin", {
alternateClassName: "Terrasoft.CameraPageMixin",
afterRender: function() {
this.callParent(arguments);
this.webcamStarted = false;
},
videoWidth: 500,
videoHeight: 380,
videoStream: null,
containerId: "WebCamModuleContainer",
photoContainerId: "PhotoModuleContainer",
onGetApplicationId: function(applicationId) {
this.alert(applicationId);
},
openWebCamClick: function() {
try {
var videoElement = document.createElement("video");
videoElement.setAttribute("autoplay", "true");
videoElement.width = this.videoWidth;
videoElement.height = this.videoHeight;
navigator.mediaDevices.getUserMedia({ video: true })
.then(function(stream) {
videoElement.srcObject = stream;
this.videoStream = stream;
var container = this.Ext.get(this.containerId);
if (container) {
container.dom.appendChild(videoElement);
this.webcamStarted = true;
} else {
window.console.error("Ошибка: элемент с идентификатором "
+ this.containerId + " не найден в DOM.");
}
}.bind(this))
.catch(function(error) {
window.console.error("Ошибка при получении доступа к веб-камере:", error);
});
} catch (e) {
window.console.error("Произошла ошибка при инициализации веб-камеры:", e);
}
},
takePhoto: function() {
var videoElement = document.querySelector("video");
if (videoElement.srcObject) {
var desiredWidth = 1000;
var desiredHeight = 1000;
var canvas = document.createElement("canvas");
canvas.width = desiredWidth;
canvas.height = desiredHeight;
var context = canvas.getContext("2d");
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
var photoData = canvas.toDataURL("image/jpeg");
var byteString = atob(photoData.split(",")[1]);
var mimeString = photoData.split(",")[0].split(":")[1].split(";")[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var blob = new Blob([ab], {type: mimeString});
var files = new File([blob], "photo.jpeg", {type: "image/jpeg"});
return files;
}
return null;
},
closeWebCamAndRemoveContainer: function() {
if (this.videoStream) {
this.videoStream.getTracks().forEach(function(track) {
track.stop();
});
}
var container = this.Ext.get(this.containerId);
if (container) {
container.dom.remove();
}
}
});
return Ext.create(Terrasoft.CameraPageMixin);
});
Здравствуйте Ислам!
После воспроизведения данного Вами кода, ошибка №1 не возникала (вероятно из-за разных версий продукта), но появлялась ошибка «Maximum call stack size exceeded error». Причина - обращение к AddRecordButton. Советую сделать замещение в diff на новую кнопку в FileDetailV2:
diff: /**SCHEMA_DIFF*/[
{
"operation": "insert",
"name": "CustomButton",
"parentName": "Detail",
"propertyName": "tools",
"values": {
"caption": "Click me",
"itemType": Terrasoft.ViewItemType.BUTTON,
"click": {"bindTo": "getWebCamClick"},
"visible": true
}
}
]/**SCHEMA_DIFF*/Добавление фотографий в деталь не выполнялось. Я внесла несколько изменений в ваш код, теперь функционал работает. При открытии модального окна вы можете несколько раз нажать на кнопку «Сделать фото» и после каждого клика будет добавлено новое фото. Прикрепляю обновленные методы CameraPageMixin:
takePhoto: function() {
var videoElement = document.querySelector("video");
if (videoElement.srcObject) {
var desiredWidth = 1000;
var desiredHeight = 1000;
var canvas = document.createElement("canvas");
canvas.width = desiredWidth;
canvas.height = desiredHeight;
var context = canvas.getContext("2d");
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
var photoData = canvas.toDataURL("image/jpeg");
var base64Part = photoData.split(",")[1];
var buffer = this.base64ToArrayBuffer(base64Part);
var mimeString = photoData.split(",")[0].split(":")[1].split(";")[0];
var blob = new Blob([buffer], {type: mimeString});
var files = new File([blob], "photo.jpeg", {type: "image/jpeg"});
return files;
}
return null;
},
base64ToArrayBuffer: function (base64) {
var binaryString = atob(base64);
var bytes = new Uint8Array(binaryString.length);
for (var i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
},Ошибка №2 возникает из-за потери контекста. В FileDetailV2 метод onFileSelect вызывает getIsNewRecord, а getIsNewRecord отправляет сокетное сообщение GetCardState на DetailModuleV2, хотя должен его отправлять в BasePageV2. Воспроизводится, если хотя бы раз открыть контейнер до перезахода на страницу. Поймать точный момент возникновения проблемы у меня не получилось, к сожалению.