Browse Source

init

feature/debug
zhangjiming 6 months ago
commit
ba9e337bef
  1. 3
      .env
  2. 30
      .gitignore
  3. 3
      .vscode/extensions.json
  4. 33
      README.md
  5. 1
      env.d.ts
  6. 13
      index.html
  7. 4905
      package-lock.json
  8. 42
      package.json
  9. 8
      postcss.config.js
  10. BIN
      public/favicon.ico
  11. 12
      src/App.vue
  12. 31
      src/assets/base.css
  13. BIN
      src/assets/entry1.png
  14. BIN
      src/assets/entry2.png
  15. BIN
      src/assets/entry3.png
  16. BIN
      src/assets/logo.png
  17. 1
      src/assets/logo.svg
  18. 7
      src/assets/main.css
  19. 2
      src/assets/menu.svg
  20. 1
      src/assets/refresh.svg
  21. 1
      src/assets/wash.svg
  22. 30
      src/components/Time.vue
  23. 20
      src/main.ts
  24. 23
      src/router/index.ts
  25. 58
      src/services/axios.ts
  26. 108
      src/services/socket.ts
  27. 12
      src/stores/counter.ts
  28. 34
      src/style.css
  29. 9
      src/utils/index.ts
  30. 9
      src/views/AboutView.vue
  31. 43
      src/views/HomeView.vue
  32. 17
      tailwind.config.js
  33. 12
      tsconfig.app.json
  34. 11
      tsconfig.json
  35. 18
      tsconfig.node.json
  36. 20
      vite.config.ts

3
.env

@ -0,0 +1,3 @@
VITE_API_HOST=window.location.hostname
VITE_API_PORT=80
VITE_WS_PATH=/api/v1/app/ws/state

30
.gitignore

@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

3
.vscode/extensions.json

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

33
README.md

@ -0,0 +1,33 @@
# A1800
基质喷涂转印
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
## 约定
目录:
views: 主要页面
components: 子组件
services: API接口
assets: 资源(图片)
utils: 实用工具
.env 环境变量(如IP,Port)
.env.local 本地环境变量

1
env.d.ts

@ -0,0 +1 @@
/// <reference types="vite/client" />

13
index.html

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

4905
package-lock.json
File diff suppressed because it is too large
View File

42
package.json

@ -0,0 +1,42 @@
{
"name": "a1800",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build"
},
"dependencies": {
"@vueuse/rxjs": "^12.5.0",
"axios": "^1.7.9",
"dayjs": "^1.11.13",
"pinia": "^2.3.0",
"ramda": "^0.30.1",
"rxjs": "^7.8.1",
"vant": "^4.9.16",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.0",
"@types/node": "^22.10.2",
"@types/ramda": "^0.30.2",
"@types/rx": "^4.1.4",
"@vitejs/plugin-vue": "^5.2.1",
"@vitejs/plugin-vue-jsx": "^4.1.1",
"@vue/tsconfig": "^0.7.0",
"autoprefixer": "^10.4.20",
"npm-run-all2": "^7.0.2",
"postcss": "^8.5.1",
"postcss-import": "^16.1.0",
"tailwindcss": "^3.4.17",
"typescript": "~5.6.3",
"vite": "^6.0.5",
"vite-plugin-vue-devtools": "^7.6.8",
"vue-tsc": "^2.1.10"
}
}

8
postcss.config.js

@ -0,0 +1,8 @@
export default {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {},
},
}

BIN
public/favicon.ico

12
src/App.vue

@ -0,0 +1,12 @@
<script setup lang="ts">
import { RouterLink, RouterView } from "vue-router";
import HelloWorld from "./components/HelloWorld.vue";
</script>
<template>
<RouterView />
</template>
<style scoped>
</style>

31
src/assets/base.css

@ -0,0 +1,31 @@
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
font-weight: normal;
}
body {
min-height: 100vh;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 16px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
}

BIN
src/assets/entry1.png

After

Width: 220  |  Height: 274  |  Size: 9.0 KiB

BIN
src/assets/entry2.png

After

Width: 220  |  Height: 274  |  Size: 9.8 KiB

BIN
src/assets/entry3.png

After

Width: 220  |  Height: 274  |  Size: 9.9 KiB

BIN
src/assets/logo.png

After

Width: 166  |  Height: 38  |  Size: 3.1 KiB

1
src/assets/logo.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>

7
src/assets/main.css

@ -0,0 +1,7 @@
@import './base.css';
#app {
max-width: 1280px;
max-height: 800px;
overflow: hidden;
}

2
src/assets/menu.svg

@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="14.016000747680664" height="12.976000785827637" viewBox="0 0 14.016000747680664 12.976000785827637"><g><path d="M12.944,2.38419e-7Q13.392,2.38419e-7,13.704,0.312Q14.016,0.624,14.016,1.072L14.016,1.888Q14.016,2.336,13.704,2.648Q13.392,2.96,12.944,2.96L1.072,2.96Q0.624,2.96,0.312,2.648Q0,2.336,0,1.888L0,1.072Q0,0.624,0.312,0.312Q0.624,0,1.072,0L12.944,2.38419e-7ZM12.944,5.008Q13.392,5.008,13.704,5.32Q14.016,5.632,14.016,6.08L14.016,6.896Q14.016,7.344,13.704,7.656Q13.392,7.968,12.944,7.968L1.072,7.968Q0.624,7.968,0.312,7.656Q0,7.344,0,6.896L0,6.08Q0,5.632,0.312,5.32Q0.624,5.008,1.072,5.008L12.944,5.008ZM12.944,10.016Q13.392,10.016,13.704,10.328Q14.016,10.64,14.016,11.088L14.016,11.904Q14.016,12.352,13.704,12.664Q13.392,12.976,12.944,12.976L1.072,12.976Q0.624,12.976,0.312,12.664Q0,12.352,0,11.904L0,11.088Q0,10.64,0.312,10.328Q0.624,10.016,1.072,10.016L12.944,10.016Z" fill="#26509C" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></svg>

