this.$refs.xxx.$refs.xxxForm.model

时间: 2025-06-21 19:38:26 AIGC 浏览: 35
<think>嗯,用户想了解Vue.js中this.$refs的用法和嵌套引用的具体例子。首先,我得回顾一下Vue.js的官方文档关于refs的部分。记得ref是用来直接访问子组件或者DOM元素的。用户提到嵌套引用,可能需要如何在多层组件结构中使用ref。 首先,基本用法应该是给元素或组件添加ref属性,然后通过this.$refs访问。比如在模板里写<input ref="myInput">,然后在方法里用this.$refs.myInput来获取这个DOM节点。这部分应该没问题。 接下来是嵌套组件的情况。比如父组件引用子组件,子组件又引用孙组件。用户可能想知道如何通过父组件的ref访问孙组件。这时候可能需要逐层访问。比如父组件里有个子组件Child,子组件有个ref是childRef,那么父组件可以通过this.$refs.childRef来获取子组件实例,然后子组件自己的$refs里可能有孙组件的引用。比如this.$refs.childRef.$refs.grandchildRef。不过需要注意,这种链式访问可能在组件结构变化时变得脆弱,所以需要谨慎使用。 另外,用户可能需要具体的代码示例。比如在父组件中定义子组件的ref,然后在子组件中定义孙组件的ref,再在父组件的方法里通过链式调用访问孙组件的方法或属性。这时候需要确保ref在渲染完成后存在,可能在mounted钩子中使用。 还要注意,Vue的响应式系统通常不推荐直接操作DOM或子组件,应该优先考虑props和events。但在某些情况下,比如管理焦点或集成第三方库时,使用ref是合理的。 用户的问题还可能涉及动态生成的组件或v-for循环中的ref。在v-for里使用ref时,this.$refs会得到一个数组。比如循环生成多个子组件,每个都有相同的ref名称,那么this.$refs.myRef会是一个数组,包含各个实例。这时候访问需要索引,比如this.$refs.myRef[0]。但如果在嵌套结构中动态生成,可能需要更复杂的处理。 另外,考虑到Vue 3中的变化,Composition API中使用ref可能需要不同的方式,但用户的问题可能是关于Vue 2的,所以需要明确版本。不过用户没有特别说明,可能默认是Vue 2的情况。 总结,回答应该包括基本用法、嵌套组件中的链式访问、动态生成的ref处理、注意事项以及代码示例。还要提醒用户尽量避免过度使用ref,保持数据驱动的原则。同时,结合用户提供的引用内容,可能需要注意代码结构和可读性,比如引用[2]中提到的对象结构,保持代码清晰。</think>### Vue.js 中 `this.$refs` 嵌套引用用法详解 #### 一、基础用法 `this.$refs` 是 Vue.js 提供的直接访问 DOM 元素或子组件实例的接口。通过为元素或组件添加 `ref` 属性实现: ```html <template> <div ref="parentDiv"> <ChildComponent ref="childComp" /> </div> </template> <script> export default { mounted() { // 访问 DOM 元素 console.log(this.$refs.parentDiv); // 输出: <div>...</div> // 访问子组件实例 console.log(this.$refs.childComp); // 输出: ChildComponent 实例 } } </script> ``` #### 二、嵌套组件引用 在多层嵌套结构中,可通过链式访问逐级获取子组件引用: ```html <!-- ParentComponent.vue --> <template> <ChildComponent ref="childRef" /> </template> <!-- ChildComponent.vue --> <template> <GrandchildComponent ref="grandchildRef" /> </template> <script> // ParentComponent 中访问孙组件 this.$refs.childRef.$refs.grandchildRef.someMethod(); ``` #### 三、动态生成组件的引用处理 在 `v-for` 循环中,`this.$refs` 会返回数组: ```html <template> <div v-for="item in items" :key="item.id"> <ChildComponent ref="dynamicRefs" /> </div> </template> <script> export default { mounted() { // 获取第一个子组件实例 const firstChild = this.$refs.dynamicRefs[0]; } } </script> ``` #### 四、引用深度验证 建议使用 `$refs` 时增加存在性校验: ```javascript if (this.$refs.childRef && this.$refs.childRef.$refs.grandchildRef) { this.$refs.childRef.$refs.grandchildRef.updateData(); } ``` #### 五、最佳实践 1. **优先使用 props/events**:仅在需要直接操作 DOM 或第三方库集成时使用 `$refs`[^2] 2. **避免深度耦合**:超过三层的嵌套引用应考虑重构组件结构 3. **生命周期注意**:确保在 `mounted` 或 `$nextTick` 后访问 `$refs` ```html <!-- 典型表单验证场景 --> <template> <form ref="form"> <input ref="username" v-model="user.name"> <button @click.prevent="validate">Submit</button> </form> </template> <script> export default { methods: { validate() { if (!this.$refs.username.value) { this.$refs.username.focus(); } } } } </script> ```
阅读全文

相关推荐

以下mreditor.vue代碼頁面獲得json資料時,將位於MRInfo/?format=json中mrcase字段內的字串與,另一個位於DNTag/?format=json的drf api中字段為dnname內的字串比對,mrcase欄位中與dnname欄位找到相同的字串時,獲取其在DNTag/?format=json中的dntag的id與原位於MRInfo/?format=json中mrinfo的id,然後將此dntag id與mrinfo id到MRDN/?format=json與獲取的json資料比對,若dntag id與mrinfo id在與MRDN/?format=json與獲取的json資料比對后顯示為已建立關聯的json資料,則不做任何動作,若無建立關連,則在MRDN/?format=json的位置以post方法建立dntag id與mrinfo id關聯的json資料: mreditor.vue代碼: <template> <WangEditor v-model="content" @response="(msg) => content = msg" /> 病態名稱: {{ currentDnTags.join(';') }} 病態名稱: 無關聯病態名稱 <mreditor1 ref="mreditor1" /> <mrdncrud v-if="showDnCrud" @tag-updated="handleTagUpdated" />
<button @click="toggleDisplayFormat">{{ displayButtonText }}</button> <button @click="resetAll" class="reset-btn">輸入新醫案</button> <button @click="toggleDnCrud" class="dncrud-btn"> {{ showDnCrud ? '隱藏病態編輯' : '編輯病態' }} </button> <input v-model="fetchId" placeholder="輸入醫案ID" type="number" min="1" /> <button @click="fetchById">載入醫案</button> <button @click="updateContent" class="update-btn">更新醫案</button> <button @click="deleteContent" class="delete-btn">刪除醫案</button> <button @click="submitContent" class="submit-btn">提交醫案</button> 醫案 ID: {{ submittedId }} 醫案編輯器
</template> <script> import WangEditor from './WangEditor.vue'; import mreditor1 from './mreditor1.vue'; import mrdncrud from './mrdncrud.vue'; // 导入病态编辑组件 import LZString from 'lz-string'; export default { name: 'mreditor', components: { WangEditor, mreditor1, mrdncrud }, data() { return { content: '', submittedId: null, fetchId: null, dnTags: [], showRawHtml: false, stateVersion: '1.0', autoSaveTimer: null, autoSaveInterval: 30000, currentDnTags: [], // 存储当前医案的病态名称 dnTagMap: {}, // 标签ID到名称的映射 showDnCrud: false // 控制病态编辑面板显示 }; }, computed: { highlightedContent() { if (!this.dnTags.length || !this.content) return this.content; const tempEl = document.createElement('div'); tempEl.innerHTML = this.content; const walker = document.createTreeWalker( tempEl, NodeFilter.SHOW_TEXT ); const nodes = []; while (walker.nextNode()) { nodes.push(walker.currentNode); } nodes.forEach(node => { let text = node.nodeValue; let newHtml = text; this.dnTags .slice() .sort((a, b) => b.length - a.length) .forEach(tag => { const regex = new RegExp( this.escapeRegExp(tag), 'g' ); newHtml = newHtml.replace( regex, ${tag} ); }); if (newHtml !== text) { const span = document.createElement('span'); span.innerHTML = newHtml; node.parentNode.replaceChild(span, node); } }); return tempEl.innerHTML; }, displayContent() { if (this.showRawHtml) { return this.escapeHtml(this.content); } return this.highlightedContent; }, displayButtonText() { return this.showRawHtml ? '顯示渲染格式' : '顯示原始標籤'; } }, watch: { content: { handler() { this.debouncedSaveState(); }, deep: true } }, async mounted() { await this.fetchDNTags(); this.restoreState(); this.setupAutoSave(); }, activated() { console.log('醫案編輯器被激活'); this.restoreState(); this.setupAutoSave(); }, deactivated() { console.log('醫案編輯器被停用'); this.saveState(); this.clearAutoSave(); }, beforeDestroy() { this.clearAutoSave(); }, methods: { // 切换病态编辑面板显示 toggleDnCrud() { this.showDnCrud = !this.showDnCrud; if (this.showDnCrud) { // 调整布局以显示编辑面板 document.querySelector('.tag-panel').style.display = 'block'; } else { document.querySelector('.tag-panel').style.display = 'none'; } }, // 处理标签更新事件 handleTagUpdated() { console.log('病态标签已更新,刷新数据'); this.fetchDNTags(); // 刷新标签数据 }, escapeHtml(unsafe) { if (!unsafe) return ''; return unsafe .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'"); }, escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }, setupAutoSave() { this.clearAutoSave(); this.autoSaveTimer = setInterval(() => { if (this.content || this.submittedId) { console.log('自动保存状态...'); this.saveState(); } }, this.autoSaveInterval); }, clearAutoSave() { if (this.autoSaveTimer) { clearInterval(this.autoSaveTimer); this.autoSaveTimer = null; } }, debouncedSaveState() { this.clearAutoSave(); this.autoSaveTimer = setTimeout(() => { this.saveState(); this.setupAutoSave(); }, 2000); }, saveState() { const formData = this.$refs.mreditor1 ? this.$refs.mreditor1.getFormData() : { }; const state = { version: this.stateVersion, content: this.content, submittedId: this.submittedId, formData: formData, showRawHtml: this.showRawHtml, currentDnTags: this.currentDnTags, // 保存病态名称 timestamp: new Date().getTime() }; if (this.content.length > 2000) { try { state.compressed = true; state.content = LZString.compressToUTF16(this.content); } catch (e) { console.error('压缩失败,使用原始数据', e); state.compressed = false; } } sessionStorage.setItem('medicalRecordState', JSON.stringify(state)); }, restoreState() { const savedState = sessionStorage.getItem('medicalRecordState'); if (!savedState) return; try { const state = JSON.parse(savedState); if (state.version !== this.stateVersion) { console.warn('状态版本不匹配,跳过恢复'); return; } let content = state.content; if (state.compressed) { try { content = LZString.decompressFromUTF16(content); } catch (e) { console.error('解压失败,使用原始数据', e); } } this.content = content; this.submittedId = state.submittedId; this.showRawHtml = state.showRawHtml; this.currentDnTags = state.currentDnTags || []; // 恢复病态名称 if (this.$refs.mreditor1 && state.formData) { this.$refs.mreditor1.setFormData(state.formData); } console.log('医案状态已恢复'); } catch (e) { console.error('状态恢复失败', e); sessionStorage.removeItem('medicalRecordState'); } }, clearState() { sessionStorage.removeItem('medicalRecordState'); }, toggleDisplayFormat() { this.showRawHtml = !this.showRawHtml; this.saveState(); }, async fetchDNTags() { try { const response = await fetch('DNTag/?format=json'); const data = await response.json(); this.dnTags = data .map(item => item.dnname) .filter(name => name && name.trim().length > 0); // 构建ID到名称的映射 this.dnTagMap = {}; data.forEach(item => { if (item.id && item.dnname) { this.dnTagMap[item.id] = item.dnname; } }); } catch (error) { console.error('获取标签失败:', error); alert('标签数据加载失败,高亮功能不可用'); } }, async fetchById() { if (!this.fetchId) { alert('請輸入有效的醫案ID'); return; } try { const response = await fetch(MRInfo/${this.fetchId}/?format=json); if (response.ok) { const data = await response.json(); if (this.$refs.mreditor1) { this.$refs.mreditor1.formData.mrname = data.mrname || ''; this.$refs.mreditor1.formData.mrposter = data.mrposter || ''; } this.content = data.mrcase || ''; this.submittedId = data.id; this.fetchId = null; // 处理病态名称显示 if (data.dntag && Array.isArray(data.dntag)) { this.currentDnTags = data.dntag.map(id => this.dnTagMap[id] || 未知標籤(${id}) ); } else { this.currentDnTags = []; } await this.fetchDNTags(); this.saveState(); alert('醫案數據加載成功!'); } else if (response.status === 404) { alert('未找到該ID的醫案'); } else { throw new Error('獲取醫案失敗'); } } catch (error) { console.error('Error:', error); alert(獲取醫案失敗: ${error.message}); } }, async submitContent() { if (!this.$refs.mreditor1) return; const formData = this.$refs.mreditor1.getFormData(); const postData = { mrcase: this.content, ...formData }; try { const response = await fetch('MRInfo/?format=json', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(postData), }); if (response.ok) { const data = await response.json(); this.submittedId = data.id; // 处理返回的病态名称 if (data.dntag && Array.isArray(data.dntag)) { this.currentDnTags = data.dntag.map(id => this.dnTagMap[id] || 未知標籤(${id}) ); } else { this.currentDnTags = []; } this.saveState(); alert('醫案提交成功!'); } else { throw new Error('提交失败'); } } catch (error) { console.error('Error:', error); alert(提交失败: ${error.message}); } }, async updateContent() { if (!this.submittedId || !this.$refs.mreditor1) return; const formData = this.$refs.mreditor1.getFormData(); const postData = { mrcase: this.content, ...formData }; try { const response = await fetch(MRInfo/${this.submittedId}/?format=json, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(postData), }); if (response.ok) { const data = await response.json(); // 更新病态名称显示 if (data.dntag && Array.isArray(data.dntag)) { this.currentDnTags = data.dntag.map(id => this.dnTagMap[id] || 未知標籤(${id}) ); } this.saveState(); alert('醫案更新成功!'); } else { throw new Error('更新失败'); } } catch (error) { console.error('Error:', error); alert(更新失败: ${error.message}); } }, async deleteContent() { if (!this.submittedId) return; if (!confirm('確定要刪除這個醫案嗎?')) return; try { const response = await fetch(MRInfo/${this.submittedId}/?format=json, { method: 'DELETE', headers: { 'Content-Type': 'application/json', } }); if (response.ok) { this.clearState(); this.resetAll(); alert('醫案刪除成功!'); } else { throw new Error('刪除失败'); } } catch (error) { console.error('Error:', error); alert(刪除失败: ${error.message}); } }, resetAll() { this.content = ''; this.submittedId = null; this.fetchId = null; this.showRawHtml = false; this.currentDnTags = []; // 重置病态名称 this.showDnCrud = false; // 隐藏病态编辑面板 if (this.$refs.mreditor1) { this.$refs.mreditor1.resetForm(); } this.clearState(); // 确保隐藏编辑面板 document.querySelector('.tag-panel').style.display = 'none'; } } }; </script> <style scoped> .wangeditor { flex: 1; padding: 10px; overflow-y: auto; } .right-panel { position: fixed; top: 55px; bottom: 45px; right: 0; width: 30%; background: lightblue; padding: 1px; z-index: 100; overflow-y: auto; } /* 病态名称显示样式 */ .dntag-display { display: flex; margin-top: 1px; padding: 10px; background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); } .field-name { font-weight: bold; min-width: 80px; color: #495057; font-size: 1rem; } .dntag-value { flex-grow: 1; color: #212529; font-weight: 500; padding-left: 10px; border-left: 2px solid #ffc107; } .tag-panel { position: fixed; top: 400px; bottom: 45px; right: 0; width: 30%; background: lightyellow; padding: 10px; z-index: 100; overflow-y: auto; display: none; /*默认隐藏 */ } .content-display { position: fixed; top: 490px; left: 0; width: 70%; bottom: 45px; z-index: 999; background-color: white; overflow-y: auto; padding: 10px; border: 1px solid #eee; white-space: pre-wrap; } .sticky-footer { display: flex; justify-content: flex-end; align-items: center; position: fixed; bottom: 0; left: 0; width: 100%; background-color: #ffd800ff; z-index: 999; padding: 10px 20px; box-sizing: border-box; flex-wrap: wrap; } .sticky-footer > span { margin-left: 5px; display: flex; align-items: center; } /* 新增病态编辑按钮样式 */ .dncrud-btn { background-color: #9c27b0; color: white; border: none; padding: 2px 8px; border-radius: 4px; cursor: pointer; margin-left: 10px; } .dncrud-btn:hover { background-color: #7b1fa2; } .submitted-id { padding: 2px; background-color: #e2f0fd; color: #004085; border-radius: 4px; } .reset-btn { margin-left: 10px; padding: 2px; background-color: #dc3545; border: none; color: white; border-radius: 4px; cursor: pointer; } .reset-btn:hover { background-color: #c82333; } .id-input { display: flex; align-items: center; } .id-input input { width: 100px; padding: 2px 5px; margin-right: 5px; border: 1px solid #ccc; border-radius: 4px; } .submit-btn { background-color: #28a745; color: white; border: none; padding: 2px 8px; border-radius: 4px; cursor: pointer; } .update-btn { background-color: #007bff; color: white; border: none; padding: 2px 8px; border-radius: 4px; cursor: pointer; } .delete-btn { background-color: #dc3545; color: white; border: none; padding: 2px 8px; border-radius: 4px; cursor: pointer; } .submit-btn:hover { background-color: #218838; } .update-btn:hover { background-color: #0069d9; } .delete-btn:hover { background-color: #c82333; } </style>

