<firefox, ie9> table总是被里面的tree撑破,给div设定的大小无效

本文介绍了一个使用KendoUI Tree组件时遇到的浏览器兼容性问题。该问题表现为在Firefox和IE浏览器中,Tree展开时会撑大包含它的div元素。通过设定table和直接绑定KendoUI Tree元素的固定大小解决了这一问题。
1. 问题描述
有一个div,里面有一个table,table绑定了kendo ui tree.
<div>
<table id="relativeTable">
</table>
</div>
div和table是设定了固定大小了的,在chrome下没问题,在火狐,ie下展开tree时总是把div撑的很大。

查了资料说是火狐有这个问题,可以给最外层的div设置overflow:hidden,但是没有效果。

最后同时给$("relativeTable tbody")设定了固定大小,问题解决。
也就是说,要给直接绑定kendo ui空间的对象直接指定固定大小才可以(暂时只是解决问题,不知能否推广)。
------------------------ test.html ------------------------ <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>板材库存查询系统</title> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- 引入 Popper.js 和 Bootstrap JS --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script> <script src="../js/main.js"></script> <style> .card-header { background: linear-gradient(to right, #1e3c72, #2a5298); color: white; } .search-section { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); border-radius: 10px; } .result-section { max-height: 70vh; overflow: auto; border-left: 3px solid #1e3c72; } .table-hover tbody tr:hover { background-color: rgba(42, 82, 152, 0.05); } .material-kucun { font-weight: 700; color: #1e3c72; } .material-kucun-low { color: #dc3545 !important; } .no-results { min-height: 200px; display: flex; align-items: center; justify-content: center; } .stats-card { border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); } body { background-color: #f8f9fa; padding-bottom: 2rem; } .search-control { position: relative; } .search-icon { position: absolute; left: 12px; top: 12px; color: #6c757d; } .form-control.with-icon { padding-left: 35px; } .highlight { background-color: rgba(255, 255, 0, 0.3) !important; } .info-badge { font-size: 0.8rem; font-weight: normal; } </style> </head> <body> <div class="container py-4"> <!-- 标题部分 --> <div class="text-center mb-4"> <h1 class="text-primary"><i class="bi bi-boxes"></i> 板材库存管理系统</h1> <p class="text-muted">查询订单、产品、板材及库存信息</p> </div> <!-- 统计卡片 --> <div class="row mb-4"> <div class="col-md-3"> <div class="card stats-card border-primary"> <div class="card-body"> <h5 class="card-title">订单总数</h5> <p class="card-text fs-3 text-primary" id="orderCount">0</p> </div> </div> </div> <div class="col-md-3"> <div class="card stats-card border-info"> <div class="card-body"> <h5 class="card-title">产品种类</h5> <p class="card-text fs-3 text-info" id="productCount">0</p> </div> </div> </div> <div class="col-md-3"> <div class="card stats-card border-success"> <div class="card-body"> <h5 class="card-title">板材库存</h5> <p class="card-text fs-3 text-success" id="materialCount">0</p> </div> </div> </div> <div class="col-md-3"> <div class="card stats-card border-warning"> <div class="card-body"> <h5 class="card-title">库存总量</h5> <p class="card-text fs-3 text-warning" id="totalStock">0</p> </div> </div> </div> </div> <!-- 搜索区域 --> <div class="card search-section mb-4"> <div class="card-header"> <h5 class="mb-0"><i class="bi bi-search me-2"></i>高级搜索</h5> </div> <div class="card-body"> <div class="row g-3"> <!-- 订单搜索 --> <div class="col-md-6"> <div class="search-control"> <i class="bi bi-clipboard-search search-icon"></i> <input type="text" class="form-control with-icon" id="orderSearch" placeholder="搜索订单号..." aria-label="订单号搜索"> </div> </div> <!-- 产品搜索 --> <div class="col-md-6"> <div class="search-control"> <i class="bi bi-grid search-icon"></i> <input type="text" class="form-control with-icon" id="productSearch" placeholder="搜索产品编号..." aria-label="产品编号搜索"> </div> </div> <!-- 板材搜索 --> <div class="col-md-4"> <div class="search-control"> <i class="bi bi-box search-icon"></i> <input type="text" class="form-control with-icon" id="materialSearch" placeholder="搜索板材ID或材质..." aria-label="板材搜索"> </div> </div> <!-- 木皮搜索 --> <div class="col-md-4"> <div class="search-control"> <i class="bi bi-tree search-icon"></i> <input type="text" class="form-control with-icon" id="woodSearch" placeholder="搜索木皮名称..." aria-label="木皮搜索"> </div> </div> <!-- 厚度范围 --> <div class="col-md-4"> <div class="input-group"> <span class="input-group-text"><i class="bi bi-arrows-vertical"></i></span> <input type="number" class="form-control" id="minThickness" placeholder="厚度(mm)" min="0" step="0.1"> <button class="btn btn-primary" type="button" id="thicknessBtn"> <i class="bi bi-arrow-right"></i> </button> </div> </div> </div> </div> </div> <!-- 结果区域 --> <div class="card"> <div class="card-header d-flex justify-content-between align-items-center"> <h5 class="mb-0"><i class="bi bi-table me-2"></i>查询结果</h5> <div class="text-secondary"> <span id="resultCount">0</span> 条记录 <span class="ms-2"><i class="bi bi-info-circle"></i> <small>实数据更新间: <span id="lastUpdate">--:--:--</span></small></span> </div> </div> <div class="card-body result-section"> <div class="table-responsive"> <table class="table table-hover" id="resultTable"> <thead class="table-light sticky-top"> <tr> <th>订单号</th> <th>产品信息</th> <th>产品数量</th> <th>组件</th> <th>板材</th> <th>板材/组件</th> <th>板材订购数量</th> <th>操作</th> </tr> </thead> <tbody id="resultBody"> <!-- 数据加载中 --> <tr id="loadingRow"> <td colspan="9" class="text-center py-5"> <div class="d-flex align-items-center justify-content-center"> <div class="spinner-border text-primary" role="status"> <span class="visually-hidden">加载中...</span> </div> <div class="ms-3">正在加载数据,请稍候...</div> </div> </td> </tr> </tbody> </table> </div> <!-- 空结果提示 --> <div id="noResults" class="no-results text-center py-5" style="display: none;"> <div> <i class="bi bi-inboxes text-muted" style="font-size: 3rem;"></i> <h4 class="mt-3 text-muted">没有找到匹配的记录</h4> <p class="text-muted">请尝试调整您的搜索条件</p> </div> </div> </div> </div> </div> <script type="text/javascript"> </script> <script src="../js/jsyilai.js"></script> ------------------------ index.html ------------------------ <!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>峤丞板材库存管理</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="fonts/font-awesome-4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" type="text/css" href="main/bootstrap-3.3.7-dist/css/bootstrap.css.map"> <link rel="stylesheet" type="text/css" href="css/util.css"> <link rel="stylesheet" type="text/css" href="css/main.css"> <link rel="stylesheet" type="text/css" href="css/index2.css"> <script type="text/javascript" src="js/jquery-3.2.1.min.js"></script> <script type="text/javascript" src="js/jsyilai.js"></script> <script type="module"> // 共享的DataManager类 import { DataManager } from &#39;./data/DataManager.js?&#39;; document.addEventListener(&#39;DOMContentLoaded&#39;, async () => { try { // 创建实例并挂载到window window.dataManager = new DataManager(&#39;http://127.0.0.1:8080/KuCun2&#39;); // 初始化数据 await window.dataManager.fetchAll(); console.log(&#39;Data Manager initialized successfully&#39;); // 设置iframe通信 const iframe = document.getElementById(&#39;iframeid&#39;); iframe.onload = () => { // 通知iframe数据已准备好 iframe.contentWindow.postMessage(&#39;DataManagerReady&#39;, &#39;*&#39;); }; // 如果iframe已经加载,立即发送消息 if (iframe.contentDocument.readyState === &#39;complete&#39;) { iframe.contentWindow.postMessage(&#39;DataManagerReady&#39;, &#39;*&#39;); } } catch (error) { console.error(&#39;Failed to initialize DataManager:&#39;, error); } }); </script> <style type="text/css"> *{ margin:0; padding:0; } .frame-header { height: 60px; background-color: #23262E; justify-content: space-between; } .frame-header-li{ font-family: Arial, Helvetica, sans-serif; font-size:40px; } .frame-ul{ } .frame-ul li{ border-style: solid; border-width:1px 0px 1px 0px; margin-top: 1px; height: 35px; text-align: center } #username{ position: absolute; right: 0; /* 靠右 */ } .frame-body { position: fixed; top: 60px; right: 0; bottom: 0; left: 0; display: flex; flex-direction: row; } .frame-side { scrollbar-width: none; /* firefox隐藏滚动条 */ -ms-overflow-style: none; /* IE 10+隐藏滚动条 */ overflow-x: hidden; overflow-y: auto; width: 200px; background-color:#9e5; } .frame-side::-webkit-scrollbar { display: none; /* Chrome Safari 隐藏滚动条*/ } .frame-main { flex-grow: 1; background-color:#fff; } .jiaoluo{ margin: auto; margin-right: 0px; } .menu { display: none; position: absolute; background-color: #f9f9f9; border: 1px solid #ccc; padding: 10px; list-style-type: none; margin: 0; z-index: 10; } </style> </head> <body> <div class="frame-header"> <a class=&#39;frame-header-li&#39; style="color:#fff">峤丞木材仓库管理</a> <a id="username" class=&#39;frame-header-li&#39; style="color:#520">峤丞木材仓库管理</a> <!-- 菜单 --> <ul class="menu"> <li>选项 1</li> <li>选项 2</li> <li>选项 3</li> </ul> </div> <div class="frame-body"> <div class="frame-side"> <ul id="main_u" class=&#39;frame-ul&#39; style="text-align:center;"> <li ><a href="main/test.html" target="main">首页</a></li> <li><a href="main/bancai.html" target="main">板材查询</a></li> <li><a href="main/test.html" target="main">订单板材录入</a></li> <li><a href="main/tianjia.html" target="main">test</a></li> <li><a href="main/Guanli.html" target="main">人员管理</a></li> </ul> </div> <div class="frame-main"> <!-- 内容主体区域 --> <iframe id="iframeid" name="main" src="main/bancai.html" width="100%" height="100%" frameborder="0"> </iframe> </div> </div> </body> </html> ------------------------ DataManager.js ------------------------ //{ 实体类的关联和属性列表 // "entities": { // "Dingdan": { // "properties": { // "id": "Integer", // "number": "String", // "xiadan": "Date", // "jiaohuo": "Date", // "dingdan_chanpins": "List<Dingdan_chanpin> (OneToMany)", // "dingdan_chanpins_zujians": "List<Dingdan_chanpin_zujian> (OneToMany)" // }, // "relations": [ // "关联订单产品(Dingdan_chanpin)", // "关联订单组件(Dingdan_chanpin_zujian)" // ] // }, // "Dingdan_chanpin": { // "properties": { // "id": "Integer", // "shuliang": "Integer" // }, // "relations": [ // "多对一关联订单(Dingdan)", // "多对一关联产品(Chanpin)" // ] // }, // "Dingdan_chanpin_zujian": { // "properties": { // "id": "Integer", // "shuliang": "Integer" // }, // "relations": [ // "多对一关联订单(Dingdan)", // "多对一关联组件(Chanpin_zujian)", // "多对一关联板材(Bancai)" // ] // }, // "Jinhuo": { // "properties": { // "id": "Integer", // "shuliang": "Integer", // "date": "Date" // }, // "relations": [ // "多对一关联订单(Dingdan)", // "多对一关联产品(Chanpin)", // "多对一关联组件(Zujian)", // "多对一关联板材(Bancai)", // "多对一关联用户(User)" // ] // }, // "Kucun": { // "properties": { // "id": "Integer", // "shuliang": "Long" // }, // "relations": [ // "一对一关联板材(Bancai)" // ] // }, // "Mupi": { // "properties": { // "id": "Integer", // "name": "String", // "you": "Boolean" // }, // "relations": [ // "被板材关联(Bancai - mupi1/mupi2)" // ] // }, // "User": { // "properties": { // "id": "Integer", // "name": "String", // "andy": "String", // "pass": "String", // "role": "int" // } // }, // "Zujian": { // "properties": { // "id": "Integer", // "name": "String" // }, // "relations": [ // "一对多关联产品组件(Chanpin_zujian)" // ] // }, // "Bancai": { // "properties": { // "id": "Integer", // "houdu": "Double" // }, // "relations": [ // "多对一关联材质(Caizhi)", // "多对一关联木皮(Mupi - mupi1/mupi2)", // "一对一关联库存(Kucun)" // ] // }, // "Caizhi": { // "properties": { // "id": "Integer", // "name": "String" // }, // "relations": [ // "一对多关联板材(Bancai)" // ] // }, // "Chanpin": { // "properties": { // "id": "Integer", // "bianhao": "String" // }, // "relations": [ // "一对多关联订单产品(Dingdan_chanpin)", // "一对多关联产品组件(Chanpin_zujian)" // ] // }, // "Chanpin_zujian": { // "properties": { // "id": "Integer", // "one_howmany": "Double" // }, // "relations": [ // "多对一关联产品(Chanpin)", // "多对一关联组件(Zujian)", // "多对一关联板材(Bancai)" // ] // } // }, // "relationsSummary": [ // "订单(Dingdan) 1:N 订单产品(Dingdan_chanpin)", // "订单(Dingdan) 1:N 订单组件(Dingdan_chanpin_zujian)", // "产品(Chanpin) 1:N 产品组件(Chanpin_zujian)", // "组件(Zujian) 1:N 产品组件(Chanpin_zujian)", // "板材(Bancai) 1:1 库存(Kucun)", // "材质(Caizhi) 1:N 板材(Bancai)" // ] //} /** * 解析数据关联关系,将ID引用转换为对象引用 * @param {Object} data - 从后端加载的原始数据 * @returns {Object} - 处理后的数据,包含完整的对象关联 *//** * 解析数据关联关系,将ID引用转换为对象引用 * @param {Object} data - 从后端加载的原始数据 * @returns {Object} - 处理后的数据,包含完整的对象关联 */ function resolveDataReferences(data) { // 创建ID映射表 const idMaps = {}; Object.keys(data).forEach(key => { // 确保数据存在且是数组 if (Array.isArray(data[key])) { idMaps[key] = new Map(); data[key].forEach(item => idMaps[key].set(item.id, item)); } }); // 处理多对一和一对一关系 const resolveRef = (source, sourceKey, targetKey, propertyName) => { // 确保源数据存在且是数组 if (!Array.isArray(source)) return; source.forEach(item => { // 确保关联属性存在且有id if (item[propertyName] && item[propertyName].id) { const refId = item[propertyName].id; // 确保目标映射存在 if (!idMaps[targetKey]) return; const target = idMaps[targetKey].get(refId); if (target) { item[propertyName] = target; // 建立反向引用(一对多关系) if (!target[sourceKey]) target[sourceKey] = []; if (!target[sourceKey].includes(item)) { target[sourceKey].push(item); } } } }); }; // 处理一对多关系(直接创建关联数组) const resolveOneToMany = (sourceKey, targetKey, propertyName) => { // 确保源数据存在 if (!Array.isArray(data[sourceKey]) || !Array.isArray(data[targetKey])) return; const sourceItems = data[sourceKey]; sourceItems.forEach(source => { if (!source[propertyName]) source[propertyName] = []; }); data[targetKey].forEach(target => { // 确保关联属性存在 if (target[sourceKey]?.id) { const sourceId = target[sourceKey].id; // 确保源映射存在 if (!idMaps[sourceKey]) return; const source = idMaps[sourceKey].get(sourceId); if (source && source[propertyName]) { source[propertyName].push(target); } } }); }; // 处理特定关联关系 - 添加空值检查 if (data.dingdans && data.dingdan_chanpins) { resolveOneToMany(&#39;dingdans&#39;, &#39;dingdan_chanpins&#39;, &#39;dingdan_chanpins&#39;); resolveRef(data.dingdan_chanpins, &#39;dingdans&#39;, &#39;dingdans&#39;, &#39;dingdan&#39;); } if (data.dingdans && data.dingdan_chanpin_zujians) { resolveOneToMany(&#39;dingdans&#39;, &#39;dingdan_chanpin_zujians&#39;, &#39;dingdan_chanpin_zujians&#39;); resolveRef(data.dingdan_chanpin_zujians, &#39;dingdans&#39;, &#39;dingdans&#39;, &#39;dingdan&#39;); } if (data.chanpins && data.chanpin_zujians) { resolveOneToMany(&#39;chanpins&#39;, &#39;chanpin_zujians&#39;, &#39;chanpin_zujians&#39;); resolveRef(data.chanpin_zujians, &#39;chanpins&#39;, &#39;chanpins&#39;, &#39;chanpin&#39;); } if (data.zujians && data.chanpin_zujians) { resolveOneToMany(&#39;zujians&#39;, &#39;chanpin_zujians&#39;, &#39;chanpin_zujians&#39;); resolveRef(data.chanpin_zujians, &#39;zujians&#39;, &#39;zujians&#39;, &#39;zujian&#39;); } if (data.caizhis && data.bancais) { resolveOneToMany(&#39;caizhis&#39;, &#39;bancais&#39;, &#39;bancais&#39;); resolveRef(data.bancais, &#39;caizhis&#39;, &#39;caizhis&#39;, &#39;caizhi&#39;); } if (data.bancais && data.kucuns) { resolveRef(data.bancais, &#39;kucuns&#39;, &#39;kucuns&#39;, &#39;kucun&#39;); } if (data.kucuns && data.bancais) { resolveRef(data.kucuns, &#39;bancais&#39;, &#39;bancais&#39;, &#39;bancai&#39;); } if (data.bancais && data.mupis) { resolveRef(data.bancais, &#39;mupis&#39;, &#39;mupis&#39;, &#39;mupi1&#39;); resolveRef(data.bancais, &#39;mupis&#39;, &#39;mupis&#39;, &#39;mupi2&#39;); } if (data.dingdan_chanpins && data.chanpins) { resolveRef(data.dingdan_chanpins, &#39;chanpins&#39;, &#39;chanpins&#39;, &#39;chanpin&#39;); } if (data.dingdan_chanpin_zujians && data.chanpin_zujians) { resolveRef(data.dingdan_chanpin_zujians, &#39;chanpin_zujians&#39;, &#39;chanpin_zujians&#39;, &#39;chanpin_zujian&#39;); } if (data.dingdan_chanpin_zujians && data.bancais) { resolveRef(data.dingdan_chanpin_zujians, &#39;bancais&#39;, &#39;bancais&#39;, &#39;bancai&#39;); } if (data.jinhuos) { // 进货 ↔ 相关实体 (多对一) [&#39;dingdans&#39;, &#39;chanpins&#39;, &#39;zujians&#39;, &#39;bancais&#39;, &#39;users&#39;].forEach(entity => { if (data[entity]) { resolveRef(data.jinhuos, entity, entity, entity.slice(0, -1)); } }); } return data; } /** * 数据管理器类,负责与后端API通信并管理数据 */ class DataManager { constructor(baseUrl) { this.baseUrl = baseUrl; this.data = { bancais: [], dingdans: [], mupis: [], chanpins: [], kucuns: [], dingdan_chanpin_zujians: [], chanpin_zujians: [], zujians: [], caizhis: [], dingdan_chanpins: [], users: [] }; this.isSyncing = false; this.lastSync = null; // 回调注册表 this.callbacks = { // 全局回调 all: [], // 按实体类型分类的回调 bancais: [], dingdan: [], mupi: [], chanpin: [], kucun: [], dingdan_chanpin_zujian: [], chanpin_zujian: [], zujian: [], caizhi: [], dingdan_chanpin: [], user: [], // ...其他实体 }; this.syncQueue = Promise.resolve(); } /** * 获取所有数据 * @returns {Promise<boolean>} 是否成功 */ async fetchAll() { console.log(this) try { const response = await fetch(`${this.baseUrl}/app/all`); if (!response.ok) throw new Error(&#39;Network response was not ok&#39;); const result = await response.json(); if (result.status !== 200) throw new Error(result.text || &#39;API error&#39;); const resolvedData = resolveDataReferences(result.data); // 更新本地数据 Object.keys(this.data).forEach(key => { if (resolvedData[key]) { this.data[key] = resolvedData[key]; } }); this.lastSync = new Date(); // 关键改进:数据更新后触发刷新回调 this.triggerCallbacks(&#39;refresh&#39;, &#39;all&#39;, this.data); return true; } catch (error) { console.error(&#39;Fetch error:&#39;, error); // 触发错误回调 this.triggerCallbacks(&#39;fetch_error&#39;, &#39;all&#39;, { error }); return false; } } /** * 注册回调函数 * @param {string} entity - 实体类型(如&#39;bancai&#39;)或&#39;all&#39;表示全局回调 * @param {Function} callback - 回调函数,参数为(operation, data) */ registerCallback(entity, callback) { if (!this.callbacks[entity]) { this.callbacks[entity] = []; } this.callbacks[entity].push(callback); } /** * 移除回调函数 * @param {string} entity - 实体类型单数性质 * @param {Function} callback - 要移除的回调函数 */ unregisterCallback(entity, callback) { if (!this.callbacks[entity]) return; const index = this.callbacks[entity].indexOf(callback); if (index !== -1) { this.callbacks[entity].splice(index, 1); } } /** * 触发回调 * @param {string} operation - 操作类型(&#39;add&#39;, &#39;update&#39;, &#39;delete&#39;) * @param {string} entity - 实体类型单数性质 * @param {Object} data - 相关数据 */ triggerCallbacks(operation, entity, data) { // 触发全局回调 this.callbacks.all.forEach(cb => cb(operation, entity, data)); // 触发特定实体回调 if (this.callbacks[entity]) { this.callbacks[entity].forEach(cb => cb(operation, data)); } } /** * 执行CRUD操作并触发回调 */ async crudOperation(operation, entity, data) { try { const response = await fetch(`${this.baseUrl}/app/${operation}/${entity}`, { method: &#39;POST&#39;, headers: {&#39;Content-Type&#39;: &#39;application/json&#39;}, body: JSON.stringify(data) }); if (!response.ok) throw new Error(&#39;Network response was not ok&#39;); const result = await response.json(); if (result.status !== 200) throw new Error(result.text || &#39;API error&#39;); // 自动同步数据 this.syncData(); // 触发操作成功的回调 this.triggerCallbacks(operation, entity, data); return result; } catch (error) { console.error(&#39;CRUD error:&#39;, error); // 触发操作失败的回调 this.triggerCallbacks(`${operation}_error`, entity, { data, error: error.message }); throw error; } } /** * 执行CRUD操作 * @param {string} operation - &#39;add&#39;, &#39;delete&#39;, &#39;update&#39; * @param {string} entity - 实体名称单数性质(小写) * @param {Object} data - 要发送的数据 后端要求数据格式为{属性: "值", 关联对象: {id:0}, 关联对象集: [{id:0}]} * @returns {Promise<Object>} 响应结果 */ async crudOperation(operation, entity, data) { try { const response = await fetch(`${this.baseUrl}/app/${operation}/${entity}`, { method: &#39;POST&#39;, headers: {&#39;Content-Type&#39;: &#39;application/json&#39;}, body: JSON.stringify(data) }); if (!response.ok) throw new Error(&#39;Network response was not ok&#39;); const result = await response.json(); if (result.status !== 200) throw new Error(result.text || &#39;API error&#39;); // 自动同步数据 this.syncQueue = this.syncQueue.then(async () => { await this.syncData(); // 同步完成后触发操作回调 this.triggerCallbacks(operation, entity, data); }); return result; } catch (error) { console.error(&#39;CRUD error:&#39;, error); // 触发操作失败的回调 this.triggerCallbacks(`${operation}_error`, entity, { data, error: error.message }); throw error; } } /** * 自动同步数据(防止频繁请求) */ async syncData() { if (this.isSyncing) { this.pendingSync = true; return; } this.isSyncing = true; try { await this.fetchAll(); } catch (error) { console.error(&#39;Sync failed:&#39;, error); } finally { this.isSyncing = false; // 处理等待中的同步请求 if (this.pendingSync) { this.pendingSync = false; setTimeout(() => this.syncData(), 1000); } } } /** * 添加实体 * @param {string} entity - 实体名称单数性质 * @param {Object} data - 实体数据 */ async addEntity(entity, data) { return this.crudOperation(&#39;add&#39;, entity, data); } /** * 更新实体 * @param {string} entity - 实体名称单数性质 * @param {Object} data - 实体数据(必须包含id) */ async updateEntity(entity, data) { return this.crudOperation(&#39;update&#39;, entity, data); } /** * 删除实体 * @param {string} entity - 实体名称单数性质 * @param {number} id - 实体ID */ async deleteEntity(entity, id) { return this.crudOperation(&#39;delete&#39;, entity, {id}); } /** * 新增方法:手动触发数据刷新 */ async refreshData() { return this.syncQueue = this.syncQueue.then(() => this.syncData()); } } export { DataManager }; // 创建单例实例 //const dataManager = new DataManager(&#39;http://127.0.0.1:8080/KuCun2&#39;); //// 初始化获取所有数据 //dataManager.fetchAll().then(() => { // console.log(&#39;Initial data loaded&#39;); //}); // 导出数据对象,外部可以直接访问 data.bancais, data.dingdans 等 //export const data = dataManager.data; //// 导出操作方法 //export const addEntity = dataManager.addEntity.bind(dataManager); //export const updateEntity = dataManager.updateEntity.bind(dataManager); //export const deleteEntity = dataManager.deleteEntity.bind(dataManager); //export const fetchAll = dataManager.fetchAll.bind(dataManager); 根据DataManager.js填充test.html数据 js文件
06-18
<!-- 工艺模板 --> <template> <el-container v-loading="loading"> <!-- 工具栏 --> <el-header> <!-- 左侧工具栏 --> <!-- <div class="left-panel"> <el-button type="primary" icon="el-icon-plus" @click="edit()">新增</el-button> </div> --> <!-- 右侧工具栏 --> <div class="right-panel"> <div class="right-panel-search"> <el-input v-model="procedureData.name" placeholder="名称" clearable /> <el-button icon="el-icon-refresh" @click="refreshProcedure">查看所有</el-button> <el-button type="primary" icon="el-icon-search" @click="getProcedure(0)">搜索</el-button> <el-button type="primary" icon="el-icon-plus" @click="editProcedure()">新增</el-button> </div> </div> </el-header> <!-- 列表 --> <el-main class="nopadding"> <scTable :data="procedureData.data" style="width: 100%" row-key="id" :getList="getProcedure" hidePagination :header-cell-style="{ background: &#39;#F1F3F0&#39;, color: &#39;#7B7571&#39; }"> <el-table-column label="ID" prop="id" width="50"></el-table-column> <el-table-column label="编号" prop="rule_number"></el-table-column> <el-table-column label="工艺名称" prop="name"></el-table-column> <el-table-column label="操作人" prop="user_name"></el-table-column> <el-table-column label="创建间" prop="create_time"></el-table-column> <el-table-column label="操作" fixed="right" width="150"> <template #default="scope"> <el-button plain type="primary" size="small" @click="editProcedure(scope.row)">编辑</el-button> <el-button plain type="primary" size="small" @click="delProcedure(scope.row)">删除</el-button> </template> </el-table-column> <template #pagination> <el-pagination layout="prev, pager, next, total, sizes" :current-page="procedureData.current_page" :page-size="procedureData.per_page" :total="procedureData.total" :page-sizes="[20, 50, 100]" @size-change=" (num) => { procedureData.per_page = num; getProcedure(1); } " @current-change="getProcedure" /> </template> </scTable> </el-main> <!-- 工艺工序新增编辑模板 --> <el-dialog v-model="ditVisibleGy" :close-on-click-modal="false" width="80%" :fullscreen="isFullscreen" class="dialogGxgy"> <!-- 自定义标题栏 --> <template #title> <div class="dialogtitle"> <h4 style="font-size: 17px;">{{ procedureForm.id ? &#39;编辑工艺模板&#39; : &#39;新增工艺模板&#39; }}</h4> <div class="dialog-icons"> <!-- 全屏图标 --> <el-icon @click="toggleFullscreen" class="fullscreen-icon"> <component :is="isFullscreen ? ZoomOut : FullScreen" /> </el-icon> </div> </div> </template> <el-header> <div class="gybs"> <div class="gyheader"> <h4>模板名称:</h4> <el-input v-model="procedureForm.name" placeholder="请输入模板名称" style="width: 200px" /> </div> <!-- <el-upload class="sc-file-select__upload" :action="action" multiple :show-file-list="false" :accept="accept" :before-upload="uploadBefore" :on-success="uploadSuccess" :on-error="uploadError" :headers="uploadHeaders" :data="uploadData"> <el-button type="primary" icon="el-icon-upload">上传图纸</el-button> </el-upload> --> <!-- 图片列表,横向滚动 --> </div> </el-header> <el-container v-loading="gymbLoading"> <el-aside width="250px" height="400px"> <el-card class="card_gy"> <!-- 拖拽排序 --> <div class="tzpx"> <fcDraggable v-model="itemsgy" :sort="true" handle=".icon-drag" itemKey="gongxumingcheng" direction="vertical" :animation="300" @end="onDragEnd"> <template #item="{ element, index }"> <div class="slx"> <div class="sortable-item" @click="selectItem(element)" :class="{ &#39;selected&#39;: selectedItem === element }"> <div class="item_left"> <i class="fc-icon icon-drag"></i> </div> <div class="item_content"> {{ element.gongxumingcheng }} </div> <div class="item_right"> <i class="fc-icon icon-delete" @click.stop="removeField(index)"></i> </div> </div> </div> </template> </fcDraggable> <el-empty description="暂无工序" :image-size="120" v-if="itemsgy.length === 0" /> </div> <el-button-group class="btgp"> <el-button type="primary" @click="addProcedure">添加</el-button> <el-button type="primary" @click="changeGx">选择工序</el-button> </el-button-group> </el-card> </el-aside> <el-container class="" v-loading="bomLoading" v-if="itemsgy.length > 0"> <el-header> <H3 class="ht">工序参数</H3> </el-header> <div class="formbody"> <div class="gyform" v-if="isFormFilled"> <form-create v-model:api="api" :rule="formRule" :option="formCreateOptions" /> </div> <el-empty description="请先选择工序" v-show="!isFormFilled" /> <div class="gycs" v-if="itemsgy.length > 1"> <div class="dowt"> <H3>工艺路线图</H3> </div> <div class="route"> <el-steps :active="itemsgy.length" :space="150" align-center finish-status="primary" process-status="primary"> <el-step v-for="(item, index) in itemsgy" :key="index" :title="item.gongxumingcheng" /> </el-steps> </div> </div> </div> </el-container> <div v-else style="width: 100%;"> <el-empty description="请先选择工序模板" /> </div> <el-aside width="200px" class="lf_aside"> <div class="image-preview-list"> <el-scrollbar height="400px"> <el-upload class="uploadTz" :action="action" multiple :show-file-list="false" :on-preview="handlePictureCardPreview" :before-upload="uploadBefore" :on-success="uploadSuccess" :on-error="uploadError" :headers="uploadHeaders" :data="uploadData" > <el-button type="primary">上传图纸</el-button> </el-upload> <div class="upbox"> <div class="wdg" v-for="(item, index) in fileList" :key="index"> <div class="wg_lf" @click="handlePictureCardPreview(item)"> <el-icon size="18"> <DocumentRemove /> </el-icon> <el-tooltip class="box-item" effect="dark" :content="item.original_name" placement="top"> <div class="weds">{{ item.original_name }}</div> </el-tooltip> </div> <div> <el-button type="danger" :icon="Delete" circle size="small" @click="delImg(index)"/> </div> </div> </div> <el-dialog v-model="dialogVisibleImg"> <img w-full :src="dialogImageUrl" alt="Preview Image" /> </el-dialog> </el-scrollbar> </div> </el-aside> </el-container> <template #footer> <span class="dialog-footer"> <el-button @click="ditVisibleGy = false">关闭</el-button> <el-button type="primary" @click="submitProcesses" :loading="gyloading"> 保存工艺模板 </el-button> </span> </template> </el-dialog> <!-- 选择工序弹窗 --> <el-dialog v-model="dialogVisiblexzgx" title="选择工序" width="60%"> <el-container> <el-aside width="200px"> <el-tree ref="dic" class="menu" node-key="id" :data="gxtypeList" :props="{ label: &#39;name&#39;, }" :highlight-current="true" :expand-on-click-node="false" :filter-node-method="dicFilterNode" @node-click="selectgxClass"> <template #default="{ node, data }"> <span class="custom-tree-node"> <span class="label">{{ node.label }}</span> <span class="code">{{ data.code }}</span> </span> </template> </el-tree> </el-aside> <el-main v-loading="tableloading"> <el-header v-if="processesList.data.length > 0"> <div class="right-panel"> <el-input v-model="processesList.name" placeholder="标题" class="titlese" /> <el-button icon="el-icon-refresh" @click="refresprocessesList">查看所有</el-button> <el-button type="primary" icon="el-icon-search" @click="getTemplate(1)"></el-button> </div> </el-header> <el-main> <scTable :data="processesList.data" ref="tableRef" style="width: 100%" row-key="id" :getList="getitem" @row-click="handleRowClick" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="50"></el-table-column> <el-table-column prop="id" label="ID" width="50" /> <el-table-column prop="gongxumingcheng" label="工序名称" fixed="right" /> <el-table-column prop="user_name" label="创建人" fixed="right" /> <el-table-column prop="create_time" label="创建间" fixed="right" /> <template #pagination> <el-pagination layout="prev, pager, next, total, sizes" :current-page="processesList.current_page" :page-size="processesList.per_page" :total="processesList.total" :page-sizes="[20, 50, 100]" @size-change=" (num) => { processesList.per_page = num; getTemplate(1); } " @current-change="getTemplate" /> </template> </scTable> </el-main> </el-main> </el-container> <template #footer> <div class="dialog-footer"> <el-button @click="dialogVisiblexzgx = false">取消</el-button> <el-button type="primary" @click="selectProcess" :loading="selectProcessLoading"> 确定 </el-button> </div> </template> </el-dialog> <!-- 新增工序 公共页面弹窗新增 --> <el-dialog v-model="ditVisibleProcedure" :close-on-click-modal="false" width="70%" title="工序新增"> <form-create v-model:api="api" :rule="formRuleAdd" :option="formCreateOptions" /> </el-dialog> </el-container> </template> <script setup> import { ref, watch, reactive, nextTick } from "vue"; import request from "@/utils/httpRequest"; import { ElMessage,ElMessageBox } from "element-plus"; import fcDraggable from "vuedraggable"; import formCreate from "@form-create/element-ui"; import { getFormRuleDescription } from "@/components/formCreate/src/utils/index"; // js工具 import utils from "./components/utils"; import tool from "@/utils/tool"; import config from "@/config" import { DocumentRemove, Delete } from "@element-plus/icons-vue"; // 页面loading let loading = ref(false); //上传地址 const token = tool.cookie.get("TOKEN"); const action = ref(config.BASEURL + "/system/upload/upload"); const fileList = ref([]); //上传文件列表 const dialogVisibleImg = ref(false) const dialogImageUrl = ref(&#39;&#39;) //设置请求头 const uploadHeaders = ref({ token: token, // 添加 token 到 headers }); // 设置额外字段 const uploadData = ref({ is_annex: 1, // 添加额外字段 is_annex group_id: 0, }); // 列表数据 const procedureData = ref({ current_page: 1, per_page: 10, total: 0, data: [], name: &#39;&#39;,//名称查询 }) // #region 定义工艺模板数据字段 const itemsgy = ref([])//工序列表 const formRule = ref([])//formcreate 组件 const selectedItem = ref({})// 记录当前选中工序的索引 const processLoading = ref(false)//loading const isEditor = ref(false)//用于判断是否走编辑接口 const ditVisibleGy = ref(false)//工艺模板弹窗 const formCreateOptions = ref({});//表单组件参数 //工艺form const procedureForm = ref({ good_id: &#39;&#39;,//绑定产品id name: &#39;&#39;,//工艺名称 // type_id: 0,//工艺分类 goods_name: &#39;&#39;,//绑定产品名称 item: &#39;&#39;//工序节点 }); // #endregion // #region 数据列表 function refreshProcedure() { procedureData.value.name = &#39;&#39; getProcedure() } async function getProcedure(page = 1) { if (page) { procedureData.value.current_page = page; } try { loading.value = true; let data = await request.post("/system/workmanship.workmanship_template/index", { page: procedureData.value.current_page, limit: procedureData.value.per_page, name: procedureData.value.name }); procedureData.value.current_page = data.data.current_page procedureData.value.total = data.data.total procedureData.value.data = data.data.data loading.value = false; } catch (error) { loading.value = false; } } getProcedure() // #endregion // #region 新增编辑 //点击新增 编辑 async function editProcedure(row) { itemsgy.value = [] formRule.value = [] selectedItem.value = {} fileList.value = [] if (row) { try { loading.value = true; let data = await request.post("/system/workmanship.workmanship_template/read", { id: row.id }); loading.value = false if( data.data.data.file){ fileList.value = data.data.data.file } procedureForm.value = { // goods_id: data.data.data.goods_id,//绑定产品id name: data.data.data.name,//工艺名称 // type_id: &#39;&#39;,//工艺分类 // goods_name: data.data.data.goods_name,//绑定产品名称 id: row.id } itemsgy.value = data.data.data.item for (const item of itemsgy.value) { try { let data = await request.post("/system/workmanship.workmanship_template/getItem", { id: item.id }); //value是组件的值 let content = formCreate.parseJson(data.data.form.content); const value = utils.decodeFormat(content, data.data.item, 2); item.options = value item.option = content //options是页面参数配置 formCreate.parseJson // const options = (data.data.form.options); const options = formCreate.parseJson(data.data.form.options) formCreateOptions.value = options formCreateOptions.value.submitBtn.show = false loading.value = false } catch (error) { loading.value = false; } } isEditor.value = true processLoading.value = false } catch (error) { processLoading.value = false } } else { itemsgy.value = [] procedureForm.value = { name: &#39;&#39;,//工艺名称 // type_id: &#39;&#39;,//工艺分类 goods_name: 24,//绑定产品名称 item: &#39;&#39;,//工序节点 id: &#39;&#39; } isEditor.value = false } ditVisibleGy.value = true; } // #endregion // #region 获取工序分类 const dialogVisiblexzgx = ref(false); const gymbLoading = ref(false) const gxcclist = ref([])//存储当前选中的工序列表 const tableRef = ref(null); // 绑定 scTable 组件 const gxId = ref(&#39;&#39;)//工序id // 打开工序选择弹窗,并获取工序类型数据= function changeGx() { getgxtype() } // 获取工序模板分类数据(工序类别) async function getgxtype() { try { gymbLoading.value = true let data = await request.post("/system/dictionary/getChildListByCode", { code: &#39;gongxu_type&#39; }); gxtypeList.value = data.data gxcclist.value = [] dialogVisiblexzgx.value = true; tableRef.value.clearSelection(); // 清空选中 gymbLoading.value = false; } catch (error) { gymbLoading.value = false; } } const gxtypeList = ref([])//已选中的工序 列表多选 //选择工序分类 function selectgxClass(row) { gxId.value = row.value getTemplate(1) } // #endregion // #region 获取工序模板 const tableloading = ref(false) const processesList = ref({ current_page: 1, per_page: 10, total: 0, data: [], name: &#39;&#39; })//工序模板列表 //工序form表单 const formGy = reactive({ workmanship_id: &#39;&#39;,//工艺id name: &#39;&#39;,//工序名称 piece_type: &#39;&#39;,//计件方式 dept: &#39;&#39;,//报工部门 process_quota: &#39;&#39;,//工序定额1启用2停用 price_type: &#39;&#39;,//计酬方式1计件2计工 process_price: 0,//工序单价 deduction: 0,//不合格扣款 sort: 0,//排序 }); const bomLoading = ref(false) // 根据工序分类 ID 获取对应的工序列表 async function getTemplate(page = 1) { tableloading.value = true if (page) { processesList.value.current_page = page; } let data = await request.post("/system/processes.processes_template/index", { gongxufenlei_ids: gxId.value, limit: processesList.value.per_page, page: processesList.value.current_page, name: processesList.value.name }); tableloading.value = false processesList.value.current_page = data.data.current_page processesList.value.total = data.data.total // 更新工序列表 processesList.value.data = data.data.data nextTick(() => { recoverSelection(); // 拉完数据恢复勾选 }); } // 监听工序表格的多选事件,并更新已选中的工序数据 function handleSelectionChange(selection) { // gxcclist.value = selection // ⚡ selection 是当前页面选中的 // 我们需要同步到 gxcclist 里面,保证全局勾选 // 先删除本页数据在 gxcclist 里面的 const pageIds = processesList.value.data.map(item => item.id); gxcclist.value = gxcclist.value.filter(item => !pageIds.includes(item.id)); // 再把最新的 selection 加进去 gxcclist.value = [...gxcclist.value, ...selection]; } // 恢复勾选 function recoverSelection() { if (!tableRef.value) return; const tableData = processesList.value.data tableData.forEach((row) => { const isSelected = gxcclist.value.some(item => item.id === row.id) || itemsgy.value.some(item => item.id === row.id); tableRef.value.toggleRowSelection(row, isSelected); }); } // 是否有数据 const isFormFilled = ref(false); function handleRowClick(row) { tableRef.value.toggleRowSelection(row); } // 监听 formGy 变化 watch( formGy, (newVal) => { isFormFilled.value = Object.values(newVal).some( (value) => value !== "" && value !== null && value !== undefined ); }, { deep: true } ); const selectProcessLoading = ref(false)//loading 按钮 // 确认选择工序,并关闭弹窗 async function selectProcess() { itemsgy.value = gxcclist.value refreshGx() dialogVisiblexzgx.value = false } // #endregion //#region 刷新工序展示列表最新数据 async function refreshGx() { for (const item of itemsgy.value) { let form = {} const res = await request.post("/system/crud/read", { crud_id: 105, id: item.id }); // 格式化表单数据 const value = utils.decodeFormat( formCreate.parseJson(res.data.form.content), res.data.data, 2 ); // 表单渲染规则 form = value; const options = formCreate.parseJson(res.data.form.options); //默认给子表加上一条 form.forEach((item) => { if (item.field) { if (item.field.includes("sub_")) { if (item.value.length === 0) { item.value = [{}]; } } } }); // 编辑删除默认数据,转而使用表单数据 // delete options.form; // 获取所有数据组件参数 const formData = formCreate.parseJson( formCreate.toJson(getFormRuleDescription(form)) ); formCreateOptions.value = options formCreateOptions.value.submitBtn.show = false // 整理格式 const postData = utils.formatForm(formData); // const psData = formData // **根据 id 匹配 itemsgy.value 数组的元素,并存入新字段 `options`** const targetItem = itemsgy.value.find(el => el.id === item.id); if (targetItem) { targetItem.options = postData; // 存入 options 字段 targetItem.option = form } } } // 记录用户点击的工序项(用于高亮显示) async function selectItem(item) { bomLoading.value = true selectedItem.value = item; // 更新选中状态 formRule.value = item.option;//选中 赋给表单 isFormFilled.value = true bomLoading.value = false } //删除对应已选工序模板 function removeField(index) { itemsgy.value.splice(index, 1); } // #endregion //#region 新增工序 弹出公共页面的新增 const ditVisibleProcedure = ref(false) const api = ref({}) const formRuleAdd = ref([]);//用于新增模板 async function addProcedure() { let res = await request.post("/system/crud/getCrudForm", { crud_id: 105 }); // 表单渲染规则 formRuleAdd.value = formCreate.parseJson(res.data.content) // 表单配置项 formCreateOptions.value = { onSubmit: async () => { // 表单验证通过后的提交方法 // 获取所有数据组件参数 let formData = formCreate.parseJson( formCreate.toJson(getFormRuleDescription(formRuleAdd.value)) ); // 整理格式 let postData = utils.formatForm(formData); await request.post("/system/crud/add", { crud_id: 105, form_data: formCreate.toJson(postData) }); ElMessage({ type: "success", message: "操作成功", }); ditVisibleProcedure.value = false }, ...formCreate.parseJson(res.data.options) }; ditVisibleProcedure.value = true } // #endregion const imageUrls = ref(&#39;&#39;) //#region 提交新增工艺 const gyloading = ref(false)//保存按钮loading async function submitProcesses() { if (gyloading.value) { return } // ✅ 防止双击或重复点击 if (!procedureForm.value.name) { ElMessage.error(&#39;请先填写工艺名称&#39;) return; } let newArray = []; // 先定义 newArray,确保在整个作用域内可访问 if (itemsgy.value.length > 0) { // 处理 itemsgy.value 数组,将 options 转换为 option 并删除 options 字段 newArray = itemsgy.value.map(item => { // 获取所有数据组件参数 let formData = formCreate.parseJson( formCreate.toJson(getFormRuleDescription(item.option)) ); const newItem = { ...item, option: utils.formatForm(formData)// 将 options 字段格式化后存入 option }; delete newItem.options;// 删除原 options 字段 return newItem;// 返回处理后的新对象 }) } if (fileList.value.length > 0) { // 提取所有上传图片的 URL imageUrls.value = fileList.value.map(file => file.full_path).join(&#39;,&#39;); } try { // 发送 POST 请求,将数据提交到后端接口 // let data = await request.post("/system/workmanship.workmanship_template/add", ); gymbLoading.value = true gyloading.value = true let url = procedureForm.value.id ? "/system/workmanship.workmanship_template/update" : "/system/workmanship.workmanship_template/add"; // 尝试提交 let data = await request.post(url, { name: procedureForm.value.name, // 工艺模板名称 // goods_id: procedureForm.value.goods_id, // 关联的商品 ID goods_name: procedureForm.value.goods_name, // 关联的商品名称 item: JSON.stringify(newArray), // 处理后的工艺项数据,转换为 JSON 字符串 id: procedureForm.value.id, file: imageUrls.value }); if (data.code === 1) { ElMessage({ message: &#39;操作成功&#39;, type: &#39;success&#39;, }) await getProcedure() gymbLoading.value = false gyloading.value = false ditVisibleGy.value = false } } catch (error) { // positionLoading.value = false; } } // #endregion //#region 上传附件 // 上传之前的处理 const uploadBefore = (file) => { const isImage = file.type.startsWith(&#39;image/&#39;); const isSizeOk = file.size / 1024 / 1024 < 20; // 限制文件大小最大为 5MB if (!isImage) { ElMessage.error(&#39;只能上传图片文件!&#39;) return false; } if (!isSizeOk) { ElMessage.error(&#39;图片大小不能超过 5MB!&#39;) return false; } gymbLoading.value = true; // 开启 loading return true; }; // 预览图片 const handlePictureCardPreview = (file) => { dialogImageUrl.value = file.full_path; // 设置预览的图片地址 dialogVisibleImg.value = true; // 显示对话框 }; //上传成功的回调 const uploadSuccess = (response) => { fileList.value.push({ original_name: response.data.original_name, path: response.data.fullurl, // 带域名的完整路径 full_path: response.data.url // 相对路径 }) ElMessage({ type: "success", message: "操作成功", }); gymbLoading.value = false }; // 上传失败的回调 const uploadError = (error, file) => { console.error("上传失败:", error, file); }; // 处理文件删除 // const handleRemove = (file, files) => { // fileList.value = files; // 更新文件列表 // ElMessage.info(`已删除文件: ${file.name}`); // }; //移除上传图纸 function delImg (index){ fileList.value.splice(index, 1); } // #endregion //#region 删除工艺模板 async function delProcedure(row) { ElMessageBox.confirm("确定要删除吗?这可能导致该数据无法找回", "警告", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }) .then(async () => { try { loading.value = true; await request.post("/system/workmanship.workmanship_template/delete", { id: row.id, }); ElMessage({ type: "success", message: "操作成功", }); getProcedure(); } catch (error) { loading.value = false; } }) .catch(() => { }); } // #endregion </script> <style scoped> .item { cursor: pointer; float: left; background: #fff; width: 100px; height: 100px; line-height: 100px; text-align: center; margin: 0 15px 15px 0; border: 1px solid #e6e6e6; display: block; transition: all 0.3s; /* 添加过渡效果 */ } /* 选中的样式 */ .selected { border-color: #409eff; /* 选中的边框颜色 */ background-color: #e6f7ff; /* 选中的背景颜色 */ } .cwxzlist { display: flex; } .changeCheckbox { display: block; margin-bottom: 20px; } .addwarehouse { margin-right: 10px; } :deep(.dialogGxgy .el-dialog__headerbtn) { height: 57px !important; } .dialogtitle { display: flex; justify-content: space-between; align-items: center; } .fullscreen-icon { cursor: pointer; font-size: 18px; color: #606266; transition: color 0.2s; } .fullscreen-icon:hover { color: #409eff; } .dialog-icons { display: flex; align-items: center; gap: 10px; } .gybs { display: flex; align-items: center; width: 100%; } .gyheader { margin-right: 20px; display: flex; align-items: center; width: 24%; } .card_gy { margin: 10px; min-height: 500px; position: relative; } ::v-deep.card_gy .el-card__body { width: 100%; } .tzpx { height: 400px; overflow-y: scroll; scrollbar-width: none; /* Firefox 隐藏滚动条 */ } .slx { display: flex; } .sortable-item { width: 100%; padding: 15px 20px; background: #ffffff; border: 1px solid #e4e7ed; border-radius: 8px; cursor: move; margin-bottom: 12px; transition: all 0.3s ease; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); display: flex; align-items: center; justify-content: center; font-size: 14px; color: #333; } .sortable-item:hover { background-color: #f5f5f5; border-color: #dcdfe6; color: #409eff; } .sortable-item:active { transform: scale(0.98); } .sortable-item .drag-handle { cursor: move; font-size: 18px; color: #999; margin-right: 12px; } .sortable-item .drag-handle:hover { color: #409eff; } .selected { background: #409eff; /* 选中状态变蓝色 */ color: white; font-weight: bold; } .item_left { margin-right: 8px; } .item_content { flex: 1; /* 占据中间可用空间 */ overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .item_right { margin-left: 8px; margin-left: auto; /* 自动将右侧图标推到最右 */ cursor: pointer; } .btgp { display: flex; justify-content: center; position: absolute; bottom: 3%; left: 50%; transform: translateX(-50%); } .gyform { padding: 10px; } .dowt { display: flex; justify-content: space-between; align-items: center; border-top: 1px solid #e4e7ed; border-bottom: 1px solid #e4e7ed; padding: 12px 15px; } .route { margin-top: 30px; } .image-preview-list { width: 100%; text-align: center; padding-top: 30px; /* overflow-x: scroll; */ /* overflow: scroll; */ } .image-preview-list::-webkit-scrollbar { display: none; /* Safari 和 Chrome 隐藏滚动条 */ } /* ::v-deep .el-upload-list { display: flex; } */ .lf_aside { border-left: 1px solid #e4e7ed; display: flex; justify-content: center; } .upbox { width: 100%; display: flex; /* flex-wrap: wrap; */ justify-content: center; flex-direction: column-reverse; align-items: center; } .wdg { width: 90%; border: 1px solid #e4e7ed; height: 50px; border-radius: 5px; display: flex; align-items: center; padding: 0 10px; justify-content: space-between; margin-top: 10px; } .wg_lf { display: flex; align-items: center; cursor: pointer; } .weds { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; width: 80px; display: flex; margin-left: 5px; } </style> 这是我的代码 我的代码现在 handleSelectionChange 勾选列表有问题 如果我勾选多个 然后重新获取列表就会加载不上已勾选的状态
最新发布
08-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值