1
src/assets/refresh.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="17" height="16" viewBox="0 0 17 16"><g><path d="M17,8.22051C16.802,9.16033,16.5192,10.004,16.146,10.7515C14.8736,13.2997,12.6991,14.6367,9.62261,14.76C8.16345,14.8168,6.78641,14.6293,5.48851,14.2L5.48851,14.1828L4.91453,15.5074C4.79908,15.7175,4.70464,15.7858,4.57954,15.8703C4.48084,15.937,4.30868,15.9831,4.1933,15.9949C4.07539,16.007,3.99001,15.999,3.83552,15.9547C3.7133,15.9198,3.66245,15.8637,3.62004,15.8341C3.57764,15.8045,3.48004,15.6955,3.45742,15.6733L0.556998,11.1585C0.483536,11.0352,0.441139,10.9168,0.426917,10.8008C0.412842,10.6873,0.421258,10.5911,0.446798,10.5122C0.472192,10.4333,0.514601,10.3592,0.576879,10.2902C0.633846,10.2281,0.696275,10.1711,0.763431,10.12C0.825684,10.0731,0.893499,10.0361,0.967071,10.0016C1.04053,9.967,1.09148,9.94726,1.11412,9.94231C1.13954,9.93738,1.15651,9.93001,1.1706,9.9177L6.24916,8.67935C6.52063,8.62261,6.78045,8.60384,6.94168,8.63347C7.10284,8.66309,7.138,8.67287,7.24254,8.70985C7.34722,8.74934,7.46615,8.84654,7.51877,8.94325C7.56906,9.03569,7.58946,9.1209,7.60368,9.18995C7.61776,9.25906,7.61776,9.33798,7.60368,9.42675C7.58947,9.51554,7.57815,9.57721,7.56684,9.60442C7.55274,9.63395,7.54708,9.65126,7.54708,9.66357L6.95324,10.9883C8.00521,11.341,8.99481,11.5581,9.92793,11.642C10.8612,11.7259,11.6557,11.7061,12.3089,11.5828C12.9621,11.4594,13.5728,11.2547,14.1355,10.971C14.6983,10.6873,15.1422,10.4061,15.4703,10.1298C15.7982,9.85353,16.0923,9.54769,16.3497,9.2121C16.6098,8.87664,16.771,8.64728,16.8417,8.52394C16.9095,8.40303,16.9632,8.29943,17,8.22051ZM0,7.45129C0.271467,6.3412,0.653244,5.36682,1.14809,4.52809C2.57038,2.18464,4.82406,1.04007,7.91463,1.09681C9.28612,1.11899,10.5331,1.33857,11.6585,1.7603L12.2693,0.452983C12.3551,0.310585,12.444,0.212188,12.5401,0.138203C12.6391,0.0641461,12.7387,0.0360913,12.8235,0.018759C12.9111,0.0015112,13.004,-0.00634081,13.0945,0.0060342C13.1877,0.0183369,13.2302,0.0241263,13.3085,0.0497569C13.379,0.0728424,13.394,0.076087,13.462,0.113079C13.5298,0.152581,13.5916,0.19851,13.6541,0.258818L13.7679,0.391493L16.5136,4.88827C16.5758,5.0239,16.6126,5.14726,16.6239,5.26323C16.6381,5.3767,16.6295,5.47293,16.6041,5.55184C16.5787,5.63074,16.5334,5.70481,16.4655,5.77142C16.3977,5.84044,16.3327,5.89477,16.2704,5.93176C16.2054,5.97365,16.1374,6.01073,16.0669,6.0427L15.9198,6.11181C15.8944,6.12411,15.8774,6.12906,15.8632,6.12906L10.7479,7.25147C10.4001,7.2983,10.1231,7.29096,9.91381,7.23422C9.70459,7.17748,9.5624,7.04108,9.50302,6.94484C9.44087,6.8487,9.41469,6.78551,9.4034,6.65034C9.39354,6.53211,9.40138,6.47791,9.4156,6.42117C9.42968,6.36443,9.4642,6.26721,9.48962,6.23265L10.1202,4.92522C9.08243,4.55276,8.09561,4.31344,7.15396,4.21236C6.21517,4.11119,5.42065,4.11119,4.7731,4.21236C4.12552,4.31344,3.51193,4.50096,2.93794,4.77234C2.36395,5.04362,1.90859,5.31501,1.57498,5.58881C1.24127,5.86261,0.93875,6.16109,0.667283,6.48921C0.395816,6.81731,0.223375,7.04425,0.14701,7.16761C0.0763534,7.28845,0.025419,7.38469,0,7.45129Z" fill="#0D56B0" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></svg>

1
src/assets/wash.svg
File diff suppressed because it is too large
View File

30
src/components/Time.vue

@ -0,0 +1,30 @@
<template>
<div>{{ formattedTime }}</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from "vue";
import dayjs from "dayjs";
const props = defineProps<{
format?: string;
}>();
const format = computed(() => {
return props.format || "YYYY-MM-DD HH:mm";
});
const formattedTime = ref("");
const updateClock = () => {
formattedTime.value = dayjs().format(format.value);
};
let intervalId: ReturnType<typeof setInterval> | undefined = undefined;
onMounted(() => {
updateClock(); //
intervalId = setInterval(updateClock, 1000);
});
onUnmounted(() => clearInterval(intervalId));
</script>

20
src/main.ts

@ -0,0 +1,20 @@
import "./style.css";
import "./assets/main.css";
import { createApp } from "vue";
import { createPinia } from "pinia";
import Vant from "vant";
import App from "./App.vue";
import router from "./router";
import "vant/lib/index.css";
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.use(Vant);
app.mount("#app");
console.log("API HOST:", import.meta.env.VITE_API_HOST);
console.log("API PORT:", import.meta.env.VITE_API_PORT);

23
src/router/index.ts

@ -0,0 +1,23 @@
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView,
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('../views/AboutView.vue'),
},
],
})
export default router

58
src/services/axios.ts

