動態設定網頁標題、favicon 和 logo,並更新預設圖片路徑

This commit is contained in:
koko 2025-08-20 13:26:18 +08:00
parent 2c92242cb1
commit 5d027dd085
7 changed files with 28 additions and 12 deletions

View File

@ -33,6 +33,9 @@ COPY --from=builder /app/dist /usr/share/nginx/html
# 暴露 Nginx 預設的 80 端口 # 暴露 Nginx 預設的 80 端口
EXPOSE 80 EXPOSE 80
# 2025-08-20
LABEL changelog="2025-08-20: 動態設定網頁標題與 favicon與logo與預設build_img標題由 VITE_APP_TITLE 環境變數控制favicon、logo、build_img.jpg 由 VITE_FILE_API_BASEURL 動態插入docker-entrypoint.sh 寫入 env.js 供前端讀取。"
# Nginx 已經預設啟動,所以不需要 CMD 指令 # Nginx 已經預設啟動,所以不需要 CMD 指令
COPY docker-entrypoint.sh /docker-entrypoint.sh COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh RUN chmod +x /docker-entrypoint.sh

View File

@ -1,3 +1,3 @@
#!/bin/sh #!/bin/sh
echo "window.env = { VITE_API_BASEURL: '${VITE_API_BASEURL}', VITE_FILE_API_BASEURL: '${VITE_FILE_API_BASEURL}', VITE_MQTT_BASEURL: '${VITE_MQTT_BASEURL}' };" > /usr/share/nginx/html/env.js echo "window.env = { VITE_API_BASEURL: '${VITE_API_BASEURL}', VITE_FILE_API_BASEURL: '${VITE_FILE_API_BASEURL}', VITE_MQTT_BASEURL: '${VITE_MQTT_BASEURL}', VITE_APP_TITLE: '${VITE_APP_TITLE}' };" > /usr/share/nginx/html/env.js
exec "$@" exec "$@"

View File

