完善类型配置,新增L1, L4数据展示界面
This commit is contained in:
		@@ -6,4 +6,5 @@
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import zhCN from 'ant-design-vue/es/locale/zh_CN';
 | 
			
		||||
import 'dayjs/locale/zh-cn';
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										7
									
								
								src/api/common/model.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/api/common/model.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
export interface ApiResponse<T = any> {
 | 
			
		||||
  code?: number;
 | 
			
		||||
  msg?: string;
 | 
			
		||||
  data?: T;
 | 
			
		||||
  rows?: T[];
 | 
			
		||||
  total?: number;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								src/api/data/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/api/data/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
import request from '../request';
 | 
			
		||||
import type { QueryParams } from './model';
 | 
			
		||||
 | 
			
		||||
// 获取 L1 数据
 | 
			
		||||
export function getL1Data(params: QueryParams) {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: '/jinghua/l1Data/list',
 | 
			
		||||
    method: 'get',
 | 
			
		||||
    params
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 获取 L4 数据
 | 
			
		||||
export function getL4Data(params: QueryParams) {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: '/jinghua/l4Data/list',
 | 
			
		||||
    method: 'get',
 | 
			
		||||
    params
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								src/api/data/model.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/api/data/model.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
export interface QueryParams {
 | 
			
		||||
  pageNum?: number;
 | 
			
		||||
  pageSize?: number;
 | 
			
		||||
  orderByColumn?: string;
 | 
			
		||||
  isAsc?: boolean;
 | 
			
		||||
  qrCode?: string;
 | 
			
		||||
  createTimeBegin?: string;
 | 
			
		||||
  createTimeEnd?: string;
 | 
			
		||||
}
 | 
			
		||||
@@ -4,7 +4,7 @@ import type { LmsWorkMode } from './model';
 | 
			
		||||
// 获取 LMS 工作模式
 | 
			
		||||
export const fetchLmsWorkMode = () => {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: '/jinghua/mes/work-mode',
 | 
			
		||||
    url: '/jinghua/work-mode',
 | 
			
		||||
    method: 'get',
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
@@ -12,7 +12,7 @@ export const fetchLmsWorkMode = () => {
 | 
			
		||||
// 更新 LMS 工作模式
 | 
			
		||||
export const updateLmsWorkMode = (workMode: LmsWorkMode) => {
 | 
			
		||||
  return request({
 | 
			
		||||
    url: `/jinghua/mes/work-mode/${workMode}`,
 | 
			
		||||
    url: `/jinghua/work-mode/${workMode}`,
 | 
			
		||||
    method: 'put',
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import { Modal, notification } from 'ant-design-vue';
 | 
			
		||||
import router from '@/router';
 | 
			
		||||
import { getToken } from '@/utils/auth';
 | 
			
		||||
import { Modal, notification } from 'ant-design-vue';
 | 
			
		||||
import type { AxiosRequestConfig } from "axios";
 | 
			
		||||
import type { ApiResponse } from "@/api/common/model";
 | 
			
		||||
 | 
			
		||||
const errCodeMap: { [key: string]: string } = {
 | 
			
		||||
  '403': '当前操作没有权限',
 | 
			
		||||
@@ -12,7 +14,7 @@ const errCodeMap: { [key: string]: string } = {
 | 
			
		||||
// 创建axios实例
 | 
			
		||||
const service = axios.create({
 | 
			
		||||
  baseURL: import.meta.env.VITE_APP_BASE_API as string,
 | 
			
		||||
  timeout: 10000
 | 
			
		||||
  timeout: 10000,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 请求拦截器
 | 
			
		||||
@@ -36,37 +38,46 @@ service.interceptors.request.use(
 | 
			
		||||
service.interceptors.response.use(
 | 
			
		||||
  response => {
 | 
			
		||||
    console.log(response)
 | 
			
		||||
    // 未设置状态码则默认成功状态
 | 
			
		||||
    const code = response.data.code || 200;
 | 
			
		||||
    const data = response.data;
 | 
			
		||||
 | 
			
		||||
    if (code === 200) {
 | 
			
		||||
      return response.data ?? response;
 | 
			
		||||
    } else if (code === 401) {
 | 
			
		||||
      Modal.error({
 | 
			
		||||
        title: '系统提示',
 | 
			
		||||
        content: '登录状态已过期,请重新登录',
 | 
			
		||||
        onOk: () => {
 | 
			
		||||
          router.push('/login')
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    } else {
 | 
			
		||||
      const codeStr = String(code);
 | 
			
		||||
      const errMsg = errCodeMap[codeStr] || response.data.msg || errCodeMap['default'];
 | 
			
		||||
      notification.error({
 | 
			
		||||
        message: '请求错误',
 | 
			
		||||
        description: errMsg,
 | 
			
		||||
      });
 | 
			
		||||
      return Promise.reject(response.data);
 | 
			
		||||
    switch (code) {
 | 
			
		||||
      case 200:
 | 
			
		||||
        return data ?? response;
 | 
			
		||||
      case 401:
 | 
			
		||||
        Modal.error({
 | 
			
		||||
          title: '系统提示',
 | 
			
		||||
          content: '登录状态已过期,请重新登录',
 | 
			
		||||
          onOk: () => {
 | 
			
		||||
            router.push('/login')
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
        return Promise.reject(data);
 | 
			
		||||
      default:
 | 
			
		||||
        const errMsg = errCodeMap[code] || data.msg || errCodeMap['default'];
 | 
			
		||||
        notification.error({
 | 
			
		||||
          message: '请求错误',
 | 
			
		||||
          description: errMsg,
 | 
			
		||||
        });
 | 
			
		||||
        return Promise.reject(data);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  error => {
 | 
			
		||||
    error.message = error.code === "ECONNABORTED" ? '请求超时,请稍后重试' : error.message;
 | 
			
		||||
 | 
			
		||||
    // 网络/服务器错误统一处理
 | 
			
		||||
    notification.error({
 | 
			
		||||
      message: '网络错误',
 | 
			
		||||
      description: error.message || '请求失败',
 | 
			
		||||
      message: "网络错误",
 | 
			
		||||
      description: error.message,
 | 
			
		||||
    });
 | 
			
		||||
    return Promise.reject(error);
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export default service;
 | 
			
		||||
// 类型检查
 | 
			
		||||
function request<T = any>(config: AxiosRequestConfig): Promise<ApiResponse<T>> {
 | 
			
		||||
  return service(config) as unknown as Promise<ApiResponse<T>>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default request;
 | 
			
		||||
// export default service;
 | 
			
		||||
@@ -1,153 +1,9 @@
 | 
			
		||||
@use './variables' as *;
 | 
			
		||||
* {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
	background-color: #000;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-row {
 | 
			
		||||
  height: 5vh;
 | 
			
		||||
  min-height: 5vh;
 | 
			
		||||
  
 | 
			
		||||
  &.title {
 | 
			
		||||
    height: 6vh;
 | 
			
		||||
    min-height: 6vh;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
	.title {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    font-size: $title-font-size;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.logList-row {
 | 
			
		||||
  flex: 1 1 auto;  // 修改
 | 
			
		||||
  min-height: 0;   // 新增
 | 
			
		||||
  
 | 
			
		||||
  .logList-col {
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .logList {
 | 
			
		||||
    overflow-y: auto;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.ant-col {
 | 
			
		||||
  border-right: 2px solid #fff;
 | 
			
		||||
  border-bottom: 2px solid #fff;
 | 
			
		||||
  font-size: $content-font-size;
 | 
			
		||||
  
 | 
			
		||||
  &.option {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    padding: 5px 3px 3px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &.subtitle,
 | 
			
		||||
  &.text,
 | 
			
		||||
  &.label {
 | 
			
		||||
  	text-align: center;
 | 
			
		||||
    padding: 0 1rem;
 | 
			
		||||
    line-height: 5vh;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &.logList-col {
 | 
			
		||||
    padding: 2px 2px 0 2px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ant-btn,
 | 
			
		||||
.ant-btn.ant-btn-sm {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
  background-color: #d6d6d6;
 | 
			
		||||
  color: #000;
 | 
			
		||||
  font-size: $content-font-size;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  &:hover {
 | 
			
		||||
    border: 1px solid #000;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    background-color: #000;
 | 
			
		||||
    font-size: 1vw;
 | 
			
		||||
  }
 | 
			
		||||
  &:active {
 | 
			
		||||
    transform: scale(.9);
 | 
			
		||||
    transition: 100ms;
 | 
			
		||||
    background-color: #252525;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 隐藏空列表
 | 
			
		||||
:deep(.ant-list-empty-text) {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 列表
 | 
			
		||||
.ant-list {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding-right: 0 !important;
 | 
			
		||||
 | 
			
		||||
  .ant-list-item {
 | 
			
		||||
    padding: 4px 12px;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    font-size: $log-font-size;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 下拉框
 | 
			
		||||
.ant-select {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  display: block;
 | 
			
		||||
  margin-top: 1px;
 | 
			
		||||
  
 | 
			
		||||
  :deep(.ant-select-selector) {
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    border: none;
 | 
			
		||||
    border-radius: 0;
 | 
			
		||||
    background-color: unset;
 | 
			
		||||
  }
 | 
			
		||||
  :deep(.ant-select-selection-search-input) {
 | 
			
		||||
    height: 100% !important;
 | 
			
		||||
  }
 | 
			
		||||
  :deep(.ant-select-selection-item) {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    font-size: $content-font-size;
 | 
			
		||||
    color: #adff2f;
 | 
			
		||||
  }
 | 
			
		||||
  :deep(.ant-select-selection-placeholder) {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    font-size: $content-font-size;
 | 
			
		||||
    color: #888;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  :deep(.ant-select-suffix svg) {
 | 
			
		||||
    width: 1.5em;
 | 
			
		||||
    height: 1.5em;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
  }
 | 
			
		||||
// 解决外部图标无法居中问题
 | 
			
		||||
.ant-btn:has(svg) {
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  gap: 4px;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,2 +1,3 @@
 | 
			
		||||
@forward './base';
 | 
			
		||||
@forward './variables';
 | 
			
		||||
@forward './variables';
 | 
			
		||||
@forward './ant-design';
 | 
			
		||||
@@ -41,7 +41,7 @@ defineExpose({
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@import '@/assets/styles/_variables.scss';
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.status-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										161
									
								
								src/components/LmsStatus/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								src/components/LmsStatus/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <!-- Status Item -->
 | 
			
		||||
  <div class="status-item status-button" @click="show">
 | 
			
		||||
    <i-lucide-zap class="status-icon" />
 | 
			
		||||
    <span class="status-label">LMS 状态:</span>
 | 
			
		||||
    <span class="status-value" :class="onlineStatusClass">{{ lmsStatus }}</span>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <a-modal v-model:open="dialogVisible" :title="modalTitle" :footer="null">
 | 
			
		||||
    <a-row :gutter="[0, 12]">
 | 
			
		||||
      <a-col :span="8" class="modal-label">LMS 状态</a-col>
 | 
			
		||||
      <a-col :span="16" class="modal-value">
 | 
			
		||||
        <a-switch v-model:checked="isOnline" checked-children="在线" un-checked-children="离线" @change="handleToggleOnline" />
 | 
			
		||||
      </a-col>
 | 
			
		||||
    </a-row>
 | 
			
		||||
    <a-row :gutter="[0, 12]">
 | 
			
		||||
      <template v-for="(item, index) in modalItems" :key="index">
 | 
			
		||||
        <a-col :span="8" class="modal-label">{{ item.label }}</a-col>
 | 
			
		||||
        <a-col :span="16" class="modal-value">{{ item.value }}</a-col>
 | 
			
		||||
      </template>
 | 
			
		||||
    </a-row>
 | 
			
		||||
    <div class="actions">
 | 
			
		||||
      <a-button size="large" @click="redirectTo('L1')">L1 数据</a-button>
 | 
			
		||||
      <a-button size="large" @click="redirectTo('L4')">L4 数据</a-button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </a-modal>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, onMounted, computed } from 'vue';
 | 
			
		||||
import { useRouter } from 'vue-router';
 | 
			
		||||
import { useDialog } from '@/utils/useDialog';
 | 
			
		||||
import { fetchLmsWorkMode, updateLmsWorkMode } from '@/api/lms';
 | 
			
		||||
import { message } from 'ant-design-vue';
 | 
			
		||||
 | 
			
		||||
// useDialog管理弹窗状态
 | 
			
		||||
const { visible: dialogVisible, show, hide } = useDialog();
 | 
			
		||||
 | 
			
		||||
const isOnline = ref(false);
 | 
			
		||||
const lmsStatus = computed(() => isOnline.value ? '在线' : '离线');
 | 
			
		||||
 | 
			
		||||
const onlineStatusClass = computed(() => {
 | 
			
		||||
  return isOnline.value ? 'success' : 'error';
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 当请求发送成功后才切换状态
 | 
			
		||||
async function handleToggleOnline(checked: boolean | string | number) {
 | 
			
		||||
  await updateLmsWorkMode(checked ? 1 : 0).then(() => {
 | 
			
		||||
    isOnline.value = Boolean(checked);
 | 
			
		||||
    message.success('切换成功');
 | 
			
		||||
  }).catch((error) => {
 | 
			
		||||
    message.error('切换失败');
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const modalTitle = ref('LMS 状态');
 | 
			
		||||
const modalItems = ref<{ label: string; value: string }[]>([]);
 | 
			
		||||
 | 
			
		||||
// 初始化 LMS 状态
 | 
			
		||||
async function initLmsStatus() {
 | 
			
		||||
  try {
 | 
			
		||||
    const { msg } = await fetchLmsWorkMode();
 | 
			
		||||
    isOnline.value = msg === "1";
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('获取 LMS 工作模式失败:', error);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
function redirectTo(type: string) {
 | 
			
		||||
  router.push(`/${type}-data`);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 初始化 LMS 状态
 | 
			
		||||
onMounted(initLmsStatus);
 | 
			
		||||
 | 
			
		||||
// 暴露方法
 | 
			
		||||
defineExpose({
 | 
			
		||||
  show,
 | 
			
		||||
  hide
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.status-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  gap: 8px;
 | 
			
		||||
  padding: 8px 12px;
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
  transition: all 0.2s ease;
 | 
			
		||||
  
 | 
			
		||||
  &.status-button {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    
 | 
			
		||||
    &:hover {
 | 
			
		||||
      background-color: rgba(255, 255, 255, 0.1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .status-icon {
 | 
			
		||||
    width: 16px;
 | 
			
		||||
    height: 16px;
 | 
			
		||||
    color: #8395B6;
 | 
			
		||||
    
 | 
			
		||||
    &.success {
 | 
			
		||||
      color: $success-color;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    &.error {
 | 
			
		||||
      color: $error-color;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    &.warning {
 | 
			
		||||
      color: $warning-color;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .status-label {
 | 
			
		||||
    font-size: 13px;
 | 
			
		||||
    color: #8395B6;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  .status-value {
 | 
			
		||||
    font-size: 13px;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
    
 | 
			
		||||
    &.success {
 | 
			
		||||
      color: $success-color;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    &.error {
 | 
			
		||||
      color: $error-color;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    &.warning {
 | 
			
		||||
      color: $warning-color;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.modal-label {
 | 
			
		||||
  font-size: $text-size;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.actions {
 | 
			
		||||
  margin: 20px 0 10px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 10px;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
 | 
			
		||||
  .ant-btn {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -42,7 +42,7 @@ defineExpose({
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@import '@/assets/styles/_variables.scss';
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.status-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ defineExpose({
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@import '@/assets/styles/_variables.scss';
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.status-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ defineExpose({
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@import '@/assets/styles/_variables.scss';
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.status-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ defineExpose({
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@import '@/assets/styles/_variables.scss';
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.modal-label {
 | 
			
		||||
  font-size: $text-size;
 | 
			
		||||
 
 | 
			
		||||
@@ -27,10 +27,6 @@
 | 
			
		||||
        <i-lucide-trash-2 />
 | 
			
		||||
        清空日志
 | 
			
		||||
      </a-button>
 | 
			
		||||
      <a-button @click="test" class="clear-btn">
 | 
			
		||||
        <i-lucide-trash-2 />
 | 
			
		||||
        测试
 | 
			
		||||
      </a-button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="sse-logs" ref="logContainer">      
 | 
			
		||||
@@ -81,16 +77,14 @@ let cooldownTimer: number | null = null;
 | 
			
		||||
 | 
			
		||||
// 内部日志管理
 | 
			
		||||
const logContainer = ref();
 | 
			
		||||
function test() {
 | 
			
		||||
  addSseLog('测试日志');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 使用SSE工具函数
 | 
			
		||||
const {
 | 
			
		||||
  clientId,
 | 
			
		||||
  serverUrl,
 | 
			
		||||
  isConnected,
 | 
			
		||||
  isConnecting,
 | 
			
		||||
  sseStatusText,
 | 
			
		||||
  sseStatus,
 | 
			
		||||
  sseStatusClass,
 | 
			
		||||
  logs,
 | 
			
		||||
  connect,
 | 
			
		||||
@@ -127,12 +121,11 @@ const {
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const sseStatus = ref(sseStatusText.value);
 | 
			
		||||
const modalTitle = ref('SSE 连接状态');
 | 
			
		||||
const modalItems = ref([
 | 
			
		||||
  { label: '当前状态', value: sseStatus.value },
 | 
			
		||||
  { label: '当前状态', value: sseStatus },
 | 
			
		||||
  { label: '客户端ID', value: clientId || 'hmi-main-client' },
 | 
			
		||||
  { label: '服务器地址', value: serverUrl.value }
 | 
			
		||||
  { label: '服务器地址', value: serverUrl }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
// 启动连接冷却时间
 | 
			
		||||
@@ -175,13 +168,15 @@ const handleClearSseLogs = () => {
 | 
			
		||||
 | 
			
		||||
// 监听日志变化,自动滚动
 | 
			
		||||
watch(() => logs.value.length, () => {
 | 
			
		||||
  const { scrollTop = 0, scrollHeight = 0, clientHeight = 0 } = logContainer.value;
 | 
			
		||||
  const isUserAtBottom = scrollTop + clientHeight >= scrollHeight - 10;
 | 
			
		||||
  nextTick(() => {
 | 
			
		||||
    if (logContainer.value && isUserAtBottom) {
 | 
			
		||||
      logContainer.value.scrollTop = logContainer.value.scrollHeight;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  if (logContainer.value) {
 | 
			
		||||
    const { scrollTop = 0, scrollHeight = 0, clientHeight = 0 } = logContainer.value;
 | 
			
		||||
    const isUserAtBottom = scrollTop + clientHeight >= scrollHeight - 10;
 | 
			
		||||
    nextTick(() => {
 | 
			
		||||
      if (logContainer.value && isUserAtBottom) {
 | 
			
		||||
        logContainer.value.scrollTop = logContainer.value.scrollHeight;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 暴露方法和数据
 | 
			
		||||
@@ -207,7 +202,7 @@ onBeforeUnmount(() => {
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@import '@/assets/styles/_variables.scss';
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.status-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
	"id": "主键",
 | 
			
		||||
	"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": "创建时间"
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
import { createApp } from "vue";
 | 
			
		||||
// import Antd from "ant-design-vue";
 | 
			
		||||
import App from "./App.vue";
 | 
			
		||||
 | 
			
		||||
// Pinia 状态管理
 | 
			
		||||
@@ -11,7 +10,7 @@ import router from "./router";
 | 
			
		||||
 | 
			
		||||
// 样式文件
 | 
			
		||||
import "ant-design-vue/dist/reset.css";
 | 
			
		||||
import "./assets/styles/index.scss";
 | 
			
		||||
import "@/assets/styles/index.scss";
 | 
			
		||||
 | 
			
		||||
const app = createApp(App);
 | 
			
		||||
app.use(pinia).use(router).mount("#app");
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,16 @@ const routes = [
 | 
			
		||||
		path: '/package-station',
 | 
			
		||||
		name: 'PackageStation',
 | 
			
		||||
		component: () => import('@/views/package-station/index.vue')
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		path: '/L1-data',
 | 
			
		||||
		name: 'L1Data',
 | 
			
		||||
		component: () => import('@/views/L1-data-list/index.vue')
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		path: '/L4-data',
 | 
			
		||||
		name: 'L4Data',
 | 
			
		||||
		component: () => import('@/views/L4-data-list/index.vue')
 | 
			
		||||
	}
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								src/shim-vue.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/shim-vue.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
declare module "*.vue" {
 | 
			
		||||
  import type { DefineComponent } from "vue";
 | 
			
		||||
  const component: DefineComponent<{}, {}, any>;
 | 
			
		||||
  export default component;
 | 
			
		||||
}
 | 
			
		||||
@@ -3,7 +3,8 @@ import { EventSourcePolyfill } from 'event-source-polyfill';
 | 
			
		||||
import { generateUUID } from './uuidUtils';
 | 
			
		||||
import { getToken } from '@/utils/auth';
 | 
			
		||||
 | 
			
		||||
const defaultServerUrl = 'http://192.168.1.38:18081/sse';
 | 
			
		||||
// const defaultServerUrl = 'http://192.168.1.38:18081/sse';
 | 
			
		||||
const defaultServerUrl = 'http://127.0.0.1:18081/sse';
 | 
			
		||||
 | 
			
		||||
interface EventData {
 | 
			
		||||
  timestamp: string;
 | 
			
		||||
@@ -66,7 +67,7 @@ export function useSSE(options: SSEOptions) {
 | 
			
		||||
  let connectionTimeout: number | null = null;
 | 
			
		||||
  
 | 
			
		||||
  // 计算属性
 | 
			
		||||
  const sseStatusText = computed(() => {
 | 
			
		||||
  const sseStatus = computed(() => {
 | 
			
		||||
    if (isConnecting.value) return '连接中';
 | 
			
		||||
    if (isConnected.value) return '已连接';
 | 
			
		||||
    return '未连接';
 | 
			
		||||
@@ -234,7 +235,7 @@ export function useSSE(options: SSEOptions) {
 | 
			
		||||
    isConnected,
 | 
			
		||||
    clientId,
 | 
			
		||||
    serverUrl,
 | 
			
		||||
    sseStatusText,
 | 
			
		||||
    sseStatus,
 | 
			
		||||
    sseStatusClass,
 | 
			
		||||
    connect,
 | 
			
		||||
    disconnect,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								src/views/L1-data-list/data.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/views/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,
 | 
			
		||||
];
 | 
			
		||||
@@ -0,0 +1,347 @@
 | 
			
		||||
<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" class="date-range-picker" 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-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 } from "@/api/data";
 | 
			
		||||
import type { QueryParams } from "@/api/data/model";
 | 
			
		||||
import type { L1Data } from "./types";
 | 
			
		||||
import type { Dayjs } from "dayjs";
 | 
			
		||||
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 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">
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.wrapper {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l1-data-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  padding: $spacing-lg;
 | 
			
		||||
 | 
			
		||||
  .page-header {
 | 
			
		||||
    margin-bottom: $spacing-lg;
 | 
			
		||||
    flex-shrink: 0;
 | 
			
		||||
 | 
			
		||||
    .page-title {
 | 
			
		||||
      font-size: $title-font-size;
 | 
			
		||||
      color: $text-dark;
 | 
			
		||||
      margin: 0;
 | 
			
		||||
      font-weight: 600;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .filter-section {
 | 
			
		||||
    background: $bg-light;
 | 
			
		||||
    padding: $spacing-lg;
 | 
			
		||||
    border-radius: $border-radius-lg;
 | 
			
		||||
    margin-bottom: $spacing-lg;
 | 
			
		||||
    flex-shrink: 0;
 | 
			
		||||
 | 
			
		||||
    .filter-label {
 | 
			
		||||
      font-weight: 500;
 | 
			
		||||
      color: $text-dark;
 | 
			
		||||
      font-size: $content-font-size;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .table-section {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
 | 
			
		||||
    :deep(.ant-table-wrapper) {
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
 | 
			
		||||
      .ant-spin-container,
 | 
			
		||||
      .ant-table {
 | 
			
		||||
        flex-grow: 1;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .ant-table-container {
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .ant-table-body {
 | 
			
		||||
        overflow-y: auto !important;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .detail-content {
 | 
			
		||||
    .ant-descriptions {
 | 
			
		||||
      margin-top: $spacing-md;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:deep(.ant-btn-primary) {
 | 
			
		||||
  background: $primary-color;
 | 
			
		||||
  border-color: $primary-color;
 | 
			
		||||
 | 
			
		||||
  &:hover {
 | 
			
		||||
    background: $primary-light;
 | 
			
		||||
    border-color: $primary-light;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 768px) {
 | 
			
		||||
  .l1-data-container {
 | 
			
		||||
    padding: $spacing-md;
 | 
			
		||||
 | 
			
		||||
    .filter-section {
 | 
			
		||||
      .ant-row {
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        gap: $spacing-md;
 | 
			
		||||
 | 
			
		||||
        .ant-col {
 | 
			
		||||
          width: 100% !important;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .date-range-picker {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								src/views/L1-data-list/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/views/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/L4-data-list/data.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/views/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,
 | 
			
		||||
];
 | 
			
		||||
@@ -0,0 +1,336 @@
 | 
			
		||||
<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"
 | 
			
		||||
            class="date-range-picker"
 | 
			
		||||
            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 }">
 | 
			
		||||
          <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>
 | 
			
		||||
      </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, computed, onMounted } from 'vue';
 | 
			
		||||
import { message } from 'ant-design-vue';
 | 
			
		||||
import { getL4Data } from '@/api/data';
 | 
			
		||||
import { columns } from './data';
 | 
			
		||||
import type { QueryParams } from '@/api/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,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // 添加日期范围筛选
 | 
			
		||||
    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>
 | 
			
		||||
.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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.date-range-picker {
 | 
			
		||||
  width: 300px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.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/L4-data-list/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/views/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;
 | 
			
		||||
}
 | 
			
		||||
@@ -3,6 +3,7 @@ import { ref, onMounted, onBeforeUnmount, reactive, nextTick } from 'vue';
 | 
			
		||||
import { useRealTime } from '@/utils/dateUtils';
 | 
			
		||||
import { checkOrderNumberApi, addProcessInfoApi } from '@/api/detect';
 | 
			
		||||
import type { Rule } from 'ant-design-vue/es/form';
 | 
			
		||||
import { message } from 'ant-design-vue';
 | 
			
		||||
 | 
			
		||||
// 检测设备表单规则
 | 
			
		||||
const rules: Record<string, Rule[]> = {
 | 
			
		||||
@@ -44,23 +45,9 @@ const detectFormRef = ref();
 | 
			
		||||
const packageFormRef = ref();
 | 
			
		||||
 | 
			
		||||
// 执行结果日志
 | 
			
		||||
const executionLogs = ref([
 | 
			
		||||
  '14:25:32 - 开始检测流程 SN-A538-09-2023-00018',
 | 
			
		||||
  '14:25:33 - 读取产品参数完成',
 | 
			
		||||
  '14:25:36 - 尺寸检测: 通过 (0.15mm)',
 | 
			
		||||
  '14:25:36 - 电压检测: 通过 (3.25V)',
 | 
			
		||||
  '14:25:37 - 精度检测: 通过 (98.7%)',
 | 
			
		||||
  '14:25:38 - 检测结果: 合格'
 | 
			
		||||
]);
 | 
			
		||||
const executionLogs = ref<string[]>([]);
 | 
			
		||||
 | 
			
		||||
const packageLogs = ref([
 | 
			
		||||
  '14:25:45 - 包装流程: SN-A538-09-2023-00018',
 | 
			
		||||
  '14:25:46 - 读取产品标签完成',
 | 
			
		||||
  '14:25:49 - 包装材料准备完成',
 | 
			
		||||
  '14:25:52 - 产品包装完成',
 | 
			
		||||
  '14:25:53 - 更新库存: 已包装 (18/25)',
 | 
			
		||||
  '14:25:54 - 包装结果: 正常'
 | 
			
		||||
]);
 | 
			
		||||
const packageLogs = ref<string[]>([]);
 | 
			
		||||
 | 
			
		||||
// 滚动到检测设备日志底部的函数
 | 
			
		||||
const scrollToExecutionBottom = () => {
 | 
			
		||||
@@ -262,6 +249,7 @@ const saveDetectingEdit = () => {
 | 
			
		||||
      fixtureCode: detectForm.fixtureCode
 | 
			
		||||
    }).then(res => {
 | 
			
		||||
      console.log(res)
 | 
			
		||||
      message.success('保存成功');
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    console.log('检测设备表单验证失败');
 | 
			
		||||
@@ -350,6 +338,9 @@ onBeforeUnmount(() => {
 | 
			
		||||
          :on-mes-event="handleMESEvent"
 | 
			
		||||
          :on-sse-message="handleSseMessage"
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
        <!-- LMS 状态 -->
 | 
			
		||||
        <LmsStatus />
 | 
			
		||||
      </div>
 | 
			
		||||
      <SettingsModal />
 | 
			
		||||
      <!-- <div class="right-info" @click="showSettings">
 | 
			
		||||
@@ -569,7 +560,7 @@ onBeforeUnmount(() => {
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
@import '@/assets/styles/_variables.scss';
 | 
			
		||||
@use "@/assets/styles/variables" as *;
 | 
			
		||||
 | 
			
		||||
.hmi-container {
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user