Compare commits

...

20 Commits

Author SHA1 Message Date
dfc94db91a 編輯API 方式
Some checks failed
/ build (push) Has been cancelled
2025-02-25 21:41:48 +08:00
96114b44ab 更改API 匯入方式
All checks were successful
/ build (push) Successful in 31s
2025-02-25 20:49:51 +08:00
3a642e957b testCI01
All checks were successful
/ build (push) Successful in 19s
2025-02-25 20:07:12 +08:00
513506fb80 testCI01
Some checks are pending
/ build (push) Waiting to run
2025-02-25 20:04:20 +08:00
ac6504c2ae test
All checks were successful
/ build (push) Successful in 21s
2025-02-25 19:53:48 +08:00
f70c058dec 修復 登入介面BUG
Some checks failed
test_CICD / build (push) Failing after 6s
2025-02-22 22:06:05 +08:00
ff4a04285d 11
Some checks failed
test_CICD / build (push) Failing after 2s
2025-02-22 21:42:53 +08:00
c40bd7d1b3 10
Some checks failed
test_CICD / build (push) Failing after 6s
2025-02-22 21:03:33 +08:00
a3b9f47e96 09
Some checks failed
test_CICD / build (push) Failing after 7s
2025-02-22 21:01:17 +08:00
cac89d0af0 08
Some checks failed
test_CICD / build (push) Failing after 7s
2025-02-22 20:56:09 +08:00
1d7e046413 07
Some checks failed
test_CICD / build (push) Failing after 7s
2025-02-22 20:51:41 +08:00
2b5a7cc4f8 06
Some checks failed
test_CICD / build (push) Failing after 7s
2025-02-22 20:50:56 +08:00
5f19a71c69 05
Some checks are pending
test_CICD / build (push) Waiting to run
2025-02-22 20:48:56 +08:00
e2e9fcb1ce 04
Some checks are pending
Build & Pack Release / build (push) Waiting to run
2025-02-22 20:43:47 +08:00
3303be4196 03
Some checks failed
Build & Pack Release / build (push) Failing after 7s
2025-02-22 20:40:30 +08:00
9692b3a0e8 gitea_02
Some checks are pending
Build & Pack Release / build (push) Waiting to run
2025-02-22 20:38:11 +08:00
6b26a5231f gitea cicd 01 2025-02-22 20:37:31 +08:00
f1992edb8e 增加首頁視覺 2025-02-22 20:07:20 +08:00
leo
e0a5e553c5 新增啟用或未啟用 2025-02-22 17:03:42 +08:00
leo
37b445ea63 新增健管師並顯示 2025-02-22 12:26:58 +08:00
15 changed files with 1377 additions and 224 deletions

View File

@ -0,0 +1,33 @@
on:
push:
branches:
- develop
jobs:
build:
runs-on: "frontend_runner"
steps:
- name: develop
shell: powershell
run: |
echo "Git clone_start"
# 設定變數
$projectPath = "D:\Code\Project\TCM"
$frontendPath = "D:\Code\Project\TCM\Frontend"
$apiPath = "D:\Code\Server\TCM\View"
cd D:\Code\Project\TCM
if (Test-Path "Frontend") { Remove-Item -Recurse -Force "Frontend" } # 刪除原資料
if (-not (Test-Path "Frontend")) {New-Item -Path "Frontend" -ItemType Directory -Force} # 建立資料夾
echo " Cloneing ..."
git clone -b develop http://leovip125.ddns.net:8418/TCM/Frontend.git
echo "Clone End"
# Node.js 發布
echo "發布 start"
echo "發布 end"

33
.gitea/workflows/main.yml Normal file
View File

@ -0,0 +1,33 @@
on:
push:
branches:
- main
jobs:
build:
runs-on: "frontend_runner"
steps:
- name: main
shell: powershell
run: |
echo "Git clone_start"
# 設定變數
$projectPath = "D:\Code\Project\TCM_main"
$frontendPath = "D:\Code\Project\TCM_main\Frontend"
$viewPath = "D:\Code\Server\TCM_main\View"
cd D:\Code\Project\TCM_main
if (Test-Path "Frontend") { Remove-Item -Recurse -Force "Frontend" } # 刪除原資料
if (-not (Test-Path "Frontend")) {New-Item -Path "Frontend" -ItemType Directory -Force} # 建立資料夾
echo " Cloneing ..."
git clone -b main http://leovip125.ddns.net:8418/TCM/Frontend.git
echo "Clone End"
# Node.js 發布
echo "發布 start"
echo "發布 end"

View File

@ -1 +0,0 @@
export let api_host = 'http://localhost:5291';

View File

