{this.state.text.split(' ').map((word) => word && '

本文深入探讨了React Native中使用&&操作符进行条件渲染的原理,解析了一段具体代码实现,展示了如何根据文本内容动态展示问号,以及&&在React Native中的独特用法,类似于Java中的三元运算符。

看了一遍官网,没理解什么意思,遂百度:终于知道&&和oc 里的&&不是一回事啊!

import React, { Component } from 'react';
import { AppRegistry, Text, TextInput, View } from 'react-native';

class PizzaTranslator extends Component { 
  constructor(props) { 
    super(props); 
    this.state = {text:''}; 
  } 
  render() { 
    return ( 
      <View style={{padding: 10}}> 
        <TextInput 
          style={{height: 40}} 
          placeholder="Type here to translate!" 
          onChangeText={(text) => this.setState({text})} 
        /> 
        <Text style={{padding: 10, fontSize: 42}}> 
          {this.state.text.split(' ').map((word) => word && '?').join(' ')} 
        </Text> 
      </View> 
    ); 
  }
}
// 注册应用(registerComponent)后才能正确渲染
// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册AppRegistry.registerComponent('PizzaTranslator', () => PizzaTranslator);

关于{this.state.text.split(' ').map((word) => word && '?').join(' ')}这段代码,具体可以理解为,text文本先根据空格分隔成数组,再通过map方法遍历,其中map((word)=>部分,word是遍历数组的item,=>代表匿名函数,&&则表示符号前的值不为空时,返回&&后的值,可以类似理解为java中的三元运算符相似的概念

<template> <view class="container"> <!-- 背景视频 --> <!-- 双视频缓冲区 --> <video v-if="videoBuffers[0]" v-show="currentVideoIndex === 0" :src="videoBuffers[0]" autoplay loop muted class="background-video" :class="{ 'video-active': currentVideoIndex === 0 }" @loadeddata="onVideoLoaded(0)" ref="video0" /> <video v-if="videoBuffers[1]" v-show="currentVideoIndex === 1" :src="videoBuffers[1]" autoplay loop muted class="background-video" :class="{ 'video-active': currentVideoIndex === 1 }" @loadeddata="onVideoLoaded(1)" ref="video1" /> <!-- 回显数据展示区域 --> <view class="message-container"> <view v-for="(message, index) in messages" :key="index" :class="{ 'user-css': message.isUser }" class="message-item"> <text class="message-text" :class="{ 'user-message': message.isUser }">{{ message.text }}</text> </view> </view> <!-- 底部操作栏 --> <view class="bottom-bar"> <view class="bottom-input"> <!-- 文本输入框 --> <input type="text" v-model="inputText" placeholder="说任何东西..." class="input-box" /> <!-- 发送按钮 --> <button @click="sendText" class="send-btn"> <text class="send-text">→</text> </button> </view> <!-- 录音按钮 --> <image :src="isRecording ? '/static/removeRm.png' : '/static/starRm.png'" mode="" @click="toggleRecording" class="record-btn"></image> </view> <!-- 指示器 --> <view v-if="isRecording" class="recording-indicator"> <view class="recording-circle"></view> </view> </view> </template> <script> import { Recorder } from 'opus-recorder'; export default { data() { return { isRecording: false, audioChunks: [], recorder: null, stream: null, socketTask: null, isConnected: false, reconnectAttempts: 0, maxReconnectAttempts: 5, reconnectDelay: 1000, inputText: "", // 输入的文本 messages: [], // 存储所有消息的数组 recorderManager: null, // 录音管理器 // 视频缓冲相关 videoBuffers: ["", ""], // 双缓冲区 currentVideoIndex: 0, // 当前显示的视频索引 videoMap: { ['开心']: "../../static/RoleA-00.mp4", ['你好呀']: "../../static/RoleA-01.mp4", ['有什么我可以帮你的吗?']: "../../static/RoleA-01.mp4", default: "../../static/RoleA-00.mp4" }, preloadedVideos: new Map(), // 预加载的视频缓存 isTransitioning: false, // 是否正在切换 videosLoaded: false, // 视频是否初始化完成 currentSessionId: 0, // 当前会话ID,用于区分不同的对话轮次 lastProcessedMessages: new Set(), // 存储当前会话中已处理的消息 autoScroll: true, // 控制是否自动滚动 isUserScrolling: false, // 用户是否正在手动滚动 maxMessages: 50, // 限制消息数量 messageCleanupThreshold: 100, // 清理阈值 }; }, onLoad() { // 页面加载时建立 WebSocket 连接 this.connectWebSocket(); // #ifdef APP-PLUS this.recorderManager = uni.getRecorderManager(); this.recorderManager.onStop((res) => { console.log("录音停止,文件路径:", res.tempFilePath); // 读取文件并发送二进制数据 uni.getFileSystemManager().readFile({ filePath: res.tempFilePath, success: (r) => { this.sendAudioChunk(r.data); }, fail: (err) => console.error("读取音频文件失败", err), }); this.sendListenStopMessage(); }); // #endif // 初始化视频系统 this.initVideoSystem(); // 监听用户滚动行为 this.addScrollListener(); }, methods: { // 初始化视频系统 async initVideoSystem() { try { // 立即设置初始视频 const initialVideo = this.videoMap["default"]; this.videoBuffers[0] = initialVideo; this.videosLoaded = true; // 在后台预加载其他视频 setTimeout(() => { this.preloadAllVideos(); }, 100); console.log("视频系统初始化完成"); } catch (error) { console.error("视频系统初始化失败:", error); } }, // 视频预加载策略 async preloadAllVideos() { const videoUrls = [...new Set(Object.values(this.videoMap))]; // 使用Promise.allSettled而不是for循环,提高并发性 const results = await Promise.allSettled( videoUrls.map(url => this.preloadSingleVideo(url)) ); // 记录失败的视频 const failed = results.filter(r => r.status === 'rejected'); if (failed.length > 0) { console.warn(`${failed.length}个视频预加载失败`); } console.log(`视频预加载完成: ${results.length - failed.length}/${results.length}`); }, // 预加载单个视频 preloadSingleVideo(url) { return new Promise((resolve, reject) => { if (this.preloadedVideos.has(url)) { resolve(); return; } // #ifdef H5 const video = document.createElement('video'); video.src = url; video.preload = "auto"; video.muted = true; video.loop = true; video.addEventListener('canplaythrough', () => { this.preloadedVideos.set(url, video); resolve(); }); video.addEventListener('error', (e) => { console.error(`视频预加载失败: ${url}`, e); reject(e); }); video.load(); // #endif // #ifdef APP-PLUS // 小程序端直接标记为已预加载 this.preloadedVideos.set(url, true); resolve(); // #endif }); }, // 设置视频URL(简化版本) setVideoUrl(scene) { if (this.isTransitioning) return; const newVideoUrl = this.videoMap[scene] || this.videoMap["default"]; const currentUrl = this.videoBuffers[this.currentVideoIndex]; if (currentUrl === newVideoUrl) return; this.isTransitioning = true; // 如果当前只有一个视频,直接替换 if (!this.videoBuffers[1 - this.currentVideoIndex]) { this.videoBuffers[1 - this.currentVideoIndex] = newVideoUrl; // 等待 DOM 更新后切换 this.$nextTick(() => { setTimeout(() => { this.currentVideoIndex = 1 - this.currentVideoIndex; this.isTransitioning = false; }, 300); }); } else { // 双缓冲切换 this.smoothTransition(newVideoUrl); } }, // 平滑过渡动画(简化版) smoothTransition(newVideoUrl) { const nextIndex = 1 - this.currentVideoIndex; this.videoBuffers[nextIndex] = newVideoUrl; // 强制更新 DOM this.$forceUpdate(); // 延迟切换,确保过渡动画完成 setTimeout(() => { this.currentVideoIndex = nextIndex; this.isTransitioning = false; }, 300); // 过渡动画时长 }, // 视频加载完成 onVideoLoaded(index) { console.log(`视频${index}加载完成`); }, // 建立 WebSocket 连接 connectWebSocket() { const wsUrl = "ws://106.13.215.232:8000/aiservers/v1/?device-id=1A:34:B4:02:5D:F6&client-id=web_test_client"; // 替换为你的 WebSocket 服务器地址 this.socketTask = uni.connectSocket({ url: wsUrl, success: () => { console.log("WebSocket连接成功"); }, fail: (err) => { console.error("WebSocket连接失败:", err); } }); // 监听 WebSocket 连接打开事件 uni.onSocketOpen((res) => { this.isConnected = true; console.log("WebSocket连接已打开:", res); this.sendHello(); }); // 监听 WebSocket 接收到消息事件 uni.onSocketMessage((res) => { this.handleMessage(res); }); // 监听 WebSocket 连接关闭事件 uni.onSocketClose((res) => { this.isConnected = false; console.log("WebSocket连接已关闭:", res); if (this.reconnectAttempts < this.maxReconnectAttempts) { setTimeout(() => { this.reconnectAttempts++; console.log( `尝试重连... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`); this.connectWebSocket(); }, this.reconnectDelay * this.reconnectAttempts); } else { this.addMessage("系统消息", "连接已断开,请刷新页面重试", false); } }); // 监听 WebSocket 错误事件 uni.onSocketError((res) => { console.error("WebSocket发生错误:", res); }); }, // 发送握手消息 sendHello() { const message = { type: "hello", device_id: "1A:34:B4:02:5D:F6", device_name: "UniApp设备", device_mac: "1A:34:B4:02:5D:F6", token: "your-token1", features: { mcp: true } }; uni.sendSocketMessage({ data: JSON.stringify(message), success: () => { console.log("握手消息发送成功"); }, fail: (err) => { console.error("握手消息发送失败:", err); } }); }, // 发送文本消息 sendText() { if (!this.isConnected) { this.addMessage("系统消息", "请先建立 WebSocket 连接", false); return; } // 开始新的会话轮次 this.startNewSession(); const message = { type: "listen", mode: "manual", state: "detect", text: this.inputText }; uni.sendSocketMessage({ data: JSON.stringify(message), success: () => { console.log("文本消息发送成功"); this.addMessage("用户", this.inputText, true); }, fail: (err) => { console.error("文本消息发送失败:", err); this.addMessage("系统消息", "消息发送失败", false); } }); this.inputText = ""; // 清空输入框 }, // 滚动监听器 addScrollListener() { this.$nextTick(() => { // #ifdef H5 const messageContainer = document.querySelector('.message-container'); if (messageContainer) { messageContainer.addEventListener('scroll', this.handleScroll); } // #endif }); }, // 处理滚动事件 handleScroll(event) { const container = event.target; const isAtBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 10; // 如果用户滚动到底部,启用自动滚动 // 如果用户向上滚动,暂停自动滚动 this.autoScroll = isAtBottom; }, // 处理服务器返回的消息 handleMessage(res) { if (typeof res.data === 'string') { try { const jsonMessage = JSON.parse(res.data); this.handleJsonMessage(jsonMessage); } catch (error) { console.error('解析 JSON 失败:', error); } } else if (res.data instanceof ArrayBuffer) { this.handleAudioData(res.data); } }, // 处理 JSON 消息 handleJsonMessage(message) { switch (message.type) { case 'stt': // this.addMessage("语音识别", message.text, false); break; case 'llm': this.addMessage("回复消息", message.text, false); break; case 'tts': if ((message.state === 'sentence_start' || message.state === 'sentence_end') && message.text !== undefined) { this.addMessage("语音合成", message.text, false); this.setVideoUrl(message.text) } break; default: console.log('未知类型消息:', message); } }, // 添加消息 addMessage(name, text, isUser) { // 为每个消息创建唯一标识符 const messageKey = `${this.currentSessionId}-${name}-${text}-${isUser}`; // 检查是否是同一会话中的重复消息 if (this.lastProcessedMessages.has(messageKey)) { console.log("同一会话中的重复消息,未添加:", text); return; } // 添加到已处理消息集合 this.lastProcessedMessages.add(messageKey); // 添加消息到数组 this.messages.push({ name, text, isUser, time: new Date().toLocaleTimeString(), sessionId: this.currentSessionId // 添加会话ID标识 }); console.log("消息已添加:", text); // 只有在自动滚动启用时才滚动到底部 if (this.autoScroll) { this.scrollToBottom(); } // 内存管理:限制消息数量 if (this.messages.length > this.messageCleanupThreshold) { this.messages.splice(0, this.messages.length - this.maxMessages); // 同时清理对应的已处理消息记录 this.cleanupProcessedMessages(); } }, cleanupProcessedMessages() { // 只保留最近的消息标识符 const recentMessages = new Set(); this.messages.slice(-this.maxMessages).forEach(msg => { const key = `${msg.sessionId}-${msg.name}-${msg.text}-${msg.isUser}`; recentMessages.add(key); }); this.lastProcessedMessages = recentMessages; }, // 滚动到底部 scrollToBottom() { // 使用 nextTick 确保 DOM 更新完成后再滚动 this.$nextTick(() => { // #ifdef H5 const messageContainer = document.querySelector('.message-container'); if (messageContainer) { messageContainer.scrollTop = messageContainer.scrollHeight; } // #endif // #ifdef APP-PLUS || MP-WEIXIN const query = uni.createSelectorQuery().in(this); query.select('.message-container').boundingClientRect((rect) => { if (rect) { uni.pageScrollTo({ selector: '.message-container', scrollTop: rect.height, duration: 300 // 平滑滚动动画时间 }); } }).exec(); // #endif }); }, // 处理音频数据 handleAudioData(arrayBuffer) { // this.playAudio(arrayBuffer); }, // 播放音频数据 playAudio(arrayBuffer) { const audioContext = new(window.AudioContext || window.webkitAudioContext)(); audioContext.decodeAudioData(arrayBuffer, (audioBuffer) => { const source = audioContext.createBufferSource(); source.buffer = audioBuffer; source.connect(audioContext.destination); source.start(); }); }, // 切换录音状态 toggleRecording() { this.isRecording ? this.stopRecording() : this.startRecording(); }, // 开始录音 async startRecording() { // 开始新的会话轮次 this.startNewSession(); // #ifdef APP-PLUS if (!this.recorderManager) { this.addMessage("系统消息", "当前平台不支持原生录音", false); return; } this.recorderManager.start({ duration: 60000, sampleRate: 16000, numberOfChannels: 1, encodeBitRate: 96000, format: "aac", frameSize: 50, }); this.isRecording = true; this.sendListenStartMessage(); return; // #endif // #ifdef H5 try { // 1. 获取麦克风权限 this.stream = await navigator.mediaDevices.getUserMedia({ audio: true }); // 2. 创建录音器并配置 this.recorder = new MediaRecorder(this.stream, { mimeType: 'audio/webm;codecs=opus', audioBitsPerSecond: 16000 }); this.recorder.ondataavailable = async (event) => { if (event.data && event.data.size > 0) { // 转换为ArrayBuffer发送 const buffer = await event.data.arrayBuffer(); if (this.isRecording) { this.sendAudioChunk(buffer); } } }; // 4. 录音停止时的清理 this.recorder.onstop = () => { this.stream.getTracks().forEach(track => track.stop()); this.sendListenStopMessage(); }; // 5. 开始录音(每100ms发送一次数据块) this.recorder.start(200); this.isRecording = true; // 6. 通知服务器开始接收音频 this.sendListenStartMessage(); } catch (error) { //TODO handle the exception console.error('录音启动失败:', error); } // #endif }, // 开始新会话 startNewSession() { this.currentSessionId++; this.lastProcessedMessages.clear(); console.log("开始新会话,会话ID:", this.currentSessionId); }, // 停止录音 stopRecording() { // #ifdef APP-PLUS this.recorderManager.stop(); this.isRecording = false; return; // #endif // H5 浏览器端停止 // #ifdef H5 this.recorder.stop(); this.stream.getTracks().forEach((t) => t.stop()); this.isRecording = false; // #endif }, // 发送开始录音消息 sendListenStartMessage() { if (!this.isConnected) return; const msg = { type: "listen", mode: "manual", state: "start" }; uni.sendSocketMessage({ data: JSON.stringify(msg), success: () => console.log("已通知服务器开始录音"), fail: (err) => console.error("开始录音消息发送失败:", err) }); }, // 告诉服务器:结束语音流 sendListenStopMessage() { if (!this.isConnected) return; const msg = { type: "listen", mode: "manual", state: "stop" }; uni.sendSocketMessage({ data: JSON.stringify(msg), success: () => console.log("已通知服务器停止录音"), fail: (err) => console.error("停止录音消息发送失败:", err) }); }, // 实时发送音频数据 sendAudioChunk(buffer) { if (!this.isConnected) return; uni.sendSocketMessage({ data: buffer, success: () => {}, fail: (err) => { console.error("音频数据发送失败:", err); } }); } }, // 页面卸载时关闭 WebSocket 连接 onUnload() { if (this.socketTask) { uni.closeSocket(); console.log("关闭 WebSocket 连接"); } if (this.stream) { this.stream.getTracks().forEach(track => track.stop()); } } }; </script> <style> .container { position: relative; width: 100%; height: 100vh; overflow: hidden; } .background-video { position: fixed; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; z-index: -1; opacity: 1; /* 直接设置为1,简化逻辑 */ transition: opacity 0.3s ease-in-out; animation: fade 0.3s forwards; } @keyframes fade { from { opacity: 0; } to { opacity: 1; } } .background-video.loaded { opacity: 1; /* 加载完成后变为不透明 */ } .message-container { position: absolute; top: 90px; width: min(70%, 400px); /* 限制最大宽度 */ right: 20px; max-height: calc(100vh - 180px); /* 动态计算高度 */ overflow-y: auto; z-index: 2; scroll-behavior: smooth; } /* 移动端适配 */ /* @media (max-width: 768px) { .message-container { width: calc(100% - 40px); right: 20px; left: 20px; } } */ .message-container::-webkit-scrollbar { width: 0px; } .message-container::-webkit-scrollbar-track { background: transparent; } .message-container::-webkit-scrollbar-thumb { background-color: transparent; border-radius: 0px; } .message-container::-webkit-scrollbar-thumb:hover { background-color: transparent); } .message-item { margin: 0 10px; } .message-text { padding: 10px 15px; border-radius: 18px; font-size: 14px; line-height: 1.4; word-wrap: break-word; max-width: 80%; display: inline-block; margin-bottom: 8px; } .user-css { text-align: end; } .user-message { background-color: #4CAF50; color: white; } .message-text:not(.user-message) { background-color: #ffffff; color: #333333; } .bottom-bar { position: fixed; bottom: 0; width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 10px 0px; z-index: 10; box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1); } .bottom-input { display: flex; flex: 1; position: relative; } .record-btn { width: 40px; height: 40px; border-radius: 50%; display: flex; justify-content: center; align-items: center; } .record-text { font-size: 14px; } .input-box { flex: 1; margin: 0 10px; height: 40px; border: none; background-color: #f5f5f5; border-radius: 20px; padding: 0 15px; font-size: 14px; outline: none; } .send-btn { width: 40px; height: 40px; border-radius: 50%; background-color: #4CAF50; color: white; display: flex; justify-content: center; align-items: center; position: absolute; right: 10px; } .send-text { font-size: 18px; } .recording-indicator { position: fixed; top: 20px; right: 20px; z-index: 100; } .recording-circle { width: 10px; height: 10px; background-color: #ff0000; border-radius: 50%; animation: blink 1s infinite; } @keyframes blink { 0% { opacity: 1; } 50% { opacity: 0.3; } 100% { opacity: 1; } } /deep/ .uni-video-bar { display: none !important; } </style>在这个页面使用
07-08
<template> <div> <title>{{$route.name}}</title> <h1>{{$route.name}}</h1> <aui-form id="editForm"> <div class="first-field" :class="isShowMore?'showMore':'hideMore'"> <aui-form-item label="版本号" label-width="110px"> <aui-dropdown size="small" v-model="searchForm.planId" :op="planIdOp" place-holder="请选择"></aui-dropdown> </aui-form-item> <aui-form-item label="厂区" label-width="110px"> <aui-dropdown size="small" v-model="searchForm.locationCodeStr" :op="siteCodeOp" place-holder="请选择"></aui-dropdown> </aui-form-item> <aui-form-item label="部门" label-width="110px"> <aui-dropdown size="small" ref="deptCodeRef" v-model="searchForm.deptNameStr" :op="deptOp" place-holder="请选择"></aui-dropdown> </aui-form-item> <aui-form-item label="工序" label-width="110px"> <aui-dropdown size="small" v-model="searchForm.workSerctionStr" :op="workSerctionOp"></aui-dropdown> </aui-form-item> <aui-form-item label="产品线" label-width="110px"> <aui-dropdown size="small" ref="prodLineCnNameRef" v-model="searchForm.prodLineCnNameStr" :op="prodLineOp" place-holder="请选择"></aui-dropdown> </aui-form-item> <aui-form-item label="产品族" label-width="110px"> <aui-dropdown size="small" ref="prodFamilyEnNameRef" v-model="searchForm.prodFamilyEnNameStr" :op="prodFamilyOp" place-holder="请选择"></aui-dropdown> </aui-form-item> <aui-form-item label="产品型号" label-width="110px"> <aui-dropdown size="small" ref="prodModelCodeRef" v-model="searchForm.prodModelCodeStr" :op="prodModelCodeOp" place-holder="请选择"></aui-dropdown> </aui-form-item> <aui-form-item label="物料编码" label-width="110px"> <aui-input size="small" ref="itemCodeRef" v-model="searchForm.itemCodeStr" placeholder="连续首字母或者字符可模糊匹配"></aui-input> </aui-form-item> <aui-form-item label="类型" label-width="110px"> <aui-dropdown size="small" v-model="searchForm.dataTypeStr" :op="dataTypeOp" place-holder="请选择"></aui-dropdown> </aui-form-item> <aui-form-item class="first-field-btn" label-width="0px" style="width: 265px"> <i v-show="isTriangleIconShow" class="hae-icon" :class="isShowMore?'icon-down':'icon-left-o'" @click="isShowMore = !isShowMore "></i> <aui-button type="primary" size="mini" round @click="findClick">查询</aui-button> <aui-button type="primary" size="mini" round @click="reset" style="margin-right: 8px">重置</aui-button> <FormTempBtn style="width:100px;" :form-code="formId" :formData="searchForm" @templateChanged="setFormData"></FormTempBtn> </aui-form-item> </div> </aui-form> <div class="table-auto"> <aui-grid height="100%" auto-resize ref="grid" :auto-load="false" resizable :row-class-name="rowClassName" :pager="pagerConfig" border :span-method="colspanMethod" :fetch-data="fetchData"> <template #toolbar> <aui-grid-toolbar id="scheduleSupplyDemandGridId" :setting="{ showIndex: true, sortable: Sortable, }" ref="auiToolbar" @remote-setting="remoteSetting" @save-setting="saveSetting"> <template #buttons> <div style="width: 800px; display: inline-block"> <aui-button size="mini" @click="exportData">导出</aui-button> <aui-button size="mini" @click="showBaseLoggerInfo">版本日志</aui-button> </div> </template> </aui-grid-toolbar> </template> <aui-grid-column fixed="left" title="版本" field="planId" min-width="100" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="厂区" field="locationName" min-width="100" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="部门" field="deptName" min-width="120" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="产品线" field="prodLineCnName" min-width="80" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="产品族" field="prodFamilyEnName" min-width="80" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="产品型号" field="prodModelCode" min-width="80" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="工序" field="workSerction" min-width="80" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="物料编码" field="itemCode" min-width="90" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="类型" field="dataType" min-width="80" show-overflow header-align="center" align="center"></aui-grid-column> <aui-grid-column fixed="left" title="库存" field="invQty" min-width="80" show-overflow header-align="center" align="center"> <template #default="{ row }"> <div style="color: #189ff0 !important;cursor: pointer;text-decoration: underline;" @click="operateRow(row, 'invQty')">{{ row.invQty }}</div> </template> </aui-grid-column> <aui-grid-column fixed="left" title="历史" field="hisQty" min-width="100" show-overflow header-align="center" align="center"> <template #default="{ row }"> <div :class="{ 'row-link_click': ['预计供应', '过站供应', '排产需求'].includes(row.dataType), 'row-link-red': String(row.hisQty) && row.hisQty < 0 }" @click="operateRow(row, 'hisQty')">{{ row.hisQty }}</div> </template> </aui-grid-column> <aui-grid-column v-for="(item, i) in dateItem" :key="i" :field="item.field" :title="item.title" :renderer="renderFunction" min-width="50" align="center"> </aui-grid-column> </aui-grid> </div> <StockDialog v-if="showStock" :rowData="rowData" @changeDialog="changeDialog"></StockDialog> <InProcessWorkOrderSchedule v-if="showInProcess" :rowData="rowData" @changeDialog="changeDialog" :dateItem="dateItem"></InProcessWorkOrderSchedule> <WorkOrderScheduleHistory v-if="showHistory" :rowData="rowData" @changeDialog="changeDialog" :dateItem="dateItem"></WorkOrderScheduleHistory> <aui-dialog-box title="版本日志" class="history-Info" v-model="isShowBaseLoggerInfo" width="90%" top="8%" :dragable="true" :modal-closable="false"> <base-logger-info v-bind:apiUrl="getLoggerInfoUrl" v-if="isShowBaseLoggerInfo"></base-logger-info> </aui-dialog-box> </div> </template> <script> import { Form, FormItem, Dropdown, Hae, $, DialogBox } from '@aurora/ui3' import { Grid, GridColumn, Modal, Pager, Button, GridToolbar } from '@aurora/vue3' import { FormTempBtn } from '@mxdesign/ui' import Sortable from 'sortablejs' import { remoteSettingFn, saveSettingFn, getCustomConfigsFn } from '@/utils/personSettings' import StockDialog from '@/components/supplydemandmgt/StockDialog' import InProcessWorkOrderSchedule from '@/components/supplydemandmgt/InProcessWorkOrderSchedule' import WorkOrderScheduleHistory from '@/components/supplydemandmgt/WorkOrderScheduleHistory' import BaseLoggerInfo from '../basedata/BaseLoggerInfo.vue' export default { components: { AuiDialogBox: DialogBox, AuiButton: Button, AuiForm: Form, AuiFormItem: FormItem, AuiDropdown: Dropdown, AuiGrid: Grid, AuiGridColumn: GridColumn, AuiGridToolbar: GridToolbar, FormTempBtn, StockDialog, InProcessWorkOrderSchedule, WorkOrderScheduleHistory, BaseLoggerInfo }, computed: { tableData() { return this.$refs.grid && this.$refs.grid.getTableData() ? this.$refs.grid.getTableData().tableData : [] } }, data() { return { Sortable, isShowBaseLoggerInfo: false, getLoggerInfoUrl: 'services/supplyRequireItemHeadService/getSupplyRequireLogList/page/{{pageSize}}/{{curPage}}', formId: 'scheduleSupplyDemandId', toolBoxShow: false, isShowMore: true, isTriangleIconShow: true, searchForm: { planId: '', // 版本号 locationCodeStr: '', // 厂区 deptNameStr: '', // 部门 prodLineCnNameStr: '', // 产品线 prodFamilyEnNameStr: '', // 产品族 prodModelCodeStr: '', // 产品型号 workSerctionStr: '', // 工序 itemCodeStr: '', // 编码 dataTypeStr: '' // 类型 }, // 版本号 planIdOp: { multi: false, showClearBtn: true, autoSelect: false, alwaysLoad: true, editable: true, id: 'planId', validation: { required: true }, textField: 'planId', valueField: 'planId', placeHolder: '-----请选择-----', dataset: { source: { type: 'post', url: 'services/apsSupplyRequireService/getAllPlanIdList' } } }, // 厂区 siteCodeOp: { multi: true, id: 'locationCodeId', showClearBtn: true, autoSelect: false, alwaysLoad: true, editable: true, textField: 'locationName', valueField: 'locationCode', placeHolder: '-----请选择-----', emptyDataMsg: '-----没有数据-----', dataset: { source: { type: 'post', url: 'services/apsSupplyRequireService/getAllLocationInfo' } } }, // 部门 deptOp: { multi: true, // 是否多选 id: 'deptCodeId', showClearBtn: true, autoSelect: false, alwaysLoad: true, editable: true, textField: 'deptName', valueField: 'deptName', placeHolder: '-----请选择-----', emptyDataMsg: '-----请选择厂区-----', dataset: { source: { type: 'POST', url: 'services/apsSupplyRequireService/getDeptInfo' } }, cascade: [ { trigger: '#locationCodeId', allowEmpty: false, // 是否允许空值参加级联 name: 'locationCodeStr' } ] }, // 工序 workSerctionOp: { id: 'workSerctionId', multi: true, showClearBtn: true, autoSelect: false, alwaysLoad: true, editable: true, placeHolder: '-----请选择-----', textField: 'valueInfo', valueField: 'valueInfo', dataset: { source: { type: 'post', url: 'services/apsSupplyRequireService/getAllWorkSerction' } } }, // 产品线 prodLineOp: { multi: true, id: 'prodLineId', showClearBtn: true, autoSelect: false, alwaysLoad: true, editable: true, textField: 'prodLineCnName', valueField: 'prodLineCnName', placeHolder: '-----请选择-----', dataset: { source: { type: 'post', url: 'services/apsSupplyRequireService/getProdLineList' } } }, // 产品族(系列) prodFamilyOp: { multi: true, id: 'prodFamilyId', showClearBtn: true, autoSelect: false, alwaysLoad: true, editable: true, textField: 'prodSeriesEnName', valueField: 'prodSeriesEnName', placeHolder: '-----请选择-----', dataset: { source: { type: 'post', url: 'services/apsSupplyRequireService/getProdSeriesList' } }, cascade: [ { trigger: '#prodLineId', allowEmpty: true, // 是否允许空值参加级联 name: 'prodLineCnNameStr' } ], emptyDataMsg: '-----请选择产品线-----' }, // 产品型号 prodModelCodeOp: { multi: true, id: 'prodModelId', showClearBtn: true, autoSelect: false, alwaysLoad: true, editable: true, textField: 'prodModelCode', valueField: 'prodModelCode', placeHolder: '-----请选择-----', dataset: { source: { type: 'post', url: 'services/apsSupplyRequireService/getAllProdModelList' } }, cascade: [ { trigger: '#prodFamilyId', allowEmpty: false, name: 'prodSeriesEnNameStr' } ], emptyDataMsg: '-----请选择产品族-----' }, // 类型 dataTypeOp: { multi: true, id: 'dataTypeId', showClearBtn: true, autoSelect: false, editable: true, textField: 'label', valueField: 'value', placeHolder: '-----请选择-----', dataset: { value: [ { value: '排产', label: '排产' }, { value: '预计供应', label: '预计供应' }, { value: '过站供应', label: '过站供应' }, { value: '排产需求', label: '排产需求' }, { value: '供需匹配', label: '供需匹配' } ] } }, pageFlag: false, pagerConfig: { component: Pager, attrs: { currentPage: 1, pageSize: 15, pageSizes: [15, 30, 50, 100], total: 0, layout: 'total, sizes, prev, pager, next, jumper' } }, dateItem: [], fetchData: { api: this.getData }, clickSearchForm: {}, rowData: {}, showStock: false, showInProcess: false, showHistory: false, settingType: 'scheduleSupplyDemand', setTableColumn: [] } }, methods: { showBaseLoggerInfo() { this.isShowBaseLoggerInfo = true }, // 导出 exportData() { let formData = this.searchForm Hae.ajax({ url: 'services/exportFileUtilService/exportApsSupplyRequire', data: formData, type: 'post', success: () => { Hae.confirm('导出任务已开始,你可以进入[我的导入导出>导出查询]中查看任务状态并下载导出文件!', (bool) => { if (bool) { window.open('#/ListExport') } }) } }) }, // 行合并 colspanMethod({ row, column, rowIndex, columnIndex }) { let fields = ['mergerKey', 'invQty'] // 获取当前行的 mergerKey const currentGroupKey = row.mergerKey // 获取当前列的 prop const columnProp = column.property // 计算相同 mergerKey 的行范围 const groupRows = this.tableData.filter((item) => item.mergerKey === currentGroupKey && currentGroupKey) const firstGroupRowIndex = this.tableData.findIndex( (item) => item.mergerKey === currentGroupKey && currentGroupKey ) const lastGroupRowIndex = firstGroupRowIndex + groupRows.length - 1 // 对于 fields 列,合并相同 mergerKey 的所有行 if (fields.includes(columnProp)) { if (rowIndex === firstGroupRowIndex) { return { rowspan: groupRows.length, colspan: 1 } } else { return { rowspan: 0, colspan: 0 } } } }, // 行渲染 renderFunction(h, { row, column }) { if (row.dataType === '排产需求'&& Number(row[column.property]) < 0) { return <span style={{ color: '#000', fontSize: '12px' }}>{row[column.property]}</span> } if (String(row[column.property]) && Number(row[column.property]) < 0) { return <span style={{ color: '#fe281f', fontSize: '12px' }}>{row[column.property]}</span> } else { return <span style={{ color: '#000', fontSize: '12px' }}>{row[column.property]}</span> } }, rowClassName({ seq, row, rowIndex, $rowIndex }) { if (row.dataType === '排产') { return 'row__word--remarked' } else { return '' } }, setFormData(data) { let tempArr = Object.keys(data) this.resData = data if (tempArr.length === 0) { return } this.searchForm.planId = data.planId // 版本号 this.searchForm.locationCodeStr = data.locationCodeStr // 厂区 this.searchForm.prodLineCnNameStr = data.prodLineCnNameStr // 产品线 this.searchForm.workSerctionStr = data.workSerctionStr // 工序 this.searchForm.dataTypeStr = data.dataTypeStr // 类型 // 级联关系接口先后执行 setTimeout(() => { this.$refs.deptCodeRef.widget.setValueByField(data.deptNameStr, 'deptName') // 注意: 第二个参数是下拉的value值,不是v-model的值 }, 500) setTimeout(() => { this.$refs.prodFamilyEnNameRef.widget.setValueByField(data.prodFamilyEnNameStr, 'prodSeriesEnName') }, 800) setTimeout(() => { this.$refs.prodModelCodeRef.widget.setValueByField(data.prodModelCodeStr, 'prodModelCode') }, 1500) setTimeout(() => { this.$refs.itemCodeRef.widget.setValueByField(data.itemCodeStr, 'prodItemCode') }, 2000) }, operateRow(row, flag) { this.rowData = row this.rowData.dialogFlag = flag if (flag === 'invQty') { this.showStock = true } else { if (['排产需求'].includes(row.dataType)) { this.showHistory = true } if (['预计供应', '过站供应'].includes(row.dataType)) { this.showInProcess = true } } }, handleProductionClick(row,flag){ this.rowData = row this.rowData.dialogFlag = flag if(['排产需求'].includes(row.dataType)){ this.showHistory=true } }, changeDialog() { this.rowData = {} this.showStock = false this.showHistory = false this.showInProcess = false }, reset() { // 清空选择 this.searchForm = { planId: '', // 版本号 locationCodeStr: '', // 厂区 deptNameStr: '', // 部门 prodLineCnNameStr: '', // 产品线 prodFamilyEnNameStr: '', // 产品族 prodModelCodeStr: '', // 产品型号 workSerctionStr: '', // 工序 itemCodeStr: '', // 编码 dataTypeStr: '' // 类型 } this.clickSearchForm = JSON.parse(JSON.stringify(this.searchForm)) }, // 动态日期列 columnDate() { this.dateItem = [] let params = { ...this.searchForm } this.$service.network.post('services/apsSupplyRequireService/getHeadBucketList', params).then(({ data }) => { this.pageFlag = false if (data && data.length) { data.forEach((element) => { // 将完整日期转换为月日格式 MM/DD const dateParts = element.split('-') const monthDay = dateParts.length >= 3 ? `${dateParts[1]}/${dateParts[2]}` : element this.dateItem.push({ title: monthDay, field: element }) }) } }) }, findClick() { Hae.validForm($('#editForm'), (valid) => { if (valid) { this.pageFlag = true this.getCustomConfigs() this.clickSearchForm = JSON.parse(JSON.stringify(this.searchForm)) setTimeout(() => { this.$refs.grid.handleFetch() }, 500) } }) }, // 查询 getData({ page }) { let { pageSize } = page if (this.pageFlag) { page.currentPage = 1 } let curPage = page.currentPage return new Promise((resolve, reject) => { let params = { ...this.clickSearchForm } this.$service.network .post(`services/apsSupplyRequireService/getApsSupplyRequireList/page/${pageSize}/${curPage}`, params) .then(({ data }) => { this.pageFlag = false this.isShowMore = false this.columnDate() let totalRows = data.pageVO && data.pageVO.totalRows ? data.pageVO.totalRows : 0 let result = data.result && data.result.length ? data.result : [] resolve({ result, page: { total: totalRows } }) }) }) }, getCustomConfigs() { let config = { settingType: this.settingType, grid: 'grid', auiToolbar: 'auiToolbar', setTableColumn: 'setTableColumn', dragSort: true } getCustomConfigsFn.call(this, config) }, remoteSetting(settings) { remoteSettingFn.call(this, settings, 'grid') }, saveSetting() { let customConfigs = arguments[0].columns let config = { settingType: this.settingType, customConfigs } saveSettingFn.call(this, config) } }, mounted() { let that = this // 判断是否有更多条件显示隐藏小三角 let editFormHeight = $('.first-field').outerHeight() that.isTriangleIconShow = !(editFormHeight < 38) that.isShowMore = false this.getCustomConfigs() } } </script> <style scoped src="./../unit/css/newModelPublic.css"></style> <style scoped> .first-field { padding-right: 300px !important; } :deep(.table-auto .aui-grid .aui-grid-cell) { width: 100% !important; font-size: 12px; } .table-auto { height: calc(100vh - 140px) !important; } :deep(.table-auto .aui-grid__body-wrapper) { height: calc(100vh - 280px) !important; } :deep(.aui-grid__body-wrapper::-webkit-scrollbar) { height: 12px !important; width: 12px !important; } :deep(.aui-grid__body .aui-grid-body__column .aui-grid-cell .row-link) { color: #189ff0 !important; cursor: pointer; text-decoration: underline; } :deep(.aui-grid-toolbar) { padding: 5px 0; } :deep(.aui-grid-toolbar .aui-grid-custom__wrapper) { height: 24px !important; width: 24px !important; } :deep(.aui-grid__body .aui-grid-body__column .aui-grid-cell .row-link_click) { color: #189ff0 !important; cursor: pointer; text-decoration: underline; } :deep(.aui-grid__body .aui-grid-body__column .aui-grid-cell .row-link-red) { color: #fe281f !important; } :deep(.aui-grid.fixed__sticky .row__word--remarked) { --body-background-color: #ebf1de !important; } :deep(.row__word--remarked) { background-color: #ebf1de !important; } :deep(.aui-grid .aui-pager) { padding-top: 6px !important; } </style> <style> /* 隐藏aui3个性化重置按钮 */ .aui-grid-modal__box .aui-grid-custom .aui-grid-custom__footer .aui-button:nth-child(2) { display: none !important; } </style> 中在dataItem动态生成的日期列中对应的数值类型是排产需求的点击数值展示WorkOrderScheduleHistory页面,
最新发布
08-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值