@ -3,13 +3,27 @@
<html lang="en" data-theme="dracula"> <html lang="en" data-theme="dracula">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" /> <!-- favicon 由 JS 動態插入 -->
<link <link
rel="stylesheet" rel="stylesheet"
href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.css" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.css"
/> />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cvilux EMS</title> <title>Cvilux EMS</title>
<script src="/env.js"></script>
<script>
// 動態設定 favicon
if (window.env && window.env.VITE_FILE_API_BASEURL) {
var link = document.createElement("link");
link.rel = "icon";
link.href = window.env.VITE_FILE_API_BASEURL + "/upload/favicon.ico";
document.head.appendChild(link);
}
// 動態設定網頁標題
if (window.env && window.env.VITE_APP_TITLE) {
document.title = window.env.VITE_APP_TITLE;
}
</script>
<script src="https://code.jquery.com/jquery-3.7.1.js"></script> <script src="https://code.jquery.com/jquery-3.7.1.js"></script>
<script src="https://code.jquery.com/ui/1.13.3/jquery-ui.js"></script> <script src="https://code.jquery.com/ui/1.13.3/jquery-ui.js"></script>
<!-- <script type="text/javascript" src="/requirejs/config.js"></script> --> <!-- <script type="text/javascript" src="/requirejs/config.js"></script> -->
@ -17,7 +31,6 @@
type="text/javascript" type="text/javascript"
src="/module/js/com/tridium/js/ext/require/require.min.js?" src="/module/js/com/tridium/js/ext/require/require.min.js?"
></script> --> ></script> -->
<script src="/env.js"></script>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@ -11,6 +11,7 @@ import AlarmDrawer from "@/components/alarm/AlarmDrawer.vue";
import NavbarLang from "./NavbarLang.vue"; import NavbarLang from "./NavbarLang.vue";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const user = ref(""); const user = ref("");
const menuShow = ref(true); const menuShow = ref(true);
const router = useRouter(); const router = useRouter();
@ -28,7 +29,7 @@ const toggleMenu = () => {
menuShow.value = !menuShow.value; menuShow.value = !menuShow.value;
}; };
const src = import.meta.env.MODE === "production" ? "./logo.svg" : Logo; const src = `${FILE_BASEURL}/upload/logo.png`;
const logout = () => { const logout = () => {
document.cookie = "JWT-Authorization=; Max-Age=0"; document.cookie = "JWT-Authorization=; Max-Age=0";
@ -69,8 +70,7 @@ const logout = () => {
to="/dashboard" to="/dashboard"
class="rounded-lg pl-4 text-2xl font-bold text-white flex items-center" class="rounded-lg pl-4 text-2xl font-bold text-white flex items-center"
> >
<img :src="src" alt="logo" class="w-8 me-1" /> <img :src="src" alt="logo" width="180" />
CviLux Group
</router-link> </router-link>
<NavbarBuilding /> <NavbarBuilding />
</div> </div>

View File

@ -46,7 +46,7 @@ watch(
if (formState.value.building_guid) { if (formState.value.building_guid) {
imgBaseUrl.value = newExt imgBaseUrl.value = newExt
? `${FILE_BASEURL}/upload/setting/previewImage/${formState.value.building_guid}${newExt}` ? `${FILE_BASEURL}/upload/setting/previewImage/${formState.value.building_guid}${newExt}`
: "/build_img.jpg"; : `${FILE_BASEURL}/upload/build_img.jpg`;
} }
}, },
{ immediate: true } { immediate: true }

View File

@ -1,13 +1,14 @@
<script setup> <script setup>
import { onMounted, ref, watch, inject } from "vue"; import { onMounted, ref, watch, inject } from "vue";
import { Login } from "@/apis/login"; import { Login } from "@/apis/login";
import Image from "@/assets/img/logo.svg";
import * as yup from "yup"; import * as yup from "yup";
import useFormErrorMessage from "@/hooks/useFormErrorMessage"; import useFormErrorMessage from "@/hooks/useFormErrorMessage";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import useUserInfoStore from "@/stores/useUserInfoStore"; import useUserInfoStore from "@/stores/useUserInfoStore";
import useBuildingStore from "@/stores/useBuildingStore"; import useBuildingStore from "@/stores/useBuildingStore";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const { t } = useI18n(); const { t } = useI18n();
const { openToast } = inject("app_toast"); const { openToast } = inject("app_toast");
const store = useUserInfoStore(); const store = useUserInfoStore();
@ -30,7 +31,7 @@ const togglePasswordVisibility = () => {
showPassword.value = !showPassword.value; showPassword.value = !showPassword.value;
}; };
const imageSrc = import.meta.env.MODE === "production" ? "./logo.svg" : Image; const imageSrc = `${FILE_BASEURL}/upload/logo.png`;
const doLogin = async () => { const doLogin = async () => {
const value = await handleSubmit(schema, formState.value); const value = await handleSubmit(schema, formState.value);
@ -60,8 +61,7 @@ const doLogin = async () => {
<div <div
class="flex items-center justify-center w-full mb-5 text-4xl font-bold text-red-600" class="flex items-center justify-center w-full mb-5 text-4xl font-bold text-red-600"
> >
<img :src="imageSrc" alt="logo" class="w-12 me-2" /> <img :src="imageSrc" alt="logo" width="250" />
CviLux Group
</div> </div>
<div class="w-full flex flex-col items-end my-2"> <div class="w-full flex flex-col items-end my-2">
<div class="w-full flex justify-between"> <div class="w-full flex justify-between">

View File

@ -145,7 +145,7 @@ watch(
if (buildingStore.selectedBuilding && buildingStore.selectedBuilding.building_guid) { if (buildingStore.selectedBuilding && buildingStore.selectedBuilding.building_guid) {
imgBaseUrl.value = buildingStore.previewImageExt imgBaseUrl.value = buildingStore.previewImageExt
? `${FILE_BASEURL}/upload/setting/previewImage/${buildingStore.selectedBuilding.building_guid}${newValue}` ? `${FILE_BASEURL}/upload/setting/previewImage/${buildingStore.selectedBuilding.building_guid}${newValue}`
: "/build_img.jpg"; : `${FILE_BASEURL}/upload/build_img.jpg`;
} }
}, },
{ immediate: true } { immediate: true }