@ -0,0 +1,58 @@
import axios from "axios";
const url = `${window.location.protocol}://${import.meta.env.VITE_API_HOST}:${import.meta.env.VITE_API_PORT}`;
const apiClient = axios.create({
baseURL: url, // 设置请求的根路径
timeout: 60000,
headers: {
"Content-Type": "application/json",
},
});
// 请求拦截器
// apiClient.interceptors.request.use(
// (config) => {
// const token = sessionStorage.getItem("token");
// if (!config.headers) {
// config.headers = AxiosHeaders.from({}); // 确保 config.headers 是 AxiosHeaders 类型
// }
// if (token) {
// config.headers.set("Authorization", `Bearer ${encodeURIComponent(token)}`); // 使用 set 方法设置 Authorization
// }
// return config;
// },
// error => {
// return Promise.reject(error);
// }
// );
// 响应拦截器
apiClient.interceptors.response.use(
(response) => {
if (response.data && response.data.dataType === "ZAppPromopt") {
if (response.data.ecode === "USR_NOT_EXIT") {
return Promise.resolve(response.data);
} else if (response.data.ecode === "USR_PASSWORD_ERROR") {
return Promise.resolve(response.data);
} else {
console.log("接口出错", response.data);
// eventBus.emit("show-error-modal", response.data.data);
return Promise.reject(response.data);
}
}
return response;
},
error => {
// eventBus.emit("show-error-modal", {
// messageLevel: "Error",
// title: "网络请求失败",
// info: error.message,
// });
return Promise.reject(error);
}
);
export default apiClient;

108
src/services/socket.ts

@ -0,0 +1,108 @@
import { Subject } from "rxjs";
export type SocketState = 'open' | 'close' | 'error'
class WebSocketClient {
private ws: WebSocket | null = null;
private url: string;
private reconnectAttempts: number = -1;
private maxReconnectAttempts: number = 5;
private reconnectInterval: number = 3000;
readonly dataOb = new Subject()
readonly stateOb = new Subject<SocketState>()
constructor(url: string) {
this.url = url;
}
// 连接 WebSocket
connect(): void {
try {
// WebSocket.CONNECTING (0) WebSocket.OPEN (1)
if (this.ws && this.ws.readyState <= 1) {
// 已连接
console.log(`${this.url} 正在连接或已连接,无需重复连接`);
} else {
this.ws = new WebSocket(this.url);
this.bindEvents();
}
} catch (error) {
console.error("WebSocket 连接失败:", error);
this.reconnect();
}
}
// 绑定事件
private bindEvents(): void {
if (!this.ws) return;
// 连接建立时的处理
this.ws.onopen = () => {
console.log("WebSocket 连接已建立");
this.reconnectAttempts = -1; // 重置重连次数
this.stateOb.next('open')
};
// 接收消息的处理
this.ws.onmessage = (event: MessageEvent) => {
try {
const data = JSON.parse(event.data);
// console.log('🚀 ~ WebSocketClient ~ bindEvents ~ data:', data)
this.dataOb.next(data)
} catch (error) {
console.error("消息解析错误:", error);
}
};
this.ws.onclose = () => {
this.stateOb.next('close')
console.log("WebSocket 连接已关闭");
this.reconnect();
};
this.ws.onerror = error => {
this.stateOb.next('error')
console.error("WebSocket 错误:", error);
};
}
// 重连机制
private reconnect(): void {
if (this.reconnectAttempts === -1) {
this.reconnectAttempts = 0;
}
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
console.log("达到最大重连次数,停止重连");
this.reconnectAttempts = -1;
return;
}
setTimeout(() => {
console.log(`尝试第 ${this.reconnectAttempts + 1} 次重连...`);
this.reconnectAttempts++;
this.connect();
}, this.reconnectInterval);
}
// 关闭连接
disconnect(): void {
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
}
const urlSocketMap = new Map<string, WebSocketClient>();
// 导出 WebSocket 客户端
export const createWebSocket = (url: string): WebSocketClient => {
if (urlSocketMap.has(url)) {
return urlSocketMap.get(url)!;
} else {
const client = new WebSocketClient(url);
urlSocketMap.set(url, client);
return client;
}
};

12
src/stores/counter.ts

@ -0,0 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

34
src/style.css