实现删除可单选、多选,传入两个参数 ts、uploadTime。<template> <el-form :inline="true" :model="dataForm" ref="dataForm" @keyup.enter.native="onSubmit(0)" style="height:108px;"> <el-form-item label="项目" prop="projectId" v-if="projectIdShow" style="margin-left: 0.05rem;"> <el-select v-model="dataForm.projectId" placeholder="请选择项目" > <el-option v-for="item in projectIds" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </el-form-item> <el-form-item label="设备编码" prop="deviceId"> <el-autocomplete style="width:3.3rem" size="normal" v-model="dataForm.deviceId" :popper-append-to-body="false" :fetch-suggestions="querySearchAsync" @select="handleSelect" placeholder="设备ID,如U231221040200001"> </el-autocomplete> </el-form-item> <el-form-item label="数据来源" prop="flag"> <el-select v-model="dataForm.flag" placeholder="请选择" clearable> <el-option v-for="item in flagIds" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </el-form-item> <el-form-item label="上报时间"> <el-date-picker v-model="dataForm.starttime" type="datetime" placeholder="选择起始时间" align="right" :picker-options="pickerOptions" clearable> </el-date-picker> 至 <el-date-picker v-model="dataForm.endtime" type="datetime" placeholder="选择结束时间" default-time="00:00:00" clearable> </el-date-picker> </el-form-item> <el-form-item label="SN码" prop="sn"> <el-input v-model="dataForm.sn" placeholder="输入sn码" clearable></el-input> </el-form-item> <el-form-item> <el-input v-model="dataForm.key" placeholder="其他参数名" clearable></el-input> </el-form-item> <el-form-item label="电池类型" style="margin-left: 0.25rem;"> <el-select v-model="dataForm.batteryKind" placeholder="电池类型" clearable style="width:1.5rem"> <el-option v-for="item in batteryKindOptions" :key="item.value" :label="item.label" :value="item.value" :disabled="item.disabled"> </el-option> </el-select> </el-form-item> <el-form-item> <el-button @click="onSubmit(0)" type="success" icon="el-icon-search">查询</el-button> <el-button @click="reset()" type="primary" icon="el-icon-refresh">重置</el-button> <el-button v-if="isAuth('maya:mybatteryinfo:delete')" type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button> <el-button v-if="isAuth('maya:mybatteryinfo:list')" type="info" @click="list2Export()">导出</el-button> </el-form-item> </el-form> <el-table :height="tableHeight" :data="dataList" border v-loading="dataListLoading" @selection-change="selectionChangeHandle" style="width: 100%;"> <el-table-column type="selection" header-align="center" align="center" width="50"> </el-table-column> <el-table-column prop="batteryId" header-align="center" align="center" label="设备编号" width="140"> </el-table-column> <el-table-column prop="sn" header-align="center" align="center" label="sn码" show-overflow-tooltip> </el-table-column> <el-table-column align="center" prop="batteryKind" label="电池类型"> <template slot-scope="scope"> <el-button class="custom-size-my" :stroke-width="5" :type="getBatteryKindStyle(scope.row.batteryKind)" size="mini" round > {{ getBatteryKindText(scope.row.batteryKind) }} </el-button> </template> </el-table-column> <el-table-column prop="ts" header-align="center" align="center" label="上报时间" width="140"> </el-table-column> <el-table-column prop="batteryVoltage" header-align="center" align="center" label="电压(mV)"> </el-table-column> <el-table-column prop="cellVoltage" header-align="center" align="center" label="电芯电压" show-overflow-tooltip> </el-table-column> <el-table-column prop="batteryCurrent" header-align="center" align="center" label="电流(mA)"> </el-table-column> <el-table-column prop="batterySoc" header-align="center" align="center" label="SOC(%)"> </el-table-column> <el-table-column prop="batteryHardVersion" header-align="center" align="center" label="硬件版本"> </el-table-column> <el-table-column prop="batterySoftVersion" header-align="center" align="center" label="软件版本" width="120"> </el-table-column> <el-table-column prop="batteryWorkModeValue" header-align="center" align="center" label="电池状态" width="140"> </el-table-column> <el-table-column prop="soh" header-align="center" align="center" label="SOH"> </el-table-column> <el-table-column prop="batteryTemperatureAvg" header-align="center" align="center" label="平均温度(℃)" width="100"> </el-table-column> <el-table-column prop="chargeMode" header-align="center" align="center" label="充电模式" :formatter = "chargeModeFormat" > </el-table-column> <el-table-column prop="lowBatteryWarn" header-align="center" align="center" label="低电量提示" width="100" :formatter = "lowBatteryWarnFormat" > </el-table-column> <el-table-column prop="chargeCurrentMax" header-align="center" align="center" label="最大充电电流(mA)" width="140"> </el-table-column> <el-table-column prop="dischargeCurrentMax" header-align="center" align="center" label="最大放电电流(mA)" width="140"> </el-table-column> <el-table-column prop="chargeCurrentAvg" header-align="center" align="center" label="平均充电电流(mA)" width="140"> </el-table-column> <el-table-column prop="dischargeCurrentAvg" header-align="center" align="center" label="平均放电电流(mA)" width="140"> </el-table-column> <el-table-column prop="batteryTemperatureMax" header-align="center" align="center" label="电芯最高温度(℃)" width="140"> </el-table-column> <el-table-column prop="batteryTemperatureMin" header-align="center" align="center" label="电芯最低温度(℃)" width="140"> </el-table-column> <el-table-column prop="batteryVoltageMax" header-align="center" align="center" label="电芯最高电压(mV)" width="140"> </el-table-column> <el-table-column prop="batteryVoltageMin" header-align="center" align="center" label="电芯最低电压(mV)" width="140"> </el-table-column> <el-table-column prop="batteryProtectCodeValue" header-align="center" align="center" label="保护状态"> </el-table-column> <el-table-column prop="batteryErrorCode" header-align="center" align="center" label="故障码" width="200"> </el-table-column> <el-table-column prop="mosStatusValue" header-align="center" align="center" label="MOS状态" show-overflow-tooltip> </el-table-column> <el-table-column prop="mosTemp" header-align="center" align="center" label="MOS温度(℃)" width="100"> </el-table-column> <el-table-column prop="batteryCycleTimes" header-align="center" align="center" label="循环次数"> </el-table-column> <el-table-column prop="steadyStatus" header-align="center" align="center" label="均衡状态"> </el-table-column> <el-table-column prop="imei" header-align="center" align="center" label="IMEI" width="140"> </el-table-column> <el-table-column prop="imsi" header-align="center" align="center" label="IMSI" width="140"> </el-table-column> <el-table-column prop="iccid" header-align="center" align="center" label="ICCID" width="160"> </el-table-column> <el-table-column prop="trackerSoftwareVersion" header-align="center" align="center" label="tracker软件版本" width="200"> </el-table-column> <el-table-column prop="locationMode" header-align="center" align="center" label="定位模式"> </el-table-column> <el-table-column prop="longitude" header-align="center" align="center" label="经度" width="140"> </el-table-column> <el-table-column prop="longitudeDirection" header-align="center" align="center" label="经度方向"> </el-table-column> <el-table-column prop="latitude" header-align="center" align="center" label="纬度" width="140"> </el-table-column> <el-table-column prop="latitudeDirection" header-align="center" align="center" label="纬度方向"> </el-table-column> <el-table-column prop="gpsCog" header-align="center" align="center" label="对地航向角(°)" width="120"> </el-table-column> <el-table-column prop="gpsSpeed" header-align="center" align="center" label="gps速度(Km/h)" width="120"> </el-table-column> <el-table-column prop="gpsSignal" header-align="center" align="center" label="gps信号强度" width="100"> </el-table-column> <el-table-column prop="satelliteNum" header-align="center" align="center" label="定位卫星数" width="100"> </el-table-column> <el-table-column prop="flag" header-align="center" align="center" label="数据来源" :formatter = "flagFormat"> </el-table-column> <el-table-column prop="createTime" header-align="center" align="center" label="创建时间" width="140"> </el-table-column> <el-table-column prop="updateTime" header-align="center" align="center" label="更新时间" width="140"> </el-table-column> <el-table-column prop="payload" header-align="center" align="center" label="原始数据" show-overflow-tooltip> </el-table-column> <el-table-column fixed="right" header-align="center" align="center" width="150" label="操作"> <template slot-scope="scope"> <el-button v-if="isAuth('maya:mybatteryinfo:update')" type="text" size="small" @click="addOrUpdateHandle(scope.row.ts,scope.row.batteryId)">修改</el-button> <el-button v-if="isAuth('maya:mybatteryinfo:delete')" type="text" size="small" @click="deleteHandle(scope.row.ts,scope.row.batteryId)">删除</el-button> </template> </el-table-column> </el-table> <el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100, 500]" :page-size="pageSize" :total="totalPage" layout="total, sizes, prev, pager, next, jumper"> </el-pagination> <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update> </template> <script> import AddOrUpdate from './mybatteryinfo-add-or-update' import { debounce } from '@/utils' // 表格滚动 export default { data () { return { clientHeight: document.documentElement.clientHeight, tableHeight:660,// 定义table高度 // 1:设备主动请求或上报 2:平台主动推送或下指令 3:平台指令反馈的结果 flagIds:[ { value: '1', label: '设备主动请求或上报' }, { value: '3', label: '平台指令反馈的结果' }], batteryKindOptions: [ { value: '0', label: '运营' },{ value: '1', label: '售后' },{ value: '2', label: '内测' },{ value: '3', label: '报废' },{ value: '5', label: '推广' },{ value: '6', label: '认证' },{ value: '4', label: '其他' }], dataForm: { sn: '', starttime: '', endtime: '', batteryKind: '', flag: '', deviceId: '', key: '', projectId: '' }, projectIdShow: true, snExportShow: false, projectIds:[], dataList: [], pageIndex: 1, pageSize: 20, totalPage: 0, dataListLoading: false, dataListSelections: [], addOrUpdateVisible: false, updateVisible: false, resultShowVisible: false, pickerOptions: { shortcuts: [{ text: '今天', onClick(picker) { picker.$emit('pick', new Date()); } }, { text: '昨天', onClick(picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24); picker.$emit('pick', date); } }, { text: '一周前', onClick(picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); picker.$emit('pick', date); } }, { text: '一个月前', onClick(picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24 * 30); picker.$emit('pick', date); } }, { text: '三个月前', onClick(picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24 * 90); picker.$emit('pick', date); } }] } } }, components: { AddOrUpdate }, activated () { this.getQueryMenus() this.getDataList() }, methods: { getQueryMenus () { this.$http({ url: this.$http.adornUrl(/battery/bmsbatteryinfo/getmenus), method: 'get', params: this.$http.adornParams() }).then(({data}) => { if (data && data.code === 0) { if(data.data.projectPerm===1){ this.dataForm.projectId = data.data.projectPermData //data.data.projectPerm this.projectIdShow = false // 这里只为马牙项目设置了导出功能,项目ID==38 if(data.data.projectPermData === 38 || data.data.projectPermData==='38' || data.data.projectPermData === 39 || data.data.projectPermData==='39' || data.data.projectPermData === 40 || data.data.projectPermData==='40'){ this.snExportShow = true }else{ this.snExportShow = false } }else{ this.dataForm.projectId = data.data.projectPermData //data.data.projectPerm this.projectIds = data.data.projectIds this.projectIdShow = true // 这里只为马牙项目设置了导出功能,项目ID==38 if(data.data.projectPermData === 38 || data.data.projectPermData==='38' || data.data.projectPermData === 39 || data.data.projectPermData==='39' || data.data.projectPermData === 40 || data.data.projectPermData==='40'){ this.snExportShow = true }else{ this.snExportShow = false } } if(this.dataForm.projectId === '' || this.dataForm.projectId === undefined || this.dataForm.projectId === null){ this.dataForm.projectId = 38; this.snExportShow = true } } }) }, getBatteryKindStyle(kind) { const styleMap = { 0: 'success', 1: 'warning', 2: 'primary', 3: 'danger' }; return styleMap[kind] || 'info'; }, getBatteryKindText(kind) { const map = { 0: '运营', 1: '售后', 2: '内测', 3: '报废', 5: '推广', 6: '认证', 4: '其他' }; return map[kind] || '未知类型'; }, stripTry() { this.$http({ url: this.$http.adornUrl('/battery/bmsbatteryinfo/list'), method: 'get', params: this.$http.adornParams({ 'key': this.dataForm.key, 'deviceId': this.dataForm.deviceId, 'starttime': this.dataForm.starttime, 'endtime': this.dataForm.endtime, 'batteryKind': this.dataForm.batteryKind, 'flag': this.dataForm.flag }) }).then(({data}) => { if (data && data.code === 0) { alert("data.code=="+data.code) } else { this.$message.error(data.msg) } }) }, formatJson(filterVal, jsonData) { return jsonData.map(v => filterVal.map(j => v[j])) }, // 导出当前列表 list2Export() { this.$confirm(确定对数据进行导出操作?, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$http({ url: this.$http.adornUrl('/maya/mybatteryinfo/list2Export'), method: 'get', params: this.$http.adornParams({ 'key': this.dataForm.key, 'deviceId': this.dataForm.deviceId, 'starttime': this.dataForm.starttime, 'endtime': this.dataForm.endtime, 'batteryKind': this.dataForm.batteryKind, 'sn': this.dataForm.sn, 'flag': this.dataForm.flag, 'projectId': this.dataForm.projectId }) }).then(({data}) => { if (data && data.code === 0) { this.exportList = data.data require.ensure([], () => { const { export_json_to_excel } = require('../../../vendor/Export2Excel') const tHeader = ['ID','设备ID','SN码','项目ID','IMEI','ICCID','IMSI','CSQ','经度标识','经度','纬度标识','纬度','GPS行驶速度(km/h)','对地航向角(°)','BMS软件版本号','tracker软件版本','信号强度','GPS定位卫星数','SOC(%)','循环次数','温度最高(电芯℃)','温度最低(电芯℃)','均衡状态','MOS温度(℃)','MOS状态','电池整包电压(mV)','电压最高(单节电芯mV)','电压最低(单节电芯mV)','全电芯电压(mV)','电池包状态','电流(mA)','上传时间','保护状态码','故障码','SOH','平均温度','充电模式(1标准充2快充3盲充)','低电量提示','最大充电电流','最大放电电流','平均充电电流','平均放电电流','原始数据','入库时间','更新时间']; const filterVal = ['id','batteryId','sn','projectId','imei','iccid','imsi','csq','longitudeDirection','longitude','latitudeDirection','latitude','gpsSpeed','gpsCog','batterySoftVersion','trackerSoftwareVersion','gpsSignal','satelliteNum','batterySoc','batteryCycleTimes','batteryTemperatureMax','batteryTemperatureMin','steadyStatus','mosTemp','mosStatus','batteryVoltage','batteryVoltageMax','batteryVoltageMin','cellVoltage','batteryWorkMode','batteryCurrent','ts','batteryProtectCode','batteryErrorCode','soh','batteryTemperatureAvg','chargeMode','lowBatteryWarn','chargeCurrentMax','dischargeCurrentMax','chargeCurrentAvg','dischargeCurrentAvg','payload','createTime','updateTime']; const list = this.exportList; const data = this.formatJson(filterVal,list); export_json_to_excel(tHeader, data, '马牙上报数据导出-('+this.dataForm.key+'_'+this.dataForm.starttime+'-'+this.dataForm.endtime+')'); }) } else { this.$message.error(data.msg) } }) }) }, // 充电模式 1--标准充;2--快充;3--盲充; chargeModeFormat (row, column) { console.log(row.chargeMode) if (row.chargeMode === 1) { return '标准充' } else if (row.chargeMode === 2) { return '快充' }else if (row.chargeMode === 3) { return '盲充' }else{ return '未知' } }, lowBatteryWarnFormat (row, column) { console.log(row.lowBatteryWarn) if (row.lowBatteryWarn === 1) { return '告警' } else{ return '否' } }, todoNowFormat (row, column) { console.log(row.todoNow) if (row.todoNow === 0) { return '否' } else if (row.todoNow === 1) { return '是' } }, handledFormat (row, column) { console.log(row.handled) if (row.handled === 0) { return '待处理' } else if (row.handled === 1) { return '已处理' //(发送Mqtt) } else if (row.handled === 2) { return '撤销' // (清空指令) } }, flagFormat (row, column) { console.log(row.flag) if (row.flag === 1) { return '设备上报' } else if (row.flag === 2) { return '平台指令' } }, reset(){ this.dataForm = { key: undefined, deviceId: undefined, batteryKind: undefined, starttime: undefined, endtime: undefined, flag: undefined, projectId: undefined, }; this.$refs["dataForm"].resetFields(); this.onSubmit(0) }, querySearchAsync(queryString, cb) { clearTimeout(1000); var results = [] if (queryString == '') { cb(results); } else { //掉接口需要的参数 this.$http({ url: this.$http.adornUrl('/mqtt/mqtttriad/getDeviceIds'), method: 'get', params: this.$http.adornParams({ 'deviceId': queryString, 'projectParameter': this.dataForm.projectParameter }) }).then(({data}) => { if (data && data.code === 0) { var result = data.data //循环放到一个远程搜索需要的数组 for (let i = 0; i < result.length; i++) { const element = result[i]; results.push({ value: element, id: i }) } cb(results); } else { console.log('没有数据的显示') results = [] cb(results); } }) } }, //点击出现搜索后点击的每一项 handleSelect(item) { this.id = item.id this.name = item.value }, onSubmit(pgindex) { if (pgindex==1) { this.getDataList() }else{ this.pageIndex = 1 this.getDataList() } }, // 获取数据列表 getDataList () { this.dataListLoading = true this.$http({ url: this.$http.adornUrl('/maya/mybatteryinfo/list'), method: 'get', params: this.$http.adornParams({ 'page': this.pageIndex, 'limit': this.pageSize, 'key': this.dataForm.key, 'batteryKind': this.dataForm.batteryKind, 'deviceId': this.dataForm.deviceId, 'starttime': this.dataForm.starttime, 'endtime': this.dataForm.endtime, 'sn': this.dataForm.sn, 'flag': this.dataForm.flag, 'projectId': this.dataForm.projectId }) }).then(({data}) => { if (data && data.code === 0) { this.dataList = data.page.list this.totalPage = data.page.totalCount } else { this.dataList = [] this.totalPage = 0 } this.dataListLoading = false }) }, // 每页数 sizeChangeHandle (val) { this.pageSize = val this.pageIndex = 1 this.getDataList() }, // 当前页 currentChangeHandle (val) { this.pageIndex = val this.getDataList() }, // 多选 selectionChangeHandle (val) { this.dataListSelections = val }, // 新增 / 修改 addOrUpdateHandle (ts,batteryId) { this.addOrUpdateVisible = true this.$nextTick(() => { this.$refs.addOrUpdate.init(ts,batteryId) }) }, // 删除 deleteHandle (ts,batteryId) { var ids = ts ? [ts] : this.dataListSelections.map(item => { return item.ts }) this.$confirm(确定对[id=${ids.join(',')}]进行[${ts ? '删除' : '批量删除'}]操作?, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$http({ url: this.$http.adornUrl('/maya/mybatteryinfo/delete'), method: 'post', data: this.$http.adornData(ids, false) }).then(({data}) => { if (data && data.code === 0) { this.$message({ message: '操作成功', type: 'success', duration: 1500, onClose: () => { this.getDataList() } }) } else { this.$message.error(data.msg) } }) }) } } } </script>