@ -10,7 +10,7 @@
<!-- Sidebar - Brand --> <!-- Sidebar - Brand -->
<a <a
class="sidebar-brand d-flex align-items-center justify-content-center" class="sidebar-brand d-flex align-items-center justify-content-center"
href="index.html" href="/Lamiter_pages/"
> >
<!--<div class="sidebar-brand-icon rotate-n-15"> <!--<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-laugh-wink"></i> <i class="fas fa-laugh-wink"></i>
@ -30,10 +30,10 @@
<!-- Nav Item - Dashboard --> <!-- Nav Item - Dashboard -->
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="index.html"> <NuxtLink class="nav-link" href="/Lamiter_pages/">
<i class="fas fa-fw fa-tachometer-alt"></i> <i class="fas fa-fw fa-tachometer-alt"></i>
<span>Dashboard</span></a <span>Dashboard</span>
> </NuxtLink>
</li> </li>
<!-- Divider --> <!-- Divider -->
@ -63,7 +63,7 @@
> >
<div class="bg-white py-2 collapse-inner rounded"> <div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">企業設定</h6> <h6 class="collapse-header">企業設定</h6>
<a class="collapse-item" href="/Lamiter_pages/Company_Control_page">企業管理</a> <NuxtLink class="collapse-item" href="/Lamiter_pages/Company_Control_page">企業管理</NuxtLink>
</div> </div>
</div> </div>
@ -535,7 +535,8 @@
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useHead } from "#app"; import { useHead } from "#app";
import { useRouter } from "vue-router"; // import { useRouter } from "vue-router"; //
const { $api_host } = useNuxtApp(); //API host const config = useRuntimeConfig();
const $api_host = config.public.apiHost;
const router = useRouter(); // const router = useRouter(); //
useHead({ useHead({
@ -563,43 +564,52 @@ useHead({
], ],
}); });
// //
async function logout() { const logout = async ()=> {
localStorage.removeItem("token_TCM"); localStorage.removeItem("token_TCM");
router.push("/").then(() => { router.push("/").then(() => {
window.location.reload(); window.location.reload();
}); });
} }
// 🔐 Token SSR
const authToken = useState("authToken", () => process.client ? localStorage.getItem("token_TCM") || "" : "");
var token; // // 🔍 Token
const token_check = ()=>{ const token_check = async () => {
// JWT if (!process.client) return; // client-side
token = localStorage.getItem("token_TCM");
console.log(token); const token = localStorage.getItem("token_TCM");
// token console.log("Token:", token);
if (token != null) {
$.ajax({ if (!token) {
type: "GET", console.log("無 Token轉跳首頁");
url: $api_host + "/Users/token_check_user", router.push("/Home_pages/");
return;
}
try {
const response = await fetch(`${$api_host}/Users/token_check_user`, {
method: "GET",
headers: { headers: {
Authorization: token, Authorization: token,
}, },
success: function (response) {
// 8
if(response.level<=8 ){
router.push("/Home_pages/");
}
},
error: function (xhr) {
console.log(xhr);
},
}); });
} else {
console.log("pass"); if (!response.ok) throw new Error("Token 驗證失敗");
const data = await response.json();
console.log("驗證成功:", data);
// level 8
if (data.level <= 8) {
router.push("/Home_pages/");
}
} catch (error) {
console.error("Token 驗證失敗", error);
router.push("/Home_pages/"); router.push("/Home_pages/");
} }
} };
// // 🔄
onMounted(token_check); onMounted(token_check);
</script> </script>

View File

@ -10,7 +10,7 @@
<!-- Sidebar - Brand --> <!-- Sidebar - Brand -->
<a <a
class="sidebar-brand d-flex align-items-center justify-content-center" class="sidebar-brand d-flex align-items-center justify-content-center"
href="index.html" href="/"
> >
<!--<div class="sidebar-brand-icon rotate-n-15"> <!--<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-laugh-wink"></i> <i class="fas fa-laugh-wink"></i>
@ -30,10 +30,10 @@
<!-- Nav Item - Dashboard --> <!-- Nav Item - Dashboard -->
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="index.html"> <NuxtLink class="nav-link" to="/Manage_pages">
<i class="fas fa-fw fa-tachometer-alt"></i> <i class="fas fa-fw fa-tachometer-alt"></i>
<span>Dashboard</span></a <span>Dashboard</span>
> </NuxtLink>
</li> </li>
<!-- Divider --> <!-- Divider -->
@ -63,7 +63,7 @@
> >
<div class="bg-white py-2 collapse-inner rounded"> <div class="bg-white py-2 collapse-inner rounded">
<h6 class="collapse-header">企業設定</h6> <h6 class="collapse-header">企業設定</h6>
<a class="collapse-item" href="/Manage_pages/Health_Control_page">健康管理師管理</a> <NuxtLink class="collapse-item" href="/Manage_pages/Health_Control_page">健康管理師管理</NuxtLink>
</div> </div>
</div> </div>
</li> </li>
@ -158,10 +158,10 @@
<!-- Divider --> <!-- Divider -->
<hr class="sidebar-divider d-none d-md-block" /> <hr class="sidebar-divider d-none d-md-block" />
<!-- Sidebar Toggler (Sidebar) --> <!-- Sidebar Toggler (Sidebar)
<div class="text-center d-none d-md-inline"> <div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button> <button class="rounded-circle border-0" id="sidebarToggle"></button>
</div> </div> -->
</ul> </ul>
<!-- End of Sidebar --> <!-- End of Sidebar -->
@ -474,7 +474,7 @@
<footer class="sticky-footer bg-white"> <footer class="sticky-footer bg-white">
<div class="container my-auto"> <div class="container my-auto">
<div class="copyright text-center my-auto"> <div class="copyright text-center my-auto">
<span>Copyright &copy; Your Website 2020</span> <span>Lamiter</span>
</div> </div>
</div> </div>
</footer> </footer>
@ -533,7 +533,8 @@
<script setup> <script setup>
import { useHead } from "#app"; import { useHead } from "#app";
import { useRouter } from "vue-router"; // import { useRouter } from "vue-router"; //
const { $api_host } = useNuxtApp(); //API host const config = useRuntimeConfig();
const $api_host = config.public.apiHost;
const router = useRouter(); // const router = useRouter(); //
useHead({ useHead({
@ -568,36 +569,46 @@ async function logout() {
}); });
} }
var token; // // 🔐 Token SSR
const token_check = ()=>{ const authToken = useState("authToken", () => process.client ? localStorage.getItem("token_TCM") || "" : "");
// JWT
token = localStorage.getItem("token_TCM"); // 🔍 Token
console.log(token); const token_check = async () => {
// token if (!process.client) return; // client-side
if (token != null) {
$.ajax({ const token = localStorage.getItem("token_TCM");
type: "GET", console.log("Token:", token);
url: $api_host + "/Users/token_check_user",
if (!token) {
console.log("無 Token轉跳首頁");
router.push("/Home_pages/");
return;
}
try {
const response = await fetch(`${$api_host}/Users/token_check_user`, {
method: "GET",
headers: { headers: {
Authorization: token, Authorization: token,
}, },
success: function (response) {
// 8
if(response.level<=6 ){
router.push("/Home_pages/");
}
},
error: function (xhr) {
console.log(xhr);
},
}); });
} else {
console.log("pass"); if (!response.ok) throw new Error("Token 驗證失敗");
const data = await response.json();
console.log("驗證成功:", data);
// level 6
if (data.level <= 6) {
router.push("/Home_pages/");
}
} catch (error) {
console.error("Token 驗證失敗", error);
router.push("/Home_pages/"); router.push("/Home_pages/");
} }
} };
// 🔄
//
onMounted(token_check); onMounted(token_check);
</script> </script>

View File

