优化项目结构
优化路由结构及跳转 优化系统异常捕获 1 号线增加导出功能 增加全局状态管理
This commit is contained in:
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -31,6 +31,7 @@ declare module 'vue' {
|
|||||||
ExecutionResult: typeof import('./src/components/common/ExecutionResult/index.vue')['default']
|
ExecutionResult: typeof import('./src/components/common/ExecutionResult/index.vue')['default']
|
||||||
ILucideActivity: typeof import('~icons/lucide/activity')['default']
|
ILucideActivity: typeof import('~icons/lucide/activity')['default']
|
||||||
ILucideCamera: typeof import('~icons/lucide/camera')['default']
|
ILucideCamera: typeof import('~icons/lucide/camera')['default']
|
||||||
|
ILucideCircleX: typeof import('~icons/lucide/circle-x')['default']
|
||||||
ILucideCpu: typeof import('~icons/lucide/cpu')['default']
|
ILucideCpu: typeof import('~icons/lucide/cpu')['default']
|
||||||
ILucideDatabase: typeof import('~icons/lucide/database')['default']
|
ILucideDatabase: typeof import('~icons/lucide/database')['default']
|
||||||
ILucideEdit: typeof import('~icons/lucide/edit')['default']
|
ILucideEdit: typeof import('~icons/lucide/edit')['default']
|
||||||
|
|||||||
19
package-lock.json
generated
19
package-lock.json
generated
@@ -1,15 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "rd_mes_front_hmi",
|
"name": "rd_mes_front_hmi",
|
||||||
"version": "0.0.0",
|
"version": "0.0.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "rd_mes_front_hmi",
|
"name": "rd_mes_front_hmi",
|
||||||
"version": "0.0.0",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ant-design-vue": "^4.2.6",
|
"ant-design-vue": "^4.2.6",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"unplugin-vue-components": "^28.7.0",
|
"unplugin-vue-components": "^28.7.0",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/lucide": "^1.2.66",
|
"@iconify-json/lucide": "^1.2.66",
|
||||||
"@types/event-source-polyfill": "^1.0.5",
|
"@types/event-source-polyfill": "^1.0.5",
|
||||||
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node": "^24.0.3",
|
"@types/node": "^24.0.3",
|
||||||
"@vitejs/plugin-vue": "^5.2.3",
|
"@vitejs/plugin-vue": "^5.2.3",
|
||||||
@@ -935,6 +937,13 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/file-saver": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/file-saver/-/file-saver-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/js-cookie": {
|
"node_modules/@types/js-cookie": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.6",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-3.0.6.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-3.0.6.tgz",
|
||||||
@@ -1644,6 +1653,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/file-saver": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.1.1",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ant-design-vue": "^4.2.6",
|
"ant-design-vue": "^4.2.6",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"unplugin-vue-components": "^28.7.0",
|
"unplugin-vue-components": "^28.7.0",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/lucide": "^1.2.66",
|
"@iconify-json/lucide": "^1.2.66",
|
||||||
"@types/event-source-polyfill": "^1.0.5",
|
"@types/event-source-polyfill": "^1.0.5",
|
||||||
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/node": "^24.0.3",
|
"@types/node": "^24.0.3",
|
||||||
"@vitejs/plugin-vue": "^5.2.3",
|
"@vitejs/plugin-vue": "^5.2.3",
|
||||||
|
|||||||
1
src/api/common/model.d.ts
vendored
1
src/api/common/model.d.ts
vendored
@@ -4,4 +4,5 @@ export interface ApiResponse<T = any> {
|
|||||||
data?: T;
|
data?: T;
|
||||||
rows?: T[];
|
rows?: T[];
|
||||||
total?: number;
|
total?: number;
|
||||||
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
30
src/api/line1/data/index.ts
Normal file
30
src/api/line1/data/index.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import request from '@/api/request';
|
||||||
|
import type { ExportParams, QueryParams } from "./model";
|
||||||
|
|
||||||
|
// 获取 L1 数据
|
||||||
|
export function getL1Data(params: QueryParams) {
|
||||||
|
return request({
|
||||||
|
url: "/jinghua/l1OneData/list",
|
||||||
|
method: "get",
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 报警记录 数据
|
||||||
|
export function getAlarmRecords(params: QueryParams) {
|
||||||
|
return request({
|
||||||
|
url: '/jinghua/alarmRecord/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出数据
|
||||||
|
export function exportData(data: ExportParams) {
|
||||||
|
return request({
|
||||||
|
url: "/jinghua/l1OneData/export",
|
||||||
|
method: "post",
|
||||||
|
data,
|
||||||
|
responseType: "blob",
|
||||||
|
});
|
||||||
|
}
|
||||||
14
src/api/line1/data/model.d.ts
vendored
Normal file
14
src/api/line1/data/model.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export interface QueryParams {
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
orderByColumn?: string;
|
||||||
|
isAsc?: string;
|
||||||
|
qrCode?: string;
|
||||||
|
createTimeBegin?: string;
|
||||||
|
createTimeEnd?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExportParams {
|
||||||
|
createTimeBegin?: string;
|
||||||
|
createTimeEnd?: string;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import request from '../request';
|
import request from '@/api/request';
|
||||||
import type { QueryParams } from './model';
|
import type { QueryParams } from './model';
|
||||||
|
|
||||||
// 获取 L1 数据
|
// 获取 L1 数据
|
||||||
@@ -2,7 +2,7 @@ import axios from 'axios';
|
|||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import { getToken } from '@/utils/auth';
|
import { getToken } from '@/utils/auth';
|
||||||
import { Modal, notification } from 'ant-design-vue';
|
import { Modal, notification } from 'ant-design-vue';
|
||||||
import type { AxiosRequestConfig } from "axios";
|
import type { AxiosInstance, AxiosRequestConfig } from "axios";
|
||||||
import type { ApiResponse } from "@/api/common/model";
|
import type { ApiResponse } from "@/api/common/model";
|
||||||
|
|
||||||
const errCodeMap: { [key: string]: string } = {
|
const errCodeMap: { [key: string]: string } = {
|
||||||
@@ -12,7 +12,7 @@ const errCodeMap: { [key: string]: string } = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const service = axios.create({
|
const service: AxiosInstance = axios.create({
|
||||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
});
|
});
|
||||||
@@ -37,33 +37,38 @@ service.interceptors.request.use(
|
|||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
response => {
|
response => {
|
||||||
// console.log(response);
|
if (response.config.responseType === "blob") {
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
const code = response.data.code || 200;
|
const code = response.data.code || 200;
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 200:
|
case 200:
|
||||||
return data ?? response;
|
return data;
|
||||||
case 401:
|
case 401:
|
||||||
Modal.error({
|
Modal.error({
|
||||||
title: '系统提示',
|
title: "系统提示",
|
||||||
content: '登录状态已过期,请重新登录',
|
content: "登录状态已过期,请重新登录",
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
router.push('/login')
|
router.push("/login");
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
return Promise.reject(data);
|
return Promise.reject(data);
|
||||||
default:
|
default:
|
||||||
const errMsg = errCodeMap[code] || data.msg || errCodeMap['default'];
|
|
||||||
notification.error({
|
notification.error({
|
||||||
message: '请求错误',
|
message: "请求错误",
|
||||||
description: errMsg,
|
description: errCodeMap[code] || data?.msg || errCodeMap.default,
|
||||||
});
|
});
|
||||||
return Promise.reject(data);
|
return Promise.reject(data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error => {
|
(error) => {
|
||||||
error.message = error.code === "ECONNABORTED" ? '请求超时,请稍后重试' : error.message;
|
error.message =
|
||||||
|
error.code === "ECONNABORTED"
|
||||||
|
? "请求超时,请稍后重试"
|
||||||
|
: error.message || "网络异常";
|
||||||
|
|
||||||
// 网络/服务器错误统一处理
|
// 网络/服务器错误统一处理
|
||||||
notification.error({
|
notification.error({
|
||||||
@@ -80,4 +85,3 @@ function request<T = any>(config: AxiosRequestConfig): Promise<ApiResponse<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default request;
|
export default request;
|
||||||
// export default service;
|
|
||||||
11
src/components/LmsStatus/data.ts
Normal file
11
src/components/LmsStatus/data.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export const actions = {
|
||||||
|
'line2': [
|
||||||
|
{ title: "L1 数据", path: "/line2/L1-data" },
|
||||||
|
{ title: "L4 数据", path: "/line2/L4-data" },
|
||||||
|
{ title: "报警记录", path: "/line2/alarm-records" },
|
||||||
|
],
|
||||||
|
'line1': [
|
||||||
|
{ title: "L1 数据", path: "/line1/L1-data" },
|
||||||
|
{ title: "报警记录", path: "/line1/alarm-records" },
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -20,9 +20,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-row>
|
</a-row>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<a-button size="large" @click="redirectTo('L1-data')">L1 数据</a-button>
|
<a-button v-for="act in actions[props.type as keyof typeof actions]" size="large" @click="redirectTo(act.path)">{{ act.title }}</a-button>
|
||||||
<a-button size="large" @click="redirectTo('L4-data')">L4 数据</a-button>
|
|
||||||
<a-button size="large" @click="redirectTo('alarm-records')">报警记录</a-button>
|
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
@@ -33,6 +31,14 @@ import { useRouter } from 'vue-router';
|
|||||||
import { useDialog } from '@/utils/useDialog';
|
import { useDialog } from '@/utils/useDialog';
|
||||||
import { fetchLmsWorkMode, updateLmsWorkMode } from '@/api/lms';
|
import { fetchLmsWorkMode, updateLmsWorkMode } from '@/api/lms';
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
import { actions } from './data';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// useDialog管理弹窗状态
|
// useDialog管理弹窗状态
|
||||||
const { visible: dialogVisible, show, hide } = useDialog();
|
const { visible: dialogVisible, show, hide } = useDialog();
|
||||||
@@ -77,8 +83,8 @@ async function initLmsStatus() {
|
|||||||
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
function redirectTo(type: string) {
|
function redirectTo(path: string) {
|
||||||
router.push(`/${type}`);
|
router.push(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化 LMS 状态
|
// 初始化 LMS 状态
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useDialog } from '@/utils/useDialog';
|
import { useDialog } from '@/utils/useDialog';
|
||||||
|
import { useUserStore } from '@/store';
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
// useDialog管理弹窗状态
|
// useDialog管理弹窗状态
|
||||||
const { visible: dialogVisible, show, hide } = useDialog();
|
const { visible: dialogVisible, show, hide } = useDialog();
|
||||||
@@ -29,7 +32,7 @@ const modalTitle = ref('MES 登录状态');
|
|||||||
const modalItems = ref([
|
const modalItems = ref([
|
||||||
{ label: 'MES 服务器', value: '192.168.1.100:8080'},
|
{ label: 'MES 服务器', value: '192.168.1.100:8080'},
|
||||||
{ label: '登录状态', value: mesStatus.value},
|
{ label: '登录状态', value: mesStatus.value},
|
||||||
{ label: '用户名', value: 'admin'},
|
{ label: '用户名', value: userStore.username},
|
||||||
{ label: '连接时间', value: '2024-01-15 09:30:25'},
|
{ label: '连接时间', value: '2024-01-15 09:30:25'},
|
||||||
{ label: '最后活动', value: '2024-01-15 14:25:30'}
|
{ label: '最后活动', value: '2024-01-15 14:25:30'}
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,41 +1,63 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router';
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
|
import { getToken } from "@/utils/auth";
|
||||||
|
|
||||||
|
const whiteList = ["/login"];
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: "/",
|
||||||
name: 'Index',
|
name: "Index",
|
||||||
component: () => import('@/views/index.vue')
|
component: () => import("@/views/Line2/index.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/lms',
|
path: "/lms",
|
||||||
name: 'Lms',
|
name: "Lms",
|
||||||
component: () => import('@/views/lms/index.vue')
|
component: () => import("@/views/Line1/index.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: "/login",
|
||||||
name: 'Login',
|
name: "Login",
|
||||||
component: () => import('@/views/login.vue')
|
component: () => import("@/views/login.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/package-station',
|
path: "/package-station",
|
||||||
name: 'PackageStation',
|
name: "PackageStation",
|
||||||
component: () => import('@/views/package-station/index.vue')
|
component: () => import("@/views/package-station/index.vue"),
|
||||||
},
|
},
|
||||||
{
|
// 一号线
|
||||||
path: '/L1-data',
|
{
|
||||||
name: 'L1Data',
|
path: "/line1",
|
||||||
component: () => import('@/views/L1-data-list/index.vue')
|
name: "Line1",
|
||||||
},
|
children: [
|
||||||
{
|
{
|
||||||
path: '/L4-data',
|
path: "L1-data",
|
||||||
name: 'L4Data',
|
name: "Line1L1Data",
|
||||||
component: () => import('@/views/L4-data-list/index.vue')
|
component: () => import("@/views/Line1/L1-data-list/index.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/alarm-records',
|
path: "alarm-records",
|
||||||
name: 'AlarmRecords',
|
name: "Line1AlarmRecords",
|
||||||
component: () => import('@/views/alarm-records/index.vue')
|
component: () => import("@/views/Line1/alarm-records/index.vue"),
|
||||||
}
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// 二号线
|
||||||
|
{
|
||||||
|
path: "/line2",
|
||||||
|
name: "Line2",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "L1-data",
|
||||||
|
name: "Line2L1Data",
|
||||||
|
component: () => import("@/views/Line2/L1-data-list/index.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "L4-data",
|
||||||
|
name: "Line2L4Data",
|
||||||
|
component: () => import("@/views/Line2/L4-data-list/index.vue"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
@@ -43,4 +65,29 @@ const router = createRouter({
|
|||||||
routes
|
routes
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
const token = getToken();
|
||||||
|
// 已登录,访问 login → 跳首页
|
||||||
|
if (token && to.path === "/login") {
|
||||||
|
return next("/lms");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 白名单放行
|
||||||
|
if (whiteList.includes(to.path)) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未登录,访问受保护路由
|
||||||
|
if (!token) {
|
||||||
|
return next({
|
||||||
|
path: "/login",
|
||||||
|
query: { redirect: to.fullPath },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已登录,正常访问
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
67
src/store/auth.ts
Normal file
67
src/store/auth.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import Cookies from 'js-cookie';
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { useUserStore } from './user';
|
||||||
|
import { login } from '@/api/system';
|
||||||
|
import { TokenKey as TOKEN_KEY } from "@/utils/auth";
|
||||||
|
import type { LoginInfo } from '@/api/system/model';
|
||||||
|
|
||||||
|
export const useAuthStore = defineStore('auth', () => {
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const loginLoading = ref(false);
|
||||||
|
const token = ref(Cookies.get(TOKEN_KEY) || null);
|
||||||
|
|
||||||
|
function setToken(newToken: string) {
|
||||||
|
token.value = newToken;
|
||||||
|
Cookies.set(TOKEN_KEY, newToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearToken() {
|
||||||
|
token.value = null;
|
||||||
|
Cookies.remove(TOKEN_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function authLogin(params: LoginInfo) {
|
||||||
|
try {
|
||||||
|
loginLoading.value = true;
|
||||||
|
const res = await login(params);
|
||||||
|
if (res.code === 200) {
|
||||||
|
setToken(res.token as string);
|
||||||
|
await userStore.fetchUserInfo();
|
||||||
|
message.success('登录成功');
|
||||||
|
const redirect = route.query.redirect || "/lms";
|
||||||
|
router.replace(redirect as string);
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
// 抛出错误,让调用方处理
|
||||||
|
throw new Error(res.msg || '登录失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
loginLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function logout() {
|
||||||
|
// 在实际应用中,这里可以调用后端的退出登录接口
|
||||||
|
// await doLogoutApi();
|
||||||
|
clearToken();
|
||||||
|
userStore.clearUserInfo();
|
||||||
|
await router.push('/login');
|
||||||
|
message.success('已成功退出');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
token,
|
||||||
|
loginLoading,
|
||||||
|
authLogin,
|
||||||
|
logout,
|
||||||
|
};
|
||||||
|
});
|
||||||
2
src/store/index.ts
Normal file
2
src/store/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './auth';
|
||||||
|
export * from './user';
|
||||||
@@ -1,30 +1,22 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
export interface UserInfo {
|
const USERNAME_KEY = 'username';
|
||||||
username: string;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', {
|
export const useUserStore = defineStore('user', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
token: localStorage.getItem('token') || '',
|
username: Cookies.get(USERNAME_KEY) || null,
|
||||||
userInfo: null as UserInfo | null,
|
|
||||||
}),
|
}),
|
||||||
getters: {
|
|
||||||
isLogin: (state) => !!state.token,
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
setToken(token: string) {
|
async fetchUserInfo() {
|
||||||
this.token = token;
|
// Simulate API call
|
||||||
localStorage.setItem('token', token);
|
const fetchedUsername = 'mock_user';
|
||||||
|
this.username = fetchedUsername;
|
||||||
|
Cookies.set(USERNAME_KEY, fetchedUsername);
|
||||||
},
|
},
|
||||||
setUserInfo(userInfo: UserInfo) {
|
clearUserInfo() {
|
||||||
this.userInfo = userInfo;
|
this.username = null;
|
||||||
},
|
Cookies.remove(USERNAME_KEY);
|
||||||
reset() {
|
|
||||||
this.token = '';
|
|
||||||
this.userInfo = null;
|
|
||||||
localStorage.removeItem('token');
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
const TokenKey = 'Admin-Token'
|
export const TokenKey = 'Admin-Token'
|
||||||
|
|
||||||
export function getToken() {
|
export function getToken() {
|
||||||
return Cookies.get(TokenKey)
|
return Cookies.get(TokenKey)
|
||||||
|
|||||||
17
src/utils/download.ts
Normal file
17
src/utils/download.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { saveAs } from "file-saver";
|
||||||
|
|
||||||
|
export async function download(data: Blob, fileName: string) {
|
||||||
|
// 1️⃣ 后端返回的是错误 JSON
|
||||||
|
if (data.type.includes("application/json")) {
|
||||||
|
const text = await data.text();
|
||||||
|
const err = JSON.parse(text);
|
||||||
|
throw new Error(err.msg || "导出失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2️⃣ 正常下载
|
||||||
|
const blob = new Blob([data], {
|
||||||
|
type: data.type || "application/octet-stream",
|
||||||
|
});
|
||||||
|
|
||||||
|
saveAs(blob, fileName);
|
||||||
|
}
|
||||||
317
src/views/Line1/L1-data-list/index.vue
Normal file
317
src/views/Line1/L1-data-list/index.vue
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
<template>
|
||||||
|
<div class="l1-data-container">
|
||||||
|
<div class="page-header">
|
||||||
|
<h1 class="page-title">L1数据列表</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选区域 -->
|
||||||
|
<div class="filter-section">
|
||||||
|
<a-form layout="inline" :model="formData">
|
||||||
|
<a-form-item label="日期范围">
|
||||||
|
<a-range-picker v-model:value="formData.dateRange" :placeholder="['开始日期', '结束日期']"
|
||||||
|
format="YYYY-MM-DD HH:mm:ss" show-time />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="handleSearch" :loading="loading">
|
||||||
|
<template #icon>
|
||||||
|
<i-lucide-search />
|
||||||
|
</template>
|
||||||
|
搜索
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="handleReset">
|
||||||
|
<template #icon>
|
||||||
|
<i-lucide-refresh-cw />
|
||||||
|
</template>
|
||||||
|
重置
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="handleExport">
|
||||||
|
<template #icon>
|
||||||
|
<i-lucide-save />
|
||||||
|
</template>
|
||||||
|
导出
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据表格 -->
|
||||||
|
<div class="table-section">
|
||||||
|
<a-table :columns="columns" :data-source="tableData" :loading="loading" :pagination="pagination"
|
||||||
|
@change="handleTableChange" row-key="id" size="middle" :scroll="{ x: 1200 }">
|
||||||
|
<template #bodyCell="{ column, record, index }">
|
||||||
|
<template v-if="column.key === 'index'">{{ index + 1 }}</template>
|
||||||
|
<template v-else-if="column.key === 'createTime'">
|
||||||
|
<span>{{ formatDateTime(record.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
<!-- <template v-else-if="column.key === 'productStatus'">
|
||||||
|
<a-tag :color="record.productStatus === 1 ? 'success' : 'default'">
|
||||||
|
{{ record.productStatus === 1 ? '有' : '无' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'goodFlag'">
|
||||||
|
<a-tag :color="record.goodFlag === 1 ? 'success' : 'error'">
|
||||||
|
{{ record.goodFlag === 1 ? '良品' : '不良品' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'processMemory'">
|
||||||
|
<a-tag :color="record.processMemory === 1 ? 'success' : 'default'">
|
||||||
|
{{ record.processMemory === 1 ? '已加工' : '未开工' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'functionSw'">
|
||||||
|
<a-tag :color="record.functionSw === 1 ? 'success' : 'default'">
|
||||||
|
{{ record.functionSw === 1 ? '有效' : '无效' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'visualResult'">
|
||||||
|
<a-tag :color="record.visualResult === 1 ? 'success' : 'error'">
|
||||||
|
{{ record.visualResult === 1 ? 'OK' : 'NG' }}
|
||||||
|
</a-tag>
|
||||||
|
</template> -->
|
||||||
|
<template v-else-if="column.key === 'action'">
|
||||||
|
<a-button type="link" size="small" @click="handleView(record as L1Data)">
|
||||||
|
查看详情
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ record[column.key as string] }}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 详情弹窗 -->
|
||||||
|
<a-modal v-model:open="detailVisible" title="详情信息" :footer="null" width="800px">
|
||||||
|
<div v-if="selectedRecord" class="detail-content">
|
||||||
|
<a-descriptions :column="2" bordered>
|
||||||
|
<a-descriptions-item
|
||||||
|
v-for="(value, key) in selectedRecord"
|
||||||
|
:key="key"
|
||||||
|
:label="columns.find((col) => col.key === key)?.title || key"
|
||||||
|
>
|
||||||
|
<template v-if="key === 'createTime'">
|
||||||
|
{{ formatDateTime(value) }}
|
||||||
|
</template>
|
||||||
|
<!-- <template v-else-if="key === 'productStatus'">
|
||||||
|
<a-tag :color="selectedRecord.productStatus === 1 ? 'success' : 'default'">
|
||||||
|
{{ selectedRecord.productStatus === 1 ? '有' : '无' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'goodFlag'">
|
||||||
|
<a-tag :color="selectedRecord.goodFlag === 1 ? 'success' : 'error'">
|
||||||
|
{{ selectedRecord.goodFlag === 1 ? '良品' : '不良品' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'processMemory'">
|
||||||
|
<a-tag :color="selectedRecord.processMemory === 1 ? 'success' : 'default'">
|
||||||
|
{{ selectedRecord.processMemory === 1 ? '已加工' : '未开工' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'functionSw'">
|
||||||
|
<a-tag :color="selectedRecord.functionSw === 1 ? 'success' : 'default'">
|
||||||
|
{{ selectedRecord.functionSw === 1 ? '有效' : '无效' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'visualResult'">
|
||||||
|
<a-tag :color="selectedRecord.visualResult === 1 ? 'success' : 'error'">
|
||||||
|
{{ selectedRecord.visualResult === 1 ? 'OK' : 'NG' }}
|
||||||
|
</a-tag>
|
||||||
|
</template> -->
|
||||||
|
<template v-else>
|
||||||
|
{{ value }}
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
</a-descriptions>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, onMounted } from "vue";
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
|
import { getL1Data, exportData } from "@/api/line1/data";
|
||||||
|
import type { QueryParams } from "@/api/data/model";
|
||||||
|
import type { L1Data } from "./types";
|
||||||
|
import type { Dayjs } from "dayjs";
|
||||||
|
import { download } from "@/utils/download";
|
||||||
|
import { columns } from "./data";
|
||||||
|
|
||||||
|
type DateRangeType = [Dayjs, Dayjs] | undefined;
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const loading = ref(false);
|
||||||
|
const tableData = ref<L1Data[]>([]);
|
||||||
|
const formData = reactive<{ dateRange: DateRangeType }>({
|
||||||
|
dateRange: undefined,
|
||||||
|
});
|
||||||
|
const detailVisible = ref(false);
|
||||||
|
const selectedRecord = ref<L1Data | null>(null);
|
||||||
|
|
||||||
|
// 分页配置
|
||||||
|
const pagination = reactive({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showTotal: (total: number) => `共 ${total} 条`,
|
||||||
|
pageSizeOptions: ["10", "20", "50", "100"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取数据
|
||||||
|
const fetchData = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const params: QueryParams = {
|
||||||
|
pageNum: pagination.current,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加日期范围筛选
|
||||||
|
if (formData.dateRange && formData.dateRange.length === 2) {
|
||||||
|
params.createTimeBegin = formData.dateRange[0].format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
params.createTimeEnd = formData.dateRange[1].format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getL1Data(params);
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
tableData.value = res.rows || [];
|
||||||
|
pagination.total = res.total || 0;
|
||||||
|
} else {
|
||||||
|
message.error(res.msg || "获取数据失败");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取L1数据失败:", error);
|
||||||
|
message.error("获取数据失败,请稍后重试");
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
pagination.current = 1;
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置处理
|
||||||
|
const handleReset = () => {
|
||||||
|
formData.dateRange = undefined;
|
||||||
|
pagination.current = 1;
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 导出处理
|
||||||
|
const handleExport = async () => {
|
||||||
|
try {
|
||||||
|
let params = {}
|
||||||
|
if (formData.dateRange && formData.dateRange.length === 2) {
|
||||||
|
params = {
|
||||||
|
createTimeBegin : formData.dateRange[0].format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
createTimeEnd : formData.dateRange[1].format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const blob = await exportData(params)
|
||||||
|
|
||||||
|
download(blob as any, "导出数据.xlsx")
|
||||||
|
|
||||||
|
message.success("导出成功")
|
||||||
|
} catch (err: any) {
|
||||||
|
message.error(err.message)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格变化处理(分页、排序等)
|
||||||
|
const handleTableChange = (pag: any, filters: any, sorter: any) => {
|
||||||
|
pagination.current = pag.current;
|
||||||
|
pagination.pageSize = pag.pageSize;
|
||||||
|
|
||||||
|
// 处理排序
|
||||||
|
if (sorter.field) {
|
||||||
|
// 这里可以根据需要添加排序逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
const handleView = (record: L1Data) => {
|
||||||
|
selectedRecord.value = record;
|
||||||
|
detailVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 格式化日期时间
|
||||||
|
const formatDateTime = (dateTime: string | number) => {
|
||||||
|
if (!dateTime) return null;
|
||||||
|
return new Date(dateTime).toLocaleString('zh-CN', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 组件挂载时获取数据
|
||||||
|
onMounted(() => {
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.l1-data-container {
|
||||||
|
padding: 20px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2937;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-section {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-content {
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-thead > tr > th) {
|
||||||
|
background: #f8fafc;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-tbody > tr:hover > td) {
|
||||||
|
background: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-descriptions-item-label) {
|
||||||
|
font-weight: 600;
|
||||||
|
background: #f8fafc;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onBeforeUnmount, reactive, nextTick } from 'vue';
|
import { ref, onMounted, reactive } from 'vue';
|
||||||
import { useRealTime } from '@/utils/dateUtils';
|
import { useRealTime } from '@/utils/dateUtils';
|
||||||
import { checkOrderNumberApi, addProcessInfoApi } from '@/api/detect';
|
import { checkOrderNumberApi, addProcessInfoApi } from '@/api/detect';
|
||||||
import type { Rule } from 'ant-design-vue/es/form';
|
import type { Rule } from 'ant-design-vue/es/form';
|
||||||
@@ -140,7 +140,7 @@ const handlePackagePass = () => {
|
|||||||
// SSE事件处理函数
|
// SSE事件处理函数
|
||||||
const handleL1Event = (data: any) => {
|
const handleL1Event = (data: any) => {
|
||||||
// L1_EVENT放到自动包装日志区
|
// L1_EVENT放到自动包装日志区
|
||||||
addPackageLog(`L1事件: ${data.message}`);
|
addDetectionLog(`L1事件: ${data.message}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleL4Event = (data: any) => {
|
const handleL4Event = (data: any) => {
|
||||||
@@ -280,11 +280,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
// SSE连接逻辑已迁移到SseStatus组件中
|
// SSE连接逻辑已迁移到SseStatus组件中
|
||||||
});
|
});
|
||||||
|
|
||||||
// 清理事件监听
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
// SSE断开连接逻辑已迁移到SseStatus组件中
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -314,7 +309,7 @@ onBeforeUnmount(() => {
|
|||||||
:on-sse-message="handleSseMessage" />
|
:on-sse-message="handleSseMessage" />
|
||||||
|
|
||||||
<!-- LMS 状态 -->
|
<!-- LMS 状态 -->
|
||||||
<LmsStatus />
|
<LmsStatus type="line1" />
|
||||||
</div>
|
</div>
|
||||||
<SettingsModal />
|
<SettingsModal />
|
||||||
<!-- <div class="right-info" @click="showSettings">
|
<!-- <div class="right-info" @click="showSettings">
|
||||||
48
src/views/Line2/L1-data-list/data.ts
Normal file
48
src/views/Line2/L1-data-list/data.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import type { TableColumnType, TableColumnsType } from "ant-design-vue";
|
||||||
|
|
||||||
|
const INDEX_COLUMN: TableColumnType = {
|
||||||
|
key: "index",
|
||||||
|
title: "序号",
|
||||||
|
width: 60,
|
||||||
|
fixed: true,
|
||||||
|
align: "center",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 定义操作列配置
|
||||||
|
const ACTION_COLUMN: TableColumnType = {
|
||||||
|
key: "action",
|
||||||
|
title: "操作",
|
||||||
|
width: 120,
|
||||||
|
ellipsis: true,
|
||||||
|
fixed: "right",
|
||||||
|
align: "center",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 使用 Record 类型确保键值对的安全性
|
||||||
|
export const fields: Record<string, string> = {
|
||||||
|
productStatus: "产品状态",
|
||||||
|
goodFlag: "良品标记",
|
||||||
|
processMemory: "加工记忆",
|
||||||
|
functionSw: "功能SW",
|
||||||
|
axisNumber: "轴号",
|
||||||
|
plugTerminalPressure: "插端子压力值",
|
||||||
|
plugTerminalHeight: "插端子高度值",
|
||||||
|
resistance: "电阻值",
|
||||||
|
inductorLs: "电感LS值",
|
||||||
|
inductorQ: "电感Q值",
|
||||||
|
pressureResistanceR: "耐压R值",
|
||||||
|
pressureResistanceI: "耐压I值",
|
||||||
|
visualResult: "视觉结果",
|
||||||
|
createTime: "创建时间",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 导出完整的列配置
|
||||||
|
export const columns: TableColumnsType = [
|
||||||
|
INDEX_COLUMN,
|
||||||
|
...Object.entries(fields).map(([key, title]) => ({
|
||||||
|
key,
|
||||||
|
title,
|
||||||
|
ellipsis: true,
|
||||||
|
})),
|
||||||
|
ACTION_COLUMN,
|
||||||
|
];
|
||||||
@@ -126,8 +126,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted } from "vue";
|
import { ref, reactive, onMounted } from "vue";
|
||||||
import { message } from "ant-design-vue";
|
import { message } from "ant-design-vue";
|
||||||
import { getL1Data } from "@/api/data";
|
import { getL1Data } from "@/api/line2/data";
|
||||||
import type { QueryParams } from "@/api/data/model";
|
import type { QueryParams } from "@/api/line2/data/model";
|
||||||
import type { L1Data } from "./types";
|
import type { L1Data } from "./types";
|
||||||
import type { Dayjs } from "dayjs";
|
import type { Dayjs } from "dayjs";
|
||||||
import { columns } from "./data";
|
import { columns } from "./data";
|
||||||
58
src/views/Line2/L1-data-list/types.ts
Normal file
58
src/views/Line2/L1-data-list/types.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
export interface L1Data {
|
||||||
|
/** 加工信息ID */
|
||||||
|
processInfoId: number;
|
||||||
|
|
||||||
|
/** 产品状态: 0-无, 1-有 */
|
||||||
|
productStatus: 0 | 1;
|
||||||
|
|
||||||
|
/** 良品标记: 0-不良品, 1-良品 */
|
||||||
|
goodFlag: 0 | 1;
|
||||||
|
|
||||||
|
/** 加工记忆: 0-未开工, 1-已加工 */
|
||||||
|
processMemory: 0 | 1;
|
||||||
|
|
||||||
|
/** 功能SW: 0-无效, 1-有效 */
|
||||||
|
functionSw: 0 | 1;
|
||||||
|
|
||||||
|
/** 轴号 */
|
||||||
|
axisNumber: number;
|
||||||
|
|
||||||
|
/** 上骨架时间: 年, 00~99 */
|
||||||
|
loadSkeletonYear: number;
|
||||||
|
|
||||||
|
/** 上骨架时间: 月日, 0101~1231 */
|
||||||
|
loadSkeletonMonthDay: number;
|
||||||
|
|
||||||
|
/** 上骨架时间: 时分, 0000~2459 */
|
||||||
|
loadSkeletonHourMin: number;
|
||||||
|
|
||||||
|
/** 上骨架时间: 秒, 00~59 */
|
||||||
|
loadSkeletonSecond: number;
|
||||||
|
|
||||||
|
/** 插端子压力值 */
|
||||||
|
plugTerminalPressure: number;
|
||||||
|
|
||||||
|
/** 插端子高度值 */
|
||||||
|
plugTerminalHeight: number;
|
||||||
|
|
||||||
|
/** 电阻值 */
|
||||||
|
resistance: number;
|
||||||
|
|
||||||
|
/** 电感LS值 */
|
||||||
|
inductorLs: number;
|
||||||
|
|
||||||
|
/** 电感Q值 */
|
||||||
|
inductorQ: number;
|
||||||
|
|
||||||
|
/** 耐压R值 */
|
||||||
|
pressureResistanceR: number;
|
||||||
|
|
||||||
|
/** 耐压I值 */
|
||||||
|
pressureResistanceI: number;
|
||||||
|
|
||||||
|
/** 视觉结果: 0-NG, 1-OK */
|
||||||
|
visualResult: 0 | 1;
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
createTime: string; // ISO 8601 格式,如 "2025-09-23T12:34:56"
|
||||||
|
}
|
||||||
69
src/views/Line2/L4-data-list/data.ts
Normal file
69
src/views/Line2/L4-data-list/data.ts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import type { TableColumnType, TableColumnsType } from "ant-design-vue";
|
||||||
|
|
||||||
|
const INDEX_COLUMN: TableColumnType = {
|
||||||
|
key: "index",
|
||||||
|
title: "序号",
|
||||||
|
width: 60,
|
||||||
|
fixed: true,
|
||||||
|
align: "center",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 定义操作列配置
|
||||||
|
const ACTION_COLUMN: TableColumnType = {
|
||||||
|
key: "action",
|
||||||
|
title: "操作",
|
||||||
|
width: 120,
|
||||||
|
ellipsis: true,
|
||||||
|
fixed: "right",
|
||||||
|
align: "center",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 使用 Record 类型确保键值对的安全性
|
||||||
|
export const fields: Record<string, string> = {
|
||||||
|
processInfoId: "加工信息ID",
|
||||||
|
pltNo: "PLT No",
|
||||||
|
processF1: "加工F1",
|
||||||
|
processF2: "加工F2",
|
||||||
|
goodProductF1: "良品F1",
|
||||||
|
goodProductF2: "良品F2",
|
||||||
|
electricalResult: "电气检测结果",
|
||||||
|
engraveResult: "印字检测结果",
|
||||||
|
qrCode: "二维码",
|
||||||
|
qrCodeLevel: "二维码等级",
|
||||||
|
pressure15Riveting: "压力1_5#_铆接",
|
||||||
|
height15Riveting: "高度1_5#_铆接",
|
||||||
|
pressure25Magnet1: "压力2_5#_磁石1",
|
||||||
|
height25Magnet1: "高度2_5#_磁石1",
|
||||||
|
pressure36Magnet2: "压力3_6#_磁石2",
|
||||||
|
height36Magnet2: "高度3_6#_磁石2",
|
||||||
|
torque47AxisInsert: "扭矩4_7#_轴旋入",
|
||||||
|
height47AxisInsert: "高度4_7#_轴旋入",
|
||||||
|
pressure58LowerCase: "压力5_8#_下壳装入",
|
||||||
|
height58LowerCase: "高度5_8#_下壳装入",
|
||||||
|
pressure69UpperCase: "压力6_9#_上壳装入",
|
||||||
|
height69UpperCase: "高度6_9#_上壳装入",
|
||||||
|
height79HeightCheck: "高度7_9#_高度检测",
|
||||||
|
pressure79Laser: "压力7_9#_激光",
|
||||||
|
height89Laser: "高度8_9#_激光",
|
||||||
|
value19DcrUpper: "数値1_9#_DCR(上)",
|
||||||
|
value29DcrLower: "数値2_9#_DCR(下)",
|
||||||
|
value39LcrUpperLs: "数値3_9#_LCR(上)LS",
|
||||||
|
value49LcrLowerQ: "数値4_9#_LCR(下)Q",
|
||||||
|
value59LcrLowerLs: "数値5_9#_LCR(下)LS",
|
||||||
|
value69LcrLowerQ: "数値6_9#_LCR(下)Q",
|
||||||
|
value79IrR: "数値7_9#_IR R",
|
||||||
|
value89IrI: "数値8_9#_IR I",
|
||||||
|
createTime: "创建时间"
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// 导出完整的列配置
|
||||||
|
export const columns: TableColumnsType = [
|
||||||
|
INDEX_COLUMN,
|
||||||
|
...Object.entries(fields).map(([key, title]) => ({
|
||||||
|
key,
|
||||||
|
title,
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true,
|
||||||
|
})),
|
||||||
|
ACTION_COLUMN,
|
||||||
|
];
|
||||||
317
src/views/Line2/L4-data-list/index.vue
Normal file
317
src/views/Line2/L4-data-list/index.vue
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
<template>
|
||||||
|
<div class="l4-data-container">
|
||||||
|
<div class="page-header">
|
||||||
|
<h1 class="page-title">L4数据列表</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 筛选区域 -->
|
||||||
|
<div class="filter-section">
|
||||||
|
<a-form layout="inline" :model="formData">
|
||||||
|
<a-form-item label="日期范围">
|
||||||
|
<a-range-picker v-model:value="formData.dateRange" :placeholder="['开始日期', '结束日期']"
|
||||||
|
format="YYYY-MM-DD HH:mm:ss" show-time />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="handleSearch" :loading="loading">
|
||||||
|
<template #icon>
|
||||||
|
<i-lucide-search />
|
||||||
|
</template>
|
||||||
|
搜索
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="handleReset">
|
||||||
|
<template #icon>
|
||||||
|
<i-lucide-refresh-cw />
|
||||||
|
</template>
|
||||||
|
重置
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据表格 -->
|
||||||
|
<div class="table-section">
|
||||||
|
<a-table :columns="columns" :data-source="tableData" :loading="loading" :pagination="pagination"
|
||||||
|
@change="handleTableChange" row-key="id" size="middle" :scroll="{ x: 1200 }">
|
||||||
|
<template #bodyCell="{ column, record, index }">
|
||||||
|
<template v-if="column.key === 'index'">{{ index + 1 }}</template>
|
||||||
|
<template v-if="column.key === 'createTime'">
|
||||||
|
{{ formatDateTime(record.createTime) }}
|
||||||
|
</template>
|
||||||
|
<!-- <template v-else-if="column.key === 'processF1'">
|
||||||
|
<a-tag :color="record.processF1 === 1 ? 'green' : 'red'">
|
||||||
|
{{ record.processF1 === 1 ? '已加工' : '未加工' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'processF2'">
|
||||||
|
<a-tag :color="record.processF2 === 1 ? 'green' : 'red'">
|
||||||
|
{{ record.processF2 === 1 ? '已加工' : '未加工' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'goodProductF1'">
|
||||||
|
<a-tag :color="record.goodProductF1 === 1 ? 'green' : 'red'">
|
||||||
|
{{ record.goodProductF1 === 1 ? '良品' : '不良品' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'goodProductF2'">
|
||||||
|
<a-tag :color="record.goodProductF2 === 1 ? 'green' : 'red'">
|
||||||
|
{{ record.goodProductF2 === 1 ? '良品' : '不良品' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'electricalResult'">
|
||||||
|
<a-tag :color="getElectricalResultColor(record.electricalResult)">
|
||||||
|
{{ getElectricalResultText(record.electricalResult) }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'engraveResult'">
|
||||||
|
<a-tag :color="record.engraveResult === 0 ? 'green' : 'red'">
|
||||||
|
{{ record.engraveResult === 0 ? '良品' : '不良品' }}
|
||||||
|
</a-tag>
|
||||||
|
</template> -->
|
||||||
|
<template v-else-if="column.key === 'action'">
|
||||||
|
<a-button type="link" size="small" @click="handleView(record as L4Data)">
|
||||||
|
查看详情
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ record[column.key as string] }}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 详情弹窗 -->
|
||||||
|
<a-modal v-model:open="detailModalVisible" title="L4数据详情" width="800px" :footer="null">
|
||||||
|
<div v-if="selectedRecord" class="detail-content">
|
||||||
|
<a-descriptions :column="2" bordered>
|
||||||
|
<a-descriptions-item v-for="(value, key) in selectedRecord" :key="key"
|
||||||
|
:label="columns.find((col) => col.key === key)?.title || key">
|
||||||
|
<template v-if="key === 'createTime'">
|
||||||
|
{{ formatDateTime(value) }}
|
||||||
|
</template>
|
||||||
|
<!-- <template v-else-if="key === 'processF1'">
|
||||||
|
<a-tag :color="value === 1 ? 'green' : 'red'">
|
||||||
|
{{ value === 1 ? '已加工' : '未加工' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'processF2'">
|
||||||
|
<a-tag :color="value === 1 ? 'green' : 'red'">
|
||||||
|
{{ value === 1 ? '已加工' : '未加工' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'goodProductF1'">
|
||||||
|
<a-tag :color="value === 1 ? 'green' : 'red'">
|
||||||
|
{{ value === 1 ? '良品' : '不良品' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'goodProductF2'">
|
||||||
|
<a-tag :color="value === 1 ? 'green' : 'red'">
|
||||||
|
{{ value === 1 ? '良品' : '不良品' }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'electricalResult'">
|
||||||
|
<a-tag :color="getElectricalResultColor(value)">
|
||||||
|
{{ getElectricalResultText(value) }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="key === 'engraveResult'">
|
||||||
|
<a-tag :color="value === 0 ? 'green' : 'red'">
|
||||||
|
{{ value === 0 ? '良品' : '不良品' }}
|
||||||
|
</a-tag>
|
||||||
|
</template> -->
|
||||||
|
<template v-else>
|
||||||
|
{{ value }}
|
||||||
|
</template>
|
||||||
|
</a-descriptions-item>
|
||||||
|
</a-descriptions>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, onMounted } from 'vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { getL4Data } from '@/api/line2/data';
|
||||||
|
import { columns } from './data';
|
||||||
|
import type { QueryParams } from '@/api/line2/data/model';
|
||||||
|
import type { L4Data } from './types';
|
||||||
|
import type { Dayjs } from 'dayjs';
|
||||||
|
|
||||||
|
type DateRangeType = [Dayjs, Dayjs] | undefined;
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const loading = ref(false);
|
||||||
|
const tableData = ref<L4Data[]>([]);
|
||||||
|
const detailModalVisible = ref(false);
|
||||||
|
const selectedRecord = ref<L4Data | null>(null);
|
||||||
|
|
||||||
|
// 筛选参数
|
||||||
|
const formData = reactive<{ dateRange: DateRangeType }>({
|
||||||
|
dateRange: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 分页配置
|
||||||
|
const pagination = reactive({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showTotal: (total: number, range: [number, number]) =>
|
||||||
|
`共 ${total} 条记录,当前显示第 ${range[0]}-${range[1]} 条`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 电气检测结果颜色
|
||||||
|
const getElectricalResultColor = (result: number) => {
|
||||||
|
switch (result) {
|
||||||
|
case 7: return 'green';
|
||||||
|
case 0: return 'red';
|
||||||
|
case 1: return 'orange';
|
||||||
|
case 3: return 'purple';
|
||||||
|
default: return 'default';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 电气检测结果文本
|
||||||
|
const getElectricalResultText = (result: number) => {
|
||||||
|
switch (result) {
|
||||||
|
case 0: return 'DCR不良';
|
||||||
|
case 1: return 'LCR不良';
|
||||||
|
case 3: return 'IR不良';
|
||||||
|
case 7: return '良品';
|
||||||
|
default: return '未知';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取数据
|
||||||
|
const fetchData = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const params: QueryParams = {
|
||||||
|
pageNum: pagination.current,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
orderByColumn: 'id',
|
||||||
|
isAsc: 'desc'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加日期范围筛选
|
||||||
|
if (formData.dateRange && formData.dateRange.length === 2) {
|
||||||
|
params.createTimeBegin = formData.dateRange[0].format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
params.createTimeEnd = formData.dateRange[1].format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await getL4Data(params);
|
||||||
|
|
||||||
|
if (response.code === 200) {
|
||||||
|
tableData.value = response.rows || [];
|
||||||
|
pagination.total = response.total || 0;
|
||||||
|
} else {
|
||||||
|
message.error(response.msg || "获取数据失败");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取L4数据失败:", error);
|
||||||
|
message.error("获取数据失败,请稍后重试");
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
pagination.current = 1;
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置处理
|
||||||
|
const handleReset = () => {
|
||||||
|
formData.dateRange = undefined;
|
||||||
|
pagination.current = 1;
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格变化处理(分页、排序等)
|
||||||
|
const handleTableChange = (paginationInfo: any) => {
|
||||||
|
pagination.current = paginationInfo.current;
|
||||||
|
pagination.pageSize = paginationInfo.pageSize;
|
||||||
|
fetchData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
const handleView = (record: L4Data) => {
|
||||||
|
selectedRecord.value = record;
|
||||||
|
detailModalVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 日期时间格式化
|
||||||
|
const formatDateTime = (dateTime: string | number) => {
|
||||||
|
if (!dateTime) return '-';
|
||||||
|
return new Date(dateTime).toLocaleString('zh-CN', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 组件挂载时获取数据
|
||||||
|
onMounted(() => {
|
||||||
|
fetchData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.l4-data-container {
|
||||||
|
padding: 20px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2937;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-section {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-content {
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-thead > tr > th) {
|
||||||
|
background: #f8fafc;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-tbody > tr:hover > td) {
|
||||||
|
background: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-descriptions-item-label) {
|
||||||
|
font-weight: 600;
|
||||||
|
background: #f8fafc;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
106
src/views/Line2/L4-data-list/types.ts
Normal file
106
src/views/Line2/L4-data-list/types.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
export interface L4Data {
|
||||||
|
/** 加工信息ID */
|
||||||
|
processInfoId: number;
|
||||||
|
|
||||||
|
/** PLT No */
|
||||||
|
pltNo: number;
|
||||||
|
|
||||||
|
/** 加工F1, 0:未加工 */
|
||||||
|
processF1: 0 | 1;
|
||||||
|
|
||||||
|
/** 加工F2, 1:已加工 */
|
||||||
|
processF2: 0 | 1;
|
||||||
|
|
||||||
|
/** 良品F1, 0:不良品 */
|
||||||
|
goodProductF1: 0 | 1;
|
||||||
|
|
||||||
|
/** 良品F2, 1:良品 */
|
||||||
|
goodProductF2: 0 | 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电气检测结果
|
||||||
|
* 0-DCR不良, 1-LCR不良, 3-IR不良, 7-良品
|
||||||
|
*/
|
||||||
|
electricalResult: 0 | 1 | 3 | 7;
|
||||||
|
|
||||||
|
/** 印字检测结果, 0-良品, 1-不良品 */
|
||||||
|
engraveResult: 0 | 1;
|
||||||
|
|
||||||
|
/** 二维码 */
|
||||||
|
qrCode: string;
|
||||||
|
|
||||||
|
/** 二维码等级 */
|
||||||
|
qrCodeLevel: string;
|
||||||
|
|
||||||
|
/** 压力1_5#_铆接 */
|
||||||
|
pressure15Riveting: number;
|
||||||
|
|
||||||
|
/** 高度1_5#_铆接 */
|
||||||
|
height15Riveting: number;
|
||||||
|
|
||||||
|
/** 压力2_5#_磁石1 */
|
||||||
|
pressure25Magnet1: number;
|
||||||
|
|
||||||
|
/** 高度2_5#_磁石1 */
|
||||||
|
height25Magnet1: number;
|
||||||
|
|
||||||
|
/** 压力3_6#_磁石2 */
|
||||||
|
pressure36Magnet2: number;
|
||||||
|
|
||||||
|
/** 高度3_6#_磁石2 */
|
||||||
|
height36Magnet2: number;
|
||||||
|
|
||||||
|
/** 扭矩4_7#_轴旋入 */
|
||||||
|
torque47AxisInsert: number;
|
||||||
|
|
||||||
|
/** 高度4_7#_轴旋入 */
|
||||||
|
height47AxisInsert: number;
|
||||||
|
|
||||||
|
/** 压力5_8#_下壳装入 */
|
||||||
|
pressure58LowerCase: number;
|
||||||
|
|
||||||
|
/** 高度5_8#_下壳装入 */
|
||||||
|
height58LowerCase: number;
|
||||||
|
|
||||||
|
/** 压力6_9#_上壳装入 */
|
||||||
|
pressure69UpperCase: number;
|
||||||
|
|
||||||
|
/** 高度6_9#_上壳装入 */
|
||||||
|
height69UpperCase: number;
|
||||||
|
|
||||||
|
/** 高度7_9#_高度检测 */
|
||||||
|
height79HeightCheck: number;
|
||||||
|
|
||||||
|
/** 压力7_9#_激光 */
|
||||||
|
pressure79Laser: number;
|
||||||
|
|
||||||
|
/** 高度8_9#_激光 */
|
||||||
|
height89Laser: number;
|
||||||
|
|
||||||
|
/** 数値1_9#_DCR(上) */
|
||||||
|
value19DcrUpper: number;
|
||||||
|
|
||||||
|
/** 数値2_9#_DCR(下) */
|
||||||
|
value29DcrLower: number;
|
||||||
|
|
||||||
|
/** 数値3_9#_LCR(上)LS */
|
||||||
|
value39LcrUpperLs: number;
|
||||||
|
|
||||||
|
/** 数値4_9#_LCR(下)Q */
|
||||||
|
value49LcrLowerQ: number;
|
||||||
|
|
||||||
|
/** 数値5_9#_LCR(下)LS */
|
||||||
|
value59LcrLowerLs: number;
|
||||||
|
|
||||||
|
/** 数値6_9#_LCR(下)Q */
|
||||||
|
value69LcrLowerQ: number;
|
||||||
|
|
||||||
|
/** 数値7_9#_IR R */
|
||||||
|
value79IrR: number;
|
||||||
|
|
||||||
|
/** 数値8_9#_IR I */
|
||||||
|
value89IrI: number;
|
||||||
|
|
||||||
|
/** 创建时间 (ISO 8601) */
|
||||||
|
createTime: string;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onBeforeUnmount, reactive, nextTick } from 'vue';
|
import { ref, onMounted, reactive } from 'vue';
|
||||||
import { useRealTime } from '@/utils/dateUtils';
|
import { useRealTime } from '@/utils/dateUtils';
|
||||||
import { checkOrderNumberApi, addProcessInfoApi } from '@/api/detect';
|
import { checkOrderNumberApi, addProcessInfoApi } from '@/api/detect';
|
||||||
import type { Rule } from 'ant-design-vue/es/form';
|
import type { Rule } from 'ant-design-vue/es/form';
|
||||||
@@ -276,13 +276,6 @@ onMounted(() => {
|
|||||||
// 设置当前日期
|
// 设置当前日期
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
currentDate.value = `${now.getFullYear()}年${String(now.getMonth() + 1).padStart(2, '0')}月${String(now.getDate()).padStart(2, '0')}日`;
|
currentDate.value = `${now.getFullYear()}年${String(now.getMonth() + 1).padStart(2, '0')}月${String(now.getDate()).padStart(2, '0')}日`;
|
||||||
|
|
||||||
// SSE连接逻辑已迁移到SseStatus组件中
|
|
||||||
});
|
|
||||||
|
|
||||||
// 清理事件监听
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
// SSE断开连接逻辑已迁移到SseStatus组件中
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -317,7 +310,7 @@ onBeforeUnmount(() => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- LMS 状态 -->
|
<!-- LMS 状态 -->
|
||||||
<LmsStatus />
|
<LmsStatus type="line2" />
|
||||||
</div>
|
</div>
|
||||||
<SettingsModal />
|
<SettingsModal />
|
||||||
<!-- <div class="right-info" @click="showSettings">
|
<!-- <div class="right-info" @click="showSettings">
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import { login, getCaptcha } from '@/api/system'
|
import { getCaptcha } from '@/api/system'
|
||||||
import type { LoginInfo } from '@/api/system/model'
|
import type { LoginInfo } from '@/api/system/model'
|
||||||
import type { Rule } from 'ant-design-vue/es/form';
|
import type { Rule } from 'ant-design-vue/es/form'
|
||||||
import { setToken } from '@/utils/auth';
|
import { useAuthStore } from '@/store'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
|
||||||
const router = useRouter()
|
const authStore = useAuthStore()
|
||||||
|
const { loginLoading } = storeToRefs(authStore)
|
||||||
|
|
||||||
// 表单数据
|
// 表单数据
|
||||||
const formData = reactive<LoginInfo>({
|
const formData = reactive<LoginInfo>({
|
||||||
@@ -19,8 +20,8 @@ const formData = reactive<LoginInfo>({
|
|||||||
|
|
||||||
// 验证码图片
|
// 验证码图片
|
||||||
const captchaImg = ref('')
|
const captchaImg = ref('')
|
||||||
const loading = ref(false)
|
|
||||||
const captchaLoading = ref(false)
|
const captchaLoading = ref(false)
|
||||||
|
const loadCaptchaFail = ref(false)
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
const rules: Record<string, Rule[]> = reactive({
|
const rules: Record<string, Rule[]> = reactive({
|
||||||
@@ -38,8 +39,10 @@ const rules: Record<string, Rule[]> = reactive({
|
|||||||
// 获取验证码
|
// 获取验证码
|
||||||
const refreshCaptcha = async () => {
|
const refreshCaptcha = async () => {
|
||||||
try {
|
try {
|
||||||
|
captchaImg.value = ''
|
||||||
captchaLoading.value = true
|
captchaLoading.value = true
|
||||||
await getCaptcha().then((res: any) => {
|
await getCaptcha().then((res: any) => {
|
||||||
|
loadCaptchaFail.value = false;
|
||||||
if (res.captchaOnOff) {
|
if (res.captchaOnOff) {
|
||||||
captchaImg.value = "data:image/gif;base64," + res.img
|
captchaImg.value = "data:image/gif;base64," + res.img
|
||||||
rules.code[0].required = true;
|
rules.code[0].required = true;
|
||||||
@@ -49,7 +52,8 @@ const refreshCaptcha = async () => {
|
|||||||
formData.uuid = res.uuid
|
formData.uuid = res.uuid
|
||||||
formData.code = '' // 清空验证码输入
|
formData.code = '' // 清空验证码输入
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
|
loadCaptchaFail.value = true;
|
||||||
message.error('获取验证码失败')
|
message.error('获取验证码失败')
|
||||||
console.error('获取验证码失败:', error)
|
console.error('获取验证码失败:', error)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -60,27 +64,10 @@ const refreshCaptcha = async () => {
|
|||||||
// 登录处理
|
// 登录处理
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
try {
|
try {
|
||||||
loading.value = true
|
await authStore.authLogin(formData);
|
||||||
await login(formData).then(async (res: any) => {
|
|
||||||
if (res.code === 200) {
|
|
||||||
message.success('登录成功')
|
|
||||||
setToken(res.token)
|
|
||||||
// 可以在这里保存用户信息到store
|
|
||||||
// 跳转到主页
|
|
||||||
router.push('/lms')
|
|
||||||
} else {
|
|
||||||
message.error(res.msg || '登录失败')
|
|
||||||
// 登录失败后重新获取验证码
|
|
||||||
await refreshCaptcha()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(error.message || error.msg || '登录失败,请检查网络连接')
|
message.error(error.message || '登录失败');
|
||||||
console.error('登录失败:', error)
|
await refreshCaptcha();
|
||||||
// 登录失败后重新获取验证码
|
|
||||||
await refreshCaptcha()
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,9 +145,12 @@ refreshCaptcha()
|
|||||||
alt="验证码"
|
alt="验证码"
|
||||||
class="captcha-image"
|
class="captcha-image"
|
||||||
/>
|
/>
|
||||||
<div v-else class="captcha-loading">
|
<div v-else-if="captchaLoading" class="captcha-loading">
|
||||||
<i-lucide-loader class="loading-icon" />
|
<i-lucide-loader class="loading-icon" />
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="!captchaLoading && loadCaptchaFail" class="captcha-loading">
|
||||||
|
获取失败
|
||||||
|
</div>
|
||||||
<div class="captcha-refresh-hint">
|
<div class="captcha-refresh-hint">
|
||||||
<i-lucide-refresh-cw class="refresh-icon" />
|
<i-lucide-refresh-cw class="refresh-icon" />
|
||||||
点击刷新
|
点击刷新
|
||||||
@@ -175,11 +165,11 @@ refreshCaptcha()
|
|||||||
type="primary"
|
type="primary"
|
||||||
html-type="submit"
|
html-type="submit"
|
||||||
size="large"
|
size="large"
|
||||||
:loading="loading"
|
:loading="loginLoading"
|
||||||
class="login-button"
|
class="login-button"
|
||||||
block
|
block
|
||||||
>
|
>
|
||||||
{{ loading ? '登录中...' : '登录' }}
|
{{ loginLoading ? '登录中...' : '登录' }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|||||||
Reference in New Issue
Block a user