@ -0,0 +1,34 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--primaryColor: #26509C;
--headerHeight: 54px;
--footerHeight: 62px;
}
@layer utilities {
.gradient-light {
background: linear-gradient(180deg, #ebf1fa 0%, #f8fafd 100%);
}
.gradient-dark {
background: linear-gradient(90deg, #0657C0 24%, #096AE0 101%);
}
.btn-dark {
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(90deg, #0657C0 24%, #096AE0 101%);
border-radius: 4px;
color: white;
}
.btn-light {
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(180deg, #ebf1fa 0%, #f8fafd 100%);
box-shadow: 0px -1px 0px 0px rgba(255, 255, 255, 0.3),0px 1px 5px 0px rgba(173, 173, 173, 0.47);
border-radius: 4px;
color: var(--primaryColor);
}
}

9
src/utils/index.ts

@ -0,0 +1,9 @@
export function isValidIPv4(ip: string) {
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
return ipv4Regex.test(ip);
}
export function formatRemainTime(seconds: number) {
const min = Math.floor(seconds / 60).toFixed();
const sec = (seconds % 60).toFixed();
return min.padStart(2, "0") + ":" + sec.padStart(2, "0");
}

9
src/views/AboutView.vue

@ -0,0 +1,9 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
<style>
</style>

43
src/views/HomeView.vue

@ -0,0 +1,43 @@
<template>
<header class="h-[--headerHeight] bg-primary flex items-center text-white">
<img class="w-[83px] ml-6" src="@/assets/logo.png" alt="logo" />
<div class="w-0.5 h-5 bg-white mx-3"></div>
<p class="text-lg">基质喷涂转印仪</p>
<div class="flex items-center bg-[#335AA5] px-4 py-1 rounded ml-auto">
<i class="bg-[#8CFBB7] w-[14px] h-[14px] rounded-full mr-2"></i>
<p>基质余量正常</p>
</div>
<Time class="mx-4"></Time>
<div class="flex items-center text-white px-5 py-1 mx-6 rounded gradient-light">
<img src="@/assets/menu.svg" alt="menu" />
<p class="text-lg ml-2 text-primary">菜单</p>
</div>
</header>
<main class="relative" style="height: calc(100vh - var(--headerHeight)); background: linear-gradient(180deg, #dfe8f7 0%, #ffffff 100%)">
<section class="pt-[90px] mb-5 flex justify-between px-[90px]">
<img src="@/assets/entry1.png" alt="entry1" />
<img src="@/assets/entry2.png" alt="entry1" />
<img src="@/assets/entry3.png" alt="entry1" />
</section>
<section class="flex justify-between px-[100px]">
<div class="btn-dark px-12 py-3 text-lg">开始喷涂</div>
<div class="btn-light px-12 py-3 text-lg">停止喷涂</div>
<div class="btn-dark px-12 py-3 text-lg">开始转印</div>
<div class="btn-light px-12 py-3 text-lg">停止转印</div>
</section>
<section class=" absolute right-0 bottom-0 h-[--footerHeight] flex justify-end items-start">
<div class="btn-light px-4 py-2 mr-5">
<img src="@/assets/wash.svg" alt="wash" />
<span class="font-medium ml-2">清洗管道</span>
</div>
<div class="btn-light px-4 py-2 mr-8">
<img src="@/assets/refresh.svg" alt="icon" />
<span class="font-medium ml-2">更换拨片</span>
</div>
</section>
</main>
</template>
<script setup lang="ts">
import Time from "@/components/Time.vue";
</script>

17
tailwind.config.js

@ -0,0 +1,17 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
theme: {
colors: {
primary: "#26509C",
white: "#FFF",
title: "#646566",
text: "#2C3E59",
gradient90: "linear-gradient(90deg, #0657C0 24%, #096AE0 101%)",
gradient110: "linear-gradient(110deg, #0349A8 11%, #1663B7 105%)",
gradientLight1: "linear-gradient(180deg, #EBF1FA 0%, #F8FAFD 100%)",
},
extend: {},
},
plugins: [],
};

12
tsconfig.app.json

@ -0,0 +1,12 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
tsconfig.json

@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

18
tsconfig.node.json

@ -0,0 +1,18 @@
{
"extends": "@tsconfig/node22/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

20
vite.config.ts

@ -0,0 +1,20 @@
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
import vueDevTools from "vite-plugin-vue-devtools";
// https://vite.dev/config/
export default defineConfig({
plugins: [vue(), vueJsx(), vueDevTools()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
server: {
host: "0.0.0.0",
port: 5175,
},
});
Loading…
Cancel
Save