@ -2,5 +2,9 @@
export default defineNuxtConfig({ export default defineNuxtConfig({
compatibilityDate: '2024-11-01', compatibilityDate: '2024-11-01',
devtools: { enabled: true }, devtools: { enabled: true },
plugins: ['~/plugins/api-host.js'] runtimeConfig: {
public: {
apiHost: 'http://localhost:5291',
}
}
}) })

View File

@ -87,7 +87,9 @@
import { useHead,useState } from "#app"; import { useHead,useState } from "#app";
import { ref } from "vue"; import { ref } from "vue";
import { useRouter } from "vue-router"; // import { useRouter } from "vue-router"; //
const { $api_host } = useNuxtApp(); //API host const config = useRuntimeConfig();
const $api_host = config.public.apiHost;
const router = useRouter(); // const router = useRouter(); //
definePageMeta({ definePageMeta({

View File

@ -5,14 +5,21 @@
<div style="height:30px;float:right "> <div style="height:30px;float:right ">
<button class="btn btn-outline-warning" @click="edit_show">編輯資料</button> <button class="btn btn-outline-warning" @click="edit_show">編輯資料</button>
</div> </div>
<div class="d-flex align-items-center">
<label for="enableSelect" > 是否啟用 </label>
<select class="form-control" id="enableSelect" @change="enable_change" v-model="companyenable"
style="width: 80px ;">
<option value="Y">Y</option>
<option value="N">N</option>
</select>
</div>
</div> </div>
<!--編輯企業-彈跳視窗----> <!--編輯企業-彈跳視窗---->
<div> <div>
<dialog ref="edit_Company_view" class="dialog-box"> <dialog ref="edit_Company_view" class="dialog-box">
<div><button class="btn btn-danger" style="float:right" @click="close_edit_Company_view">關閉</button> <div><button class="btn btn-danger" style="float:right" @click="close_edit_Company_view">關閉</button>
<h2>編輯企業</h2> <h2>編輯企業</h2>
@ -21,38 +28,45 @@
<!-- 表單內容 --> <!-- 表單內容 -->
<div class="form-group"> <div class="form-group">
<label for="companyName">企業名稱</label> <label for="companyName">企業名稱</label>
<input id="companyName" v-model="companyName" type="text" class="form-control" placeholder="請輸入企業名稱"> <input id="companyName" v-model="companyName" type="text" class="form-control" placeholder="請輸入企業名稱"
readonly>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="companyPhone">聯絡電話</label> <label for="companyPhone">聯絡電話</label>
<input id="companyPhone" v-model="companyPhone" type="tel" class="form-control" placeholder="請輸入聯絡電話"> <input id="companyPhone" v-model="companyPhone" type="tel" class="form-control" placeholder="請輸入聯絡電話">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="companyPhone">預設帳號</label> <label for="companyaccount">帳號</label>
<input id="companyPhone" v-model="companyaccount" type="text" class="form-control" <input id="companyaccount" v-model="companyaccount" type="text" class="form-control" readonly>
placeholder="請輸入預設帳號">
</div> </div>
<div class="form-group">
<label for="companyPhone">預設密碼</label> <!--<div class="form-group">
<input id="companyPhone" v-model="companypassword" type="text" class="form-control" <label for="enableSelect">是否啟用</label>
placeholder="請輸入預設密碼"> <select class="form-control" id="enableSelect" @change="enable_change" v-model="companyenable"
</div> style="width: 100%">
<div class="form-group">
<label>是否啟用</label>
<select style="width:100%" v-model="Enable_ON">
<option value="Y">Y</option> <option value="Y">Y</option>
<option value="N">N</option> <option value="N">N</option>
</select> </select>
</div> </div>-->
<!-- 操作按鈕 --> <!-- 操作按鈕 -->
<div class="button-group"> <div class="button-group">
<button class="btn btn-success" @click="submitCompany">確認</button> <button class="btn btn-success" @click="submit_edit_Company">確認</button>
</div> </div>
</dialog> </dialog>
</div> </div>
<!--確認是否啟用-->
<div>
<dialog ref="check_enable_view" class="dialog-box" style="width: 20%;" >
<label>{{ companyenable === 'Y' ? '確認啟用?' : '確認關閉?' }}</label>
<!-- 操作按鈕 -->
<div class="button-group">
<button class="btn btn-danger" @click = "enable_view_close">返回</button>
<button class="btn btn-success" @click="submit_edit_enable">確認</button>
</div>
</dialog>
</div>
</template> </template>
@ -63,49 +77,159 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useRouter } from "vue-router"; // import { useRouter } from "vue-router"; //
const { $api_host } = useNuxtApp(); //API host const config = useRuntimeConfig();// API
const $api_host = config.public.apiHost;
const router = useRouter(); // const router = useRouter(); //
// 🔐 token
const authToken = ref("");
//
//
const edit_Company_view = ref(null); const edit_Company_view = ref(null);
async function edit_show() { const edit_show = async () => {
await get_data();
edit_Company_view.value?.showModal(); edit_Company_view.value?.showModal();
} }
// <-> // <->
function close_edit_Company_view() { const close_edit_Company_view = () => {
edit_Company_view.value?.close(); edit_Company_view.value?.close();
} }
const company_name=ref(""); //
const enable_view_close = async() =>{
check_enable_view.value?.close();
}
// //
const get_data = async () => { const get_data = async () => {
const now_route = useRoute(); // const Company_data = await get_company_data()
const company_guid = now_route.params.guid set_Company(Company_data);
};
//
const get_company_data = async () => {
const route = useRoute(); //
const company_guid = route.params.guid; // guid
// company_guid
if (!company_guid) {
console.error("沒有找到公司 GUID");
return;
}
try { try {
const response = await fetch(`${$api_host}/api/Company_detail_table/get_campany-${company_guid}`, { const response = await $fetch(`${$api_host}/api/Company_detail_table/get_campany-${company_guid}`, {
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
Authorization: authToken.value, // authToken
}, },
}); });
if (!response.ok) throw new Error(`HTTP 錯誤! 狀態碼: ${response.status}`); return response
const data = await response.json();
company_name.value=data.company_name
} catch (error) { } catch (error) {
console.error("獲取公司資料失敗:", error); console.error("獲取公司資料失敗:", error);
} }
}
//
//
const company_name = ref("");
const companyName = ref("");
const companyPhone = ref("");
const companyaccount = ref("");
const companyenable = ref("");
let level =ref()
const set_Company = (data) => {
company_name.value = data.company_name
companyName.value = data.company_name
companyaccount.value = data.user_name
level = parseInt(data.level, 10);
if (level % 2 == 0) {
companyenable.value = 'Y'
}
else {
companyenable.value = 'N'
}
}
//
//
const check_enable_view = ref(null);
const enable_change = async () => {
if (companyenable.value == 'Y'){
if (level % 2 != 0){
level = level + 1;
check_enable_view.value?.showModal();
}
}
if (companyenable.value == 'N'){
if (level % 2 == 0){
level = level - 1;
check_enable_view.value?.showModal();
}
}
//console.log(level)
}
//
const submit_edit_enable = async () => {
console.log(level)
const route = useRoute(); //
const company_guid = route.params.guid; // guid
try {
const enable_data = {
guid: company_guid,
level:level.toString()
};
const response = await fetch(`${$api_host}/api/Company_detail_table/company_enable`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: authToken.value,
},
body: JSON.stringify(enable_data)
});
check_enable_view.value?.close();
alert('編輯成功!');
get_data();
} catch (error) {
console.error( error);
}
}
//
const submit_edit_Company = async () =>{
try {
const companyData = {
company_name: companyName.value,
username: companyaccount.value,
password: companypassword.value
};
console.log(companyData)
} catch (error) {
alert('上傳失敗,請檢查後端!');
}
}
};
// //
onMounted(get_data); // 🚀 mounted token
onMounted(() => {
if (process.client) {
// localStorage token reactive
authToken.value = localStorage.getItem("token_TCM") || "";
}
get_data(); // token 調 API
});
</script> </script>