<template> <el-dialog :title="dialogMode === 'create' ? '新建' : dialogMode === 'edit' ? '修改' : '查看'" :visible.sync="dialogVisible" :modal-append-to-body="true" append-to-body :close-on-click-modal="false" custom-class="fixed-height-dialog" width="60%" top="5vh"> <el-form label-width="80px" ref="formRef" :model="currentForm" style="height: 100%; display: flex; flex-direction: column;" :rules="rules"> <el-row :gutter="10"> <el-col :span="6"> <el-form-item size="mini" label="项目名称" prop="projectName"> <el-input v-model="currentForm.projectName" clearable style="width:100%" size="mini" :disabled="dialogMode === 'view'"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item size="mini" label="项目编号" prop="projectCode"> <el-input v-model="currentForm.projectCode" clearable style="width:100%" size="mini" :disabled="dialogMode === 'view'"></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item size="mini" label="项目周期" prop="projectDate"> <el-date-picker v-model="projectDate" range-separator="→" start-placeholder="请选择开始日期" end-placeholder="请选择结束日期" type="daterange" size="mini" style="width: 100%;" unlink-panels :disabled="dialogMode === 'view'"> </el-date-picker> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="6"> <el-form-item label="负责人" size="mini" style="width: fit-content;"> <el-input v-model="currentForm.projectUser" clearable style="width:100%" size="mini" :disabled="dialogMode === 'view'"></el-input> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="项目概述"> <el-input v-model="currentForm.remark" :rows="2" :disabled="dialogMode === 'view'"></el-input> </el-form-item> </el-col> </el-row> <el-container style="height: 100%;"> <el-header style="height: auto; flex-shrink: 0; padding-bottom: 10px;"> <el-row :gutter="10" type="flex" class="searchDialog"> <el-col :span="5"> <el-select v-model="filterForm.maintenanceCompanyName" placeholder="请选择管养单位" size="mini" clearable filterable @clear="resetSearch" :disabled="dialogMode === 'view'"> <el-option v-for="item in MaintenanceUnitoptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-col> <el-col :span="5"> <el-select v-model="filterForm.routeCode" placeholder="请选择路线编号" size="mini" clearable filterable @clear="resetSearch" :disabled="dialogMode === 'view'"> <el-option v-for="item in routeCodeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-col> <el-col :span="5"> <el-input v-model="filterForm.searchKey" placeholder="请输入边坡编号或名称" size="mini" clearable @keyup.enter.native="searchForm" @clear="resetSearch" :disabled="dialogMode === 'view'"> </el-input> </el-col> <el-col :span="5"> <el-select v-model="filterForm.evaluateLevel" placeholder="请选择技术状态等级" size="mini" clearable @clear="resetSearch" :disabled="dialogMode === 'view'"> <el-option v-for="item in evaluateLeveloptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-col> <el-col :span="2" :offset="4"> <el-button type="primary" size="mini" style="width:100%" icon="el-icon-search" @click="searchForm" :loading="loading" :disabled="dialogMode === 'view'">搜索</el-button> </el-col> </el-row> </el-header> <el-main style="overflow-y: hidden;"> <el-table ref="scrollTable" v-loading="loading" style="width: 100%;" border :data="formTabledata" :row-style="{ height: '36px' }" :cell-style="{ padding: '4px 0', textAlign: 'center' }" :header-cell-style="{ height: '36px', padding: '4px 0', lineHeight: '36px', textAlign: 'center' }" @selection-change="handleSelectionChange" :row-key="getRowkey"> <el-table-column type="selection" width="55" :selectable="isRowSelectable" :reserve-selection="true"> </el-table-column> <el-table-column label="管养单位" prop="maintenanceCompanyName" width="290" show-overflow-tooltip></el-table-column> <el-table-column label="路线编号" prop="routeCode" width="100"></el-table-column> <el-table-column label="边坡编号" prop="sideSlopeCode" width="240" show-overflow-tooltip></el-table-column> <el-table-column label="边坡名称" prop="sideSlopeName" width="267" show-overflow-tooltip></el-table-column> <el-table-column label="技术状态等级" width="137"> <template slot-scope="scope"> {{ mapEvaluateLevel(scope.row.evaluateLevel) }} </template> </el-table-column> </el-table> </el-main> <el-footer style="flex-shrink: 0; padding-top: 10px;"> <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageParams.pageNo" :page-sizes="[10, 20, 50, 100]" :page-size="pageParams.pageSize" layout="total, prev, pager, next" :total="total"> </el-pagination> </el-footer> </el-container> </el-form> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="submitForm">提交</el-button> </el-dialog> </template> <script> import { mapCfg } from "@/utils"; import { getPeriodicInspectionSideSlopePageList, addPeriodicInspection, modifyPeriodicInspection, getSelectedPeriodicInspectionSideSlopeList } from "../../api/testProject"; import { getMaintenanceCompanyList, getRouteList } from "../../api/basicInformation"; export default { name: "SideSlopeDialog", props: { visible: Boolean, // 控制弹窗显示 mode: String, // 模式:create/edit/view initialForm: Object, // 初始表单数据 }, data() { return { isInitializingSelection: false, // 初始化状态标志 dialogVisible: this.visible, // 弹窗显示状态 dialogMode: this.mode, // 当前模式 currentForm: { ...this.initialForm }, // 当前表单数据 projectDate: [], // 项目日期范围 total: 0, // 总数据量 loading: false, // 加载状态 pageParams: { // 分页参数 pageNo: 1, pageSize: 10, }, filterForm: { // 搜索条件 maintenanceCompanyName: "", routeCode: "", searchKey: "", evaluateLevel: "", }, mulitipleSelection: [], allSelection: new Map(), MaintenanceUnitoptions: [], // 管养单位选项 routeCodeOptions: [], // 路线编号选项 formTabledata: [], // 表格数据 evaluateLeveloptions: [], // 技术状态等级选项 rules: { // 表单验证规则 projectName: [ { required: true, message: "项目名称不能为空", trigger: "blur" }, ], projectCode: [ { required: true, message: "项目编码不能为空", trigger: "blur" }, ], }, }; }, watch: { // 修复1:监听visible变化时确保加载数据 async visible(val) { this.dialogVisible = val; if (val) { // 打开对话框时重置状态 this.resetAllData(); // 关键修复:确保在创建模式外加载数据 if (this.dialogMode !== 'create' && this.currentForm.id) { // 确保在DOM更新后加载数据 await this.$nextTick(); await this.LoadListData(); } } else { // 关闭对话框时重置数据 this.resetAllData(); } }, // 修复2:监听模式变化 mode(val) { this.dialogMode = val; // 当模式从创建变为编辑/查看时,确保加载数据 if (this.dialogVisible && val !== 'create' && this.currentForm.id) { this.LoadListData(); } }, // 修复3:监听初始表单数据变化 initialForm: { deep: true, immediate: true, // 添加立即执行 async handler(val) { this.currentForm = { ...val }; this.projectDate = [val.projectStartDate, val.projectEndDate]; // 关键修复:当初始表单有ID时立即加载数据 if (this.dialogVisible && val.id && this.dialogMode !== 'create') { await this.$nextTick(); await this.LoadListData(); } } }, // 同步弹窗显示状态到父组件 dialogVisible(val) { this.$emit("update:visible", val); }, projectDate: { deep: true, handler(value) { if (value && value.length === 2) { this.currentForm.projectStartDate = value[0]; this.currentForm.projectEndDate = value[1]; } }, }, }, async created() { // 初始化数据 this.getRouteList(); await this.getEvaluateLevel(); this.getMaintenanceCompanyList(); }, methods: { handleSelectionChange(selection) { // 跳过初始化阶段的选中状态变更 if (this.isInitializingSelection) return; // 获取当前页选中项的key集合 const currentPageKeys = new Set( selection.map(row => row.sideSlopeUniqueCode) ); // 处理当前页的取消选中操作 this.formTabledata.forEach(row => { const key = row.sideSlopeUniqueCode; // 仅当行在全局选中池中但不在当前页选中集合时删除 if (this.allSelection.has(key) && !currentPageKeys.has(key)) { this.allSelection.delete(key); } }); // 添加新选中的项到全局池 selection.forEach(row => { const key = row.sideSlopeUniqueCode; if (!this.allSelection.has(key)) { this.allSelection.set(key, row); } }); // 更新当前页选中引用 this.mulitipleSelection = selection; }, getRowkey(row) { return row.sideSlopeUniqueCode; }, // 判断行是否可选(查看模式禁用选择) isRowSelectable(row, index) { return this.dialogMode !== "view"; }, // 获取管养单位列表 async getMaintenanceCompanyList() { const res = await getMaintenanceCompanyList(); this.MaintenanceUnitoptions = res.map((item) => ({ value: item, label: item, })); }, // 获取路线列表 async getRouteList() { const res = await getRouteList(); this.routeCodeOptions = res.map((item) => ({ value: item.id, label: item.routeCode, })); }, // 搜索方法 searchForm() { // this.showSelectedOnly = false, this.pageParams.pageNo = 1; this.LoadListData(); }, // 重置搜索条件 resetSearch() { // this.showSelectedOnly = true, this.filterForm = { maintenanceCompanyName: "", routeCode: "", searchKey: "", evaluateLevel: "", }; this.pageParams.pageNo = 1; this.LoadListData(); }, // 重置组件状态 resetAllData() { this.resetSelection(); this.formTabledata = []; // 清空表格数据 this.total = 0; // 重置总条数 this.pageParams = { // 重置分页 pageNo: 1, pageSize: 10 }; // 重置搜索条件(可选) this.filterForm = { maintenanceCompanyName: "", routeCode: "", searchKey: "", evaluateLevel: "" }; }, // 修改原有方法 resetSelection() { this.allSelection.clear(); this.allSelection = new Map(); if (this.$refs.scrollTable) { this.$refs.scrollTable.clearSelection(); } }, // 映射技术状态等级 mapEvaluateLevel(level) { const option = this.evaluateLeveloptions.find( (item) => item.value === level ); return option.label; }, // 加载表格数据 async LoadListData() { this.loading = true; try { const params = { orgId: this.filterForm.maintenanceCompanyName, routeId: this.filterForm.routeCode, searchKey: this.filterForm.searchKey, evaluateLevel: this.filterForm.evaluateLevel, pageSize: this.pageParams.pageSize, pageNo: this.pageParams.pageNo, }; // 获取表格数据 const res = await getPeriodicInspectionSideSlopePageList(params); this.formTabledata = res.entities; this.total = res.entityCount; // 处理非创建模式的数据加载 if (this.dialogMode !== 'create' && this.currentForm.id) { // 首次加载时获取所有选中项 if (this.pageParams.pageNo === 1) { const selected = await getSelectedPeriodicInspectionSideSlopeList({ periodicId: this.currentForm.id, pageSize: 10000, // 获取所有选中项 pageNo: 1 }); // 重置全局选中池 this.allSelection.clear(); this.mulitipleSelection = selected.entities; // 存储全局选中状态 this.mulitipleSelection.forEach(item => { this.allSelection.set(item.sideSlopeUniqueCode, item); }); } // 设置当前页选中状态 this.isInitializingSelection = true; this.$nextTick(() => { this.formTabledata.forEach(row => { if (this.allSelection.has(row.sideSlopeUniqueCode)) { this.$refs.scrollTable.toggleRowSelection(row, true); } }); this.isInitializingSelection = false; }); } } catch (error) { console.error("加载数据失败:", error); this.$message.error("加载数据失败"); } finally { this.loading = false; } }, // 分页大小变化 handleSizeChange(val) { this.pageParams.pageSize = val; this.pageParams.pageNo = 1; this.LoadListData(); }, // 当前页码变化 handleCurrentChange(val) { this.pageParams.pageNo = val; this.LoadListData(); }, // 获取技术状态等级选项 async getEvaluateLevel() { const levelList = await mapCfg("Inspection.Regular.RegularEvaluateLevel")(); this.evaluateLeveloptions = levelList.map((item) => ({ value: item.key, label: item.value, })); }, // 提交表单 async submitForm() { this.$refs.formRef.validate(async (valid) => { if (valid) { // 验证是否选择了边坡 const selectedItems = Array.from(this.allSelection.values()); if (this.allSelection.size === 0) { this.$message.warning("请至少选择一个边坡"); return; } // 构造提交参数 const params = { ...this.currentForm, sideSlopeDetailList: selectedItems.map(item => ({ sideSlopeUniqueCode: item.sideSlopeUniqueCode, evaluateLevel: item.evaluateLevel, evaluateDate: item.evaluateDate || undefined })), }; // 根据模式选择操作 const action = this.dialogMode === "create" ? addPeriodicInspection : modifyPeriodicInspection; // 执行操作 try { const success = await action(params); if (success) { this.$message.success( this.dialogMode === "create" ? "新建成功" : "修改成功" ); this.$refs.scrollTable.clearSelection(); this.$emit("success"); this.dialogVisible = false; } else { this.$message.error("操作失败"); } } catch (error) { this.$message.error(error.message || "操作失败"); } } }); } }, }; </script> <style lang="scss" scoped> /* 修复1:弹性容器最小高度约束 */ :deep(.fixed-height-dialog), .formBorder2, .formBorder2 .el-container, .formBorder2 .el-main { min-height: 0 !important; } /* 表格行高优化 */ :deep(.el-table) { .el-table__row { height: 36px !important; td { padding: 4px 0 !important; } } .el-table__header { th { padding: 4px 0 !important; .cell { line-height: 28px !important; } } } /* 确保内部滚动 */ .el-table__body-wrapper { overflow-y: auto !important; max-height: calc(100vh - 400px) !important; } } /* 表单区域固定 */ .formBorder { position: relative; ///为伪元素提供定位上下文 border: thin dotted black !important; padding: 10px !important; margin-top: 15px !important; flex-shrink: 0 !important; height: auto !important; overflow: visible !important; margin-bottom: 15px !important; /* 边框的文字 */ &::before { content: "项目信息"; position: absolute; top: -8px; //调整到更合适的位置 left: 15px; //向右移动避免遮挡 background-color: #fff; //背景色需与页面背景一致 padding: 0 8px; font-size: 13px; color: #606266; z-index: 10; //提高层级确保显示 font-weight: 500; //加粗文字 pointer-events: none; //防止点击穿透 } } .formBorder2 { position: relative; border: thin dotted black; padding: 10px; flex: 1; min-height: 0; overflow: hidden; // 保留 display: flex; flex-direction: column; margin-top: 15px; &::before { content: "待检边坡"; position: absolute; top: -8px; //调整到更合适的位置 left: 15px; //向右移动避免遮挡 background-color: #fff; //背景色需与页面背景一致 padding: 0 8px; font-size: 13px; color: #606266; z-index: 10; //提高层级确保显示 font-weight: 500; //加粗文字 pointer-events: none; //防止点击穿透 } .el-container { height: auto !important; // 覆盖行内样式 flex: 1; // 填满剩余空间 display: flex; flex-direction: column; min-height: 0; .el-header { flex-shrink: 0; height: auto !important; padding-bottom: 10px; } .el-main { flex: 1; overflow: hidden; position: relative; padding: 0; } .el-footer { flex-shrink: 0; padding-top: 10px; } } } // 弹窗底部按钮区域 .dialog-footer { padding: 10px 20px; border-top: 1px solid #ebeef5; text-align: center; } // 搜索区域样式 .searchDialog { margin-top: 5px; } // 空数据样式 :deep(.el-table__empty-block) { min-height: 200px; display: flex; justify-content: center; align-items: center; } // 分页样式 :deep(.el-pagination) { padding: 5px 0; } // 表格高度控制 :deep(.el-table) { height: 100% !important; .el-table__body-wrapper { overflow-y: auto !important; } } </style>为什么待检边坡有一半被margin-top遮住了

<template class> <el-form ref="form" :model="loginform" label-width="60px" label-position="left" > <el-form-item label="用户名"> <el-input v-model="loginform.userName" label="left"></el-input> </el-form-item> <el-form-item label="密码" style="left: 0%"> <el-input v-model="loginform.pwd"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="submit()">登录</el-button> <el-button type="primary" @click="dialogFormVisible = true" >注册</el-button > <el-button style="text-align: center">取消</el-button> </el-form-item> </el-form> <el-dialog title="" :visible.sync="dialogFormVisible" append-to-body width="30%" class="registerStyle" custom-class="no-header-dialog" > <el-form :model="form" label-position="left" :rules="registerRules" ref="registerRef" > <el-form-item label="用户名" prop="userName"> <el-input v-model="form.userName" autocomplete="off" style="width: 200px; float: left" ></el-input> </el-form-item> <el-form-item prop="nickName"> <template #label>      </template> <el-input v-model="form.nickName" autocomplete="off" style="width: 200px; float: left" ></el-input> </el-form-item> <el-form-item prop="pwd"> <template #label>      </template> <el-input v-model="form.pwd" autocomplete="off" style="width: 200px; float: left" ></el-input> </el-form-item> <el-form-item label="手机号" prop="phoneCode"> <el-input v-model="form.phoneCode" autocomplete="off" style="width: 200px; float: left" ></el-input> </el-form-item> <el-form-item> <template #label>      </template> <el-upload class="avatar-uploader" action="http://localhost:8081/file/upload" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" style="width: 200px; float: left" > </el-upload> </el-form-item> <el-form-item prop="roleId"> <template #label>      </template> <el-radio-group v-model="form.roleId" style="width: 300px; float: left" > <el-radio-button label="1">管理员</el-radio-button> <el-radio-button label="2">用户</el-radio-button> <el-radio-button label="3">教练</el-radio-button> </el-radio-group> </el-form-item> <el-form-item style="float: center"> <el-button type="primary" @click="register()">注册</el-button> <el-button @click="resetForm('form')">重置</el-button> </el-form-item> </el-form> </el-dialog> </template> <script> import { login } from "@/api/Login"; import { register } from "@/api/Login"; export default { name: "LoginView", data() { return { pic: "", formLabelWidth: "150px", dialogFormVisible: false, form: { roleId: 2, }, loginform: { userName: "", pwd: "", }, registerRules: { userName: [ { required: true, message: "请输入活动名称", trigger: "blur" }, { min: 6, max: 10, message: "长度在 6 到 10 个字符", trigger: "blur", }, ], nickName: [ { required: true, message: "请输入昵称", trigger: "blur" }, { min: 1, max: 6, message: "长度在 1 到 6 个字符", trigger: "blur" }, ], pwd: [ { required: true, message: "请输入密码", trigger: "blur" }, { min: 6, max: 10, message: "长度在 6 到 10 个字符", trigger: "blur", }, ], phoneCode: [ { required: true, message: "请输入手机号", trigger: "blur" }, { min: 11, max: 11, message: "请输入正确的手机号", trigger: "blur" }, ], roleId: [ { required: true, message: "请选择注册角色", trigger: "blur" }, ], }, }; }, methods: { //回显 handleAvatarSuccess(res, file) { console.log(res.data.url) this.pic = res.data.url; this.form.pic = res.data.url; }, //设置文件格式 beforeAvatarUpload(file) { const isLt2M = file.size / 1024 / 1024 < 10; if (!isLt2M) { this.$message.error("上传头像图片大小不能超过 2MB!"); } return isLt2M; }, //登录 submit() { login(this.loginform).then((resp) => { console.log(resp.data.data); if (resp.data.code == 200) { this.$message(resp.data.data.message); if (resp.data.data.user.roleId == 1) { this.$router.push("/admin"); } else if (resp.data.data.user.roleId == 2) { localStorage.setItem("userId", resp.data.data.user.id); this.$router.push("/user"); } else { this.$router.push("/coach"); } } else { console.log(resp.data.message); // location.reload(); } }); }, //注册 register() { register(this.form).then((resp) => { if (resp.data.code == 200) { this.$message.success(resp.data.message + "请登录"); this.dialogFormVisible = false; } else { this.$message.error(resp.data.message + "请重新输入"); this.$refs.registerRef.resetFields(); } }); }, //重置表单 resetForm() { this.$refs.registerRef.resetFields(); }, }, }; </script> <style> .avatar-uploader .el-upload { border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; position: relative; overflow: hidden; } .avatar-uploader .el-upload:hover { border-color: #409eff; } .avatar-uploader-icon { font-size: 28px; color: #8c939d; width: 178px; height: 178px; line-height: 178px; text-align: center; } .avatar { width: 178px; height: 178px; display: block; } .no-header-dialog .el-dialog__header { display: none; } .el-dialog .el-dialog__body { display: flex; justify-content: center; align-items: center; background: url("@/assets/register.jpg"); } .building { background: url("@/assets/login.jpg"); width: 100%; height: 100%; position: fixed; background-size: cover; opacity: 0.7; } .main { background: url("@/assets/login.jpg"); background-size: cover; /* 背景图片覆盖整个div */ background-repeat: no-repeat; /* 背景图片不重复 */ background-position: center; /* 背景图片居中显示 */ text-align: center; background-color: #fff; border-radius: 20px; width: 350px; height: 300px; margin: auto; position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; justify-content: center; align-items: center; } </style>上传成功后返回图片路径为http://localhost:8081/files/userPic/67944_div2.png

<template> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <el-form-item label="接收人" prop="receiverId"> <el-select v-model="queryParams.receiverId" placeholder="请选择" clearable filterable style="width: 150px"> <el-option v-for="user in userList" :key="user.id" :label="user.nickName" :value="user.id" /> </el-select> </el-form-item> <el-form-item label="发送时间" prop="createdAt"> <el-date-picker v-model="queryParams.createdAt" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd" /> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['mod:im_mes:add']">发起聊天</el-button> </el-form-item> </el-form> {{ currentUser.deptName }} {{ currentUser.nickName }} <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> 会话列表 {{ contact.nickName ? contact.nickName.substring(0, 1) : '' }} {{ contact.nickName }}({{ currentUser.dept.deptName }}) {{ contact.lastMsg }} {{ currentContact.nickName ? currentContact.nickName.substring(0, 1) : '' }} {{ currentContact.nickName }} {{ getContactName(message.senderId).substring(0, 1) }} {{ message.content }} <el-image :src="getFileUrl(message.content)" :preview-src-list="[getFileUrl(message.content)]" fit="cover" style="max-width: 200px; max-height: 200px; border-radius: 4px;"></el-image> {{ getFileName(message.content) }} {{ formatFileSize(message.fileSize) }} <el-button type="text" @click="downloadFile(message.content)" style="margin-left: 10px;">下载</el-button> {{ message.content }} {{ formatTime(message.createdAt) }} {{ currentUser.nickName.substring(0, 1) }} <el-upload :action="uploadFileUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :show-file-list="false" :headers="headers" :data="{ type: 'image' }"> <el-button size="mini" icon="el-icon-picture" title="上传图片"></el-button> </el-upload> <el-upload :action="uploadFileUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :show-file-list="false" :headers="headers" :data="{ type: 'video' }"> <el-button size="mini" icon="el-icon-video-camera" title="上传视频"></el-button> </el-upload> <el-upload :action="uploadFileUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :show-file-list="false" :headers="headers" :data="{ type: 'file' }"> <el-button size="mini" icon="el-icon-document" title="上传文件"></el-button> </el-upload> <el-input type="textarea" :rows="3" placeholder="请输入消息..." v-model="newMessage" @keydown.enter.native="sendMessage" resize="none"> </el-input> <el-button type="primary" size="small" @click="sendMessage">发送</el-button> 请选择左侧聊天/或在组织中选择人员聊天 <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body> <el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form-item label="接收人" prop="receiverId"> <el-select v-model="form.receiverId" placeholder="请选择接收人"> <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId"></el-option> </el-select> </el-form-item> <el-form-item label="内容" prop="content"> <el-input v-model="form.content" type="textarea" placeholder="请输入内容" /> </el-form-item> </el-form> <el-button type="primary" @click="submitForm">发送</el-button> <el-button @click="cancel">取消</el-button> </el-dialog> </template> <script> import { listIm_mes, addIm_mes, } from "@/im/sys/api/im_mes" import { getUserProfile, listUser } from "@/api/system/user" import { getToken } from "@/utils/auth" import store from "@/store" import dayjs from 'dayjs' export default { name: "Im_mes", data() { return { // 遮罩层 loading: true, // 选中数组 ids: [], // 非多个禁用 multiple: true, // 显示搜索条件 showSearch: false, // 总条数 total: 0, // 消息记录表格数据 im_mesList: [], // 弹出层标题 title: "", // 是否显示弹出层 open: false, // 查询参数 queryParams: { pageNum: 1, pageSize: 100, receiverId: null, senderId: null, createdAt: null, content: null, }, options: { img: store.getters.avatar, }, // 表单参数 form: {}, // 表单校验 rules: { receiverId: [{ required: true, message: "接收人不能为空", trigger: "blur" }], content: [{ required: true, message: "内容不能为空", trigger: "blur" }] }, // 聊天相关数据 userList: [], // 所有用户列表 contactList: [], // 联系人列表 activeContact: null, // 当前选中的联系人ID currentContact: {}, // 当前联系人信息 currentUser: { userId: store.getters.userId, nickName: store.getters.nickName, avatar: store.getters.avatar, deptName: store.getters.dept ? store.getters.dept.deptName : '未知部门' }, // 当前登录用户 newMessage: "", // 新消息内容 pollInterval: null, // 轮询定时器 // 文件上传相关 uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", headers: { Authorization: "Bearer " + getToken(), }, uploadingFile: null, // 正在上传的文件信息 } }, computed: { filteredMessages() { if (!this.activeContact || !this.currentUser.userId) return []; return this.im_mesList .filter(msg => { // 添加空值检查 if (!msg || !msg.senderId || !msg.receiverId) return false; return ( (msg.senderId === this.activeContact && msg.receiverId === this.currentUser.userId) || (msg.receiverId === this.activeContact && msg.senderId === this.currentUser.userId) ); }) .sort((a, b) => new Date(a.sendTime || a.createdAt) - new Date(b.sendTime || b.createdAt)); } }, created() { this.getCurrentUser(); this.getUserList(); this.getList(); // 启动轮询,每5秒获取一次新消息 this.pollInterval = setInterval(() => { this.getList(); }, 500000); }, beforeDestroy() { // 组件销毁前清除定时器 if (this.pollInterval) { clearInterval(this.pollInterval); } }, watch: { // 当消息列表更新时,自动滚动到底部 filteredMessages: { handler() { this.$nextTick(() => { this.scrollToBottom(); }); }, deep: true } }, methods: { /** 时间格式处理 */ formatTime(time) { return dayjs(time).format('YYYY-MM-DD HH:mm:ss') }, /** 格式化显示时间(用于联系人列表) */ formatDisplayTime(time) { if (!time) return ''; const now = dayjs(); const messageTime = dayjs(time); const diffDays = now.diff(messageTime, 'day'); if (diffDays === 0) { return messageTime.format('HH:mm'); } else if (diffDays === 1) { return '昨天'; } else if (diffDays < 7) { return ${diffDays}天前; } else { return messageTime.format('MM-DD'); } }, /** 格式化文件大小 */ formatFileSize(size) { if (!size) return '0 B'; const units = ['B', 'KB', 'MB', 'GB']; let index = 0; let fileSize = size; while (fileSize >= 1024 && index < units.length - 1) { fileSize /= 1024; index++; } return ${fileSize.toFixed(2)} ${units[index]}; }, /** 获取文件URL - 完整版本 */ getFileUrl(path) { if (!path) return ''; // 如果已经是完整URL,直接返回 if (path.startsWith('http') || path.startsWith('blob:')) return path; // 获取基础API URL(可能只是路径部分) const baseApi = process.env.VUE_APP_BASE_API || ''; // 如果baseApi已经是完整URL,直接拼接 if (baseApi.startsWith('http')) { const normalizedPath = path.startsWith('/') ? path : '/' + path; return baseApi + normalizedPath; } // 如果baseApi只是路径部分,需要拼接当前域名 const protocol = window.location.protocol; const hostname = window.location.hostname; const port = window.location.port ? :${window.location.port} : ''; // 构建完整的基础URL const fullBaseUrl = ${protocol}//${hostname}${port}${baseApi}; // 确保路径格式正确 const normalizedPath = path.startsWith('/') ? path : '/' + path; return fullBaseUrl + normalizedPath; }, /** 获取文件名 */ getFileName(path) { if (!path) return '未知文件'; return path.substring(path.lastIndexOf('/') + 1); }, /** 下载文件 */ downloadFile(path) { const link = document.createElement('a'); link.href = this.getFileUrl(path); link.download = this.getFileName(path); link.style.display = 'none'; document.body.appendChild(link); link.click(); document.body.removeChild(link); }, /** 上传前校验 */ handleBeforeUpload(file) { const fileType = file.type; const isImage = fileType.includes('image'); const isVideo = fileType.includes('video'); const isLt10M = file.size / 1024 / 1024 < 10; if (!isLt10M) { this.$modal.msgError('上传文件大小不能超过 10MB!'); return false; } // 保存当前上传的文件信息 this.uploadingFile = { name: file.name, size: file.size, type: isImage ? 2 : isVideo ? 3 : 4 }; return true; }, /** 上传成功处理 */ handleUploadSuccess(res, file) { if (res.code === 200) { // 自动发送文件消息 this.sendFileMessage(res.fileName, this.uploadingFile.type, this.uploadingFile.size); } else { this.$modal.msgError(res.msg || '上传失败'); } this.uploadingFile = null; }, /** 发送文件消息 */ sendFileMessage(fileName, mediaType, fileSize) { if (!this.activeContact) { this.$modal.msgWarning('请先选择联系人'); return; } const newMsg = { receiverId: this.activeContact, senderId: this.currentUser.userId, content: fileName, room: "default", type: 1, mediaType: mediaType, // 2:图片, 3:视频, 4:文件 fileSize: fileSize, status: 1, createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss'), }; addIm_mes(newMsg).then(response => { try { let responseData; if (response && typeof response === 'object') { responseData = response.data || response.result || response; } let messageToAdd; if (responseData && typeof responseData === 'object') { messageToAdd = { id: responseData.id || temp-${Date.now()}, receiverId: responseData.receiverId || this.activeContact, senderId: responseData.senderId || this.currentUser.userId, content: responseData.content || fileName, mediaType: responseData.mediaType || mediaType, fileSize: responseData.fileSize || fileSize, createdAt: responseData.createdAt || responseData.sendTime || newMsg.createdAt, ...responseData }; } else { messageToAdd = { id: temp-${Date.now()}, ...newMsg, isLocal: true }; } this.im_mesList.push(messageToAdd); // 更新联系人最后一条消息 const contact = this.contactList.find(c => c.id === this.activeContact); if (contact) { let lastMsg = ''; if (mediaType === 2) { lastMsg = '[图片]'; } else if (mediaType === 3) { lastMsg = '[视频]'; } else { lastMsg = '[文件] ' + this.getFileName(fileName); } contact.lastMsg = lastMsg; contact.time = this.formatDisplayTime(messageToAdd.createdAt); } this.$nextTick(() => { this.scrollToBottom(); }); } catch (error) { console.error('处理响应时出错:', error); this.$modal.msgError('处理消息时出错'); } }).catch(error => { console.error("发送失败:", error); this.$modal.msgError("发送失败"); }); }, /** 获取头像地址 */ getFullAvatarUrl(avatarPath) { if (!avatarPath) return ''; // 如果已经是完整URL,直接返回 if (avatarPath.startsWith('http')) return avatarPath; // 拼接基础URL(根据您的实际后端地址配置) return process.env.VUE_APP_BASE_API + avatarPath; }, /** 获取当前登录用户信息 */ getCurrentUser() { // 从store获取基本信息 this.currentUser = { userId: store.getters.userId, nickName: store.getters.nickName, avatar: store.getters.avatar, deptName: store.getters.dept ? store.getters.dept.deptName : '未知部门' }; // 如果需要更详细信息,可以调用API getUserProfile().then(response => { if (response.data) { this.currentUser = { ...this.currentUser, ...response.data, deptName: response.data.dept ? response.data.dept.deptName : '未知部门' }; } }).catch(error => { console.error('获取用户信息失败', error); }); }, /** 获取用户列表 */ getUserList() { listUser().then(response => { this.userList = response.rows; // 初始化联系人列表 this.initContactList(); }); }, /** 初始化联系人列表 */ initContactList() { // 从消息记录中提取联系人 const contactMap = {}; this.im_mesList.forEach(msg => { // 对方是发送人 if (msg.senderId !== this.currentUser.userId) { if (!contactMap[msg.senderId]) { const user = this.userList.find(u => u.userId === msg.senderId); contactMap[msg.senderId] = { id: msg.senderId, nickName: user ? user.nickName : '用户' + msg.senderId, avatar: user ? user.avatar : '', lastMsg: this.getLastMessagePreview(msg), time: this.formatTime(msg.createdAt, true) }; } } // 对方是接收人 if (msg.receiverId !== this.currentUser.userId) { if (!contactMap[msg.receiverId]) { const user = this.userList.find(u => u.userId === msg.receiverId); contactMap[msg.receiverId] = { id: msg.receiverId, nickName: user ? user.nickName : '用户' + msg.receiverId, avatar: user ? user.avatar : '', lastMsg: this.getLastMessagePreview(msg), time: this.formatTime(msg.createdAt, true) }; } } }); this.contactList = Object.values(contactMap); }, /** 获取最后一条消息预览 */ getLastMessagePreview(msg) { if (msg.mediaType === 2) { return '[图片]'; } else if (msg.mediaType === 3) { return '[视频]'; } else if (msg.mediaType === 4) { return '[文件] ' + this.getFileName(msg.content); } else { return msg.content; } }, /** 获取消息记录列表 - 优化版本 */ getList() { this.loading = true; listIm_mes(this.queryParams).then(response => { // 处理消息列表,确保文件路径正确 this.im_mesList = response.rows.map(msg => { // 如果是文件类型的消息,确保content字段是完整URL if (msg.mediaType && msg.mediaType !== "text" && msg.content) { console.log('原始content:', msg.content); console.log('VUE_APP_BASE_API:', process.env.VUE_APP_BASE_API); // 如果content不是完整URL,则转换为完整URL if (!msg.content.startsWith('http')) { msg.content = this.getFileUrl(msg.content); console.log('转换后content:', msg.content); } } return msg; }); this.total = response.total; this.loading = false; // 更新联系人列表 this.initContactList(); }).catch(() => { this.loading = false; }); }, // 取消按钮 cancel() { this.open = false; this.reset(); }, // 表单重置 reset() { this.form = { id: null, receiverId: null, senderId: this.currentUser.userId, content: null, createdAt: null, room: "default", type: 1, mediaType: 1, status: 1 }; this.resetForm("form"); }, /** 搜索按钮操作 */ handleQuery() { this.queryParams.pageNum = 1; this.getList(); }, /** 重置按钮操作 */ resetQuery() { this.resetForm("queryForm"); this.handleQuery(); }, // 多选框选中数据 handleSelectionChange(selection) { this.ids = selection.map(item => item.id); this.multiple = !selection.length; }, /** 新增按钮操作 */ handleAdd() { this.reset(); this.open = true; this.title = "发起聊天"; }, /** 提交按钮 */ submitForm() { this.$refs["form"].validate(valid => { if (valid) { this.form.senderId = this.currentUser.userId; this.form.createdAt = dayjs().format('YYYY-MM-DD HH:mm:ss'); addIm_mes(this.form).then(response => { this.$modal.msgSuccess("发送成功"); this.open = false; this.getList(); // 如果这是一个新的联系人,添加到联系人列表 if (!this.contactList.find(c => c.id === this.form.receiverId)) { const user = this.userList.find(u => u.userId === this.form.receiverId); if (user) { this.contactList.push({ id: user.userId, nickName: user.nickName, lastMsg: this.form.content, time: this.formatTime(new Date()) }); } } }); } }); }, // 聊天相关方法 selectContact(contact) { this.activeContact = contact.id; this.currentContact = contact; }, sendMessage() { if (!this.newMessage.trim() || !this.activeContact) return; const newMsg = { receiverId: this.activeContact, senderId: this.currentUser.userId, content: this.newMessage, room: "default", type: 1, mediaType: 1, fileSize: this.newMessage.length, status: 1, createdAt: dayjs().format('YYYY-MM-DD HH:mm:ss'), }; // 保存原始消息内容,以防需要回退 const originalMessage = this.newMessage; addIm_mes(newMsg).then(response => { try { // 处理API响应 let responseData; if (response && typeof response === 'object') { responseData = response.data || response.result || response; } let messageToAdd; if (responseData && typeof responseData === 'object') { // 使用服务器返回的数据 messageToAdd = { id: responseData.id || temp-${Date.now()}, receiverId: responseData.receiverId || this.activeContact, senderId: responseData.senderId || this.currentUser.userId, content: responseData.content || originalMessage, createdAt: responseData.createdAt || responseData.sendTime || newMsg.createdAt, ...responseData }; } else { // 创建本地消息 messageToAdd = { id: temp-${Date.now()}, ...newMsg, isLocal: true }; } // 添加到消息列表 this.im_mesList.push(messageToAdd); // 清空输入框 this.newMessage = ""; // 更新联系人最后一条消息 const contact = this.contactList.find(c => c.id === this.activeContact); if (contact) { contact.lastMsg = messageToAdd.content; contact.time = this.formatDisplayTime(messageToAdd.createdAt); } // 重新排序消息列表 this.im_mesList = [...this.im_mesList].sort((a, b) => new Date(a.createdAt || 0) - new Date(b.createdAt || 0) ); // 滚动到底部 this.$nextTick(() => { this.scrollToBottom(); }); } catch (error) { console.error('处理响应时出错:', error); this.$modal.msgError('处理消息时出错'); } }).catch(error => { console.error("发送失败:", error); this.$modal.msgError("发送失败"); // 即使API失败,也在本地显示消息 const localMessage = { id: temp-${Date.now()}, ...newMsg, isLocal: true, sendStatus: 'failed' }; this.im_mesList.push(localMessage); this.newMessage = ""; }); }, getContactName(contactId) { if (contactId === this.currentUser.userId) return this.currentUser.nickName; const contact = this.userList.find(c => c.userId === contactId); return contact ? contact.nickName : '用户' + contactId; }, scrollToBottom() { const container = this.$refs.messageContainer; if (container) { container.scrollTop = container.scrollHeight; } } } } </script> 以上若依前端代码只要getList后,消息窗口图片就显示为http://127.0.0.1/dev-api/profile/upload/2025/09/12/CN-wp6_20250912112412A010.jpg,正常上传图片或附件都能正常显示,是什么问题,请给出修改后的完整代码

<template> <side-slope-dialog :visible="dialogVisible" :mode="currentMode" :initial-form="currentForm" @update:visible="dialogVisible = $event" @success="handleDialogSuccess" /> <el-container style="height: 100%"> <el-header> <el-row :gutter="10" type="flex" justify="left"> <el-col :span="3"> <el-input v-model="searchParams.projectName" placeholder="项目名称或编号" size="mini" clearable @clear="resetSearch" /> </el-col> <el-col :span="3"> <el-select v-model="searchParams.status" placeholder="项目状态" size="mini" clearable @clear="resetSearch"> <el-option v-for="item in StatusOptions" :key="item.value" :label="item.label" :value="item.value" filterable /> </el-select> </el-col> <el-col :span="6"> <el-date-picker v-model="searchProjectDate" range-separator="→" start-placeholder="请选择开始日期" end-placeholder="请选择结束日期" type="daterange" size="mini" style="width: 100%" value-format="yyyy-MM-dd" @clear="resetSearch" /> </el-col> <el-col :span="1.5"> <el-button type="primary" size="mini" @click="handleSearch">查询</el-button> </el-col> <el-col :span="1.5"> <el-button type="success" size="mini" style="width: 100%" @click="openCreateDialog">新建</el-button> </el-col> </el-row> </el-header> <el-main> <el-table :data="tableData" border style="width: 100%" :main-height="400" :header-row-style="() => { return 'line-height:15px'; }" :cell-style="{ textAlign: 'center' }" :header-cell-style="{ textAlign: 'center' }"> <el-table-column label="序号" type="index" width="120"></el-table-column> <el-table-column label="项目名称" prop="projectName" width="250"></el-table-column> <el-table-column label="项目编号" prop="projectCode" width="150"></el-table-column> <el-table-column label="项目周期" width="250"> <template slot-scope="scope"> {{ formatDateRange(scope.row.projectStartDate, scope.row.projectEndDate) }} </template> </el-table-column> <el-table-column label="项目状态" width="200"> <template slot-scope="scope"> {{ getStatusText(scope.row.status) }} </template> </el-table-column> <el-table-column label="边坡总数" prop="sideSlopeTotalCount" width="150"></el-table-column> <el-table-column label="已完成边坡数" prop="sideSlopeCompleteCount" width="194"></el-table-column> <el-table-column label="完成率" width="150"> <template slot-scope="scope"> {{ calculateCompletionRate( scope.row.sideSlopeCompleteCount, scope.row.sideSlopeTotalCount ) }} </template> </el-table-column> <el-table-column label="操作" width="200"> <template slot-scope="scope"> <el-button @click="openViewDialog(scope.row)" type="text" size="small">查看</el-button> <el-button @click="openEditDialog(scope.row)" type="text" size="small">编辑</el-button> <el-button @click="deleteItem(scope.row)" type="text" size="small">删除</el-button> </template> </el-table-column> </el-table> </el-main> <el-footer> <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" layout="total,prev, sizes, pager, next,jumper" :current-page.sync="pageParams.pageNo" :page-size="pageParams.pageSize" :page-sizes="[10, 40, 60, 100]" :total="pageParams.total"> </el-pagination> </el-footer> </el-container> </template> <script> import sideSlopeDialog from './sideSlopeDialog.vue' import { mapCfg } from '@/utils' import { getPeriodicInspectionPageList, deletePeriodicInspection } from '../../api/testProject' export default { name: 'ProjectManagement', components: { sideSlopeDialog }, data() { return { searchParams: { projectName: '', status: '', projectStartDate: '', projectEndDate: '' }, searchProjectDate: [], StatusOptions: [], tableData: [], pageParams: { pageNo: 1, pageSize: 10, total: 0 }, dialogVisible: false, currentMode: 'create', currentForm: { projectCode: '', projectName: '', projectStartDate: '', projectEndDate: '', projectUser: '', remark: '', sideSlopeDetailList: [] } } }, watch: { searchProjectDate(newVal) { if (newVal && newVal.length === 2) { this.searchParams.projectStartDate = newVal[0] this.searchParams.projectEndDate = newVal[1] } else { this.searchParams.projectStartDate = '' this.searchParams.projectEndDate = '' } } }, async created() { await this.getStatus() this.loadTableData() }, methods: { getStatusText(statusValue) { const option = this.StatusOptions.find((opt) => opt.value === statusValue) return option ? option.label : '' }, openCreateDialog() { this.currentMode = 'create' this.currentForm = { projectCode: '', projectName: '', projectStartDate: '', projectEndDate: '', projectUser: '', remark: '', sideSlopeDetailList: [] } this.dialogVisible = true }, openEditDialog(row) { this.currentMode = 'edit' this.currentForm = { ...row, projectStartDate: row.projectStartDate, projectEndDate: row.projectEndDate } this.dialogVisible = true }, openViewDialog(row) { this.currentMode = 'view' this.currentForm = { ...row, projectStartDate: row.projectStartDate, projectEndDate: row.projectEndDate } this.dialogVisible = true }, handleDialogSuccess() { this.pageParams.pageNo = 1 this.loadTableData() }, async loadTableData() { const startTime = this.searchParams.projectStartDate ? new Date(this.searchParams.projectStartDate).getTime() : null const endTime = this.searchParams.projectEndDate ? new Date(this.searchParams.projectEndDate).getTime() : null const params = { pageNo: this.pageParams.pageNo, pageSize: this.pageParams.pageSize, searchKey: this.searchParams.projectName, status: this.searchParams.status, startTime, endTime } try { const res = await getPeriodicInspectionPageList(params) this.tableData = res.entities this.pageParams.total = res.entityCount } catch (error) { console.error('加载项目列表失败', error) } }, handleSearch() { this.pageParams.pageNo = 1 this.loadTableData() }, resetSearch() { this.searchParams = { projectName: '', status: '', projectStartDate: '', projectEndDate: '' } this.searchProjectDate = [] this.handleSearch() }, async deleteItem(row) { try { await this.$confirm('确定要删除该项目吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }) await deletePeriodicInspection({ periodicId: row.id }) this.$message.success('删除成功') if (this.tableData.length === 1 && this.pageParams.pageNo > 1) { this.pageParams.pageNo -= 1 } this.loadTableData() } catch (error) { if (error !== 'cancel') { this.$message.error('删除失败') } } }, async getStatus() { const dictList = await mapCfg('Inspection.Periodic.PeriodicInspectionStatus')() this.StatusOptions = dictList.map((item) => ({ value: item.key, label: item.value })) }, formatDateRange(start, end) { if (!start || !end) return '' const format = (dateStr) => dateStr.substring(0, 10) return ${format(start)} 至 ${format(end)} }, calculateCompletionRate(completed, total) { if (!total) return '0%' return ${((completed / total) * 100).toFixed(1)}% }, handleSizeChange(val) { this.pageParams.pageSize = val this.loadTableData() }, handleCurrentChange(val) { this.pageParams.pageNo = val this.loadTableData() } } } </script> <style lang="scss" scoped> .el-header { color: #333; text-align: center; line-height: 60px; } .el-main { color: #333; text-align: center; line-height: 100%; padding-left: 5px; padding-top: 0px; } .pagination { margin-top: 20px; text-align: center; } </style> <template> <el-dialog :title="dialogMode === 'create' ? '新建' : dialogMode === 'edit' ? '修改' : '查看'" :visible.sync="dialogVisible" :modal-append-to-body="true" append-to-body :close-on-click-modal="false" custom-class="fixed-height-dialog" width="60%" top="5vh"> <el-form label-width="80px" ref="formRef" :model="currentForm" style="height: 100%; display: flex; flex-direction: column;" :rules="rules"> <el-row :gutter="10"> <el-col :span="6"> <el-form-item size="mini" label="项目名称" prop="projectName"> <el-input v-model="currentForm.projectName" clearable style="width:100%" size="mini" :disabled="dialogMode === 'view'"></el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item size="mini" label="项目编号" prop="projectCode"> <el-input v-model="currentForm.projectCode" clearable style="width:100%" size="mini" :disabled="dialogMode === 'view'"></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item size="mini" label="项目周期" prop="projectDate"> <el-date-picker v-model="projectDate" range-separator="→" start-placeholder="请选择开始日期" end-placeholder="请选择结束日期" type="daterange" size="mini" style="width: 100%;" unlink-panels :disabled="dialogMode === 'view'"> </el-date-picker> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="6"> <el-form-item label="负责人" size="mini" style="width: fit-content;"> <el-input v-model="currentForm.projectUser" clearable style="width:100%" size="mini" :disabled="dialogMode === 'view'"></el-input> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="项目概述"> <el-input v-model="currentForm.remark" :rows="2" :disabled="dialogMode === 'view'"></el-input> </el-form-item> </el-col> </el-row> <el-container style="height: 100%; display: flex; flex-direction: column;"> <el-header style="height: auto; flex-shrink: 0; padding-bottom: 10px;"> <el-row :gutter="10" type="flex" class="searchDialog"> <el-col :span="5"> <el-select v-model="filterForm.maintenanceCompanyName" placeholder="请选择管养单位" size="mini" clearable filterable @clear="resetSearch" :disabled="dialogMode === 'view'"> <el-option v-for="item in MaintenanceUnitoptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-col> <el-col :span="5"> <el-select v-model="filterForm.routeCode" placeholder="请选择路线编号" size="mini" clearable filterable @clear="resetSearch" :disabled="dialogMode === 'view'"> <el-option v-for="item in routeCodeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option> </el-select> </el-col> <el-col :span="5"> <el-input v-model="filterForm.searchKey" placeholder="请输入边坡编号或名称" size="mini" clearable @keyup.enter.native="searchForm" @clear="resetSearch" :disabled="dialogMode === 'view'"> </el-input> </el-col> <el-col :span="5"> <el-select v-model="filterForm.evaluateLevel" placeholder="请选择技术状态等级" size="mini" clearable @clear="resetSearch" :disabled="dialogMode === 'view'"> <el-option v-for="item in evaluateLeveloptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-col> <el-col :span="2" :offset="4"> <el-button type="primary" size="mini" style="width:100%" icon="el-icon-search" @click="searchForm" :loading="loading" :disabled="dialogMode === 'view'">搜索</el-button> </el-col> </el-row> </el-header> <el-main style="flex: 1; overflow-y: auto; padding: 0;"> <el-table ref="scrollTable" v-loading="loading" style="width: 100%;" border :data="formTabledata" :height="tableHeight" :header-row-style="{ height: '40px' }" :header-cell-style="{ padding: '0', height: '40px', lineHeight: '40px', textAlign: 'center', }" :cell-style="{ textAlign: 'center' }" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55" :selectable="isRowSelectable"> </el-table-column> <el-table-column label="管养单位" prop="maintenanceCompanyName" width="290" show-overflow-tooltip></el-table-column> <el-table-column label="路线编号" prop="routeCode" width="100"></el-table-column> <el-table-column label="边坡编号" prop="sideSlopeCode" width="240" show-overflow-tooltip></el-table-column> <el-table-column label="边坡名称" prop="sideSlopeName" width="267" show-overflow-tooltip></el-table-column> <el-table-column label="技术状态等级" width="137"> <template slot-scope="scope"> {{ mapEvaluateLevel(scope.row.evaluateLevel) }} </template> </el-table-column> </el-table> </el-main> <el-footer style="flex-shrink: 0; padding-top: 10px;"> <el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageParams.pageNo" :page-sizes="[10, 20, 50, 100]" :page-size="pageParams.pageSize" layout="total, sizes, prev, pager, next" :total="total" :disabled="dialogMode === 'view'"> </el-pagination> </el-footer> </el-container> </el-form> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="submitForm">提交</el-button> </el-dialog> </template> <script> import { mapCfg } from "@/utils"; import { getPeriodicInspectionSideSlopePageList, addPeriodicInspection, modifyPeriodicInspection, } from "../../api/testProject"; import { getMaintenanceCompanyList, getRouteList } from "../../api/basicInformation"; export default { name: "SideSlopeDialog", props: { visible: Boolean, // 控制弹窗显示 mode: String, // 模式:create/edit/view initialForm: Object, // 初始表单数据 }, data() { return { mulitipleSelection:[], dialogVisible: this.visible, // 弹窗显示状态 dialogMode: this.mode, // 当前模式 currentForm: { ...this.initialForm }, // 当前表单数据 projectDate: [], // 项目日期范围 total: 0, // 总数据量 loading: false, // 加载状态 pageParams: { // 分页参数 pageNo: 1, pageSize: 10, }, filterForm: { // 搜索条件 maintenanceCompanyName: "", routeCode: "", searchKey: "", evaluateLevel: "", }, allSelection: [], MaintenanceUnitoptions: [], // 管养单位选项 routeCodeOptions: [], // 路线编号选项 formTabledata: [], // 表格数据 evaluateLeveloptions: [], // 技术状态等级选项 tableHeight: 200, // 表格高度 rules: { // 表单验证规则 projectName: [ { required: true, message: "项目名称不能为空", trigger: "blur" }, ], projectCode: [ { required: true, message: "项目编码不能为空", trigger: "blur" }, ], }, }; }, watch: { // 监听模式变化 mode(val) { this.dialogMode = val; if (val === "edit" && this.dialogVisible) { this.resetSearch(); } }, // 监听弹窗显示状态变化 visible(val) { this.dialogVisible = val; if (val) { this.resetSearch(); this.$nextTick(() => { this.calculateTableHeight(); }); } else { // 关闭弹窗时重置选择状态 this.resetSelection(); } }, // 同步弹窗显示状态到父组件 dialogVisible(val) { this.$emit("update:visible", val); }, // 监听初始表单数据变化 initialForm: { deep: true, handler(val) { this.currentForm = { ...val }; this.projectDate = val.projectStartDate && val.projectEndDate ? [val.projectStartDate, val.projectEndDate] : []; } }, // 处理日期范围变化 projectDate: { deep: true, handler(value) { if (value && value.length === 2) { this.currentForm.projectStartDate = value[0]; this.currentForm.projectEndDate = value[1]; } }, }, }, async created() { // 初始化数据 await this.getEvaluateLevel(); this.getMaintenanceCompanyList(); this.getRouteList(); this.LoadListData(); }, mounted() { // 计算表格高度并监听窗口变化 this.calculateTableHeight(); window.addEventListener("resize", this.calculateTableHeight); }, beforeDestroy() { // 移除事件监听 window.removeEventListener("resize", this.calculateTableHeight); }, methods: { // 判断行是否可选(查看模式禁用选择) isRowSelectable(row, index) { return this.dialogMode !== "view"; }, // 获取管养单位列表 async getMaintenanceCompanyList() { const res = await getMaintenanceCompanyList(); this.MaintenanceUnitoptions = res.map((item) => ({ value: item, label: item, })); }, // 获取路线列表 async getRouteList() { const res = await getRouteList(); this.routeCodeOptions = res.map((item) => ({ value: item.id, label: item.routeCode, })); }, // 搜索方法 searchForm() { this.pageParams.pageNo = 1; this.LoadListData(); }, // 重置搜索条件 resetSearch() { this.filterForm = { maintenanceCompanyName: "", routeCode: "", searchKey: "", evaluateLevel: "", }; this.pageParams.pageNo = 1; this.LoadListData(); }, // 重置选择状态 resetSelection() { this.allSelection = []; if (this.$refs.scrollTable) { this.$refs.scrollTable.clearSelection(); } }, // 处理选择变化 handleSelectionChange(val) { this.mulitipleSelection = val; console.log(this.mulitipleSelection) // 查看模式不允许修改选择 if (this.dialogMode === 'view') return; // 创建当前页选择的唯一标识集合 const currentPageSelections = new Set( val.map((item) => item.sideSlopeCode) ); // 更新全量选择:先移除当前页的数据,再添加新选择 this.allSelection = [ ...this.allSelection.filter( (item) => !currentPageSelections.has(item.sideSlopeCode) ), ...val, ]; }, // 映射技术状态等级 mapEvaluateLevel(level) { const option = this.evaluateLeveloptions.find( (item) => item.value === level ); return option .label ; }, // 加载表格数据 async LoadListData() { this.loading = true; const params = { orgId: this.filterForm.maintenanceCompanyName, routeId: this.filterForm.routeCode, searchKey: this.filterForm.searchKey, evaluateLevel: this.filterForm.evaluateLevel, pageSize: this.pageParams.pageSize, pageNo: this.pageParams.pageNo, }; try { const res = await getPeriodicInspectionSideSlopePageList(params); this.formTabledata = res.entities; this.total = res.entityCount; } catch (error) { console.error("加载边坡列表失败", error); } finally { this.loading = false; } }, // 分页大小变化 handleSizeChange(val) { this.pageParams.pageSize = val; this.pageParams.pageNo = 1; this.LoadListData(); }, // 当前页码变化 handleCurrentChange(val) { this.pageParams.pageNo = val; this.LoadListData(); }, // 获取技术状态等级选项 async getEvaluateLevel() { const levelList = await mapCfg("Inspection.Regular.RegularEvaluateLevel")(); this.evaluateLeveloptions = levelList.map((item) => ({ value: item.key, label: item.value, })); }, // 提交表单 async submitForm() { this.$refs.formRef.validate(async (valid) => { if (valid) { // 验证是否选择了边坡 if (this.allSelection.length === 0) { this.$message.warning("请至少选择一个边坡"); return; } // 构造提交参数 const params = { ...this.currentForm, sideSlopeDetailList: this.allSelection.map((item) => ({ sideSlopeUniqueCode: item.sideSlopeCode, evaluateLevel: item.evaluateLevel, evaluateDate: item.evaluateDate ? item.evaluateDate : undefined, })), }; // 根据模式选择操作 const action = this.dialogMode === "create" ? addPeriodicInspection : modifyPeriodicInspection; // 执行操作 const res = await action(params); if (res === true) { this.$message.success( this.dialogMode === "create" ? "新建成功" : "修改成功" ); this.$emit("success"); this.dialogVisible = false; } else { this.$message.error(res.message || "操作失败"); } } }); }, // 计算表格高度(自适应) calculateTableHeight() { this.$nextTick(() => { try { const dialogBody = document.querySelector( ".fixed-height-dialog .el-dialog__body" ); if (dialogBody) { const bodyHeight = dialogBody.clientHeight; const headerHeight = document.querySelector(".formBorder")?.offsetHeight || 0; const searchHeight = document.querySelector(".formBorder2 .el-header")?.offsetHeight || 0; const footerHeight = document.querySelector(".formBorder2 .el-footer")?.offsetHeight || 0; const padding = 30; // 安全边距 this.tableHeight = bodyHeight - headerHeight - searchHeight - footerHeight - padding; } } catch (e) { console.warn("高度计算错误", e); this.tableHeight = 300; // 默认高度 } }); }, }, }; </script> <style lang="scss" scoped> :deep(.fixed-height-dialog) { .el-dialog { display: flex; flex-direction: column; max-height: 80vh !important; height: 80vh !important; .el-dialog__body { flex: 1; overflow: hidden; padding: 15px 20px; display: flex; flex-direction: column; } } } // 项目信息区域样式 .formBorder { position: relative; border: thin dotted black; padding: 10px; flex-shrink: 0; &::before { content: "项目信息"; position: absolute; top: -10px; left: 40px; background-color: #fff; padding: 0 10px; font-size: 14px; color: #606266; } } // 待检边坡区域样式 .formBorder2 { margin-top: 15px; position: relative; border: thin dotted black; padding: 10px; flex: 1; min-height: 0; display: flex; flex-direction: column; &::before { content: "待检边坡"; position: absolute; top: -10px; left: 40px; background-color: #fff; padding: 0 10px; font-size: 14px; color: #606266; } } // 弹窗底部按钮区域 .dialog-footer { padding: 10px 20px; border-top: 1px solid #ebeef5; text-align: center; } // 搜索区域样式 .searchDialog { margin-top: 5px; } // 空数据样式 :deep(.el-table__empty-block) { min-height: 200px; display: flex; justify-content: center; align-items: center; } // 分页样式 :deep(.el-pagination) { padding: 5px 0; } </style> 取得已选择的定期检查边坡列表接口 【GET】/sshm/rest/periodicInspection/getSelectedPeriodicInspectionSideSlopeList 参数: periodicId------定期检查Id 修改和查看模式能够看到已经勾选的表格项 表格项的唯一id为 sideSlopeUniqueCode

<template> <el-card class="process-card"> 固定多图 <el-button type="text" class="delete-button" icon="el-icon-delete" @click="$emit('delete')"></el-button> <el-form ref="form" :model="formData" label-width="100px" :rules="rules" class="process-form-content"> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="排序:" prop="sortsNum"> <el-input-number v-model="formData.sortsNum" :min="1" :max="999999999"></el-input-number> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="8"> <el-form-item label="阶段时长:" prop="stageDuration"> <el-select v-model="formData.stageDuration" placeholder="请选择阶段时长"> <el-option v-for="i in 60" :key="i" :label="i" :value="i"></el-option> </el-select> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="阶段名称:" prop="stageName"> <el-input v-model="formData.stageName" placeholder="请输入阶段名称" maxlength="10" show-word-limit></el-input> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="阶段提醒:" prop="stageRemind"> <el-radio-group v-model="formData.stageRemind"> <el-radio label="0">阶段结束时需要弹框提醒</el-radio> <el-radio label="1">阶段结束时不作提醒</el-radio> </el-radio-group> </el-form-item> <el-form-item label="图片:" prop="imageCover"> <SuperReaderUpload :imgSize="30 * 1024 * 1024" :showTip="false" :isKbOrMb="300000" @handleSuccess="handlePicSuccess" @handleRemove="handlePicRemove" :fullUrl="true" :file-list="fileList" :limit="99" /> 支持jpg, jpeg, png格式,小于30MB,最多可上传99张图片 </el-form-item> </el-col> </el-row> </el-form> </el-card> </template> <script> import SuperReaderUpload from '@/components/Upload/SuperReaderUpload.vue'; export default { name: 'superReaderFixedManyImageComponent', components: { SuperReaderUpload }, props: { index: { type: Number, required: true } }, data() { return { rules: { stageDuration: [{ required: true, message: '请选择阶段时长', trigger: 'change' }], stageName: [{ required: true, message: '请输入阶段名称', trigger: 'blur' }], stageRemind: [{ required: true, message: '请选择阶段提醒方式', trigger: 'change' }], imageCover: [{ required: true, message: '请上传图片', trigger: 'change' }] }, fileList: [] // 上传图片已有图片列表 }; }, props: { formData: { type: Object, default: () => ({ stageDuration: '', stageName: '', stageRemind: '1', courseProcessFixedImgCoList: [] }) } }, watch: { formData: { handler(newVal) { this.$emit('update', newVal); }, deep: true } }, methods: { handlePicSuccess() { if(this.fileList.length > 0) { this.fileList.map((file)=>{ this.formData.courseProcessFixedImgCoList.push({imgCover:file.url}); }) } }, handlePicRemove() { this.formData.imageCover = ''; }, resetForm() { this.$refs.form.resetFields(); }, // 添加表单校验方法 validate() { return new Promise((resolve, reject) => { this.$refs.form.validate((valid) => { if (valid) { resolve(true); } else { reject(false); } }); }); } } }; </script> <style scoped> .process-card { margin-top: 10px; margin-bottom: 20px; border: 1px solid #dcdfe6; border-radius: 4px; } .card-header { display: flex; justify-content: space-between; align-items: center; padding: 0; } .card-title { display: flex; align-items: center; font-size: 14px; font-weight: bold; } .delete-button { padding: 0; font-size: 20px; color: #2a2a3b; } .process-form-content { padding: 0 20px 0 0; /* 调整内边距,减少右边距 */ } /* 修复/deep/选择器 */ :deep(.el-card__header) { padding: 5px 20px; } :deep(.el-form-item) { margin-bottom: 12px; } :deep(.el-select) { width: 100%; } </style> 这段代码在上传图片时就会报Cannot read properties of undefined (reading 'length') 这个错误是怎么回事?

<template> <eh-layout card full-content> <el-form :inline="true" :model="searchForm" label-width="80px" class="search-form" > <el-button class="custom-btn" @click="generateReport" :loading="loadingGenerate">核算</el-button> <el-select v-model="searchForm.type" placeholder="请选择查询类型" style="width: 140px;" clearable > <el-option label="加工单号" value="jgdh"></el-option> <el-option label="单据日期" value="documentDate"></el-option> <el-option label="产品名称" value="cpmc"></el-option> <el-option label="规格型号" value="ggxh"></el-option> <el-option label="高级查询" value="cpmcAndGgxh"></el-option> </el-select> <template v-if="searchForm.type === 'jgdh'"> <el-input v-model="searchForm.keyword" placeholder="请输入加工单号" style="width: 230px;" @keyup.enter.native="onSearch" /> </template> <template v-else-if="searchForm.type === 'documentDate'"> <el-date-picker v-model="searchForm.documentDate" type="date" placeholder="选择单据日期" value-format="yyyy-MM-dd" style="width: 230px;" @change="onSearch" /> </template> <template v-else-if="searchForm.type === 'cpmc'"> <el-input v-model="searchForm.cpmc" placeholder="请输入产品名称" style="width: 230px;" @keyup.enter.native="onSearch" clearable /> </template> <template v-else-if="searchForm.type === 'ggxh'"> <el-input v-model="searchForm.ggxh" placeholder="请输入规格型号" style="width: 230px;" @keyup.enter.native="onSearch" clearable /> </template> <template v-else-if="searchForm.type === 'cpmcAndGgxh'"> <el-input v-model="searchForm.keyword" placeholder="请输入加工单号" style="width: 230px;" @keyup.enter.native="onSearch" /> <el-input v-model="searchForm.cpmc" placeholder="请输入产品名称" style="width: 230px;" @keyup.enter.native="onSearch" clearable /> <el-input v-model="searchForm.ggxh" placeholder="请输入规格型号" style="width: 230px;" @keyup.enter.native="onSearch" clearable /> <el-date-picker v-model="searchForm.documentDate" type="date" placeholder="选择单据日期" value-format="yyyy-MM-dd" style="width: 230px;" @change="onSearch" /> </template> <el-button icon="el-icon-search" @click="onSearch" /> <el-button icon="el-icon-refresh-right" @click="resetSearch" /> </el-form> <el-table v-loading="loading" :data="tableData" style="width: 100%" row-key="header.id" :expand-row-keys="expandedRowKeys" @expand-change="handleExpandChange" border stripe > <el-table-column type="expand"> <template #default="props"> <el-table :data="props.row.mxList" border size="mini" style="width: 95%; margin: 0 auto" > <el-table-column prop="cbxm" label="成本项目" width="380" /> <el-table-column prop="zxwlmc" label="子项物料名称" width="389" /> <el-table-column prop="zxwlxhl" label="子项物料耗用量" width="400" align="right" /> <el-table-column prop="zxwlje" label="子项物料金额" width="400" align="right" /> </el-table> </template> </el-table-column> <el-table-column prop="header.jgdh" label="加工单号" width="250" sortable /> <el-table-column prop="header.cpmc" label="产品名称" width="250" /> <el-table-column prop="header.ggxh" label="规格型号" width="250" /> <el-table-column prop="header.dw" label="主单位" width="250" /> <el-table-column prop="header.rksl" label="入库数量(主单位)" width="200" align="right" /> <el-table-column prop="header.fdw" label="辅单位" width="250" /> <el-table-column prop="header.rkslfdw" label="入库数量(辅单位)" width="200" align="right" /> <el-table-column prop="header.zcb" label="总成本" width="207" align="right" /> <el-table-column prop="header.dwcb" label="单位成本(主单位)" width="150" align="right" /> <el-table-column prop="header.dwcbfdw" label="单位成本(辅单位)" width="150" align="right" /> <el-table-column prop="header.documentDate" label="单据日期" width="150" align="right"> <template #default="scope"> {{ formatDate(scope.row.header.documentDate) }} </template> </el-table-column> </el-table> <el-pagination background layout="prev, pager, next, sizes, total" :total="totalRecords" :page-size="pageSize" :current-page="currentPage" @size-change="handleSizeChange" @current-change="handlePageChange" /> </eh-layout> </template> <script> export default { name: 'WorkOrderPagination', data() { return { tableData: [], // 表格数据 totalRecords: 0, // 总记录数 currentPage: 1, // 当前页码 pageSize: 10, // 每页显示数量 expandedRowKeys: [], // 当前展开的行keys searchForm: { type: null, // 默认查询类型为空 keyword: '', // 查询关键词 documentDate: '', cpmc: '', ggxh: '' }, loading: false,//列表加载状态 loadingGenerate: false//核算按钮状态 }; }, mounted() { this.fetchData(); }, methods: { // 获取数据 async fetchData() { this.loading = true try { const params = { page: this.currentPage, pageSize: this.pageSize, cpmc: this.searchForm.cpmc?.trim() || '', // 始终传递,空则为空字符串 ggxh: this.searchForm.ggxh?.trim() || '' }; if (this.searchForm.jgdh) params.jgdh = this.searchForm.jgdh?.trim() || ''; if (this.searchForm.documentDate) params.documentDate = this.searchForm.documentDate; if (this.searchForm.cpmc) params.cpmc = this.searchForm.cpmc?.trim() || ''; if (this.searchForm.ggxh) params.ggxh = this.searchForm.ggxh?.trim() || ''; const response = await this.$http.post( 'uempCostRcbjsdController!findCostByCodeAndDateRange.m', params ); this.tableData = response.rows; this.totalRecords = parseInt(response.records); // 每次加载新数据时,清空展开的行 this.expandedRowKeys = []; } catch (error) { console.error('获取数据失败:', error); this.$message.error('数据加载失败'); } this.loading = false }, // 分页改变 handlePageChange(page) { this.currentPage = page; this.fetchData(); }, // 每页数量改变 handleSizeChange(size) { this.pageSize = size; this.currentPage = 1; this.fetchData(); }, // 格式化货币显示 formatCurrency(value) { if (!value) return '0.00'; const num = parseFloat(value); return num.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }, formatDate(timestamp) { if (!timestamp) return '--'; const date = new Date(timestamp); // 注意:JS 时间戳是毫秒,直接可用 const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始 const day = String(date.getDate()).padStart(2, '0'); return ${year}-${month}-${day}; }, // 处理展开行变化 handleExpandChange(row, expandedRows) { // 只保留当前展开的行 this.expandedRowKeys = expandedRows.length > 0 ? [row.header.id] : []; }, onSearch() { this.currentPage = 1 this.fetchData() }, // 重置方法 resetSearch() { this.searchForm = { type: null, // 重置为不选中任何选项 keyword: '', documentDate: '' }; this.currentPage = 1; this.fetchData(); // 重置后自动查询所有数据 }, // 核算 generateReport() { this.loadingGenerate = true this.$http .post('uempCostRcbjsdController!generateDailyCostReport.m') .then(response => { if (response.type === 'error') { this.$message.error(response.data || '操作失败'); } else if (response.type === 'warn' || response.type === 'warning') { this.$message.warning(response.data || '操作完成'); } else { this.$message.success(response.data || '核算成功,数据已刷新'); } }) .catch(error => { console.error('请求失败:', error); this.$message.error('网络错误,请检查连接或联系管理员'); }) .finally(() => { this.loadingGenerate = false; }); } } }; </script> <style scoped> /* 筛选*/ .search-form { display: flex; justify-content: flex-end; align-items: center; } .search-controls { display: flex; align-items: center; } .search-container { display: flex; align-items: center; gap: 10px; margin-left: 10px; } .custom-btn { background-color: #4068E0; border-color: #4068E0; color: #fff; border-radius: 18px; /* 圆角 */ } ::v-deep .el-table th, ::v-deep .el-table td { text-align: center !important; /* 水平居中 */ vertical-align: middle; /* 垂直居中(可选) */ height: 40px; padding: 6px 0; } /* 可选:让表头背景色更清晰 */ ::v-deep .el-table th.is-leaf, ::v-deep .el-table th > .cell { text-align: center !important; font-weight: 600; } </style> 能把这个组件改成使用 <eh-grid吗

最新推荐

recommend-type

学习一下二维码相关的,集成下 zxing.zip

学习一下二维码相关的,集成下 zxing.zip
recommend-type

生成二维码,可以带企业logo.zip

生成二维码,可以带企业logo.zip
recommend-type

Hyperledger Fabric v2与Accord Project Cicero智能合约开发指南

标题和描述中提到的“hlf-cicero-contract:Accord Project Cicero与Hyperledger Fabric v2签约”以及“半西约合同”暗示了与智能合约和区块链技术相关的知识点。下面详细说明这些知识点: ### 智能合约与区块链技术 智能合约是一套运行在区块链上的程序,当合约条款被触发时,合约会自动执行相应的操作。这种自动执行的特点使得智能合约特别适合于执行多方之间的可信交易,它能减少或消除中介服务的需要,从而降低交易成本并提高效率。 区块链技术是一种分布式账本技术,通过加密算法和共识机制保证了交易数据的不可篡改性和透明性。区块链上的每一笔交易都会被网络中的多个节点验证并记录,确保了交易记录的安全性。 ### Hyperledger Fabric v2 Hyperledger Fabric 是由Linux基金会托管的一个开源项目,它是企业级区块链框架,旨在为商业应用提供安全、模块化、可扩展的区块链平台。Hyperledger Fabric v2.2是该框架的一个版本。 Hyperledger Fabric v2支持链码(Chaincode)概念,链码是部署在Hyperledger Fabric网络上的应用程序,它可以被用来实现各种智能合约逻辑。链码在运行时与网络中的背书节点和排序服务交互,负责验证、执行交易以及维护账本状态。 ### Accord Project Cicero Accord Project Cicero 是一个开源的智能合同模板和执行引擎,它允许开发者使用自然语言来定义合同条款,并将这些合同转换为可以在区块链上执行的智能合约。CiceroMark是基于Markdown格式的一种扩展,它允许在文档中嵌入智能合约逻辑。 通过Accord Project Cicero,可以创建出易于理解、可执行的智能合约。这些合同可以与Hyperledger Fabric集成,利用其提供的安全、透明的区块链网络环境,从而使得合同条款的执行更加可靠。 ### 智能合约的安装与部署 描述中提到了“安装”和“启动”的步骤,这意味着为了使用HLF v2.2和Accord Project Cicero,需要先进行一系列的配置和安装工作。这通常包括设置环境变量(例如HLF_INSTALL_DIR)、安装区块链网络(Test-Net)以及安装其他必需的软件工具(如jq)。 jq是一个轻量级且灵活的命令行JSON处理器,常用于处理JSON数据。在区块链项目中,jq可以帮助开发者处理链码或智能合约的数据,特别是在与网络节点交互时。 ### JavaScript 标签 标签“JavaScript”表明本项目或相关文档中会涉及到JavaScript编程语言。Hyperledger Fabric v2支持多种智能合约语言,其中JavaScript是一个广泛使用的选项。JavaScript在编写链码时提供了灵活的语法和强大的库支持,是进行区块链开发的一个流行选择。 ### 文件结构 文件名称列表“hlf-cicero-contract-master”暗示这是一个包含所有相关文件和资源的项目源代码目录。这个名称通常表明开发者可以从该目录开始探索、安装和配置项目的所有组件。 ### 综合知识点 1. 智能合约与区块链技术可以自动化执行多方面可信交易,降低交易成本并提高效率。 2. Hyperledger Fabric v2为企业提供一个安全、模块化、可扩展的区块链平台。 3. Accord Project Cicero结合Markdown格式的CiceroMark,将自然语言定义的合同条款转换为可执行的智能合约。 4. 智能合约的安装和部署涉及到一系列配置步骤,包括设置环境变量、安装必要的软件工具等。 5. JavaScript是编写智能合约的流行语言之一,为区块链开发提供灵活性和强大的库支持。 6. 项目文件结构表明从一个主目录可以探索和配置所有项目相关文件和资源。 以上是根据文件标题、描述、标签以及文件名称列表所提取的相关知识点。这些知识点对于理解Hyperledger Fabric v2和Accord Project Cicero在智能合约中的应用尤为重要。
recommend-type

深度神经网络优化技巧全解析

# 深度神经网络优化技巧全解析 ## 1 超越 Sigmoid 函数 在神经网络中,Sigmoid 函数曾被广泛使用,但它存在一些问题,如梯度消失。研究人员一直在寻找更好的激活函数,且不同的激活函数在不同场景下表现各异。 ### 1.1 ReLU 函数登场 如今,修正线性单元(ReLU)成为了 Sigmoid 的常用替代函数。与 Sigmoid 相比,ReLU 非常简单,以下是其 Python 实现: ```python def relu(z): if z <= 0: return 0 else: return z ``` ReLU 由两段直
recommend-type

什么是噪声功率密度

<think> 嗯,用户这次问的是噪声功率密度的定义,结合之前的系统指令和站内引用,需要给出清晰准确的中文解释。用户可能是电子工程或通信专业的学生,正在学习噪声相关的理论基础,也可能是工程师需要实际应用概念。从引用来[^1]看,用户对相位噪声的定义有基础认知,但需要系统梳理核心概念。 噪声功率密度最本质的定义应该是单位带宽内的噪声功率。引用[^2]提到电阻热噪声的例子很典型,50Ω电阻在300K环境下功率谱密度是定值(0.9nV/√Hz)²,这说明: 1. 它描述的是噪声功率随频率分布的密度 2. 与带宽强相关(带宽加倍则总功率加倍) 3. 单位通常用W/Hz或V²/Hz 维纳-辛钦定理(
recommend-type

Libshare: Salesforce的高效可重用模块集合

Salesforce是一个云基础的CRM平台,它允许用户构建定制应用程序来满足特定的业务需求。Apex是Salesforce平台上的一个强类型编程语言,用于开发复杂的业务逻辑,通过触发器、类和组件等实现。这些组件使得开发者可以更高效地构建应用程序和扩展Salesforce的功能。 在提到的"libshare:经过测试的Salesforce可重用模块"文件中,首先介绍了一个名为Libshare的工具包。这个工具包包含了一系列已经过测试的可重用模块,旨在简化和加速Salesforce应用程序的开发。 Libshare的各个组成部分的知识点如下: 1. 设置模块:在Salesforce应用程序中,应用程序设置的管理是必不可少的一部分。设置模块提供了一种简便的方式存储应用程序的设置,并提供了一个易用的API来与之交互。这样,开发者可以轻松地为不同的环境配置相同的设置,并且可以快速地访问和修改这些配置。 2. Fluent断言模块:断言是单元测试中的关键组成部分,它们用于验证代码在特定条件下是否表现预期。Fluent断言模块受到Java世界中Assertj的启发,提供了一种更流畅的方式来编写断言。通过这种断言方式,可以编写更易于阅读和维护的测试代码,提高开发效率和测试质量。 3. 秒表模块:在性能调优和效率测试中,记录方法的执行时间是常见的需求。秒表模块为开发者提供了一种方便的方式来记录总时间,并跟踪每种方法所花费的时间。这使得开发者能够识别瓶颈并优化代码性能。 4. JsonMapper模块:随着Web API的广泛应用,JSON数据格式在应用程序开发中扮演了重要角色。JsonMapper模块为开发者提供了一个更高级别的抽象,用于读取和创建JSON内容。这能够大幅简化与JSON数据交互的代码,并提高开发效率。 5. utils模块:在软件开发过程中,经常会遇到需要重复实现一些功能的情况,这些功能可能是通用的,例如日期处理、字符串操作等。utils模块提供了一系列已经编写好的实用工具函数,可以用于节省时间,避免重复劳动,提高开发效率。 6. 记录器模块:记录器通常用于记录应用程序的运行日志,以便于问题诊断和性能监控。系统提供的System.debug功能虽然强大,但在大型应用中,统一的记录器包装器可以使得日志管理更加高效。记录器模块支持记录器名称,并且可以对日志进行适当的封装。 7. App Logger模块:App Logger模块扩展了记录器模块的功能,它允许开发者将日志语句保存到一个精心设计的App Log对象中。此外,App Logger模块支持存储长达56k字符的日志内容,这对于复杂应用的监控和调试非常有用。 8. 应用程序任务模块:在处理异步作业时,例如批量数据处理或定时任务,需要有一个框架来管理和跟踪这些任务。应用程序任务模块提供了一个框架,用于处理可排队的作业,并能够跟踪这些任务的执行情况。 通过Libshare提供的这些模块,Salesforce的开发者能够减少开发工作量,加快开发速度,并提高代码质量。这些模块能够帮助开发者避免重复的“造轮子”工作,专注于核心业务逻辑的实现。同时,由于Libshare作为托管程序包发布,开发者无需担心代码的维护和管理,只需将其添加到自己的Salesforce组织中即可使用。 Libshare的发布也强调了可重用性的重要性,这是软件工程领域中长期提倡的一个原则。通过使用可重用的组件,开发者能够遵循DRY(Don't Repeat Yourself)原则,从而减少代码的冗余,提高生产效率,同时降低因重复编写相同代码而导致错误的风险。 总之,Libshare是一个有价值的资源,对于那些希望在Salesforce平台上快速构建高效、可靠应用程序的开发者来说,这些预置的、经过测试的模块无疑是一个强大的助手。
recommend-type

机器学习技术要点与应用解析

# 机器学习技术要点与应用解析 ## 1. 机器学习基础概念 ### 1.1 数据类型与表示 在编程中,数据类型起着关键作用。Python 具有动态类型特性,允许变量在运行时改变类型。常见的数据类型转换函数包括 `bool()`、`int()`、`str()` 等。例如,`bool()` 函数可将值转换为布尔类型,`int()` 用于将值转换为整数类型。数据类型还包括列表(`lists`)、字典(`dictionaries`)、元组(`tuples`)等集合类型,其中列表使用方括号 `[]` 表示,字典使用花括号 `{}` 表示,元组使用圆括号 `()` 表示。 ### 1.2 变量与命名
recommend-type

点击歌曲没反应

<think> 我们之前已经讨论了如何将音频文件显示在QListView中,并希望实现点击播放。现在遇到的问题是点击列表项没有反应。 原因分析: 1. 我们没有将点击信号连接到播放槽函数。 2. 播放列表(QMediaPlaylist)可能没有正确添加媒体。 3. 媒体路径可能不正确。 解决方案: 按照之前的思路,我们需要做以下几步: 步骤1:确保已经创建了QMediaPlayer和QMediaPlaylist对象,并且播放器设置了播放列表。 步骤2:将QListView的点击信号(clicked)连接到自定义的槽函数,在该槽函数中设置播放列表的当前索引并播放。 步骤3:
recommend-type

SM-CNN-Torch: Torch实现短文本对排名的CNN模型

标题中提到的“SM-CNN-Torch”是一个深度学习框架Torch的实现版本,它基于Severyn和Moschitti在2015年SIGIR会议上发表的一篇论文所描述的卷积神经网络(CNN)模型。这篇论文的内容主要关注的是如何利用CNN对短文本对进行有效的排名,这一点对于问题回答(question-answering, QA)系统来说至关重要。实施该CNN模型的目标是为了更好地处理问答系统中的文本对比较问题,例如,在搜索引擎中确定哪些文档与用户的查询更加相关。 在描述中提到了如何使用该仓库中的代码。首先,用户需要安装Torch库,这是实现和运行SM-CNN-Torch模型的前提条件。接着,用户需要使用提供的脚本(fetch_and_preprocess.sh)下载并预处理GloVe(Global Vectors for Word Representation)字嵌入数据。这一数据集是预先训练好的词向量,能够将单词转换为连续的向量表示,这在深度学习模型中是处理文本的基本步骤。 在模型准备工作中,还需要注意的是Python版本,因为模型运行依赖于Python环境,建议的版本为2.7或更高版本。此外,描述中还提到了并行处理的线程数设置,这表明模型在运行过程中可能会涉及到并行计算,以加速计算过程。通过设置环境变量OMP_NUM_THREADS,可以指定并行计算时的线程数。 文件名称列表中的“SM-CNN-Torch-master”表示这是该仓库的主目录,包含了所有实现Severyn和Moschitti CNN模型的相关文件。 该存储库还包含了一些附加信息,例如,原始Torch实现已经被PyTorch版本所取代。PyTorch是Torch的一个分支,它提供了更多的功能和更易于使用的接口,对研究人员和开发者来说更加友好。此外,该仓库目前仅用于存档目的,这意味着原始的Torch代码不再被积极维护,而是作为一种历史记录保留下来。 标签“deep-learning”表明该项目是一个深度学习项目,所使用的模型是深度神经网络,特别是卷积神经网络。标签“question-answering”则直接指向了问题回答系统,这是深度学习的一个重要应用领域。标签“convolutional-neural-networks”指明了所使用的网络类型是卷积神经网络,它在图像处理和自然语言处理中都有广泛应用。而“Lua”标签则是因为Torch是用Lua语言编写的,尽管它通常与Python一起使用,但也有一个使用Lua的版本。 总的来说,SM-CNN-Torch是一个专门针对短文本对排名的深度学习模型的实现,它允许研究人员和开发者利用已经发表的研究成果来搭建和测试自己的模型,同时为了解其背后原理和实现细节提供了具体的代码和数据处理流程。
recommend-type

Python与机器学习基础入门

# Python与机器学习基础入门 ## 1. Python环境与包管理 ### 1.1 Anaconda与Miniconda Anaconda 功能丰富,自带集成开发环境(IDE)和独立于官方 Python 仓库的包仓库。若不需要这些额外功能,可选择安装 Miniconda,它仅包含 Conda 和 Python,安装包更小。 ### 1.2 Conda 与 pip 的对比 - **安装方式**:Conda 和 pip 在安装包时操作相似,例如使用 Conda 安装特定版本的 Keras 可使用命令 `conda install keras=2.2.4`。 - **功能特点**: