Qr
This commit is contained in:
parent
6150baa25d
commit
11e8e84064
@ -2,22 +2,27 @@
|
|||||||
ViewData["Title"] = "QR Scanner";
|
ViewData["Title"] = "QR Scanner";
|
||||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||||
}
|
}
|
||||||
<style>
|
<style scoped>
|
||||||
@@font-face {
|
.error {
|
||||||
font-family: 'OCR-A';
|
font-weight: bold;
|
||||||
src: url('../assets/fonts/ocraext.ttf');
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.QrPrintFont {
|
.barcode-format-checkbox {
|
||||||
font-family: 'OCR-A', monospace;
|
margin-right: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table td img {
|
select {
|
||||||
display: block !important;
|
width: 200px; /* Adjust width as needed */
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartialUser.cshtml")
|
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartialUser.cshtml")
|
||||||
<div id="registerItem" class="row">
|
<div id="registerItem" class="row">
|
||||||
<div class="row card">
|
<div class="row card">
|
||||||
@ -28,11 +33,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
<div id="app" v-if="displayStatus == null" data-aos="fade-right">
|
<select v-if="displayStatus == null" class="form-select" v-model="selectedCameraId" v-on:change="updateCamera">
|
||||||
<h1 data-aos="fade-right">QR & Barcode Scanner</h1>
|
<option v-for="device in videoInputDevices" :key="device.deviceId" :value="device.deviceId">
|
||||||
<div id="reader" data-aos="fade-right"></div>
|
{{ device.label || `Camera ${videoInputDevices.indexOf(device) + 1}` }}
|
||||||
</div>
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div id="registerItem" v-if="displayStatus == null" data-aos="fade-right">
|
||||||
|
<p style="text-align:center; padding:10px;">Scan QR Code Here:</p>
|
||||||
|
<qrcode-stream :constraints="selectedConstraints"
|
||||||
|
:formats="['qr_code']"
|
||||||
|
:track="trackFunctionSelected.value"
|
||||||
|
v-on:camera-on="onCameraReady"
|
||||||
|
v-on:detect="onDecode"
|
||||||
|
v-on:error="onError">
|
||||||
|
</qrcode-stream>
|
||||||
|
|
||||||
|
<p class="error">{{ error }}</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
<!--RECEIVE OR RETURN INTERFACE -->
|
<!--RECEIVE OR RETURN INTERFACE -->
|
||||||
<div style="text-align: center; margin: 20px 0;" v-if="displayStatus === 'arrived'">
|
<div style="text-align: center; margin: 20px 0;" v-if="displayStatus === 'arrived'">
|
||||||
<h2>Item Receive Information :</h2>
|
<h2>Item Receive Information :</h2>
|
||||||
@ -242,7 +261,7 @@
|
|||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-4 col-form-label">Consignment Note : </label>
|
<label class="col-sm-4 col-form-label">Consignment Note : </label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="file" v-model="consignmentNote" class="form-control-file" v-on:change="handleFileUpload" accept="image/png, image/jpeg, application/pdf" />
|
<input type="file" v-on:change="handleFileUpload" class="form-control-file" accept="image/png, image/jpeg, application/pdf" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -295,7 +314,7 @@
|
|||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-4 col-form-label">Consignment Note:</label>
|
<label class="col-sm-4 col-form-label">Consignment Note:</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<input type="file" v-model="consignmentNote" class="form-control-file" v-on:change="handleFileUpload" accept="image/png, image/jpeg, application/pdf" />
|
<input type="file" class="form-control-file" v-on:change="handleFileUpload" accept="image/png, image/jpeg, application/pdf" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Return Item</button>
|
<button type="submit" class="btn btn-primary">Return Item</button>
|
||||||
@ -330,17 +349,15 @@
|
|||||||
@{
|
@{
|
||||||
await Html.RenderPartialAsync("_ValidationScriptsPartial");
|
await Html.RenderPartialAsync("_ValidationScriptsPartial");
|
||||||
}
|
}
|
||||||
|
<script src="~/js/vue-qrcode-reader.umd.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/html5-qrcode/minified/html5-qrcode.min.js"></script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const app = Vue.createApp({
|
const app = Vue.createApp({
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
thisItem: null,
|
thisItem: null,
|
||||||
qrCodeResult: null,
|
|
||||||
html5QrCodeScanner: null,
|
|
||||||
debounceTimeout: null,
|
|
||||||
selectedUser: "",
|
selectedUser: "",
|
||||||
selectedStation: "",
|
selectedStation: "",
|
||||||
stationList: [],
|
stationList: [],
|
||||||
@ -353,14 +370,33 @@
|
|||||||
consignmentNote: null,
|
consignmentNote: null,
|
||||||
receiveReturn: null,
|
receiveReturn: null,
|
||||||
UniqueID: null,
|
UniqueID: null,
|
||||||
|
|
||||||
|
//QR VARIABLE
|
||||||
|
qrCodeResult: null,
|
||||||
|
debounceTimeout: null,
|
||||||
|
error: "",
|
||||||
|
selectedConstraints: { facingMode: "environment" },
|
||||||
|
trackFunctionSelected: { text: 'outline', value: null },
|
||||||
|
barcodeFormats: {
|
||||||
|
qr_code: true, // Hanya mendukung QR Code
|
||||||
|
code_128: true,
|
||||||
|
ean_13: true
|
||||||
|
},
|
||||||
|
constraintOptions: [
|
||||||
|
{ label: "Rear Camera", constraints: { facingMode: "environment" } },
|
||||||
|
{ label: "Front Camera", constraints: { facingMode: "user" } }
|
||||||
|
],
|
||||||
|
videoInputDevices: [],
|
||||||
|
selectedCameraId: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.trackFunctionSelected.value = this.paintOutline;
|
||||||
this.fetchStation();
|
this.fetchStation();
|
||||||
this.fetchUser();
|
this.fetchUser();
|
||||||
this.startScanner();
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
handleFileUpload(event) {
|
handleFileUpload(event) {
|
||||||
const file = event.target.files[0];
|
const file = event.target.files[0];
|
||||||
|
|
||||||
@ -486,41 +522,6 @@
|
|||||||
alert('Inventory PSTW Error: An error occurred.');
|
alert('Inventory PSTW Error: An error occurred.');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
startScanner() {
|
|
||||||
|
|
||||||
let qrboxFunction = function (viewfinderWidth, viewfinderHeight) {
|
|
||||||
let minEdgePercentage = 0.7; // 70%
|
|
||||||
let minEdgeSize = Math.min(viewfinderWidth, viewfinderHeight);
|
|
||||||
let qrboxSize = Math.floor(minEdgeSize * minEdgePercentage);
|
|
||||||
return {
|
|
||||||
width: qrboxSize,
|
|
||||||
height: qrboxSize
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
fps: 60,
|
|
||||||
qrbox: qrboxFunction
|
|
||||||
};
|
|
||||||
|
|
||||||
navigator.mediaDevices.getUserMedia({ video: true })
|
|
||||||
.then(() => {
|
|
||||||
this.html5QrCodeScanner = new Html5QrcodeScanner("reader", config, false);
|
|
||||||
this.html5QrCodeScanner.render((decodedText) => {
|
|
||||||
if (!this.debounceTimeout) {
|
|
||||||
this.debounceTimeout = setTimeout(() => {
|
|
||||||
this.qrCodeResult = decodedText;
|
|
||||||
this.UniqueID = decodedText.split('/').pop();
|
|
||||||
this.fetchItem(decodedText.split('/').pop());
|
|
||||||
this.debounceTimeout = null;
|
|
||||||
}, this.debounceTime);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error("Error accessing camera:", err);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async fetchItem(itemid) {
|
async fetchItem(itemid) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/InvMainAPI/GetItem/' + itemid, {
|
const response = await fetch('/InvMainAPI/GetItem/' + itemid, {
|
||||||
@ -542,7 +543,7 @@
|
|||||||
this.thisItem = null;
|
this.thisItem = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to fetch item information');
|
this.error = 'Qr Code Not Register to the system';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching item information:', error);
|
console.error('Error fetching item information:', error);
|
||||||
@ -590,8 +591,6 @@
|
|||||||
this.displayStatus = null;
|
this.displayStatus = null;
|
||||||
this.qrCodeResult = null;
|
this.qrCodeResult = null;
|
||||||
this.thisItem = null;
|
this.thisItem = null;
|
||||||
|
|
||||||
this.startScanner();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
resetForm() {
|
resetForm() {
|
||||||
@ -603,6 +602,76 @@
|
|||||||
this.updateItemMovement();
|
this.updateItemMovement();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Split Url dapatkan unique ID Je
|
||||||
|
onDecode(detectedCodes) {
|
||||||
|
if (detectedCodes.length > 0) {
|
||||||
|
this.qrCodeResult = detectedCodes[0].rawValue; // Ambil URL dari rawValue
|
||||||
|
this.UniqueID = this.qrCodeResult.split('/').pop(); // Ambil UniqueID dari URL
|
||||||
|
this.fetchItem(this.UniqueID);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//Showing Qr Error
|
||||||
|
onError(err) {
|
||||||
|
let message = `[${err.name}]: `;
|
||||||
|
if (err.name === "NotAllowedError") {
|
||||||
|
message += "You have to allow camera accecss.";
|
||||||
|
} else if (err.name === "NotFoundError") {
|
||||||
|
message += "There's no camera detect.";
|
||||||
|
} else if (err.name === "NotReadableError") {
|
||||||
|
message += "You are using camera on the other application.";
|
||||||
|
} else {
|
||||||
|
message += err.message;
|
||||||
|
}
|
||||||
|
this.error = message;
|
||||||
|
},
|
||||||
|
|
||||||
|
//Setting Camera
|
||||||
|
async onCameraReady() {
|
||||||
|
try {
|
||||||
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
this.videoInputDevices = devices.filter(device => device.kind === 'videoinput');
|
||||||
|
|
||||||
|
if (this.videoInputDevices.length > 0) {
|
||||||
|
// Keep the selected camera if already chosen
|
||||||
|
if (!this.selectedCameraId) {
|
||||||
|
this.selectedCameraId = this.videoInputDevices[0].deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedConstraints = { deviceId: { exact: this.selectedCameraId } };
|
||||||
|
} else {
|
||||||
|
this.error = "No camera detected.";
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.error = "Error accessing camera: " + err.message;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//Update Camera Category
|
||||||
|
updateCamera() {
|
||||||
|
this.selectedConstraints = { deviceId: { exact: this.selectedCameraId } };
|
||||||
|
},
|
||||||
|
|
||||||
|
//Red box if QR Detect
|
||||||
|
paintOutline(detectedCodes, ctx) {
|
||||||
|
for (const detectedCode of detectedCodes) {
|
||||||
|
const [firstPoint, ...otherPoints] = detectedCode.cornerPoints;
|
||||||
|
|
||||||
|
ctx.strokeStyle = 'red'; // Warna garis merah
|
||||||
|
ctx.lineWidth = 3;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(firstPoint.x, firstPoint.y);
|
||||||
|
for (const { x, y } of otherPoints) {
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
}
|
||||||
|
ctx.lineTo(firstPoint.x, firstPoint.y);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//Ni return message
|
||||||
receiveReturnMessage() {
|
receiveReturnMessage() {
|
||||||
$("#returnModal").modal("show");
|
$("#returnModal").modal("show");
|
||||||
},
|
},
|
||||||
@ -612,6 +681,7 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
app.component("qrcode-stream", VueQrcodeReader.QrcodeStream);
|
||||||
|
|
||||||
app.mount('#registerItem');
|
app.mount('#registerItem');
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"applicationUrl": "http://192.168.11.107:5124",
|
"applicationUrl": "http://localhost:5124",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@
|
|||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"applicationUrl": "https://192.168.11.107:7036;http://192.168.11.107:5124",
|
"applicationUrl": "https://localhost:7036;http://localhost:5124",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
|
|||||||
3
wwwroot/js/vue-qrcode-reader.umd.js
Normal file
3
wwwroot/js/vue-qrcode-reader.umd.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user