View File

@ -8,7 +8,7 @@
<div class="row"> <div class="row">
<div v-for="company in companies" :key="company.guid" class="col-xl-3 col-md-6 mb-4"> <div v-for="company in companies" :key="company.guid" class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2" @click="edit_company(company.guid)"> <div :class="['card', 'shadow', 'h-100', 'py-2', company.level == '8' ? 'border-left-primary' : 'border-left-warning']" @click="edit_company(company.guid)">
<div class="card-body"> <div class="card-body">
<div class="row no-gutters align-items-center"> <div class="row no-gutters align-items-center">
<div class="col mr-2"> <div class="col mr-2">
@ -28,7 +28,7 @@
</div> </div>
<!--新增企業-彈跳視窗--> <!--新增企業-彈跳視窗-->
<div> <div>
@ -69,24 +69,28 @@
</div> </div>
</template> </template>
<script setup > <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useRouter } from "vue-router"; // import { useRouter } from "vue-router"; //
const { $api_host } = useNuxtApp(); //API host const config = useRuntimeConfig();
const $api_host = config.public.apiHost;
const router = useRouter(); // const router = useRouter(); //
// 🔐 token
const authToken = ref("");
const add_Company_view = ref(null); const add_Company_view = ref(null);
// //
async function add_company() { const add_company = async () => {
companyName.value =""; companyName.value = "";
companyPhone.value = ""; companyPhone.value = "";
companyaccount.value =""; companyaccount.value = "";
companypassword.value = ""; companypassword.value = "";
add_Company_view.value?.showModal(); add_Company_view.value?.showModal();
} }
// <-> // <->
function close_add_Company_view() { const close_add_Company_view = () => {
add_Company_view.value?.close(); add_Company_view.value?.close();
} }
@ -96,60 +100,91 @@ const companyName = ref("");
const companyPhone = ref(""); const companyPhone = ref("");
const companyaccount = ref(""); const companyaccount = ref("");
const companypassword = ref(""); const companypassword = ref("");
async function submitCompany() { const submitCompany = async () => {
try { try {
const companyData = { const companyData = {
lastname:companyName.value, lastname: companyName.value,
username: companyaccount.value, username: companyaccount.value,
password: companypassword.value password: companypassword.value
}; };
console.log(companyData) console.log(companyData)
const response = await fetch(`${$api_host}/api/Company_detail_table/Add_campany`, { const response = await fetch(`${$api_host}/api/Company_detail_table/Add_campany`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json',
Authorization: authToken.value,
}, },
body: JSON.stringify(companyData) body: JSON.stringify(companyData)
}); });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
add_Company_view.value?.close(); add_Company_view.value?.close();
alert('上傳成功!'); alert('上傳成功!');
get_data(); get_data();
} catch (error) { } catch (error) {
alert('上傳失敗,請檢查後端!'); alert('上傳失敗,請檢查後端!');
} }
} }
//
const companies = ref([]);
const get_data = async () => {
try {
const response = await fetch(`${$api_host}/api/Company_detail_table/get_all_campany`);
if (!response.ok) throw new Error(`HTTP 錯誤! 狀態碼: ${response.status}`);
const data = await response.json(); //
companies.value = data; // const get_data = async () => {
} catch (error) { const All_Companies = await get_All_Companies();//
console.error('獲取公司資料失敗:', error); set_All_Companies_data(All_Companies);
} }
// 📌
const get_All_Companies = async () => {
if (!process.client) return; // client-side
//const token = localStorage.getItem("token_TCM");
try {
const response = await $fetch(`${$api_host}/api/Company_detail_table/get_all_campany`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: authToken.value,
},
});
console.log("✅ 獲取成功", response);
return response
} catch (error) {
console.error("🔴 獲取公司資料失敗", error);
}
}; };
//
const companies = ref([]);
const set_All_Companies_data = (data) => {
console.log(data)
companies.value = data; //
}
// //
async function edit_company(guid){ const edit_company = async (guid) => {
console.log(guid) console.log(guid)
router.push("/Lamiter_pages/Company-"+guid); router.push("/Lamiter_pages/Company-" + guid);
} }
// //
onMounted(get_data); // 🚀 mounted token
onMounted(() => {
if (process.client) {
// localStorage token reactive
authToken.value = localStorage.getItem("token_TCM") || "";
}
get_data(); // token 調 API
});
</script> </script>

View File

