diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..4552074 --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,34 @@ +/**config api */ +import { ref } from "vue" + +const env = ref(process.env.NODE_ENV || "development") +// if (process.env.VUE_APP_TEST) { +// env = "test"; +// } + +const config = ref({ + development: { + // API_URI: "https://localhost:7260/api", + API_URI: "https://bma-ehr.frappet.synology.me/api/v1", + MEET_URI: "meet.frappet.com", + }, + test: { + API_URI: "http://localhost:5010/api/v1", + MEET_URI: "meet.frappet.com", + }, + production: { + API_URI: `${window.location.protocol}//${window.location.host}/api/v1`, + API_URI_ORG_TREE: "https://s3cluster.frappet.com/bma-ehr-fpt/organization/strueture/tree_20230707_115124.json", + MEET_URI: "meet.frappet.com", + }, +}) + +const API_URI = ref(config.value[env.value].API_URI) +const MEET_URI = ref(config.value[env.value].MEET_URI) + +export default { + env: env.value, + config: config.value, + API_URI: API_URI.value, + MEET_URI: MEET_URI.value, +} diff --git a/src/api/test/api.test.ts b/src/api/test/api.test.ts new file mode 100644 index 0000000..66e6b63 --- /dev/null +++ b/src/api/test/api.test.ts @@ -0,0 +1,11 @@ +/** + * API Structure + Org Chart + */ +import env from "../index" + +const tttt = `${env.API_URI}/test` + +export default { + gettttt: `${tttt}`, + puttttt: (id: string) => `${tttt}/${id}`, +} diff --git a/src/app.config.ts b/src/app.config.ts new file mode 100644 index 0000000..801594d --- /dev/null +++ b/src/app.config.ts @@ -0,0 +1,12 @@ +/**ใช้รวมไฟล์ย่อยๆ ของ api แต่ละไฟล์ */ + +/** API Metadata */ +import testtest from "./api/test/api.test" + +const API = { + ...testtest, +} + +export default { + API: API, +} diff --git a/src/main.ts b/src/main.ts index c19ea47..a100a49 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,7 @@ import { createPinia } from "pinia" import "@vuepic/vue-datepicker/dist/main.css" import "quasar/src/css/index.sass" +import http from "./plugins/http" // import './assets/main.css' @@ -29,4 +30,7 @@ app.component( "datepicker", defineAsyncComponent(() => import("@vuepic/vue-datepicker")) ) + +app.config.globalProperties.$http = http + app.mount("#app") diff --git a/src/modules/02_transfer/views/Main.vue b/src/modules/02_transfer/views/Main.vue index 1a3505f..041f9b6 100644 --- a/src/modules/02_transfer/views/Main.vue +++ b/src/modules/02_transfer/views/Main.vue @@ -1,174 +1,149 @@ - \ No newline at end of file + diff --git a/src/plugins/axios.ts b/src/plugins/axios.ts new file mode 100644 index 0000000..79bba4e --- /dev/null +++ b/src/plugins/axios.ts @@ -0,0 +1,25 @@ +import axios from "axios" +import config from "process" +// import { dotnetPath } from "../path/axiosPath"; +// import { getToken } from "@baloise/vue-keycloak"; +import keycloak from "../plugins/keycloak" + +const axiosInstance = axios.create({ + withCredentials: false, +}) + +// axiosInstance.defaults.baseURL = dotnetPath; +axiosInstance.interceptors.request.use( + async (config) => { + const token = await keycloak.token + config.headers = { + Authorization: `Bearer ${token}`, + } + return config + }, + (error) => { + Promise.reject(error) + } +) + +export default axiosInstance diff --git a/src/plugins/filters.ts b/src/plugins/filters.ts new file mode 100644 index 0000000..d5f1d75 --- /dev/null +++ b/src/plugins/filters.ts @@ -0,0 +1,22 @@ +/** + * GLOABL Filters + * - ไฟล์นี้จะไว้เก็บฟังก์ชันง่าย ๆ พวก Helper Functions ทั้งหลาย + */ + + +const filters = { + + /** + * ฟังก์ชัน compactNumber ใช้แปลงตัวเลขยาว ๆ ให้กลายเป็นเลขสั้น ๆ แบบที่พวก Social Media ชอบใช้กัน เช่น 1,000 แปลงเป็น 1K หรือ 1,000,000 แปลงเป็น 1M + * วิธีใช้ : {{ $filters.compactNumber(value) }} + * + * @param val รับค่าพารามิเตอร์เป็นตัวแปรชนิดตัวเลข + * @returns คืนค่าเป็นตัวเลขที่แปลงค่าแล้ว + */ + compactNumber (val: number) { + const formatter = Intl.NumberFormat('en', { notation: 'compact'}) + return formatter.format(val) + } +} + +export default filters; \ No newline at end of file diff --git a/src/plugins/http.ts b/src/plugins/http.ts new file mode 100644 index 0000000..494c9aa --- /dev/null +++ b/src/plugins/http.ts @@ -0,0 +1,45 @@ +import Axios, { type AxiosRequestConfig, type AxiosResponse } from "axios"; +import keycloak from "./keycloak"; + +const http = Axios.create({ + timeout: 1000000000, // เพิ่มค่า timeout + headers: { + "X-Requested-With": "XMLHttpRequest", + }, +}); + +http.interceptors.request.use( + async function (config: AxiosRequestConfig) { + await keycloak.updateToken(1); + config.headers = config.headers ?? {}; + const token = keycloak.token; + // const token = localStorage.getItem("access_token") + // const token = + // "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxU2VKV2dVRFVlNXZwNS13Q1ZHaG9lT2l4bDJTTkdKemthLU5ZN211NXZJIn0.eyJleHAiOjE2NzI0MTI1NDksImlhdCI6MTY3MjM3NjU0OSwiYXV0aF90aW1lIjoxNjcyMzc2NTQ5LCJqdGkiOiI1MTVhY2IwNC1jODQ3LTQzM2YtYjUxOC03ODUzMzJhY2ZjNWYiLCJpc3MiOiJodHRwczovL2tleWNsb2FrLmZyYXBwZXQuc3lub2xvZ3kubWUvYXV0aC9yZWFsbXMvYm1hLWVociIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJlZmM5YjRlMC1mZGU2LTQ1NDQtYmU1OS1lMTA0MjEwMjUzZjAiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJibWEtZWhyIiwibm9uY2UiOiI3NjMyMGI3ZS0xZTMxLTQ5ODYtYWIzOC1iOTUyYjFlODY3OGYiLCJzZXNzaW9uX3N0YXRlIjoiMDZlNTBkZjktNzAyNi00ZGIwLTkxMjgtMWY3Y2FiYTRkNDEyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwczovL2xvY2FsaG9zdDo3MDA2Il0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLWJtYS1laHIiLCJvZmZsaW5lX2FjY2VzcyIsImFkbWluIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBlbWFpbCBwcm9maWxlIiwic2lkIjoiMDZlNTBkZjktNzAyNi00ZGIwLTkxMjgtMWY3Y2FiYTRkNDEyIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInJvbGUiOlsiZGVmYXVsdC1yb2xlcy1ibWEtZWhyIiwib2ZmbGluZV9hY2Nlc3MiLCJhZG1pbiIsInVtYV9hdXRob3JpemF0aW9uIl0sIm5hbWUiOiJTeXN0ZW0gQWRtaW5pc3RyYXRvciIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwiZ2l2ZW5fbmFtZSI6IlN5c3RlbSIsImZhbWlseV9uYW1lIjoiQWRtaW5pc3RyYXRvciIsImVtYWlsIjoiYWRtaW5AbG9jYWxob3N0In0.xmfJ3pzI-jLYsaiFXyjTW7gfAEpvUmMVsp9BsB1CfRCVOKiGBbuZhnQY8W-1SWVAx1NjJ55L-zMHPK6hk1dRPLbEse3DlIBZw04W9j8m-Wz3eqdHf_UCjmrXb8qAwkeq0Iaxq9mVfJJeQWeKhFBi-Ff8ek4hCXTYDICXS8ny_BaC5WkyrefHQ2xBqQjwRyoxsg4IoVMjXYNb8L9A-4BNlRfs928SqgFYCRlF5h6zw_rC0XoLrGTmqeacBdpey-r3j2g_lTqWy8mQg2T9s65IDqW3kFPOsr0SVO88sjlFbN9Et0L57RmiqORk_RwzbWg-_Yb6dOuolXsnjBOhOoTzkA"; + if (token) config.headers.Authorization = `Bearer ${token}`; + return config; + }, + function (error: any) { + return Promise.reject(error); + } +); + +http.interceptors.response.use( + function (response: AxiosResponse) { + return response; + }, + function (error: any) { + if (typeof error !== undefined) { + // eslint-disable-next-line no-prototype-builtins + if (error.hasOwnProperty("response")) { + if (error.response.status === 401 || error.response.status === 403) { + // Store.commit("SET_ERROR_MESSAGE", error.response.data.message); + // Store.commit("REMOVE_ACCESS_TOKEN") + } + } + } + return Promise.reject(error); + } +); + +export default http; diff --git a/src/plugins/keycloak.ts b/src/plugins/keycloak.ts new file mode 100644 index 0000000..fa1aa50 --- /dev/null +++ b/src/plugins/keycloak.ts @@ -0,0 +1,23 @@ +/** + * front connect to keycloak + */ +import Keycloak from "keycloak-js"; +// import config from "../app.config"; +// import http from "../shared/http"; +// import router from "../router"; + +const initOptions = { + // url: "https://keycloak.frappet.synology.me/auth/", + realm: "bma-ehr", + clientId: "bma-ehr-vue3", + url: "https://identity.frappet.com/", + // realm: "bma-ehr-exam", + // clientId: "bma-ehr-exam-vue3", +}; //option keycloak ที่จะ connect + +const keycloak = Keycloak(initOptions); + +keycloak.onAuthSuccess = () => {}; //เพิ่มlogin สำเร็จจะมาทำฟังก์ชันนี้ + +await keycloak.init({ checkLoginIframe: false }); //ทำการ connect keycloak +export default keycloak; diff --git a/src/router/index.ts b/src/router/index.ts index 684c1c1..a41df9c 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -6,6 +6,9 @@ const Dashboard = () => import("@/modules/01_dashboard/views/Dashboard.vue") import ModuleTransfer from "@/modules/02_transfer/router.ts" import ModuleLeave from "@/modules/03_leave/router.ts" +// TODO: ใช้หรือไม่? +import keycloak from "@/plugins/keycloak" + const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ @@ -18,6 +21,10 @@ const router = createRouter({ path: "/", name: "dashboard", component: Dashboard, + meta: { + Auth: true, + Key: [7], + }, }, ...ModuleTransfer, ...ModuleLeave, @@ -26,4 +33,20 @@ const router = createRouter({ ], }) +router.beforeEach((to, from, next) => { + if (to.meta.Auth) { + if (!keycloak.authenticated) { + keycloak.login({ + redirectUri: `${window.location.protocol}//${window.location.host}${to.path}`, + locale: "th", + }) + } else { + next() + } + } else { + next() + } + // next(); +}) + export default router diff --git a/src/views/MainLayout.vue b/src/views/MainLayout.vue index dc96faa..77b3ca8 100644 --- a/src/views/MainLayout.vue +++ b/src/views/MainLayout.vue @@ -1,49 +1,69 @@ diff --git a/vite.config.ts b/vite.config.ts index e1be6c5..acd8eb4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,20 +1,30 @@ -import { fileURLToPath, URL } from 'node:url' +import { fileURLToPath, URL } from "node:url" -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import vueJsx from '@vitejs/plugin-vue-jsx' -import { quasar, transformAssetUrls } from '@quasar/vite-plugin' +import { defineConfig } from "vite" +import vue from "@vitejs/plugin-vue" +import vueJsx from "@vitejs/plugin-vue-jsx" +import { quasar, transformAssetUrls } from "@quasar/vite-plugin" // https://vitejs.dev/config/ export default defineConfig({ - plugins: [vue({ - template: { transformAssetUrls } - }), quasar({ - sassVariables: 'src/style/quasar-variables.sass' - }), vueJsx()], - resolve: { - alias: { - '@': fileURLToPath(new URL('./src', import.meta.url)) - } - } + plugins: [ + vue({ + template: { transformAssetUrls }, + }), + quasar({ + sassVariables: "src/style/quasar-variables.sass", + }), + vueJsx(), + ], + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, + build: { + target: "esnext", + }, + server: { + port: 3007, + }, })