API web services

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2024-11-27 16:08:36 +07:00
parent 67787dab34
commit b11a943885
7 changed files with 259 additions and 97 deletions

View file

@ -0,0 +1,7 @@
import env from "../index";
const apiKey = `${env.API_URI}/org/apiKey`;
export default {
apiKeyMain: apiKey,
};

View file

@ -46,6 +46,9 @@ import backup from "./api/04_system/api.backup";
/** API Command/*/ /** API Command/*/
import command from "./api/05_command/api.command"; import command from "./api/05_command/api.command";
/** API Webservices*/
import webservices from "./api/06_webservices/api.webservices";
// environment variables // environment variables
export const compettitivePanel = import.meta.env.VITE_COMPETITIVE_EXAM_PANEL; export const compettitivePanel = import.meta.env.VITE_COMPETITIVE_EXAM_PANEL;
export const qualifyDisableExamPanel = import.meta.env export const qualifyDisableExamPanel = import.meta.env
@ -120,6 +123,8 @@ const API = {
...backup, ...backup,
/** command*/ /** command*/
...command, ...command,
/** webservices*/
...webservices,
}; };
export default { export default {

View file

@ -1,76 +1,155 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive, ref } from "vue"; import { computed, reactive, ref, watch } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
/** importType*/
import type { ListApi } from "@/modules/06_webservices/interface/index/Main"; import type { ListApi } from "@/modules/06_webservices/interface/index/Main";
import type { FormCreate } from "@/modules/06_webservices/interface/request/Main"; import type { FormCreate } from "@/modules/06_webservices/interface/request/Main";
import type { ResApiName } from "@/modules/06_webservices/interface/response/Main";
/** importComponents*/
import DialogHeader from "@/components/DialogHeader.vue"; import DialogHeader from "@/components/DialogHeader.vue";
/** use*/
const $q = useQuasar(); const $q = useQuasar();
const { dialogMessageNotify } = useCounterMixin(); const {
dialogMessageNotify,
showLoader,
hideLoader,
messageError,
dialogConfirm,
success,
} = useCounterMixin();
/** props*/
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
const props = defineProps({
fetchData: {
type: Function,
required: true,
},
});
const isAPIKey = ref<boolean>(false); const topicRef = ref<any>(null); //refinput /
const topicRef = ref<any>(null); const isAPIKey = ref<boolean>(false); //status API Key
const apiKey = ref<string>(""); const apiKey = ref<string>(""); // API Key
const options = ref<ListApi[]>([ const options = ref<ListApi[]>([]); // API
{ label: "API 1", value: "API 1" },
{ label: "API 2", value: "API 2" },
{ label: "API 3", value: "API 3" },
]);
// form API Key
const formData = reactive<FormCreate>({ const formData = reactive<FormCreate>({
topic: "", name: "", ///
access: [], apiId: [], //id API
}); });
const titleName = computed<string>(() => { const titleName = computed<string>(() => {
return !isAPIKey.value ? "สร้าง API Key" : "API Key"; return !isAPIKey.value ? "สร้าง API Key" : "API Key";
}); });
/** ฟังก์ชันเรียกรายการข้อมูล API ที่เข้าถึงได้*/
function fetchListApiKeyName() {
showLoader();
http
.get(config.API.apiKeyMain + "/name")
.then(async (res) => {
const data = (await res.data?.result) || [];
options.value = data.map((e: ResApiName) => ({
label: e.name,
value: e.id,
}));
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** ฟังก์ชันยืนยันการสร้าง API Key */
function onCreateAPIKey() { function onCreateAPIKey() {
topicRef.value.validate(); topicRef.value.validate();
// /
if (topicRef.value.validate()) { if (topicRef.value.validate()) {
if (formData.access.length > 0) { // API popup API Key
console.log(formData); if (formData.apiId.length > 0) {
apiKey.value = "APIKEY"; dialogConfirm($q, async () => {
isAPIKey.value = true; showLoader();
await http
.post(config.API.apiKeyMain, {
...formData,
name: formData.name.replace(/\s+/g, ""), //
})
.then(async (res) => {
const data = await res.data.result;
apiKey.value = data;
success($q, "สร้าง API Key สำเร็จ");
isAPIKey.value = true;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
});
} else { } else {
// Popup API
dialogMessageNotify($q, "กรุณาเลือก API ที่เข้าถึงได้"); dialogMessageNotify($q, "กรุณาเลือก API ที่เข้าถึงได้");
} }
} }
} }
/** ฟังก์ชันคัดลอก API API Key*/
function onCopyToClipboard() { function onCopyToClipboard() {
navigator.clipboard.writeText(apiKey.value); navigator.clipboard.writeText(apiKey.value);
} }
/**
* งกนป popup
* าม API Key ใหเรยกขอมลรายการ web services ใหม
*/
function onCloseDialog() { function onCloseDialog() {
// API Key
if (isAPIKey.value) {
props.fetchData?.();
}
modal.value = false; modal.value = false;
isAPIKey.value = false; isAPIKey.value = false;
formData.topic = ""; formData.name = "";
formData.access = []; formData.apiId = [];
} }
/**
* การเปลยนแปลงขอมลของ `modal`
* modal เป True เรยกรายการขอม API เขาถงได
*/
watch(modal, (val) => {
if (val) {
fetchListApiKeyName();
}
});
</script> </script>
<template> <template>
<q-dialog v-model="modal" persistent> <q-dialog v-model="modal" persistent>
<q-card style="width: 700px; max-width: 80vw"> <q-card style="width: 700px; max-width: 80vw">
<!-- header -->
<DialogHeader :tittle="titleName" :close="onCloseDialog" /> <DialogHeader :tittle="titleName" :close="onCloseDialog" />
<q-separator /> <q-separator />
<q-card-section v-if="!isAPIKey"> <q-card-section>
<div class="row q-col-gutter-sm"> <div class="row q-col-gutter-sm">
<div class="col-12"> <!-- /คำอธบาย -->
<div class="col-12" v-if="!isAPIKey">
<q-input <q-input
ref="topicRef" ref="topicRef"
class="inputgreen" class="inputgreen"
dense dense
outlined outlined
v-model="formData.topic" v-model="formData.name"
label="ชื่อ/คำอธิบาย" label="ชื่อ/คำอธิบาย"
hide-bottom-space hide-bottom-space
lazy-rules lazy-rules
@ -78,22 +157,8 @@ function onCloseDialog() {
/> />
</div> </div>
<div class="col-12"> <!-- apiKey -->
API เขาถงได <div class="col-12" v-else>
<q-option-group
:options="options"
type="checkbox"
keep-color
color="primary"
v-model="formData.access"
/>
</div>
</div>
</q-card-section>
<q-card-section v-else>
<div class="row q-col-gutter-sm">
<div class="col-12">
<span class="text-red"> <span class="text-red">
* API Key านลางนจะแสดงเพยงครงเดยว * API Key านลางนจะแสดงเพยงครงเดยว
ขอใหทำสำเนาไวในทปลอดภ ขอใหทำสำเนาไวในทปลอดภ
@ -114,21 +179,24 @@ function onCloseDialog() {
</q-input> </q-input>
</div> </div>
<!-- API เขาถงได -->
<div class="col-12"> <div class="col-12">
API เขาถงได API เขาถงได
<q-option-group <q-option-group
disable :disable="isAPIKey"
:options="options" :options="options"
type="checkbox" type="checkbox"
keep-color keep-color
color="primary" color="primary"
v-model="formData.access" v-model="formData.apiId"
/> />
</div> </div>
</div> </div>
</q-card-section> </q-card-section>
<q-separator /> <q-separator />
<!-- footer -->
<q-card-actions align="right" class="bg-white text-teal"> <q-card-actions align="right" class="bg-white text-teal">
<q-btn <q-btn
:label="!isAPIKey ? 'สร้าง API Key' : 'ปิด'" :label="!isAPIKey ? 'สร้าง API Key' : 'ปิด'"

View file

@ -1,8 +1,19 @@
interface ListWebServices { interface ListWebServices {
createdAt: string;
createdFullName: string;
createdUserId: string;
id: string; id: string;
topic: string; keyApi: string;
access: string[]; name: string;
amount: string; amount: number;
apiNames: ApiNames[];
}
interface ApiNames {
id: string;
methodApi: string;
name: string;
pathApi: string;
} }
interface ListApi { interface ListApi {

View file

@ -1,6 +1,6 @@
interface FormCreate { interface FormCreate {
topic: string; name: string;
access: string[]; apiId: string[];
} }
export type { FormCreate }; export type { FormCreate };

View file

@ -5,4 +5,17 @@ interface ResListWebServices {
amount: string; amount: string;
} }
export type { ResListWebServices }; interface ResApiName {
createdAt: string;
createdFullName: string;
createdUserId: string;
id: string;
lastUpdateFullName: string;
lastUpdateUserId: string;
lastUpdatedAt: string;
methodApi: string;
name: string;
pathApi: string;
}
export type { ResListWebServices, ResApiName };

View file

@ -3,41 +3,62 @@ import { onMounted, ref } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import http from "@/plugins/http";
import config from "@/app.config";
/** importType*/ /** importType*/
import type { QTableProps } from "quasar"; import type { QTableProps } from "quasar";
import type { ListWebServices } from "@/modules/06_webservices/interface/index/Main"; import type { ListWebServices } from "@/modules/06_webservices/interface/index/Main";
import type { ResListWebServices } from "@/modules/06_webservices/interface/response/Main"; import type { ResApiName } from "@/modules/06_webservices/interface/response/Main";
import DialogApiKey from "@/modules/06_webservices/components/DialogApiKey.vue"; /** importComponents*/
import DialogUsability from "@/modules/06_webservices/components/DialogUsability.vue"; import DialogApiKey from "@/modules/06_webservices/components/DialogApiKey.vue"; // API Key
import DialogUsability from "@/modules/06_webservices/components/DialogUsability.vue"; //
/** use*/ /** use*/
const $q = useQuasar(); const $q = useQuasar();
const { dialogRemove } = useCounterMixin(); const {
dialogRemove,
showLoader,
hideLoader,
messageError,
success,
date2Thai,
} = useCounterMixin();
/** Table*/ /** Table*/
const rows = ref<ListWebServices[]>([]); const rows = ref<ListWebServices[]>([]); // webservices
const keyword = ref<string>(""); const keyword = ref<string>(""); // webservices
const visibleColumns = ref<string[]>(["topic", "access", "amount"]); const visibleColumns = ref<string[]>([
"name",
"apiNames",
"amount",
"createdAt",
"createdFullName",
]);
const columns = ref<QTableProps["columns"]>([ const columns = ref<QTableProps["columns"]>([
{ {
name: "topic", name: "name",
align: "left", align: "left",
label: "ชื่อ-คำอธิบาย", label: "ชื่อ-คำอธิบาย",
sortable: true, sortable: true,
field: "topic", field: "name",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{ {
name: "access", name: "apiNames",
align: "left", align: "left",
label: "API ที่เข้าถึง", label: "API ที่เข้าถึง",
sortable: true, sortable: true,
field: "access", field: "apiNames",
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
format(val) {
return val
.map((e: ResApiName) => `<div class='q-mt-sm'>-${e.name}</div>`)
.join("");
},
}, },
{ {
name: "amount", name: "amount",
@ -48,36 +69,78 @@ const columns = ref<QTableProps["columns"]>([
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{
name: "createdAt",
align: "left",
label: "วันที่สร้าง",
sortable: true,
field: "createdAt",
format(val) {
return date2Thai(val, false, true);
},
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "createdFullName",
align: "left",
label: "ผู้ดำเนินการ",
sortable: true,
field: "createdFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]); ]);
/** API Key*/ /** API Key*/
const modalApiKey = ref<boolean>(false); const modalApiKey = ref<boolean>(false); //popup API Key
/** usability*/ /** usability*/
const modalUsability = ref<boolean>(false); const modalUsability = ref<boolean>(false); //popup
function fetchListWebServices() { /** ฟังก์ชันเรียกข้อมูลรายการ Web services*/
const data: ResListWebServices[] = [ async function fetchListWebServices() {
{ showLoader();
id: "", await http
topic: "รายการ web services 1", .get(config.API.apiKeyMain + "/list")
access: ["API1", "API2", "API3"], .then(async (res) => {
amount: "1", const data = await res.data.result;
}, rows.value = data;
{ })
id: "", .catch((err) => {
topic: "รายการ web services 2", messageError($q, err);
access: ["API1", "API2", "API3"], })
amount: "2", .finally(() => {
}, hideLoader();
]; });
rows.value = data;
} }
/**
* งก ลบขอมลรายการ Web services
* @param id รายการ Web services องการลบ
* เมอสำเรจจะเรยกฟงก 'fetchListWebServices' มาเรยกขอมลรายการ web servcice ใหม
*/
function onDeleteData(id: string) { function onDeleteData(id: string) {
dialogRemove($q, () => {}); dialogRemove($q, () => {
showLoader();
http
.delete(config.API.apiKeyMain + `/${id}`)
.then(async () => {
// web servcice
await fetchListWebServices();
success($q, "ลบข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
});
} }
/** hook เมื่อเรียก Components จะเรียกฟังก์ชัน 'fetchListWebServices' เรียกข้อมูลรายการ webservices*/
onMounted(() => { onMounted(() => {
fetchListWebServices(); fetchListWebServices();
}); });
@ -98,6 +161,7 @@ onMounted(() => {
</div> </div>
<q-card flast bordered class="q-pa-md"> <q-card flast bordered class="q-pa-md">
<!-- toolbar -->
<div class="items-center col-12 row q-col-gutter-sm"> <div class="items-center col-12 row q-col-gutter-sm">
<q-btn <q-btn
class="q-ml-sm" class="q-ml-sm"
@ -139,13 +203,14 @@ onMounted(() => {
/> />
</div> </div>
<!-- Table -->
<div class="col-12 q-pt-sm"> <div class="col-12 q-pt-sm">
<d-table <d-table
ref="table" ref="table"
:columns="columns" :columns="columns"
:rows="rows" :rows="rows"
row-key="id" row-key="id"
:filters="keyword" :filter="keyword"
flat flat
bordered bordered
:paging="true" :paging="true"
@ -176,40 +241,33 @@ onMounted(() => {
</q-btn></q-td </q-btn></q-td
> >
<q-td v-for="col in props.cols" :key="col.name" :props="props"> <q-td v-for="col in props.cols" :key="col.name" :props="props">
<div v-if="col.name === 'access'"> <!-- <div v-if="col.name === 'apiNames'">
<q-list dense> <q-list dense>
<q-item v-for="(item, key) in col.value"> <q-item v-for="(item, key) in col.value">
<q-item-section> - {{ item }}</q-item-section> <q-item-section>- {{ item.name }}</q-item-section>
</q-item> </q-item>
</q-list> </q-list>
</div> </div> -->
<div v-html="col.value ? col.value : '-'"></div>
<div v-else> <div>
{{ col.value ? col.value : "-" }} <!-- {{ col.value ? col.value : "-" }} -->
</div> </div>
</q-td> </q-td>
</q-tr> </q-tr>
</template> </template>
<!-- <template v-slot:pagination="scope">
งหมด {{ total }} รายการ
<q-pagination
v-model="currentPage"
active-color="primary"
color="dark"
:max="Number(maxPage)"
size="sm"
boundary-links
direction-links
:max-pages="5"
@update:model-value="fetchListUsers"
></q-pagination>
</template> -->
</d-table> </d-table>
</div> </div>
</q-card> </q-card>
<DialogApiKey v-model:modal="modalApiKey" /> <!-- สราง API Key -->
<DialogUsability y v-model:modal="modalUsability" /> <DialogApiKey
v-model:modal="modalApiKey"
:fetch-data="fetchListWebServices"
/>
<!-- การใชงาน -->
<DialogUsability v-model:modal="modalUsability" />
</template> </template>
<style scoped></style> <style scoped></style>