Compare commits

...

7 Commits

55 changed files with 411 additions and 294 deletions

View File

@ -1,4 +0,0 @@
VITE_API_BASEURL = "https://ibms-Empower-api.production.mjmtech.com.tw"
VITE_FILE_API_BASEURL = "https://ibms-Empower.production.mjmtech.com.tw"
VITE_MQTT_BASEURL = "wss://mqttwss.mjm-staging.developers-homelab.net"
VITE_FORGE_BASEURL = "https://ibms-Empower.production.mjmtech.com.tw/dist"

View File

@ -1,4 +0,0 @@
VITE_API_BASEURL = "https://ibms-Empower-api.production.mjmtech.com.tw"
VITE_FILE_API_BASEURL = "https://ibms-Empower.production.mjmtech.com.tw"
VITE_MQTT_BASEURL = "wss://mqttwss.mjm-staging.developers-homelab.net"
VITE_FORGE_BASEURL = "https://ibms-Empower.production.mjmtech.com.tw/dist"

View File

@ -1,3 +0,0 @@
VITE_API_BASEURL = "http://220.132.206.5:8008"
VITE_FILE_API_BASEURL = "http://220.132.206.5:8085/file"
VITE_FORGE_BASEURL = "http://localhost:5173"

View File

@ -0,0 +1,7 @@
node_modules
.git
.gitignore
Dockerfile
docker-compose.yml
README.md
.vs

View File

@ -7,7 +7,7 @@ NET_TRAEFIK=net-traefik_svc
# Image: org/name # Image: org/name
IMAGE_PROJ_NAME=proj_bims_ils IMAGE_PROJ_NAME=proj_bims_ils
IMAGE_NAME=empower-front IMAGE_NAME=empower-front
TAG_VERSION=0.1.0 TAG_VERSION=0.1.7
# Remote # Remote
REMOTE_URL=harbor.mjm-staging.developers-homelab.net REMOTE_URL=harbor.mjm-staging.developers-homelab.net

43
Dockerfile Normal file
View File

@ -0,0 +1,43 @@
# 使用 Node.js 作為基礎映像
FROM node:18-alpine AS builder
# 設定工作目錄
WORKDIR /app
# 複製 package.json 和 package-lock.json (或 yarn.lock) 到工作目錄
COPY package*.json ./
# 安裝依賴
RUN npm install --legacy-peer-deps
# 複製所有檔案到工作目錄
COPY . .
# 清理緩存並重新構建
RUN npm cache clean --force
RUN rm -rf node_modules
RUN npm install --legacy-peer-deps
# 構建前端應用 (如果需要)
RUN npm run build --omit=dev
# 使用一個更小的映像來提供靜態文件 (例如 Nginx)
FROM nginx:alpine
# 將構建好的靜態檔案複製到 Nginx 的預設目錄
COPY --from=builder /app/dist /usr/share/nginx/html
# (可選) 複製自定義 Nginx 設定檔
# COPY nginx.conf /etc/nginx/conf.d/default.conf
# 暴露 Nginx 預設的 80 端口
EXPOSE 80
# 2025-10-01 說明
LABEL changelog="2025-10-01: 1.fix 修正 draggable 元素的 mousedown 事件綁定 2.修正 nav 使用者無法按出drop down"
# Nginx 已經預設啟動,所以不需要 CMD 指令
COPY docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

5
docker-entrypoint.sh Normal file
View File

@ -0,0 +1,5 @@
#!/bin/sh
echo "window.env = { VITE_API_BASEURL: '${VITE_API_BASEURL}', VITE_FILE_API_BASEURL: '${VITE_FILE_API_BASEURL}', VITE_APP_TITLE: '${VITE_APP_TITLE}' };" > /usr/share/nginx/html/env.js
sed -i "s|<title>.*</title>|<title>${VITE_APP_TITLE}</title>|g" /usr/share/nginx/html/index.html
sed -i "s|<link rel=\"icon\" href=\".*\"|<link rel=\"icon\" href=\"${VITE_FILE_API_BASEURL}/favicon.ico\"|g" /usr/share/nginx/html/index.html
exec "$@"

View File

@ -10,6 +10,7 @@
/> />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>新創賦能</title> <title>新創賦能</title>
<script src="/env.js"></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> -->

View File

