This commit is contained in:
ArifHilmi 2025-03-03 08:00:11 +08:00
parent 6150baa25d
commit 11e8e84064
3 changed files with 145 additions and 72 deletions

View File

@ -2,22 +2,27 @@
ViewData["Title"] = "QR Scanner";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<style>
@@font-face {
font-family: 'OCR-A';
src: url('../assets/fonts/ocraext.ttf');
<style scoped>
.error {
font-weight: bold;
color: red;
}
.QrPrintFont {
font-family: 'OCR-A', monospace;
.barcode-format-checkbox {
margin-right: 10px;
white-space: nowrap;
display: inline-block;
}
.table td img {
display: block !important;
select {
width: 200px; /* Adjust width as needed */
padding: 5px;
font-size: 16px;
}
</style>
@await Html.PartialAsync("~/Areas/Inventory/Views/_InventoryPartialUser.cshtml")
<div id="registerItem" class="row">
<div class="row card">
@ -28,11 +33,25 @@
</div>
<div class="card-body">
<div id="app" v-if="displayStatus == null" data-aos="fade-right">
<h1 data-aos="fade-right">QR & Barcode Scanner</h1>
<div id="reader" data-aos="fade-right"></div>
</div>
<select v-if="displayStatus == null" class="form-select" v-model="selectedCameraId" v-on:change="updateCamera">
<option v-for="device in videoInputDevices" :key="device.deviceId" :value="device.deviceId">
{{ device.label || `Camera ${videoInputDevices.indexOf(device) + 1}` }}
</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 -->
<div style="text-align: center; margin: 20px 0;" v-if="displayStatus === 'arrived'">
<h2>Item Receive Information :</h2>
@ -190,7 +209,7 @@
<div class="form-group row">
<label class="col-sm-4 col-form-label">Deploy Station : </label>
<div class="col-sm-8">
<select class="btn btn-primary dropdown-toggle col-md-10" v-model="selectedStation" >
<select class="btn btn-primary dropdown-toggle col-md-10" v-model="selectedStation">
<option class="btn-light" value="" disabled selected>Select Station</option>
<option class="btn-light" v-for="(station, index) in stationList" :key="index" :value="station.stationId">{{ station.stationName}}</option>
</select>
@ -242,7 +261,7 @@
<div class="form-group row">
<label class="col-sm-4 col-form-label">Consignment Note : </label>
<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>
@ -295,7 +314,7 @@
<div class="form-group row">
<label class="col-sm-4 col-form-label">Consignment Note:</label>
<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>
<button type="submit" class="btn btn-primary">Return Item</button>
@ -330,17 +349,15 @@
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
<script src="https://cdn.jsdelivr.net/npm/html5-qrcode/minified/html5-qrcode.min.js"></script>
<script src="~/js/vue-qrcode-reader.umd.js"></script>
<script>
const app = Vue.createApp({
data() {
return {
thisItem: null,
qrCodeResult: null,
html5QrCodeScanner: null,
debounceTimeout: null,
selectedUser: "",
selectedStation: "",
stationList: [],
@ -352,15 +369,34 @@
remark: null,
consignmentNote: 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() {
this.trackFunctionSelected.value = this.paintOutline;
this.fetchStation();
this.fetchUser();
this.startScanner();
},
methods: {
handleFileUpload(event) {
const file = event.target.files[0];
@ -486,41 +522,6 @@
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) {
try {
const response = await fetch('/InvMainAPI/GetItem/' + itemid, {
@ -542,7 +543,7 @@
this.thisItem = null;
}
} else {
console.error('Failed to fetch item information');
this.error = 'Qr Code Not Register to the system';
}
} catch (error) {
console.error('Error fetching item information:', error);
@ -590,8 +591,6 @@
this.displayStatus = null;
this.qrCodeResult = null;
this.thisItem = null;
this.startScanner();
},
resetForm() {
@ -603,6 +602,76 @@
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() {
$("#returnModal").modal("show");
},
@ -612,6 +681,7 @@
},
},
});
app.component("qrcode-stream", VueQrcodeReader.QrcodeStream);
app.mount('#registerItem');

View File

@ -13,7 +13,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://192.168.11.107:5124",
"applicationUrl": "http://localhost:5124",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
@ -22,7 +22,7 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://192.168.11.107:7036;http://192.168.11.107:5124",
"applicationUrl": "https://localhost:7036;http://localhost:5124",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}

File diff suppressed because one or more lines are too long