commit
ba9e337bef
36 changed files with 5517 additions and 0 deletions
-
3.env
-
30.gitignore
-
3.vscode/extensions.json
-
33README.md
-
1env.d.ts
-
13index.html
-
4905package-lock.json
-
42package.json
-
8postcss.config.js
-
BINpublic/favicon.ico
-
12src/App.vue
-
31src/assets/base.css
-
BINsrc/assets/entry1.png
-
BINsrc/assets/entry2.png
-
BINsrc/assets/entry3.png
-
BINsrc/assets/logo.png
-
1src/assets/logo.svg
-
7src/assets/main.css
-
2src/assets/menu.svg
-
1src/assets/refresh.svg
-
1src/assets/wash.svg
-
30src/components/Time.vue
-
20src/main.ts
-
23src/router/index.ts
-
58src/services/axios.ts
-
108src/services/socket.ts
-
12src/stores/counter.ts
-
34src/style.css
-
9src/utils/index.ts
-
9src/views/AboutView.vue
-
43src/views/HomeView.vue
-
17tailwind.config.js
-
12tsconfig.app.json
-
11tsconfig.json
-
18tsconfig.node.json
-
20vite.config.ts
@ -0,0 +1,3 @@ |
|||
VITE_API_HOST=window.location.hostname |
|||
VITE_API_PORT=80 |
|||
VITE_WS_PATH=/api/v1/app/ws/state |
@ -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 |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"recommendations": ["Vue.volar"] |
|||
} |
@ -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 本地环境变量 |
@ -0,0 +1 @@ |
|||
/// <reference types="vite/client" />
|
@ -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
File diff suppressed because it is too large
View File
@ -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" |
|||
} |
|||
} |
@ -0,0 +1,8 @@ |
|||
export default { |
|||
plugins: { |
|||
'postcss-import': {}, |
|||
'tailwindcss/nesting': {}, |
|||
tailwindcss: {}, |
|||
autoprefixer: {}, |
|||
}, |
|||
} |
@ -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> |
@ -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; |
|||
} |
After Width: 220 | Height: 274 | Size: 9.0 KiB |
After Width: 220 | Height: 274 | Size: 9.8 KiB |
After Width: 220 | Height: 274 | Size: 9.9 KiB |
After Width: 166 | Height: 38 | Size: 3.1 KiB |
@ -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> |
@ -0,0 +1,7 @@ |
|||
@import './base.css'; |
|||
|
|||
#app { |
|||
max-width: 1280px; |
|||
max-height: 800px; |
|||
overflow: hidden; |
|||
} |
@ -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> |
@ -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
File diff suppressed because it is too large
View File
@ -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> |
@ -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); |
@ -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 |
@ -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; |
@ -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; |
|||
} |
|||
}; |
@ -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 } |
|||
}) |
@ -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); |
|||
} |
|||
} |
@ -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"); |
|||
} |
@ -0,0 +1,9 @@ |
|||
<template> |
|||
<div class="about"> |
|||
<h1>This is an about page</h1> |
|||
</div> |
|||
</template> |
|||
|
|||
<style> |
|||
|
|||
</style> |
@ -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> |
@ -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: [], |
|||
}; |
@ -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/*"] |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
{ |
|||
"files": [], |
|||
"references": [ |
|||
{ |
|||
"path": "./tsconfig.node.json" |
|||
}, |
|||
{ |
|||
"path": "./tsconfig.app.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"] |
|||
} |
|||
} |
@ -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, |
|||
}, |
|||
}); |
Write
Preview
Loading…
Cancel
Save
Reference in new issue