updated linkage

This commit is contained in:
Warunee Tamkoo 2024-10-05 12:23:02 +07:00
parent 1f65a8d6a7
commit 447bbd90c8
5 changed files with 457 additions and 39 deletions

View file

@ -1,27 +1,41 @@
<script setup lang="ts">
import { ref } from "vue";
import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import { useLinkageStore } from "@/stores/linkage";
import DialogHeader from "./DialogHeader.vue";
const $q = useQuasar();
const { showLoader, hideLoader } = useCounterMixin();
const store = useLinkageStore();
const modal = defineModel<boolean>("modal", { required: true });
const step = ref<number>(1);
const devices = ref<string>("");
const devicesData = ref<string[]>(["Generic EMV Smartcard Reader0"]);
const devicesOp = ref<string[]>([]);
/** 1.เสียบบัตรประชาชนเข้ากับเครื่องอ่าน*/
function fetchDeviceLists() {
step.value++;
async function fetchDeviceLists() {
showLoader();
await store.fetchDeviceLists($q);
hideLoader();
}
/** 2.เลือกเครื่องอ่านบัตร*/
function readDevice() {
step.value++;
async function readDevice() {
showLoader();
await store.readDevice($q);
await store.getInfo($q); // CID
await store.postReadIdCard($q); // id card
await store.amiEnvironment($q);
await store.amiConnect($q);
await store.amiRequest($q, 9080);
hideLoader();
}
function verifyPin() {
step.value++;
async function verifyPin() {
showLoader();
await store.authentication($q);
await store.verifyPin($q);
hideLoader();
}
/**
@ -32,7 +46,7 @@ function verifyPin() {
function filterOption(val: string, update: Function) {
update(() => {
const newVal = val.toLocaleUpperCase();
devicesOp.value = devicesData.value.filter(
store.devicesOp = store.devicesData.filter(
(v: string) => v.toLocaleUpperCase().indexOf(newVal) > -1
);
});
@ -40,8 +54,6 @@ function filterOption(val: string, update: Function) {
function onClose() {
modal.value = false;
step.value = 1;
devices.value = "";
}
</script>
@ -69,14 +81,14 @@ function onClose() {
title="เสียบบัตรประชาชนเข้ากับเครื่องอ่าน"
style="font-size: 12px"
:icon="
step === 1
store.step === 1
? 'mdi-pencil'
: step > 1
: store.step > 1
? 'done'
: 'mdi-numeric-1'
"
>
<div class="row" v-if="step === 1">
<div class="row" v-if="store.step === 1">
<q-btn
color="primary"
label="ดำเนินการต่อ"
@ -89,15 +101,15 @@ function onClose() {
<q-timeline-entry
title="เลือกเครื่องอ่านบัตร"
:icon="
step === 2
store.step === 2
? 'mdi-pencil'
: step > 2
: store.step > 2
? 'done'
: 'mdi-numeric-2'
"
:color="step < 2 ? 'grey-4' : ''"
:color="store.step < 2 ? 'grey-4' : ''"
>
<div class="row" v-if="step === 2">
<div class="row" v-if="store.step === 2">
<q-form
greedy
@submit.prevent
@ -107,7 +119,7 @@ function onClose() {
<div>
<q-select
dense
v-model="devices"
v-model="store.devices"
label="เลือกเครื่องอ่านบัตร"
outlined
emit-value
@ -119,7 +131,7 @@ function onClose() {
option-label="name"
option-value="id"
class="inputgreen"
:options="devicesOp"
:options="store.devicesOp"
use-input
:rules="[(val:string) => !!val || `${'กรุณาเลือกเลือกเครื่องอ่านบัตร'}`,]"
@filter="(inputValue:string,doneFn:Function) => filterOption(inputValue, doneFn) "
@ -149,15 +161,15 @@ function onClose() {
<q-timeline-entry
title="เชื่อมต่อและใส่ PIN"
:icon="
step === 3
store.step === 3
? 'mdi-pencil'
: step > 3
: store.step > 3
? 'done'
: 'mdi-numeric-3'
"
:color="step < 3 ? 'grey-4' : ''"
:color="store.step < 3 ? 'grey-4' : ''"
>
<div class="row" v-if="step === 3">
<div class="row" v-if="store.step === 3">
<q-btn
color="primary"
label="ดำเนินการต่อ"
@ -169,6 +181,14 @@ function onClose() {
</q-card-section>
</q-card>
</q-card-section>
<q-card-actions v-if="store.tKey" align="right">
<q-btn
label="ยกเลิกการเชื่อมต่อ"
color="negative"
@click="store.disconnect($q)"
/>
</q-card-actions>
</q-card>
</q-dialog>
</template>

View file

@ -607,6 +607,7 @@ onMounted(async () => {
:family-data="FamilyData"
:Ops="Ops"
:Ops-filter="OpsFilter"
:id-card="InformationData.idCard"
/>
</template>

View file

@ -6,6 +6,7 @@ import { useRoute, useRouter } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import { useLinkageStore } from "@/stores/linkage";
import {
AddressDataDefualt,
FamilyDataDefualt,
@ -27,12 +28,13 @@ import FormAddressPage from "@/modules/05_placement/components/PersonalDetail/Ch
import FormFamilyPage from "@/modules/05_placement/components/PersonalDetail/CheckInformation/03_FormFamily.vue";
const modal = defineModel<boolean>("modal", { required: true });
const idCard = defineModel<string>("idCard", { required: true });
const $q = useQuasar();
const route = useRoute();
const router = useRouter();
const mixin = useCounterMixin();
const { showLoader, hideLoader, messageError } = mixin;
const store = useLinkageStore();
const props = defineProps({
Ops: {
@ -215,15 +217,7 @@ function onSubmit() {
/** ดึงข้อมูลรายละเอียด */
async function amiRequest() {
// await http
// .get(config.API.path)
// .then(async(res) => {
// const data = await res.data.result;
// })
// .catch((e) => {
// messageError($q, e);
// })
// .finally(() => {});
await store.amiRequest($q, 5000, idCard.value, "001");
}
/** เช็คค่า modal เมื่อเป็น true ใช้งาน ฟังชั่น */

View file

@ -8,7 +8,7 @@ interface ChangeActive {
//ข้อมูลส่วนตัว
interface Information {
idCard: string | null;
idCard: string;
prefix: string | null;
prefixId: string | null;
fullName: string | null;
@ -121,7 +121,7 @@ const defaultAddress: Address = {
};
const defaultInformation: Information = {
idCard: null,
idCard: "",
prefix: null,
prefixId: null,
fullName: null,

403
src/stores/linkage.ts Normal file
View file

@ -0,0 +1,403 @@
import { ref } from "vue";
import { defineStore } from "pinia";
import { useCounterMixin } from "./mixin";
const { messageError, success } = useCounterMixin();
export const useLinkageStore = defineStore("linkageData", () => {
const apiURL = ref<string>("http://127.0.0.1:51548"); // API URL From Agent
const devices = ref<string>(""); // ค่าเครื่องอ่านบัตรที่เลือก
const devicesData = ref<string[]>([]); // รายการเครื่องอ่านบัตรจากการดึงครั้งแรก
const devicesOp = ref<string[]>([]); // รายการเครื่องอ่านบัตรสำหรับ options
const step = ref<number>(1); // ขั้นตอนการทำงาน login linkage
const CID = ref<string>(""); // id ของ card (16 char)
const xKey = ref<string>("");
const envelopGMXs = ref<string>("");
/** API
* @param {any} q this quasar
*/
function fetchDeviceLists(q: any) {
fetch(`${apiURL.value}/smart-card/device`, {
method: "GET",
})
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then(async (data) => {
devicesOp.value = await data.devices;
devicesData.value = await data.devices;
step.value = 2;
})
.catch(async (error) => {
messageError(q, error);
// remove when api ready
devicesOp.value = await [
"Generic Smart Card Reader Interface 0",
"Windows Hello for Business 1",
];
devicesData.value = await [
"Generic Smart Card Reader Interface 0",
"Windows Hello for Business 1",
];
step.value = 2;
});
}
/** connect device
* @param {any} q this quasar
*/
function readDevice(q: any) {
fetch(`${apiURL.value}/smart-card/connect/?deviceName=${devices.value}`, {
method: "GET",
})
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then(async (data) => {
return;
})
.catch((error) => {
messageError(q, error);
});
}
/** CID
* @param {any} q this quasar
*/
async function getInfo(q: any) {
fetch(`${apiURL.value}/smart-card/info`, {
method: "GET",
})
.then(function (response) {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then(async (data) => {
CID.value = await data.cid;
return;
})
.catch((error) => {
messageError(q, error);
});
}
const PID = ref<string>("");
/** ดึงข้อมูล personalID/ id card
* @param {any} q this quasar
*/
async function postReadIdCard(q: any) {
fetch(`${apiURL.value}/smart-card/read/`, {
method: "POST",
body: JSON.stringify({
fields: ["personalID", "engName", "expireDate"],
}),
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then(async (data) => {
PID.value = await data.personalID;
return;
})
.catch((error) => {
messageError(q, error);
});
}
/** setting ami environment
* @param {any} q this quasar
*/
function amiEnvironment(q: any) {
fetch(`${apiURL.value}/ami/environment`, {
method: "POST",
body: JSON.stringify({
host: "lkbmabk.bma.go.th",
port: "20000",
}),
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then((data) => {
console.log("amiEnvironment===>", data);
return;
})
.catch((error) => {
messageError(q, error);
});
}
/**
* connect ami
* @param q this quasar
*/
function amiConnect(q: any) {
fetch(`${apiURL.value}/ami/connect`, {
method: "GET",
})
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then((data) => {
console.log("amiConnect===>", data);
return;
})
.catch((error) => {
messageError(q, error);
});
}
/**
* card authentication
* @param q this quasar
*/
function authentication(q: any) {
fetch(`${apiURL.value}/smart-card/authentication`, {
method: "GET",
})
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then(function (data) {
console.log("authentication===>", data);
return;
})
.catch((error) => {
messageError(q, error);
});
}
/**
* verify pin
* @param q this quasar
*/
async function verifyPin(q: any) {
const requestOptions = {
method: "POST",
body: JSON.stringify({
crossAuthen: {
random: ascii_to_hexa(xKey.value),
},
privateAccess: true,
}),
headers: {
"Content-Type": "application/json",
},
};
fetch(`${apiURL.value}/smart-card/verify`, requestOptions)
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then(async (data) => {
envelopGMXs.value = await data.crossAuthen.envelope;
await amiRequest(q, 9081);
})
.catch((error) => {
messageError(q, error);
// remove when api ready
amiRequest(q, 9081);
});
}
const officeid = ref<string>("00301"); // office id เป็นรหัสของ กทม (00301)
const tKey = ref<string>("");
const officeCode = ref<string>("00023");
const versionCode = ref<string>("00001");
/**
*
* @param {any} q this quasar
* @param {number} code (9080)
* @param {string} serviceCode service code (001)
* @param {string} idcard
*/
async function amiRequest(
q: any,
code: number,
idcard?: string,
serviceCode?: string
) {
let message = "";
if (code === 9080) {
message = `${code}${PID.value}${CID.value}${officeid.value}`;
} else if (code === 9081) {
const x = xKey.value;
const y = envelopGMXs.value;
message = `${code}${PID.value}${CID.value}${x}${y}`;
} else if (code === 5000) {
const T = tKey.value;
message = `${code}${T}${officeCode.value}${versionCode.value}${serviceCode}${idcard}`;
}
fetch(`${apiURL.value}/ami/request`, {
method: "POST",
headers: { "Content-type": "application/json; charset=UTF-8" },
body: JSON.stringify({
message: message,
}),
})
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then(async (data) => {
const convertData = await bin2String(data);
let removeText = await convertData.substr(9); // ตัด CODEREQ[4] + Status[5]
if (code === 9080) {
xKey.value = await removeText;
step.value = 3;
} else if (code === 9081) {
tKey.value = removeText;
step.value = 4;
}
})
.catch(async (error) => {
messageError(q, error);
// remove when api ready
if (code === 9080) {
step.value = 3;
} else if (code === 9081) {
const tRes = await [
57, 48, 56, 49, 48, 48, 48, 48, 48, 53, 57, 56, 57, 51, 51, 52, 49,
55, 51, 100, 49, 52, 51, 50, 50, 51, 51, 100, 100, 54, 100, 100, 54,
50, 51, 99, 53, 51, 56, 55, 101,
];
const convertData = await bin2String(tRes);
tKey.value = await convertData.substr(9);
step.value = 4;
}
});
}
function disconnect(q: any) {
fetch(`${apiURL.value}/smart-card/disconnect`, {
method: "GET",
})
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error("Something went wrong");
})
.then((data) => {
devices.value = "";
devicesData.value = [];
devicesOp.value = [];
step.value = 1;
PID.value = "";
CID.value = "";
xKey.value = "";
envelopGMXs.value = "";
tKey.value = "";
success(q, "disconnect successful.");
})
.catch((error) => {
messageError(q, error);
//remove when api ready
devices.value = "";
devicesData.value = [];
devicesOp.value = [];
step.value = 1;
PID.value = "";
CID.value = "";
xKey.value = "";
envelopGMXs.value = "";
tKey.value = "";
});
}
/**
* byte string
* @param {Array} array byte
* @returns {string} string
*/
function bin2String(array: number[]) {
// Creating new byte array using
// Uint8Array instance
let byteArray = new Uint8Array(array);
// Creating textDecoder instance
let decoder = new TextDecoder("utf-8");
// Using decode method to get string output
let str = decoder.decode(byteArray);
return str;
// return String.fromCharCode.apply(String, array);
}
/**
* text ascii hexa
* @param str
* @returns
*/
function ascii_to_hexa(str: string) {
var arr1 = [];
for (var n = 0, l = str.length; n < l; n++) {
var hex = Number(str.charCodeAt(n)).toString(16);
arr1.push(hex);
}
return arr1.join("");
}
return {
devicesData,
devices,
devicesOp,
step,
CID,
PID,
tKey,
fetchDeviceLists,
readDevice,
getInfo,
postReadIdCard,
amiEnvironment,
amiConnect,
authentication,
verifyPin,
amiRequest,
disconnect,
};
});