@ -10,7 +10,7 @@ import {
DELETE_ACCOUNT_USER_API, DELETE_ACCOUNT_USER_API,
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
export const getAccountUserList = async (search_condition = {}) => { export const getAccountUserList = async (search_condition = {}) => {
const res = await instance.post(GET_ACCOUNT_USERLIST_API, search_condition); const res = await instance.post(GET_ACCOUNT_USERLIST_API, search_condition);

View File

@ -23,7 +23,7 @@ import {
POST_ALERT_MQTT_REFRESH, POST_ALERT_MQTT_REFRESH,
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
export const getAlertFormId = async (uuid) => { export const getAlertFormId = async (uuid) => {
const res = await instance.post(GET_ALERT_FORMID_API, uuid); const res = await instance.post(GET_ALERT_FORMID_API, uuid);

View File

@ -28,7 +28,7 @@ import {
POST_ASSET_ELEC_SETTING_API, POST_ASSET_ELEC_SETTING_API,
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
import { object } from "yup"; import { object } from "yup";
export const getAssetMainList = async (building_guid) => { export const getAssetMainList = async (building_guid) => {

View File

@ -7,7 +7,7 @@ import {
GET_ALL_DEVICE_API, GET_ALL_DEVICE_API,
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
export const getBuildings = async () => { export const getBuildings = async () => {
const res = await instance.post(GET_BUILDING_API); const res = await instance.post(GET_BUILDING_API);

View File

@ -13,7 +13,7 @@ import {
GET_DASHBOARD_ALARMOPERATION_INFO_API, GET_DASHBOARD_ALARMOPERATION_INFO_API,
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
export const getDashboardInit = async (page_type = "SR") => { export const getDashboardInit = async (page_type = "SR") => {
const res = await instance.post(GET_DASHBOARD_INIT_API, { const res = await instance.post(GET_DASHBOARD_INIT_API, {

View File

@ -18,7 +18,7 @@ import {
POST_TIME_ELEC_API, POST_TIME_ELEC_API,
} from "./api"; } from "./api";
import instance, { fileInstance } from "@/util/request"; import instance, { fileInstance } from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
import downloadExcel from "@/util/downloadExcel"; import downloadExcel from "@/util/downloadExcel";
export const getRealTimeData = async () => { export const getRealTimeData = async () => {

View File

@ -1,6 +1,6 @@
import instance from "@/util/request"; import instance from "@/util/request";
import { GET_FORGETOKEN_API, GET_FORGEURN_API } from "./api"; import { GET_FORGETOKEN_API, GET_FORGEURN_API } from "./api";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
export const getUrn = async () => { export const getUrn = async () => {
const res = await instance.post(GET_FORGEURN_API); const res = await instance.post(GET_FORGEURN_API);

View File

@ -1,5 +1,5 @@
// graph // graph
const BASEURL = import.meta.env.VITE_API_BASEURL; const BASEURL = window.env?.VITE_API_BASEURL;
export const GET_GRAPH_SIDEBAR_API = `/GraphManage/GraphManageTreeList`; export const GET_GRAPH_SIDEBAR_API = `/GraphManage/GraphManageTreeList`;
export const UPDATE_GRAPH_SIDEBAR_API = `/GraphManage/EditGraphManageTree`; export const UPDATE_GRAPH_SIDEBAR_API = `/GraphManage/EditGraphManageTree`;

View File

@ -1,5 +1,5 @@
// history // history
const BASEURL = import.meta.env.VITE_API_BASEURL; const BASEURL = window.env?.VITE_API_BASEURL;
export const GET_HISTORY_SIDEBAR_API = `/api/History/GetDeviceInfo`; export const GET_HISTORY_SIDEBAR_API = `/api/History/GetDeviceInfo`;
export const GET_HISTORY_POINT_API = `/api/History/GetAllDevPoi`; export const GET_HISTORY_POINT_API = `/api/History/GetAllDevPoi`;
export const GET_HISTORY_DATA_API = `/api/History/GetHistoryData`; export const GET_HISTORY_DATA_API = `/api/History/GetHistoryData`;

View File

@ -1,6 +1,6 @@
import { POST_LOGIN } from "./api"; import { POST_LOGIN } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
export async function Login({ account, password }) { export async function Login({ account, password }) {
const res = await instance.post(POST_LOGIN, { const res = await instance.post(POST_LOGIN, {

View File

@ -12,7 +12,7 @@ import {
DELETE_OPERATION_COMPANY_API, DELETE_OPERATION_COMPANY_API,
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
import dayjs from "dayjs"; import dayjs from "dayjs";
export const getOperationRecord = async ({ export const getOperationRecord = async ({

View File

@ -1,5 +1,5 @@
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
import { import {
POST_SETTING_POINT_API, POST_SETTING_POINT_API,
GET_SETTING_TYPE_API, GET_SETTING_TYPE_API,

View File

@ -3,7 +3,7 @@ import {
POST_SET_SAMBA_DIRECTORY, POST_SET_SAMBA_DIRECTORY,
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
/** /**
* 開關 RTSP * 開關 RTSP

View File

@ -7,7 +7,7 @@ import {
POST_MQTT_TOPIC_STOP_API, POST_MQTT_TOPIC_STOP_API,
} from "./api"; } from "./api";
import instance from "@/util/request"; import instance from "@/util/request";
import apihandler from "@/util/apihandler"; import apihandler from "@/util/apiHandler";
export const getSystemFloors = async (building_tag, sub_system_tag) => { export const getSystemFloors = async (building_tag, sub_system_tag) => {
const res = await instance.post(GET_SYSTEM_FLOOR_LIST_API, { const res = await instance.post(GET_SYSTEM_FLOOR_LIST_API, {

View File

@ -1,12 +1,6 @@
<script setup> <script setup>
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { computed, defineProps, onMounted, ref, watch } from "vue"; import { defineProps } from "vue";
/* ----------------------------------------------------------------
id名.showModal(): 開啟 modal
id名.close(): 關閉 modal
詳細請參考 daisyUI
------------------------------------------------------------------- */
const props = defineProps({ const props = defineProps({
id: String, id: String,
@ -14,52 +8,40 @@ const props = defineProps({
onCancel: Function, onCancel: Function,
modalClass: String, modalClass: String,
width: Number || String, width: Number || String,
draggable: { draggable: { type: Boolean, default: false },
type: Boolean, backdrop: { type: Boolean, default: true },
default: false, modalStyle: { type: Object, default: () => ({}) },
},
backdrop: {
type: Boolean,
default: true,
},
modalStyle: {
type: Object,
default: {},
},
}); });
const dom = ref(null)
onMounted(() => {
document.querySelector(`#${props.id}[open]`)?.addEventListener("load",()=>{
console.log("loading")
})
document.querySelector(`#${props.id}`).addEventListener("load",()=>{
console.log("loading")
})
})
</script> </script>
<template> <template>
<!-- Open the modal using ID.showModal() method --> <dialog
<!-- :class="twMerge('modal', open && innerOpen ? 'modal-open' : 'modal-close')" --> :id="id"
<dialog ref="dom" :id="id" :class="twMerge( :class="
'modal', twMerge(
backdrop 'modal',
? '' backdrop ? '' : 'focus-visible:outline-none backdrop:bg-transparent'
: 'focus-visible:outline-none backdrop:bg-transparent', )
)" :style="modalStyle" v-draggable="draggable"> "
<div :class="twMerge( :style="modalStyle"
'modal-box static rounded-md border border-info py-5 px-6 overflow-y-scroll bg-normal', v-draggable="
modalClass draggable ? { handle: '[data-drag-handle]', target: '.modal-box' } : false
) "
" :style="{ maxWidth: isNaN(width) ? width : `${width}px` }"> >
<div class="text-2xl font-bold"> <div
<slot name="modalTitle"> :class="
{{ title }} twMerge(
</slot> 'modal-box static rounded-md border border-info py-5 px-6 overflow-y-auto bg-normal',
modalClass
)
"
:style="{ maxWidth: isNaN(width) ? width : `${width}px` }"
>
<!-- 把手只在這裡按下才可拖動 -->
<div class="text-2xl font-bold select-none" data-drag-handle>
<slot name="modalTitle">{{ title }}</slot>
</div> </div>
<div class="min-h-[200px]"> <div class="min-h-[200px]">
<slot name="modalContent"></slot> <slot name="modalContent"></slot>
</div> </div>
@ -68,25 +50,17 @@ onMounted(() => {
<slot name="modalAction"></slot> <slot name="modalAction"></slot>
</div> </div>
</div> </div>
<form v-if="backdrop" method="dialog" class="modal-backdrop"> <form v-if="backdrop" method="dialog" class="modal-backdrop">
<button @click="() => { <button
onCancel ? onCancel() : cancel(); @click="
} () => {
"> onCancel && onCancel();
}
"
>
close close
</button> </button>
</form> </form>
</dialog> </dialog>
</template> </template>
<style lang="css" scoped>
.modal-box::before {
@apply fixed top-1 right-1 h-5 w-5 rotate-90 bg-no-repeat z-10 bg-[url('../../assets/img/table/content-box-background01.svg')] bg-center;
content: "";
}
.modal-action::after {
@apply absolute -bottom-3 -left-4 h-5 w-5 rotate-90 bg-no-repeat z-10 bg-[url('../../assets/img/table/content-box-background05.svg')] bg-center;
content: "";
}
</style>

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import { ref, onMounted, onUnmounted } from "vue"; import { ref, onMounted, onUnmounted } from "vue";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const forgeDom = ref(null); const forgeDom = ref(null);
let viewer = null; let viewer = null;

View File

@ -164,7 +164,7 @@ const initForge = async () => {
// }); // });
// }); // });
// }); // });
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const viewer = await initViewer(forgeDom.value) const viewer = await initViewer(forgeDom.value)
const filePath = `${FILE_BASEURL}/upload/forge/0.svf`; const filePath = `${FILE_BASEURL}/upload/forge/0.svf`;
await loadModel(viewer, filePath) await loadModel(viewer, filePath)

View File

@ -93,7 +93,7 @@ const createSprites = async (dataVizExtn) => {
const DataVizCore = Autodesk.DataVisualization.Core; const DataVizCore = Autodesk.DataVisualization.Core;
const viewableType = DataVizCore.ViewableType.SPRITE; const viewableType = DataVizCore.ViewableType.SPRITE;
let spriteColor = new THREE.Color(0xffffff); let spriteColor = new THREE.Color(0xffffff);
const BASEURL = import.meta.env.VITE_FORGE_BASEURL; const BASEURL = window.env?.VITE_FORGE_BASEURL;
const spriteIconUrl = `${BASEURL}/hotspot.svg`; const spriteIconUrl = `${BASEURL}/hotspot.svg`;
const style = new DataVizCore.ViewableStyle( const style = new DataVizCore.ViewableStyle(
viewableType, viewableType,

View File

@ -1,4 +1,4 @@
const BASEURL = import.meta.env.VITE_API_BASEURL; const BASEURL = window.env?.VITE_API_BASEURL;
export const POST_LOGIN = `${BASEURL}/api/Login/`; export const POST_LOGIN = `${BASEURL}/api/Login/`;
export const GET_AUTHPAGE_API = `${BASEURL}/api/GetUsrFroList`; export const GET_AUTHPAGE_API = `${BASEURL}/api/GetUsrFroList`;
export const GET_SUBAUTHPAGE_API = `${BASEURL}/api/Device/GetMainSub`; export const GET_SUBAUTHPAGE_API = `${BASEURL}/api/Device/GetMainSub`;

View File

@ -1,4 +1,4 @@
const BASEURL = import.meta.env.VITE_API_BASEURL; const BASEURL = window.env?.VITE_API_BASEURL;
export const GET_FORGETOKEN_API = `${BASEURL}/api/forge/oauth/token`; export const GET_FORGETOKEN_API = `${BASEURL}/api/forge/oauth/token`;
export const GET_FORGEURN_API = `${BASEURL}/api/Device/GetBuild`; export const GET_FORGEURN_API = `${BASEURL}/api/Device/GetBuild`;

View File

@ -1,64 +1,97 @@
const moveModal = (elmnt) => { // src/directives/draggable.js
console.log(elmnt); // 用法:在 Modal 外層加 v-draggable="{ handle: '[data-drag-handle]', target: '.modal-box' }"
var pos1 = 0, // - handle只在這個節點按下才可拖動
pos2 = 0, // - target實際被拖動的 DOM預設用 el 本身)
pos3 = 0,
pos4 = 0;
document.body.addEventListener("mousedown", dragMouseDown, {
passive: false,
});
function dragMouseDown(e) { function createDraggable(el, options = {}) {
console.log("dragMouseDown", e); const cancelSelector =
e = e || window.event; 'input, textarea, select, button, [contenteditable="true"], [data-drag-cancel]';
const target =
(options.target && el.querySelector(options.target)) ||
el.querySelector('.modal-box') ||
el;
const handle =
(options.handle && el.querySelector(options.handle)) || target;
let startX = 0,
startY = 0,
originLeft = 0,
originTop = 0,
dragging = false;
// 只在「左鍵」且「不是表單控制項」時啟動拖曳
function onMouseDown(e) {
if (e.button !== 0) return;
// 點到可互動元件就不要拖(也不要 preventDefault讓它能聚焦
if (e.target.matches(cancelSelector) || e.target.closest(cancelSelector)) {
return;
}
// 這裡才開始準備拖曳
dragging = true;
const rect = target.getBoundingClientRect();
originLeft = rect.left;
originTop = rect.top;
startX = e.clientX;
startY = e.clientY;
// 只有在真的要拖時才阻止預設,避免選字/圖片拖移
e.preventDefault(); e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX; // 以視窗為座標系比較直觀
pos4 = e.clientY; target.style.position = 'fixed';
document.body.addEventListener("mouseup", closeDragElement, { target.style.left = '0px';
passive: false, target.style.top = '0px';
}); target.style.transform = `translate(${originLeft}px, ${originTop}px)`;
// call a function whenever the cursor moves:
document.body.addEventListener("mousemove", elementDrag, { window.addEventListener('mousemove', onMouseMove, { passive: false });
passive: false, window.addEventListener('mouseup', onMouseUp, { passive: true });
});
} }
function elementDrag(e) { function onMouseMove(e) {
e = e || window.event; if (!dragging) return;
e.preventDefault(); const dx = e.clientX - startX;
// calculate the new cursor position: const dy = e.clientY - startY;
pos1 = pos3 - e.clientX; target.style.transform = `translate(${originLeft + dx}px, ${originTop + dy}px)`;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = elmnt.offsetTop - pos2 + "px";
elmnt.style.left = elmnt.offsetLeft - pos1 + "px";
} }
function closeDragElement() { function onMouseUp() {
// stop moving when mouse button is released: dragging = false;
document.body.removeEventListener("mouseup", closeDragElement); window.removeEventListener('mousemove', onMouseMove);
document.body.removeEventListener("mousemove", elementDrag); window.removeEventListener('mouseup', onMouseUp);
} }
};
handle.style.cursor = 'move';
handle.addEventListener('mousedown', onMouseDown, { passive: false });
// 提供清理函式給 unmounted 用
return () => {
handle.removeEventListener('mousedown', onMouseDown);
window.removeEventListener('mousemove', onMouseMove);
window.removeEventListener('mouseup', onMouseUp);
};
}
export const draggable = { export const draggable = {
install(app) { install(app) {
app.directive("draggable", { app.directive('draggable', {
mounted: (el, binding, vnode, prevVnode) => { mounted(el, binding) {
console.log("draggable", $(`#${el.id}`).draggable); // 允許 v-draggable 或 v-draggable="true" 或 v-draggable="{ handle, target }"
if (binding.value) { const enabled =
if ($(`#${el.id}`).draggable) { binding.value === '' || binding.value === true || typeof binding.value === 'object';
$(`#${el.id}`).draggable({ if (!enabled) return;
cursor: "move",
scroll: true, // 以前用 jQuery UI 的判斷會在沒有 $ 或 .draggable 時噴錯,直接移除
container: ".app-container", const options = typeof binding.value === 'object' ? binding.value : {};
}); el.__dragCleanup__ = createDraggable(el, options);
} else { },
moveModal(el); unmounted(el) {
} if (el.__dragCleanup__) {
el.__dragCleanup__();
delete el.__dragCleanup__;
} }
}, },
}); });

View File

@ -72,7 +72,7 @@ export default function useForgeSprite() {
const DataVizCore = Autodesk.DataVisualization.Core; const DataVizCore = Autodesk.DataVisualization.Core;
const viewableType = DataVizCore.ViewableType.SPRITE; const viewableType = DataVizCore.ViewableType.SPRITE;
let spriteColor = new THREE.Color(0xffffff); let spriteColor = new THREE.Color(0xffffff);
const BASEURL = import.meta.env.VITE_FORGE_BASEURL; const BASEURL = window.env?.VITE_FORGE_BASEURL;
const spriteIconUrl = `${BASEURL}/hotspot.svg`; const spriteIconUrl = `${BASEURL}/hotspot.svg`;
const style = new DataVizCore.ViewableStyle( const style = new DataVizCore.ViewableStyle(
viewableType, viewableType,

Binary file not shown.

View File

@ -5,7 +5,7 @@ import System from "@/views/system/System.vue";
import SystemFloor from "@/views/system/SystemFloor.vue"; import SystemFloor from "@/views/system/SystemFloor.vue";
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL), history: createWebHashHistory(window.env?.BASE_URL),
routes: [ routes: [
{ {
path: "/login", path: "/login",

View File

@ -11,7 +11,7 @@ const useHeatmapBarStore = defineStore("heatmap", () => {
const getConfig = async () => { const getConfig = async () => {
const api = const api =
import.meta.env.MODE === "production" window.env?.MODE === "production"
? "/dist/config.json" ? "/dist/config.json"
: "/config.json"; : "/config.json";
const res = await axios.get(api); const res = await axios.get(api);

View File

@ -1,4 +1,4 @@
const BASEURL = import.meta.env.VITE_API_BASEURL; const BASEURL = window.env?.VITE_API_BASEURL;
export default function downloadExcel(res) { export default function downloadExcel(res) {
let disposition = res.headers.get("Content-Disposition"); let disposition = res.headers.get("Content-Disposition");

View File

@ -1,6 +1,6 @@
import useGetCookie from "@/hooks/useGetCookie"; import useGetCookie from "@/hooks/useGetCookie";
import axios from "axios"; import axios from "axios";
const BASEURL = import.meta.env.VITE_API_BASEURL; const BASEURL = window.env?.VITE_API_BASEURL;
const instance = axios.create({ const instance = axios.create({
baseURL: BASEURL, baseURL: BASEURL,

View File

@ -10,7 +10,7 @@ import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast"); const { openToast, cancelToastOpen } = inject("app_toast");
const { companyOptions, departmentList, floors } = inject("asset_modal_options"); const { companyOptions, departmentList, floors } = inject("asset_modal_options");
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const { searchParams, changeParams } = useSearchParam(); const { searchParams, changeParams } = useSearchParam();
const totalCoordinates = ref({}); const totalCoordinates = ref({});

View File

@ -10,7 +10,7 @@ import useUserInfoStore from "@/stores/useUserInfoStore";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const { searchParams, changeParams } = useSearchParam(); const { searchParams, changeParams } = useSearchParam();
const { updateLeftFields, formErrorMsg, formState } = inject( const { updateLeftFields, formErrorMsg, formState } = inject(
"asset_table_modal_form" "asset_table_modal_form"

View File

@ -4,7 +4,7 @@ import { ref, computed, inject, watch, onMounted } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import Menu from "@/components/customUI/Menu.vue"; import Menu from "@/components/customUI/Menu.vue";
const { t } = useI18n(); const { t } = useI18n();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const { formState } = inject("asset_table_modal_form"); const { formState } = inject("asset_table_modal_form");
const columns = computed(() => [ const columns = computed(() => [
{ {

View File

@ -8,7 +8,7 @@ import { postMqttTopic, postMqttTopicStop } from "@/apis/system";
const { t } = useI18n(); const { t } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast"); const { openToast, cancelToastOpen } = inject("app_toast");
const { formState } = inject("asset_table_modal_form"); const { formState } = inject("asset_table_modal_form");
const BASEURL = import.meta.env.VITE_MQTT_BASEURL; const BASEURL = window.env?.VITE_MQTT_BASEURL;
const iotSchemaTag = inject("iotSchemaTag"); const iotSchemaTag = inject("iotSchemaTag");
// MQTT // MQTT

View File

@ -7,7 +7,7 @@ import { twMerge } from "tailwind-merge";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const { totalCoordinates } = inject("asset_table_data"); const { totalCoordinates } = inject("asset_table_data");
const { floors } = inject("asset_modal_options"); const { floors } = inject("asset_modal_options");
const { updateRightFields, formErrorMsg, formState } = inject( const { updateRightFields, formErrorMsg, formState } = inject(

View File

@ -15,7 +15,7 @@ import "yup-phone-lite";
import useFormErrorMessage from "@/hooks/useFormErrorMessage"; import useFormErrorMessage from "@/hooks/useFormErrorMessage";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const props = defineProps({ const props = defineProps({
editRecord: Object, editRecord: Object,

View File

@ -14,7 +14,7 @@ import { computed, inject, ref, watch, onMounted, onUnmounted } from "vue";
import useBuildingStore from "@/stores/useBuildingStore"; import useBuildingStore from "@/stores/useBuildingStore";
import { getSystemDevices, getSystemRealTime } from "@/apis/system"; import { getSystemDevices, getSystemRealTime } from "@/apis/system";
import DashboardRefrig from "./components/DashboardRefrig.vue"; import DashboardRefrig from "./components/DashboardRefrig.vue";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const buildingStore = useBuildingStore(); const buildingStore = useBuildingStore();
const subscribeData = ref([]); const subscribeData = ref([]);

View File

@ -10,7 +10,7 @@ import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const { searchParams, changeParams } = useSearchParam(); const { searchParams, changeParams } = useSearchParam();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const props = defineProps({ const props = defineProps({
data: { data: {

View File

@ -2,7 +2,7 @@
import { ref, computed } from "vue"; import { ref, computed } from "vue";
import useSearchParam from "@/hooks/useSearchParam"; import useSearchParam from "@/hooks/useSearchParam";
const { searchParams, changeParams } = useSearchParam(); const { searchParams, changeParams } = useSearchParam();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,

View File

@ -10,7 +10,7 @@ import {
} from "@/apis/graph"; } from "@/apis/graph";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const BASEURL = window.env?.VITE_FILE_API_BASEURL;
const props = defineProps({ const props = defineProps({
updateEditRecord: Function, updateEditRecord: Function,

View File

@ -8,7 +8,7 @@ import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast"); const { openToast, cancelToastOpen } = inject("app_toast");
const { sidebar_data } = inject("current_dir"); const { sidebar_data } = inject("current_dir");
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const columns = computed(() => [ const columns = computed(() => [
{ {

View File

@ -8,7 +8,7 @@ import useSearchParam from "@/hooks/useSearchParam";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast"); const { openToast, cancelToastOpen } = inject("app_toast");
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const { searchParams } = useSearchParam(); const { searchParams } = useSearchParam();
const { dataSource, openModal, updateEditRecord, search, tableLoading } = const { dataSource, openModal, updateEditRecord, search, tableLoading } =

View File

@ -12,7 +12,7 @@ import Select from "@/components/customUI/Select.vue";
import SearchSelect from "@/components/customUI/SearchSelect.vue"; import SearchSelect from "@/components/customUI/SearchSelect.vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const props = defineProps({ const props = defineProps({
editRecord: Object, editRecord: Object,

View File

@ -70,7 +70,7 @@ import { getSystemDevices } from "@/apis/system";
import { setRtspEnable } from "@/apis/rtsp"; // setSambaDirectory import { setRtspEnable } from "@/apis/rtsp"; // setSambaDirectory
import useActiveBtn from "@/hooks/useActiveBtn"; import useActiveBtn from "@/hooks/useActiveBtn";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const DEFAULT_MONITOR_URL = const DEFAULT_MONITOR_URL =
"http://192.168.0.219:8026/?url=rtsp://admin02:mjmAdmin_99@192.168.0.200:554/stream1?tcp"; "http://192.168.0.219:8026/?url=rtsp://admin02:mjmAdmin_99@192.168.0.200:554/stream1?tcp";

View File

@ -7,7 +7,7 @@ import { useI18n } from "vue-i18n";
import useBuildingStore from "@/stores/useBuildingStore"; import useBuildingStore from "@/stores/useBuildingStore";
const storeBuild = useBuildingStore(); const storeBuild = useBuildingStore();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const { t } = useI18n(); const { t } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast"); const { openToast, cancelToastOpen } = inject("app_toast");

View File

@ -1,38 +1,22 @@
<script setup> <script setup>
import Table from "@/components/customUI/Table.vue"; import Table from "@/components/customUI/Table.vue";
import VendorModal from "./VendorModal.vue"; import VendorModal from "./VendorModal.vue";
import { getOperationCompanyList,deleteOperationCompany } from "@/apis/operation"; import {
getOperationCompanyList,
deleteOperationCompany,
} from "@/apis/operation";
import { onMounted, ref, inject, computed } from "vue"; import { onMounted, ref, inject, computed } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const { openToast, cancelToastOpen } = inject("app_toast"); const { openToast, cancelToastOpen } = inject("app_toast");
const columns = computed(() => [ const columns = computed(() => [
{ { title: t("operation.vendor"), key: "name" },
title: t("operation.vendor"), { title: t("operation.contact_person"), key: "contact_person" },
key: "name", { title: t("operation.phone"), key: "phone" },
}, { title: t("operation.email"), key: "email" },
{ { title: t("operation.created_at"), key: "created_at" },
title: t("operation.contact_person"), { title: t("operation.operation"), key: "operation", width: 200 },
key: "contact_person",
},
{
title: t("operation.phone"),
key: "phone",
},
{
title: t("operation.email"),
key: "email",
},
{
title: t("operation.created_at"),
key: "created_at",
},
{
title: t("operation.operation"),
key: "operation",
width: 200,
},
]); ]);
const dataSource = ref([]); const dataSource = ref([]);
@ -49,7 +33,9 @@ onMounted(() => {
getDataSource(); getDataSource();
}); });
const formState = ref({ // ====== Modal ======
const MODAL_ID = "company_modal";
const emptyForm = () => ({
contact_person: "", contact_person: "",
email: "", email: "",
name: "", name: "",
@ -60,22 +46,36 @@ const formState = ref({
address: "", address: "",
}); });
const openModal = (record) => { const formState = ref(emptyForm());
if (record.id) {
formState.value = { ...record }; // (/)
} else { const openModal = (payload) => {
formState.value = { const el = document.getElementById(MODAL_ID);
contact_person: "",
email: "", //
name: "", if (payload === false) {
phone: "", try {
remark: "", el?.close?.();
tax_id_number: "", } catch {}
city: "", return;
address: "", }
};
// true
if (payload === true || payload == null) {
formState.value = emptyForm();
try {
el?.showModal?.();
} catch {}
return;
}
// record
if (payload && typeof payload === "object") {
formState.value = { ...emptyForm(), ...payload }; //
try {
el?.showModal?.();
} catch {}
} }
company_modal.showModal();
}; };
const remove = async (id) => { const remove = async (id) => {
@ -95,15 +95,19 @@ const remove = async (id) => {
<template> <template>
<div class="flex justify-start items-center mt-10 mb-5"> <div class="flex justify-start items-center mt-10 mb-5">
<h3 class="text-xl mr-5">{{ $t("assetManagement.company") }}</h3> <h3 class="text-xl mr-5">{{ $t("assetManagement.company") }}</h3>
<!-- 子層會渲染新增按鈕照你的原樣 -->
<VendorModal <VendorModal
:formState="formState" :formState="formState"
:getData="getDataSource" :getData="getDataSource"
:openModal="openModal" :openModal="openModal"
/> />
</div> </div>
<Table :columns="columns" :dataSource="dataSource" :loading="loading"> <Table :columns="columns" :dataSource="dataSource" :loading="loading">
<template #bodyCell="{ record, column, index }"> <template #bodyCell="{ record, column, index }">
<template v-if="column.key === 'index'">{{ index + 1 }}</template> <template v-if="column.key === 'index'">{{ index + 1 }}</template>
<template v-else-if="column.key === 'operation'"> <template v-else-if="column.key === 'operation'">
<button <button
class="btn btn-sm btn-success text-white mr-2" class="btn btn-sm btn-success text-white mr-2"
@ -118,6 +122,7 @@ const remove = async (id) => {
{{ $t("button.delete") }} {{ $t("button.delete") }}
</button> </button>
</template> </template>
<template v-else> <template v-else>
{{ record[column.key] }} {{ record[column.key] }}
</template> </template>

View File

@ -1,23 +1,21 @@
<script setup> <script setup>
import { ref, onMounted, defineProps, inject, watch } from "vue"; import { ref, inject } from "vue";
import * as yup from "yup"; import * as yup from "yup";
import "yup-phone-lite"; import "yup-phone-lite";
import useFormErrorMessage from "@/hooks/useFormErrorMessage"; import useFormErrorMessage from "@/hooks/useFormErrorMessage";
import { import { postOperationCompany, updateOperationCompany } from "@/apis/operation";
postOperationCompany,
updateOperationCompany,
} from "@/apis/operation";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const { openToast } = inject("app_toast"); const { openToast } = inject("app_toast");
const props = defineProps({ const props = defineProps({
formState: Object, formState: Object,
getData: Function, getData: Function,
openModal: Function openModal: Function, // / modal
}); });
const deptScheme = yup.object({ const schema = yup.object({
name: yup.string().required(t("button.required")), name: yup.string().required(t("button.required")),
contact_person: yup.string().nullable(true), contact_person: yup.string().nullable(true),
email: yup.string().email().nullable(true), email: yup.string().email().nullable(true),
@ -28,34 +26,104 @@ const deptScheme = yup.object({
remark: yup.string().nullable(true), remark: yup.string().nullable(true),
}); });
const { formErrorMsg, handleSubmit, handleErrorReset, updateScheme } = const { formErrorMsg, handleSubmit, handleErrorReset } =
useFormErrorMessage(deptScheme); useFormErrorMessage(schema);
const loading = ref(false);
const MODAL_ID = "company_modal";
/** ====== 關閉 Modal多重保險 ====== */
const closeModal = () => {
// 1) boolean
if (typeof props.openModal === "function") {
try {
if (props.openModal.length >= 1) {
// openModal(false)
props.openModal(false);
} else {
// toggler false
try {
props.openModal(false);
} catch {
props.openModal();
}
}
return;
} catch (_) {}
}
// 2) <dialog> close() Modal
const el = document.getElementById(MODAL_ID);
if (el?.close) {
try {
el.close();
return;
} catch (_) {}
}
// 3) Modal
try {
el?.dispatchEvent?.(new CustomEvent("close", { bubbles: true }));
} catch (_) {}
};
/** ====== 開啟 Modal呼叫父層 ====== */
const openModal = () => {
if (typeof props.openModal === "function") {
try {
if (props.openModal.length >= 1) props.openModal(true);
else props.openModal();
} catch {
//
}
}
};
const onCancel = () => { const onCancel = () => {
handleErrorReset(); //
company_modal.close(); //
closeModal();
}; };
const onOk = async () => { const onOk = async () => {
const value = await handleSubmit(deptScheme, props.formState); try {
if (props.formState?.id) { loading.value = true;
res = await updateOperationCompany(value);
} else { const value = await handleSubmit(schema, props.formState);
res = await postOperationCompany(value);
} let res;
if (res.isSuccess) { if (props.formState?.id) {
props.getData(); // API id updateOperationCompany(props.formState.id, value)
onCancel(); res = await updateOperationCompany(value);
} else { } else {
openToast("error", res.msg, "#company_modal"); res = await postOperationCompany(value);
}
if (res?.isSuccess) {
await props.getData?.();
props.openModal(false);
//
closeModal();
//
handleErrorReset();
props.openModal(false);
openToast?.("success", t("common.success"), `#${MODAL_ID}`);
} else {
openToast?.("error", res?.msg ?? t("common.failed"), `#${MODAL_ID}`);
}
} catch (err) {
openToast?.("error", err?.message ?? t("common.failed"), `#${MODAL_ID}`);
} finally {
loading.value = false;
} }
}; };
</script> </script>
<template> <template>
<button class="btn btn-sm btn-add " @click.stop.prevent="props.openModal"> <button class="btn btn-sm btn-add" @click.stop.prevent="openModal">
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }} <font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
</button> </button>
<Modal <Modal
id="company_modal" id="company_modal"
:title="props.formState?.id ? t('button.edit') : t('button.add')" :title="props.formState?.id ? t('button.edit') : t('button.add')"
@ -63,87 +131,79 @@ const onOk = async () => {
width="710" width="710"
> >
<template #modalContent> <template #modalContent>
<form ref="form" class="mt-5 w-full flex flex-wrap justify-between"> <form class="mt-5 w-full flex flex-wrap justify-between">
<Input :value="formState" class="my-2" name="name"> <Input :value="props.formState" class="my-2" name="name">
<template #topLeft>{{ $t("operation.name") }}</template> <template #topLeft>{{ $t("operation.name") }}</template>
<template #bottomLeft <template #bottomLeft>
><span class="text-error text-base"> <span class="text-error text-base">{{ formErrorMsg.name }}</span>
{{ formErrorMsg.name }} </template>
</span></template </Input>
></Input <Input :value="props.formState" class="my-2" name="contact_person">
>
<Input :value="formState" class="my-2" name="contact_person">
<template #topLeft>{{ $t("operation.contact_person") }}</template> <template #topLeft>{{ $t("operation.contact_person") }}</template>
<template #bottomLeft <template #bottomLeft>
><span class="text-error text-base"> <span class="text-error text-base">{{
{{ formErrorMsg.contact_person }} formErrorMsg.contact_person
</span></template }}</span>
></Input </template>
> </Input>
<Input :value="formState" class="my-2" name="phone"> <Input :value="props.formState" class="my-2" name="phone">
<template #topLeft>{{ $t("operation.phone") }}</template> <template #topLeft>{{ $t("operation.phone") }}</template>
<template #bottomLeft <template #bottomLeft>
><span class="text-error text-base"> <span class="text-error text-base">{{ formErrorMsg.phone }}</span>
{{ formErrorMsg.phone }} </template>
</span></template </Input>
></Input <Input :value="props.formState" class="my-2" name="email">
>
<Input :value="formState" class="my-2" name="email">
<template #topLeft>{{ $t("operation.email") }}</template> <template #topLeft>{{ $t("operation.email") }}</template>
<template #bottomLeft <template #bottomLeft>
><span class="text-error text-base"> <span class="text-error text-base">{{ formErrorMsg.email }}</span>
{{ formErrorMsg.email }} </template>
</span></template </Input>
></Input <Input :value="props.formState" class="my-2" name="city">
>
<Input :value="formState" class="my-2" name="city">
<template #topLeft>{{ $t("operation.city") }}</template> <template #topLeft>{{ $t("operation.city") }}</template>
<template #bottomLeft <template #bottomLeft>
><span class="text-error text-base"> <span class="text-error text-base">{{ formErrorMsg.city }}</span>
{{ formErrorMsg.city }} </template>
</span></template </Input>
></Input <Input :value="props.formState" class="my-2" name="address">
>
<Input :value="formState" class="my-2" name="address">
<template #topLeft>{{ $t("operation.address") }}</template> <template #topLeft>{{ $t("operation.address") }}</template>
<template #bottomLeft <template #bottomLeft>
><span class="text-error text-base"> <span class="text-error text-base">{{ formErrorMsg.address }}</span>
{{ formErrorMsg.address }} </template>
</span></template </Input>
></Input <Input :value="props.formState" class="my-2" name="tax_id_number">
>
<Input :value="formState" class="my-2" name="tax_id_number">
<template #topLeft>{{ $t("operation.tax_id_number") }}</template> <template #topLeft>{{ $t("operation.tax_id_number") }}</template>
<template #bottomLeft <template #bottomLeft>
><span class="text-error text-base"> <span class="text-error text-base">{{
{{ formErrorMsg.tax_id_number }} formErrorMsg.tax_id_number
</span></template }}</span>
></Input </template>
> </Input>
<Input :value="formState" class="my-2" name="remark"> <Input :value="props.formState" class="my-2" name="remark">
<template #topLeft>{{ $t("operation.remark") }}</template> <template #topLeft>{{ $t("operation.remark") }}</template>
<template #bottomLeft <template #bottomLeft>
><span class="text-error text-base"> <span class="text-error text-base">{{ formErrorMsg.remark }}</span>
{{ formErrorMsg.remark }} </template>
</span></template </Input>
></Input
>
</form> </form>
</template> </template>
<template #modalAction> <template #modalAction>
<button <button
type="reset" type="button"
class="btn btn-outline-success mr-2" class="btn btn-outline-success mr-2"
@click.prevent="onCancel" @click.prevent="onCancel"
:disabled="loading"
> >
{{ $t("button.cancel") }} {{ $t("button.cancel") }}
</button> </button>
<button <button
type="submit" type="button"
class="btn btn-outline-success" class="btn btn-outline-success"
@click.stop.prevent="onOk" @click.stop.prevent="onOk"
:disabled="loading"
> >
<span v-if="loading" class="loading loading-spinner loading-xs mr-2" />
{{ $t("button.submit") }} {{ $t("button.submit") }}
</button> </button>
</template> </template>

View File

@ -11,7 +11,7 @@ const { currentFloor, subscribeData } = inject("system_deviceList");
const { getCurrentInfoModalData, selected_dbid } = inject( const { getCurrentInfoModalData, selected_dbid } = inject(
"system_selectedDevice" "system_selectedDevice"
); );
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const asset_floor_chart = ref(null); const asset_floor_chart = ref(null);
const sameOption = { const sameOption = {

View File

@ -8,7 +8,7 @@ const { getCurrentInfoModalData, selected_dbid } = inject(
const { subscribeData } = inject("system_deviceList"); const { subscribeData } = inject("system_deviceList");
const { showData } = useSystemShowData(); const { showData } = useSystemShowData();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const fitToView = (forge_dbid, spriteDbId) => { const fitToView = (forge_dbid, spriteDbId) => {
selected_dbid.value = [forge_dbid, spriteDbId]; selected_dbid.value = [forge_dbid, spriteDbId];

View File

@ -2,7 +2,7 @@
import { computed, inject, watch, ref } from "vue"; import { computed, inject, watch, ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = window.env?.VITE_FILE_API_BASEURL;
const { selectedDeviceCog } = inject("system_selectedDevice"); const { selectedDeviceCog } = inject("system_selectedDevice");
const imgData = ref([]); const imgData = ref([]);