Как полученное фото передать в запись детали без костилей?
Сейчас там происходит загрузка файла, я заменил кнопку и хочу сделать так: При нажатии открывается веб камера и снимается фото.
Мне это фото нужно загрузить в деталь обратно как он делал при выборе файла.
Нравится
Здравствуйте Ислам!
После воспроизведения данного Вами кода, ошибка №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. Воспроизводится, если хотя бы раз открыть контейнер до перезахода на страницу. Поймать точный момент возникновения проблемы у меня не получилось, к сожалению.