@ -1,11 +1,346 @@
<template> <template>
<div>lamiter 的首頁</div> <div>
<!-- Main Content -->
<div id="content">
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800"> Lamiter 的首頁</h1>
<a href="#" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i
class="fas fa-download fa-sm text-white-50"></i> Generate Report</a>
</div>
<!-- Content Row -->
<div class="row">
<!-- Earnings (Monthly) Card Example -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Earnings (Monthly)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">$40,000</div>
</div>
<div class="col-auto">
<i class="fas fa-calendar fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Earnings (Monthly) Card Example -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-success shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">
Earnings (Annual)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">$215,000</div>
</div>
<div class="col-auto">
<i class="fas fa-dollar-sign fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Earnings (Monthly) Card Example -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-info shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Tasks
</div>
<div class="row no-gutters align-items-center">
<div class="col-auto">
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">50%</div>
</div>
<div class="col">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar"
style="width: 50%" aria-valuenow="50" aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
<div class="col-auto">
<i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Pending Requests Card Example -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-warning shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
Pending Requests</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">18</div>
</div>
<div class="col-auto">
<i class="fas fa-comments fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Content Row -->
<div class="row">
<!-- Area Chart -->
<div class="col-xl-8 col-lg-7">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Earnings Overview</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-area">
<canvas id="myAreaChart"></canvas>
</div>
</div>
</div>
</div>
<!-- Pie Chart -->
<div class="col-xl-4 col-lg-5">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Revenue Sources</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-pie pt-4 pb-2">
<canvas id="myPieChart"></canvas>
</div>
<div class="mt-4 text-center small">
<span class="mr-2">
<i class="fas fa-circle text-primary"></i> Direct
</span>
<span class="mr-2">
<i class="fas fa-circle text-success"></i> Social
</span>
<span class="mr-2">
<i class="fas fa-circle text-info"></i> Referral
</span>
</div>
</div>
</div>
</div>
</div>
<!-- Content Row -->
<div class="row">
<!-- Content Column -->
<div class="col-lg-6 mb-4">
<!-- Project Card Example -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Projects</h6>
</div>
<div class="card-body">
<h4 class="small font-weight-bold">Server Migration <span class="float-right">20%</span>
</h4>
<div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar" style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Sales Tracking <span class="float-right">40%</span>
</h4>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar" style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Customer Database <span
class="float-right">60%</span></h4>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" style="width: 60%" aria-valuenow="60"
aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Payout Details <span class="float-right">80%</span>
</h4>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Account Setup <span
class="float-right">Complete!</span></h4>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" style="width: 100%"
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
<!-- Color System -->
<div class="row">
<div class="col-lg-6 mb-4">
<div class="card bg-primary text-white shadow">
<div class="card-body">
Primary
<div class="text-white-50 small">#4e73df</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-success text-white shadow">
<div class="card-body">
Success
<div class="text-white-50 small">#1cc88a</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-info text-white shadow">
<div class="card-body">
Info
<div class="text-white-50 small">#36b9cc</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-warning text-white shadow">
<div class="card-body">
Warning
<div class="text-white-50 small">#f6c23e</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-danger text-white shadow">
<div class="card-body">
Danger
<div class="text-white-50 small">#e74a3b</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-secondary text-white shadow">
<div class="card-body">
Secondary
<div class="text-white-50 small">#858796</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-light text-black shadow">
<div class="card-body">
Light
<div class="text-black-50 small">#f8f9fc</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-dark text-white shadow">
<div class="card-body">
Dark
<div class="text-white-50 small">#5a5c69</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<!-- Illustrations -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Illustrations</h6>
</div>
<div class="card-body">
<div class="text-center">
<img class="img-fluid px-3 px-sm-4 mt-3 mb-4" style="width: 25rem;"
src="/img/undraw_posting_photo.svg" alt="...">
</div>
<p>Add some quality, svg illustrations to your project courtesy of <a target="_blank"
rel="nofollow" href="https://undraw.co/">unDraw</a>, a
constantly updated collection of beautiful svg images that you can use
completely free and without attribution!</p>
<a target="_blank" rel="nofollow" href="https://undraw.co/">Browse Illustrations on
unDraw &rarr;</a>
</div>
</div>
<!-- Approach -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Development Approach</h6>
</div>
<div class="card-body">
<p>SB Admin 2 makes extensive use of Bootstrap 4 utility classes in order to reduce
CSS bloat and poor page performance. Custom CSS classes are used to create
custom components and custom utility classes.</p>
<p class="mb-0">Before working with this theme, you should become familiar with the
Bootstrap framework, especially the utility classes.</p>
</div>
</div>
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
</div>
</template> </template>
<script setup> <script setup>
import { onMounted } from "vue"; import { onMounted } from "vue";
const { $api_host } = useNuxtApp(); const config = useRuntimeConfig();// API
const $api_host = config.public.apiHost;
definePageMeta({ definePageMeta({
layout: "default", // layout: "default", //

View File

@ -4,16 +4,22 @@
新增健管師 新增健管師
</button> </button>
<br /><br /> <br /><br />
<div>
<p>啟用數量: {{ healther_count.enabled }} 未啟用數量: {{ healther_count.disabled }} 總數: {{ healther_count.total }}
</p>
</div>
<br /><br />
<div class="row"> <div class="row">
<div v-for="healther in healthers" :key="health.guid" class="col-xl-3 col-md-6 mb-4"> <div v-for="healther in healthers" :key="healther.guid" class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2" @click="edit_health(health.guid)"> <div :class="['card', 'shadow', 'h-100', 'py-2', healther.level == '6' ? 'border-left-primary' : 'border-left-warning']" @click="go_healther_page(healther.guid)">
<div class="card-body"> <div class="card-body">
<div class="row no-gutters align-items-center"> <div class="row no-gutters align-items-center">
<div class="col mr-2"> <div class="col mr-2">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1"> <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
健管師名稱 健管師名稱
</div> </div>
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ health.health_name }}</div> <div class="h5 mb-0 font-weight-bold text-gray-800">{{ healther.health_name }}</div>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<i class="fas fa-user-tie fa-2x text-gray-300"></i> <!-- 改為人圖標 --> <i class="fas fa-user-tie fa-2x text-gray-300"></i> <!-- 改為人圖標 -->
@ -66,8 +72,11 @@
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useRouter } from "vue-router"; // import { useRouter } from "vue-router"; //
const { $api_host } = useNuxtApp(); //API host const config = useRuntimeConfig();// API
const $api_host = config.public.apiHost;
const router = useRouter(); // const router = useRouter(); //
const authToken = ref("");// 🔐 token
const add_Health_view = ref(null); const add_Health_view = ref(null);
definePageMeta({ definePageMeta({
@ -75,7 +84,7 @@ definePageMeta({
}) })
// //
async function add_health_manager() { const add_health_manager = async () => {
healthName.value = ""; healthName.value = "";
healthPhone.value = ""; healthPhone.value = "";
healthaccount.value = ""; healthaccount.value = "";
@ -84,7 +93,7 @@ async function add_health_manager() {
} }
// <-> // <->
function close_add_Health_view() { const close_add_Health_view = () => {
add_Health_view.value?.close(); add_Health_view.value?.close();
} }
@ -93,31 +102,30 @@ const healthName = ref("");
const healthPhone = ref(""); const healthPhone = ref("");
const healthaccount = ref(""); const healthaccount = ref("");
const healthpassword = ref(""); const healthpassword = ref("");
async function submitCompany() { const submitHealth = async () => {
try { try {
const healthData = { const healthData = {
lastname: companyName.value, lastname: healthName.value,
username: companyaccount.value, username: healthaccount.value,
password: companypassword.value password: healthpassword.value,
company_guid: company_guid.value
}; };
console.log(companyData) console.log(healthData)
const response = await fetch(`${$api_host}/api/Company_detail_table/Add_campany`, { const response = await $fetch(`${$api_host}/api/Health_detail_table/Add_health`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json',
Authorization: authToken.value,
}, },
body: JSON.stringify(companyData) body: JSON.stringify(healthData)
}); });
add_Health_view.value?.close();
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
add_Company_view.value?.close();
alert('上傳成功!'); alert('上傳成功!');
get_data(); get_data();
} catch (error) { } catch (error) {
console.error(error);
alert('上傳失敗,請檢查後端!'); alert('上傳失敗,請檢查後端!');
} }
@ -125,42 +133,115 @@ async function submitCompany() {
const company_guid = ref ("") const company_guid = ref("") //GUID
// //
const get_data = async () => { const get_data = async () => {
const authToken = useState("authToken", () => process.client ? localStorage.getItem("token_TCM") || "" : ""); await get_company_basic_data();
console.log(authToken) const All_Health_data = await get_all_health_data();
await get_company_basic_data() set_All_Health_data(All_Health_data);
await get_all_health_data() const All_Count = await get_all_count();
set_All_Health_Count(All_Count);
} }
// //
const get_company_basic_data = async () => { const get_company_basic_data = async () => {
try { try {
const response = await fetch(`${$api_host}/Users/token_check_user`, { const response = await $fetch(`${$api_host}/Users/token_check_user`, {
method: 'GET',
headers: { headers: {
Authorization: token, "Content-Type": "application/json",
Authorization: authToken.value,
}, },
}); });
if (!response.ok) throw new Error(`HTTP 錯誤! 狀態碼: ${response.status}`); company_guid.value = response.guid
const data = await response.json();
company_guid.value = data.guid
} catch (error) { } catch (error) {
console.error('企業基礎資料失敗:', error); console.error('企業基礎資料失敗:', error);
} }
} }
// //
const get_all_health_data = async()=>{ const get_all_health_data = async () => {
console.log(company_guid.value)
try {
const response = await $fetch(`${$api_host}/api/Health_detail_table/get_company_all_health-${company_guid.value}`, {
method: 'GET',
headers: {
"Content-Type": "application/json",
Authorization: authToken.value,
},
});
return response;
} catch (error) {
console.error(error);
}
}
//
const get_all_count = async () => {
try {
const response = await $fetch(`${$api_host}/api/Health_detail_table/get_company_all_health_count-${company_guid.value}`, {
method: 'GET',
headers: {
"Content-Type": "application/json",
Authorization: authToken.value,
},
});
return response;
} catch (error) {
console.error(error);
}
}
//
//
const healthers = ref([]);
const set_All_Health_data = (data) => {
console.log(data)
healthers.value = data
}
//
const healther_count = ref({ enabled: 0, disabled: 0, total: 0, });
const set_All_Health_Count = (data) => {
let all_count = 0;
for (let i = 0; i < data.length; i++) {
let d = data[i];
if (d.level == '5') {
healther_count.value.disabled = d.level_count; //
}
if (d.level == '6') {
healther_count.value.enabled = d.level_count; //
}
all_count += d.level_count; //
}
healther_count.value.total = all_count
console.log(healther_count)
}
//
const go_healther_page =(guid) =>{
router.push("/Manage_pages/health_person-" + guid);
} }
// //
onMounted(get_data); // 🚀 mounted token
onMounted(() => {
if (process.client) {
// localStorage token reactive
authToken.value = localStorage.getItem("token_TCM") || "";
}
get_data(); // token 調 API
});
</script> </script>
<style> <style>
/* 簡單美化對話框 */ /* 簡單美化對話框 */
.dialog-box { .dialog-box {

View File

@ -0,0 +1,154 @@
<template>
<div>
<h1>健管師資料 - {{ healther_name }}</h1>
<!-- 你可以根據這個 name 來顯示詳細資料 -->
<div class="d-flex align-items-center">
<label for="enableSelect" > 是否啟用 </label>
<select class="form-control" id="enableSelect" @change="enable_change" v-model="healtherenable"
style="width: 80px ;">
<option value="Y">Y</option>
<option value="N">N</option>
</select>
</div>
</div>
<!--確認是否啟用-->
<div>
<dialog ref="check_enable_view" class="dialog-box" style="width: 20%;" >
<label>{{ healtherenable === 'Y' ? '確認啟用?' : '確認關閉?' }}</label>
<!-- 操作按鈕 -->
<div class="button-group">
<button class="btn btn-danger" @click = "enable_view_close">返回</button>
<button class="btn btn-success" @click="submit_edit_enable">確認</button>
</div>
</dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from "vue-router"; //
const config = useRuntimeConfig();// API
const $api_host = config.public.apiHost;
const router = useRouter(); //
const authToken = ref("");// 🔐 token
const add_Health_view = ref(null);
definePageMeta({
layout: 'defaultmanager' //
})
//
const enable_view_close = async() =>{
check_enable_view.value?.close();
}
//
const get_data = async () => {
const Healther_data = await get_healther_data();
set_Healther(Healther_data);
};
const get_healther_data =async()=>{
const route = useRoute(); //
const health_guid = route.params.guid; // guid
// company_guid
if (!health_guid) {
console.error("沒有找到公司 GUID");
return;
}
try {
const response = await $fetch(`${$api_host}/api/Health_detail_table/get_health_person-${health_guid}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: authToken.value, // authToken
},
});
return response
} catch (error) {
console.error("獲取健管師資料失敗:", error);
}
}
//
const healther_name=ref('');
const healtherenable = ref("");
let level =ref()
const set_Healther = (data) =>{
console.log(data)
healther_name.value = data.health_name
level = parseInt(data.level, 10);
if (level % 2 == 0) {
healtherenable.value = 'Y'
}
else {
healtherenable.value = 'N'
}
}
//
//
const check_enable_view = ref(null);
const enable_change = async () => {
if (healtherenable.value == 'Y'){
if (level % 2 != 0){
level = level + 1;
check_enable_view.value?.showModal();
}
}
if (healtherenable.value == 'N'){
if (level % 2 == 0){
level = level - 1;
check_enable_view.value?.showModal();
}
}
//console.log(level)
}
//
const submit_edit_enable = async () => {
console.log(level)
const route = useRoute(); //
const health_guid = route.params.guid; // guid
try {
const enable_data = {
guid: health_guid,
level:level.toString()
};
const response = await fetch(`${$api_host}/api/Health_detail_table/healther_enable`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: authToken.value,
},
body: JSON.stringify(enable_data)
});
check_enable_view.value?.close();
alert('編輯成功!');
get_data();
} catch (error) {
console.error( error);
}
}
//
// 🚀 mounted token
onMounted(() => {
if (process.client) {
// localStorage token reactive
authToken.value = localStorage.getItem("token_TCM") || "";
}
get_data(); // token 調 API
});
</script>

View File

@ -1,11 +1,345 @@
<template> <template>
<div> <div>
Manager 的首頁 <!-- Main Content -->
<div id="content">
<!-- Begin Page Content -->
<div class="container-fluid">
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800"> Manager 的首頁</h1>
<a href="#" class="d-none d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i
class="fas fa-download fa-sm text-white-50"></i> Generate Report</a>
</div>
<!-- Content Row -->
<div class="row">
<!-- Earnings (Monthly) Card Example -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Earnings (Monthly)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">$40,000</div>
</div>
<div class="col-auto">
<i class="fas fa-calendar fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Earnings (Monthly) Card Example -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-success shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">
Earnings (Annual)</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">$215,000</div>
</div>
<div class="col-auto">
<i class="fas fa-dollar-sign fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Earnings (Monthly) Card Example -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-info shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Tasks
</div>
<div class="row no-gutters align-items-center">
<div class="col-auto">
<div class="h5 mb-0 mr-3 font-weight-bold text-gray-800">50%</div>
</div>
<div class="col">
<div class="progress progress-sm mr-2">
<div class="progress-bar bg-info" role="progressbar"
style="width: 50%" aria-valuenow="50" aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
<div class="col-auto">
<i class="fas fa-clipboard-list fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Pending Requests Card Example -->
<div class="col-xl-3 col-md-6 mb-4">
<div class="card border-left-warning shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
Pending Requests</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">18</div>
</div>
<div class="col-auto">
<i class="fas fa-comments fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Content Row -->
<div class="row">
<!-- Area Chart -->
<div class="col-xl-8 col-lg-7">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Earnings Overview</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-area">
<canvas id="myAreaChart"></canvas>
</div>
</div>
</div>
</div>
<!-- Pie Chart -->
<div class="col-xl-4 col-lg-5">
<div class="card shadow mb-4">
<!-- Card Header - Dropdown -->
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">Revenue Sources</h6>
<div class="dropdown no-arrow">
<a class="dropdown-toggle" href="#" role="button" id="dropdownMenuLink"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-sm fa-fw text-gray-400"></i>
</a>
<div class="dropdown-menu dropdown-menu-right shadow animated--fade-in"
aria-labelledby="dropdownMenuLink">
<div class="dropdown-header">Dropdown Header:</div>
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="chart-pie pt-4 pb-2">
<canvas id="myPieChart"></canvas>
</div>
<div class="mt-4 text-center small">
<span class="mr-2">
<i class="fas fa-circle text-primary"></i> Direct
</span>
<span class="mr-2">
<i class="fas fa-circle text-success"></i> Social
</span>
<span class="mr-2">
<i class="fas fa-circle text-info"></i> Referral
</span>
</div>
</div>
</div>
</div>
</div>
<!-- Content Row -->
<div class="row">
<!-- Content Column -->
<div class="col-lg-6 mb-4">
<!-- Project Card Example -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Projects</h6>
</div>
<div class="card-body">
<h4 class="small font-weight-bold">Server Migration <span class="float-right">20%</span>
</h4>
<div class="progress mb-4">
<div class="progress-bar bg-danger" role="progressbar" style="width: 20%"
aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Sales Tracking <span class="float-right">40%</span>
</h4>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar" style="width: 40%"
aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Customer Database <span
class="float-right">60%</span></h4>
<div class="progress mb-4">
<div class="progress-bar" role="progressbar" style="width: 60%" aria-valuenow="60"
aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Payout Details <span class="float-right">80%</span>
</h4>
<div class="progress mb-4">
<div class="progress-bar bg-info" role="progressbar" style="width: 80%"
aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<h4 class="small font-weight-bold">Account Setup <span
class="float-right">Complete!</span></h4>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar" style="width: 100%"
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
<!-- Color System -->
<div class="row">
<div class="col-lg-6 mb-4">
<div class="card bg-primary text-white shadow">
<div class="card-body">
Primary
<div class="text-white-50 small">#4e73df</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-success text-white shadow">
<div class="card-body">
Success
<div class="text-white-50 small">#1cc88a</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-info text-white shadow">
<div class="card-body">
Info
<div class="text-white-50 small">#36b9cc</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-warning text-white shadow">
<div class="card-body">
Warning
<div class="text-white-50 small">#f6c23e</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-danger text-white shadow">
<div class="card-body">
Danger
<div class="text-white-50 small">#e74a3b</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-secondary text-white shadow">
<div class="card-body">
Secondary
<div class="text-white-50 small">#858796</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-light text-black shadow">
<div class="card-body">
Light
<div class="text-black-50 small">#f8f9fc</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card bg-dark text-white shadow">
<div class="card-body">
Dark
<div class="text-white-50 small">#5a5c69</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<!-- Illustrations -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Illustrations</h6>
</div>
<div class="card-body">
<div class="text-center">
<img class="img-fluid px-3 px-sm-4 mt-3 mb-4" style="width: 25rem;"
src="/img/undraw_posting_photo.svg" alt="...">
</div>
<p>Add some quality, svg illustrations to your project courtesy of <a target="_blank"
rel="nofollow" href="https://undraw.co/">unDraw</a>, a
constantly updated collection of beautiful svg images that you can use
completely free and without attribution!</p>
<a target="_blank" rel="nofollow" href="https://undraw.co/">Browse Illustrations on
unDraw &rarr;</a>
</div>
</div>
<!-- Approach -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Development Approach</h6>
</div>
<div class="card-body">
<p>SB Admin 2 makes extensive use of Bootstrap 4 utility classes in order to reduce
CSS bloat and poor page performance. Custom CSS classes are used to create
custom components and custom utility classes.</p>
<p class="mb-0">Before working with this theme, you should become familiar with the
Bootstrap framework, especially the utility classes.</p>
</div>
</div>
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- End of Main Content -->
</div> </div>
</template> </template>
<script setup> <script setup>
definePageMeta({
layout: 'defaultmanager' // definePageMeta({
}) layout: 'defaultmanager' //
})
</script> </script>

View File

@ -1,26 +1,24 @@
<template></template> <template></template>
<script setup> <script setup>
import { useHead } from "#app"; //Head import { useHead } from "#app"; // Head
import { ref } from "vue"; import { ref, onMounted } from "vue"; //
import { onMounted } from "vue"; // import { useRouter } from "vue-router"; //
import { useRouter } from "vue-router"; // const config = useRuntimeConfig();
const { $api_host } = useNuxtApp(); //API host const $api_host = config.public.apiHost;
const router = useRouter(); // const router = useRouter(); //
definePageMeta({ definePageMeta({
layout: false, // layout layout: false, // layout
}); });
// Head
useHead({ useHead({
title: "Lamiter", title: "Lamiter",
meta: [ meta: [
{ charset: "utf-8" }, { charset: "utf-8" },
{ "http-equiv": "X-UA-Compatible", content: "IE=edge" }, { "http-equiv": "X-UA-Compatible", content: "IE=edge" },
{ { name: "viewport", content: "width=device-width, initial-scale=1, shrink-to-fit=no" },
name: "viewport",
content: "width=device-width, initial-scale=1, shrink-to-fit=no",
},
{ name: "description", content: "" }, { name: "description", content: "" },
{ name: "author", content: "" }, { name: "author", content: "" },
], ],
@ -28,12 +26,11 @@ useHead({
{ {
rel: "stylesheet", rel: "stylesheet",
href: "https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i", href: "https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i",
}, // `styles.css` public/css },
{ rel: "stylesheet", href: "/css/sb-admin-2.min.css" }, { rel: "stylesheet", href: "/css/sb-admin-2.min.css" },
{ rel: "stylesheet", href: "/vendor/fontawesome-free/css/all.min.css" }, { rel: "stylesheet", href: "/vendor/fontawesome-free/css/all.min.css" },
], ],
script: [ script: [
//{ src: 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js', crossorigin: 'anonymous' },
{ src: "/vendor/jquery/jquery.min.js" }, { src: "/vendor/jquery/jquery.min.js" },
{ src: "/vendor/bootstrap/js/bootstrap.bundle.min.js" }, { src: "/vendor/bootstrap/js/bootstrap.bundle.min.js" },
{ src: "/vendor/jquery-easing/jquery.easing.min.js" }, { src: "/vendor/jquery-easing/jquery.easing.min.js" },
@ -41,44 +38,49 @@ useHead({
], ],
}); });
console.log($api_host); // 🔐 Token SSR
var token; // const authToken = useState("authToken", () => process.client ? localStorage.getItem("token_TCM") || "" : "");
//token // 🔍 Token
function token_check() { async function token_check() {
// JWT if (!process.client) return; // client-side
token = localStorage.getItem("token_TCM");
console.log(token); const token = localStorage.getItem("token_TCM");
// token console.log("Token:", token);
if (token != null) {
$.ajax({ if (!token) {
type: "GET", console.log("無 Token轉跳首頁");
url: $api_host + "/Users/token_check_user", router.push("/Home_pages/").then(() => {
window.location.reload();
});
return;
}
try {
const response = await fetch(`${$api_host}/Users/token_check_user`, {
method: "GET",
headers: { headers: {
Authorization: token, Authorization: token,
}, },
success: function (response) {
// 10 BOSS
if(response.level>=9){
router.push("/Lamiter_pages/");
}
// 9
if(response.level==8){
router.push("/Manage_pages/");
}
},
error: function (xhr) {
console.log("false");
},
}); });
} else {
console.log("pass"); if (!response.ok) throw new Error("Token 驗證失敗");
const data = await response.json();
console.log("驗證成功:", data);
if (data.level >= 9) {
router.push("/Lamiter_pages/");
} else if (data.level == 8) {
router.push("/Manage_pages/");
}
} catch (error) {
console.error("Token 驗證失敗", error);
router.push("/Home_pages/"); router.push("/Home_pages/");
} }
} }
// // 🔄
onMounted(() => { onMounted(token_check);
token_check();
});
</script> </script>

View File

@ -1,4 +0,0 @@
export default defineNuxtPlugin(nuxtApp => {
// 定義 api_host 為全局變數
nuxtApp.provide('api_host', 'http://localhost:5291');
});