// ==UserScript== // @name KJL后台-商品列表页添加按钮和调整列表项 // @namespace Violentmonkey Scripts // @match https://www.kujiale.com/pub/saas/admin/brandgoods/all* // @match https://www.kujiale.com/pub/saas/workbench/brandgoods/all* // @grant none // @require https://d3js.org/d3.v7.min.js // @version 1.8.1 // @author hejie13250 // @description 2025/3/30 1:05:58 // ==/UserScript== (function () { 'use strict'; const DEBUG_MODE = true; // 调试模式 // 调试日志 function log(...args) { if (DEBUG_MODE) console.log('[KUJIALE]', ...args); } // 注入样式 function appendStyle() { const STYLE_CONTENT = ` .bTiGAY, .keMTLz { display: unset; border-radius: 2px; color: rgb(255, 255, 255); background: #88858A; padding: 2px; } .goeuoF { margin-right: 4px; } tbody tr.StyledBodyRowTr-kSBvgt > td:nth-child(1), tbody tr.StyledBodyRowTr-kSBvgt.fApoPa > td:nth-child(1), tbody tr.StyledBodyRowTr-kSBvgt > td:nth-child(2), tbody tr.StyledBodyRowTr-kSBvgt.fApoPa > td:nth-child(2), tbody tr.StyledBodyRowTr-kSBvgt > td:nth-last-child(2), tbody tr.StyledBodyRowTr-kSBvgt.fApoPa > td:nth-last-child(2), tbody tr.StyledBodyRowTr-kSBvgt > td:nth-last-child(1), tbody tr.StyledBodyRowTr-kSBvgt.fApoPa > td:nth-last-child(1) { background: #FFFFFFED; } #wb-app-container .wb-fixedSider, .Sider-siderWrapper_448bb .Sider-collapseBtn_3d285 { display: none; /* 默认隐藏侧边栏 */ } table.StyledTable-diJSpn.irqLUa thead tr th:nth-last-child(2), tr.StyledBodyRowTr-kSBvgt td:nth-last-child(2), .app__StyledHeader-sc-19hozu1-1, .app__StyleExtraContentPlugins-sc-19hozu1-0 { display: none; } /* 侧边栏展开按钮样式 */ .Sider-collapseBtn { position: fixed; left: 0; top: 0; height: 110px; width: 150px; background: #0000; transform: translateY(-50%); z-index: 1000; cursor: pointer; } table.StyledTable-diJSpn.irqLUa tbody { display: none; } /* 新增渐变显示效果 */ table.StyledTable-diJSpn.irqLUa tbody { opacity: 0; /* 初始完全透明 */ display: table-row-group; /* 保持表格行组布局 */ transition: opacity 0.5s ease-in-out; /* 半秒的渐变效果 */ } /* 当添加show类时显示内容 */ table.StyledTable-diJSpn.irqLUa tbody.show { opacity: 1; /* 完全不透明 */ } /* 表头 */ .irqLUa thead th { padding: 2px 4px; } thead tr th { height: 40px; } th.table-mode__Th-sc-1yn5aku-1:nth-child(13) > div:nth-child(1) > div:nth-child(2), .htbUul .StyledHeaderContent-gwiBRL .StyledHeaderIconWrapper-ckhjhe, th.table-mode__Th-sc-1yn5aku-1:nth-child(7) > div:nth-child(1) > div:nth-child(2) { display: none; } .fwwEgAW { position: absolute; left: 1px; bottom: 45px; } .leKfqU { padding: 5px; } .jZKSUl { padding: 5px; } .irqLUa thead .StyledHeaderContent-gwiBRL { padding: 5px; } .Eqqwv { width: 120px; } tr.StyledBodyRowTr-kSBvgt td:nth-child(1), tr.StyledBodyRowTr-kSBvgt td:nth-child(2), tr.StyledBodyRowTr-kSBvgt td:nth-last-child(2), tr.StyledBodyRowTr-kSBvgt td:nth-last-child(1) { cursor: default; } tr.StyledBodyRowTr-kSBvgt > td { padding: 0px 5px !important; } .Link-qfJUS.dtwGsR { padding: 4px 4px; } .fnmwsn { margin-bottom: 0px; } .djGvpx:hover { background: #9d8b; } .spanNum { margin-right: 5px; } .custom-btn { display: inline-block; } .Link-qfJUS.dtwGsR { fontSize: 14px !important; margin-bottom: 5px; padding: 2px 4px; border-radius: 4px; } /* 工具企业可见为“可见”时图片边框样式 */ .visible-highlight { border: 3px solid #4CAF50 !important; /* 绿色边框 */ border-radius: 4px; width: 76px; margin-top: 5px; margin-bottom: 5px; } /* 工具企业可见为“不可见”时图片边框样式 */ .invisible-highlight { border: 3px solid #F44336 !important; /* 红色边框 */ border-radius: 4px; width: 76px; margin-top: 5px; margin-bottom: 5px; } /* 当前行为目录时 */ .transparent-highlight { border: 3px solid transparent !important; /* 透明边框 */ border-radius: 4px; width: 76px; margin-top: 5px; margin-bottom: 5px; } /* 节点样式 */ .graph-node { background: white; border: 1px solid #eee; border-radius: 12px; overflow: hidden; transition: transform 0.1s, box-shadow 0.1s, width 0.3s; /* 添加宽度过渡效果 */ flex-direction: column; /* 改为上下结构 */ font-size: 14px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); cursor: default; /* 默认光标 */ width: 300px; /* 初始宽度 */ height: 150px; /* 初始高度 */ z-index: 1; transition: height 0.3s ease, transform 0.1s, box-shadow 0.1s, width 0.3s; overflow: hidden; /* 确保内容不会溢出 */ } .graph-node:hover { border: 1px solid #eee; width: auto; /* 悬停时宽度自动调整 */ min-width: 300px; /* 确保最小宽度 */ height: 180px; /* 悬停时增加高度 */ box-shadow: 0 4px 10px rgb(66, 49, 16); /* 鼠标悬停时增加阴影 */ cursor: text; /* 鼠标悬停时变为选择文本光标 */ z-index: 100 !important; } /* 按钮容器初始完全隐藏且不占空间 */ .graph-node-buttons { display: none; /* 初始不显示 */ justify-content: space-around; padding: 5px 0; border-top: 1px solid #eee; opacity: 0; transition: opacity 0.3s ease; } .graph-node-button { padding: 0px 10px; border-radius: 4px; } .graph-node-button:hover { cursor: pointer; background: #dfe; } /* 鼠标悬停时显示按钮容器 */ .graph-node:hover .graph-node-buttons { display: flex; /* 显示容器 */ opacity: 1; /* 淡入效果 */ } /* 确保节点内容区域高度固定 */ .graph-node-content { flex: 1; display: flex; padding: 10px; gap: 10px; min-height: 100px; /* 固定内容区域高度 */ } .graph-node-name { font-weight: bold; padding: 10px; background: #f5f5f5; border-bottom: 1px solid #eee; height: 40px; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .graph-node-content { flex: 1; display: flex; /* 改为左右结构 */ padding: 10px; gap: 10px; } .graph-node-image { width: 80px; height: 80px; object-fit: cover; cursor: pointer; border-radius: 4px; border: 2px solid #ddd; /* 添加边框 */ transition: border-color 0.2s; /* 添加边框颜色的过渡效果 */ } .graph-node-image:hover { border-color: #999; /* 鼠标悬停时边框颜色变深 */ } .graph-node-text { display: flex; flex-direction: column; flex: 1; /* 让文本部分占据剩余空间 */ } .text-item { white-space: nowrap; /* 禁止换行 */ overflow: hidden; /* 隐藏溢出内容 */ text-overflow: ellipsis; /* 显示省略号 */ max-width: 100%; /* 限制最大宽度 */ display: block; /* 确保作为块级元素显示 */ font-size: 14px; /* 设置字体大小 */ line-height: 1.5; /* 设置行高 */ color: #333; /* 设置文本颜色 */ transition: all 0.3s; /* 添加过渡效果 */ } `; // 创建style元素并注入样式 const style = document.createElement('style'); style.type = 'text/css'; style.appendChild(document.createTextNode(STYLE_CONTENT)); document.head.appendChild(style); } appendStyle(); // 创建侧边栏展开按钮 const collapseBtn = document.createElement('div'); collapseBtn.className = 'Sider-collapseBtn'; document.body.appendChild(collapseBtn); // 获取侧边栏元素 const fixedSider = document.querySelector('#wb-app-container .wb-fixedSider'); if (fixedSider) { // 初始化侧边栏样式 fixedSider.style.transition = 'width 0.3s ease, opacity 0.3s ease'; // 过渡动画 fixedSider.style.overflow = 'hidden'; // 隐藏溢出内容 fixedSider.style.width = '0'; // 初始宽度为0 fixedSider.style.opacity = '0'; // 初始完全透明 // 防抖计时器和状态标志 let debounceTimer; let isSiderVisible = false; // 显示侧边栏函数 const showSider = () => { clearTimeout(debounceTimer); // 清除隐藏计时器 fixedSider.style.display = 'block'; fixedSider.style.width = '200px'; // 设置展开宽度 fixedSider.style.opacity = '1'; // 完全不透明 isSiderVisible = true; // 更新状态 }; // 隐藏侧边栏函数 const hideSider = () => { debounceTimer = setTimeout(() => { fixedSider.style.width = '0'; // 宽度归零 fixedSider.style.opacity = '0'; // 完全透明 // 过渡结束后执行 fixedSider.addEventListener('transitionend', function transitionEnd() { if (fixedSider.style.width === '0px') { fixedSider.removeEventListener('transitionend', transitionEnd); fixedSider.style.display = 'none'; // 完全隐藏 isSiderVisible = false; // 更新状态 } }, { once: true }); // 只执行一次 }, 100); // 延迟100ms执行 }; // 按钮点击事件 - 切换侧边栏状态 collapseBtn.addEventListener('click', (e) => { e.stopPropagation(); // 阻止事件冒泡 if (isSiderVisible) { hideSider(); // 如果可见则隐藏 } else { showSider(); // 如果隐藏则显示 } }); // 鼠标离开侧边栏时隐藏 fixedSider.addEventListener('mouseleave', hideSider); // 鼠标进入侧边栏时取消隐藏计时器 fixedSider.addEventListener('mouseenter', () => { clearTimeout(debounceTimer); }); } let idColumnIndex = null; // 商品ID列索引 let toolVisibleColumnIndex = null; // 工具可见列索引 let brandSeriesColumnIndex = null; // 品牌系列列索引 let productStatusColumnIndex = null; // 产品状态列索引 let publishStatusColumnIndex = null; // 发布状态列索引 let modelColumnIndex = null; // 型号列索引 let productCodeColumnIndex = null; // 产品代码列索引 let customCodeColumnIndex = null; // 自定义代码列索引 let renderCategoryColumnIndex = null; // 渲染类别列索引 let materialColumnIndex = null; // 材质列索引 let baseMaterialColumnIndex = null; // 基础材质列索引 let creatorColumnIndex = null; // 创建者列索引 let createDateColumnIndex = null; // 创建日期列索引 let hasAlerted = false; // 标记是否已经提示过 // 初始化列索引(只提示一次) function initColumnIndexes() { const headerRow = document.querySelector('.StyledTable-diJSpn > thead:nth-child(2) > tr'); const headers = headerRow.querySelectorAll('th'); let foundId = false; let foundToolVisible = false; let foundBrandSeries = false; let foundProductStatus = false; let foundPublishStatus = false; for (let i = 0; i < headers.length; i++) { const header = headers[i]; const headerContent = header.querySelector('.StyledHeaderContent-gwiBRL'); if (!foundId && header.textContent.includes('商品ID')) { idColumnIndex = i + 1; foundId = true; } if (!foundToolVisible && headerContent && headerContent.textContent.trim() === '工具企业库可见') { toolVisibleColumnIndex = i + 1; foundToolVisible = true; } if (!foundBrandSeries && header.textContent.includes('品牌系列')) { brandSeriesColumnIndex = i + 1; foundBrandSeries = true; } if (!foundProductStatus && header.textContent.includes('商品状态')) { productStatusColumnIndex = i + 1; foundProductStatus = true; } if (!foundPublishStatus && header.textContent.includes('发布状态')) { publishStatusColumnIndex = i + 1; foundPublishStatus = true; } if (header.textContent.includes('型号')) { modelColumnIndex = i + 1; } if (header.textContent.includes('产品编码')) { productCodeColumnIndex = i + 1; } if (header.textContent.includes('自定义编码')) { customCodeColumnIndex = i + 1; } if (header.textContent.includes('渲染分类')) { renderCategoryColumnIndex = i + 1; } if (header.textContent.includes('材质')) { materialColumnIndex = i + 1; } if (header.textContent.includes('基材')) { baseMaterialColumnIndex = i + 1; } if (header.textContent.includes('创建者')) { creatorColumnIndex = i + 1; } if (header.textContent.includes('创建日期')) { createDateColumnIndex = i + 1; } } // 如果找到所有必需列 const requiredColumnsFound = foundId && foundToolVisible; // 如果找到商品状态和发布状态列,准备移动内容 const statusColumnsFound = foundProductStatus && foundPublishStatus && foundBrandSeries; if (requiredColumnsFound) { hasAlerted = false; // 重置提示状态 console.log('列索引初始化成功'); return true; } // 如果未找到所有必需列且未提示过 // if (!hasAlerted) { // const missingColumns = []; // if (!foundId) missingColumns.push('"商品ID"'); // if (!foundToolVisible) missingColumns.push('"工具企业库可见"'); // alert(`请开启以下列后刷新页面:${missingColumns.join('和')}\n\n操作步骤:\n1. 点击表格右上角的"列设置"按钮\n2. 勾选缺少的列\n3. 刷新页面`); // hasAlerted = true; // } return false; } // 更新可见性检查和高亮函数,返回布尔值表示是否应该继续初始化 function updateProductDisplayStatus() { if (toolVisibleColumnIndex === null) { if (!initColumnIndexes()) { log('无法初始化列索引,可见性检查中止'); return false; } } let shouldInitialize = false; const rows = document.querySelectorAll('tr.StyledBodyRowTr-kSBvgt'); rows.forEach(row => { const visibilityCell = row.querySelector(`td:nth-child(${toolVisibleColumnIndex})`); if (!visibilityCell) return; const visibilityText = visibilityCell.textContent.trim(); const targetDiv = row.querySelector('td:nth-child(2) > div:nth-child(1) > div:nth-child(1)'); if (!targetDiv) return; // 移除可能存在的旧样式 targetDiv.classList.remove('visible-highlight', 'invisible-highlight', 'transparent-highlight'); if (visibilityText === '可见') { targetDiv.classList.add('visible-highlight'); shouldInitialize = true; // 有可见行,需要初始化 } else if (visibilityText === '不可见') { targetDiv.classList.add('invisible-highlight'); shouldInitialize = true; // 有不可见行,需要初始化 } else { targetDiv.classList.add('transparent-highlight'); // 其他情况不设置shouldInitialize标志 } // 新增:移动状态信息到品牌系列列 if (brandSeriesColumnIndex && productStatusColumnIndex && publishStatusColumnIndex) { const brandSeriesTd = row.querySelector(`td:nth-child(${brandSeriesColumnIndex})`); const productStatusTd = row.querySelector(`td:nth-child(${productStatusColumnIndex})`); const publishStatusTd = row.querySelector(`td:nth-child(${publishStatusColumnIndex})`); if (brandSeriesTd && productStatusTd && publishStatusTd) { // 获取品牌系列原始内容(保留HTML结构) const brandSeriesContent = brandSeriesTd.querySelector('div') || brandSeriesTd; // 获取状态内容 const productStatusDiv = productStatusTd.querySelector('div') || productStatusTd; const publishStatusDiv = publishStatusTd.querySelector('div') || publishStatusTd; // 清空品牌系列td并重新构建内容 brandSeriesTd.innerHTML = ''; // 创建容器div const containerDiv = document.createElement('div'); containerDiv.style.display = 'flex'; containerDiv.style.flexDirection = 'column'; containerDiv.style.gap = '4px'; // 添加品牌系列div(保留原始结构和样式) const brandSeriesDiv = document.createElement('div'); brandSeriesDiv.innerHTML = brandSeriesContent.innerHTML; containerDiv.appendChild(brandSeriesDiv); // 添加商品状态div const productStatusContainer = document.createElement('div'); productStatusContainer.style.fontSize = '12px'; productStatusContainer.style.color = '#666'; productStatusContainer.textContent = `商品状态: ${productStatusDiv.textContent.trim()}`; containerDiv.appendChild(productStatusContainer); // 添加发布状态div const publishStatusContainer = document.createElement('div'); publishStatusContainer.style.fontSize = '12px'; publishStatusContainer.style.color = '#666'; publishStatusContainer.textContent = `发布状态: ${publishStatusDiv.textContent.trim()}`; containerDiv.appendChild(publishStatusContainer); // 将容器添加到td brandSeriesTd.appendChild(containerDiv); // 隐藏原始状态列 productStatusTd.style.display = 'none'; publishStatusTd.style.display = 'none'; } } }); return shouldInitialize; } let TAB_TEXT = ''; let currentType = ''; const TYPE_MAPPING = { '厨卫定制': 'cabinet', '全屋家具定制': 'wardrobe', '门窗定制': 'doorwindow' }; // 更新标签页信息的函数 function updateTabInfo() { const tabElement = document.querySelector('div.BaseNode-ddnpWv.jaYkes.Tab-fzpsPV.lnGuGN.muya-tabs-tab.muya-pangu-tabs-tab.muya-tabs-active-tab.muya-pangu-tabs-active-tab > button'); TAB_TEXT = tabElement ? tabElement.textContent.trim() : ''; currentType = TYPE_MAPPING[TAB_TEXT] || ''; } // 确保全局模态窗口变量已定义 let attrModalMask = null; let attrModalContent = null; let attrTablesContainer = null; // 初始化属性窗口函数 function initAttributeModal() { if (attrModalMask) return; // 如果已经存在则不重复创建 attrModalMask = document.createElement('div'); attrModalMask.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:999;display:none;'; attrModalContent = document.createElement('div'); attrModalContent.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:white;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px rgba(0,0,0,0.15);width:500px;height:600px;'; attrTablesContainer = document.createElement('div'); attrTablesContainer.style.cssText = 'overflow:auto;width:100%;height:100%;padding:20px;'; attrModalContent.appendChild(attrTablesContainer); attrModalMask.appendChild(attrModalContent); document.body.appendChild(attrModalMask); // 点击遮罩层关闭窗口 attrModalMask.addEventListener('click', (e) => { if (e.target === attrModalMask) { attrModalMask.style.display = 'none'; } }); } // 创建浮动窗口 function createFloatingWindow() { const modalMask = document.createElement('div'); modalMask.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:999;display:none;'; const modalContent = document.createElement('div'); modalContent.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:white;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px rgba(0,0,0,0.15);'; const tablesContainer = document.createElement('div'); tablesContainer.style.cssText = 'overflow:hidden;width:100%;height:100%;position:relative;'; modalContent.appendChild(tablesContainer); modalMask.appendChild(modalContent); document.body.appendChild(modalMask); // 点击遮罩层关闭窗口 modalMask.addEventListener('click', (e) => { if (e.target === modalMask) { modalMask.style.display = 'none'; } }); // 动态设置窗口大小 function setSize(width, height) { if (typeof width === 'string' && width.endsWith('%')) { modalContent.style.width = width; modalContent.style.left = `calc(50% - ${parseInt(width) / 2}%)`; // 居中 } else { modalContent.style.width = `${width}px`; modalContent.style.left = `calc(50% - ${width / 2}px)`; // 居中 } if (typeof height === 'string' && height.endsWith('%')) { modalContent.style.height = height; modalContent.style.top = `calc(50% - ${parseInt(height) / 2}%)`; // 居中 } else { modalContent.style.height = `${height}px`; modalContent.style.top = `calc(50% - ${height / 2}px)`; // 居中 } } return { modalMask, tablesContainer, setSize }; } const { modalMask, tablesContainer, setSize } = createFloatingWindow(); // 创建表格 function createTable(title, columns, rows) { const table = document.createElement('table'); table.style.cssText = 'width:100%;margin-top:20px;border-collapse:collapse;font-size:14px;'; const thead = document.createElement('thead'); thead.innerHTML = `${columns.map(col => `${col}`).join('')}`; const tbody = document.createElement('tbody'); rows.forEach(row => { const tr = document.createElement('tr'); tr.innerHTML = row.map(cell => `${cell}`).join(''); tbody.appendChild(tr); }); table.appendChild(thead); table.appendChild(tbody); const wrapper = document.createElement('div'); wrapper.style.marginTop = '20px'; const titleEl = document.createElement('h3'); titleEl.textContent = title; titleEl.style.cssText = 'font-size:16px;margin:0 0 10px 0;color:#333;'; wrapper.appendChild(titleEl); wrapper.appendChild(table); return wrapper; } // 获取数据 async function getData(obsBgId) { if (!attrTablesContainer) { initAttributeModal(); } attrTablesContainer.innerHTML = '
加载中...
'; attrModalMask.style.display = 'block'; try { const urls = [ `https://www.kujiale.com/editor/api/site/param/bizproperty/editordata/query?obsBrandGoodId=${obsBgId}`, `https://www.kujiale.com/dcscms/api/custom/brandgood/attribute?start=0&num=30&obsBgId=${obsBgId}`, `https://www.kujiale.com/editor/api/site/input/parameters/${obsBgId}` ]; const responses = await Promise.all(urls.map(url => fetch(url).then(r => r.json()).catch(e => { console.error(`请求失败: ${url}`, e); return null; }) )); attrTablesContainer.innerHTML = ''; const contentWrapper = document.createElement('div'); contentWrapper.style.cssText = 'max-height: 100%; overflow-y: auto; padding: 10px; border: 1px solid #ddd; border-radius: 4px;'; // 处理第一个API响应 if (responses[0]?.d?.length > 0) { const title = '自定义输出属性'; const columns = ['属性名称', '属性引用名', '属性值']; const rows = responses[0].d.map(item => [item.name, item.key, item.value]); contentWrapper.appendChild(createTable(title, columns, rows)); } // 处理第二个API响应 if (responses[1]?.d?.result?.length > 0) { const title = '自定义属性'; const columns = ['属性名称', '属性引用名', '属性值']; const rows = responses[1].d.result.map(item => [item.attributeName, item.quoteName, item.attributeValue]); contentWrapper.appendChild(createTable(title, columns, rows)); } // 处理第三个API响应 if (Array.isArray(responses[2]) && responses[2].length > 0) { const title = '自定义参数'; const columns = ['参数名称', '参数引用名']; const rows = responses[2].map(item => [item.displayName, item.paramName]); contentWrapper.appendChild(createTable(title, columns, rows)); } // 如果没有数据,显示提示 if (contentWrapper.children.length === 0) { contentWrapper.innerHTML = '
未找到相关属性数据
'; } attrTablesContainer.appendChild(contentWrapper); } catch (error) { console.error('获取数据失败:', error); attrTablesContainer.innerHTML = '
数据加载失败,请稍后再试
'; } } // 递归获取所有节点(包括顶层父节点和所有子节点) async function getAllNodes(obsBgId, result = [], level = 0) { try { const url = `https://www.kujiale.com/editor/api/site/editordata?obsbrandgoodid=${obsBgId}`; log(`发送请求: ${url}, 层级: ${level}`); const response = await fetch(url); const data = await response.json(); log(`请求响应:`, data); // 提取当前节点信息 if (data?.model) { const currentNode = data.model; const node = { id: currentNode.obsBrandGoodId, name: currentNode.name, displayCoverImgUrl: currentNode.displayCoverImgUrl, level: level, children: [] }; // 获取对接编码 const dockCodeResponse = await fetch(`https://www.kujiale.com/editor/api/site/param/bizproperty/editordata/query?obsBrandGoodId=${node.id}`); const dockCodeData = await dockCodeResponse.json(); const dockCodeEntry = dockCodeData.d.find(entry => entry.name === "对接编码"); node.dockCode = dockCodeEntry ? dockCodeEntry.value : "未定义"; // 如果是顶层节点,直接添加到结果中 if (level === 0) { result.push(node); } // 提取子节点信息 if (data?.resource?.models) { log(`发现子节点:`, data.resource.models); for (const model of data.resource.models) { const childNode = await getAllNodes(model.obsBrandGoodId, [], level + 1); if (childNode.length > 0) { node.children.push(childNode[0]); // 添加子节点 } } } // 如果不是顶层节点,返回当前节点 if (level !== 0) { return [node]; } } } catch (error) { log(`获取节点 ${obsBgId} 数据失败:`, error); } return result; } // 画节点 function drawGraph(data) { tablesContainer.innerHTML = ''; // 创建画布和容器 const canvas = document.createElement('canvas'); canvas.style.position = 'absolute'; canvas.style.top = '0'; canvas.style.left = '0'; canvas.style.width = '100%'; canvas.style.height = '100%'; canvas.style.pointerEvents = 'none'; tablesContainer.appendChild(canvas); const nodesContainer = document.createElement('div'); nodesContainer.style.position = 'absolute'; nodesContainer.style.transformOrigin = '0 0'; nodesContainer.style.opacity = '0'; tablesContainer.appendChild(nodesContainer); // 创建独立的属性窗口 const attrModalMask = document.createElement('div'); attrModalMask.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:999;display:none;'; const attrModalContent = document.createElement('div'); attrModalContent.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);background:white;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px rgba(0,0,0,0.15);width:500px;height:600px;'; const attrTablesContainer = document.createElement('div'); attrTablesContainer.style.cssText = 'overflow:auto;width:100%;height:100%;padding:20px;'; attrModalContent.appendChild(attrTablesContainer); attrModalMask.appendChild(attrModalContent); document.body.appendChild(attrModalMask); // 坐标转换系统 let transform = { x: 0, y: 0, k: 1 }; // 初始化D3树布局 const root = d3.hierarchy(data[0], d => d.children); const treeLayout = d3.tree() .nodeSize([250, 310]) .separation((a, b) => a.parent === b.parent ? 2 : 3); treeLayout(root); // 创建节点元素 const nodes = root.descendants(); nodes.forEach(node => { const el = document.createElement('div'); el.className = 'graph-node'; el.style.position = 'absolute'; el.style.width = '300px'; el.style.left = `${node.x}px`; el.style.top = `${node.y}px`; el.style.zIndex = '1'; // 创建底部按钮容器 const buttonsContainer = document.createElement('div'); buttonsContainer.className = 'graph-node-buttons'; // 详情按钮 const detailBtn = document.createElement('span'); detailBtn.className = 'graph-node-button'; detailBtn.textContent = '详情'; detailBtn.addEventListener('click', (e) => { e.stopPropagation(); window.open(`https://www.kujiale.com/pub/saas/brandgoods/detail?obsbrandgoodsid=${node.data.id}`); }); // 属性按钮 const attrBtn = document.createElement('span'); attrBtn.className = 'graph-node-button'; attrBtn.textContent = '属性'; attrBtn.addEventListener('click', async (e) => { e.stopPropagation(); await getData(node.data.id); }); buttonsContainer.appendChild(detailBtn); buttonsContainer.appendChild(attrBtn); // 编辑按钮(根据条件显示) const editBtn = document.createElement('span'); if (currentType) { editBtn.className = 'graph-node-button'; editBtn.textContent = '打开'; editBtn.addEventListener('click', (e) => { e.stopPropagation(); window.open(`https://www.kujiale.com/vc/modeleditor/new?tooltype=${currentType}&obsbrandgoodid=${node.data.id}`); }); buttonsContainer.appendChild(editBtn); } // 创建节点时,按钮容器初始为隐藏状态 el.innerHTML = `
${node.data.name}
层级: ${node.data.level + 1}
对接编码: ${node.data.dockCode}
`; el.appendChild(buttonsContainer); // 节点的鼠标悬停事件 el.addEventListener('mouseenter', () => { document.querySelectorAll('.graph-node').forEach(n => n.style.zIndex = '1'); el.style.zIndex = '100'; const imageWidth = el.querySelector('.graph-node-image').offsetWidth; const textWidth = el.querySelector('.graph-node-text').offsetWidth; const padding = 20; const totalWidth = imageWidth + textWidth + padding + 10; el.style.width = `${totalWidth}px`; // 显示按钮 const buttons = el.querySelector('.graph-node-buttons'); if (buttons) { buttons.style.opacity = '1'; } }); el.addEventListener('mouseleave', () => { el.style.zIndex = '1'; el.style.width = '300px'; // 隐藏按钮 const buttons = el.querySelector('.graph-node-buttons'); if (buttons) { buttons.style.opacity = '0'; } }); nodesContainer.appendChild(el); // 图片点击事件 el.querySelector('img').addEventListener('click', e => { e.stopPropagation(); window.open(`https://www.kujiale.com/pub/saas/brandgoods/detail?obsbrandgoodsid=${node.data.id}`); }); }); // 更新视图函数 function updateView() { const { k, x, y } = transform; nodesContainer.style.transform = `translate(${x}px, ${y}px) scale(${k})`; const rect = tablesContainer.getBoundingClientRect(); canvas.width = rect.width; canvas.height = rect.height; const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.save(); ctx.translate(x, y); ctx.scale(k, k); ctx.strokeStyle = '#999'; ctx.lineWidth = 2; root.links().forEach(link => { const source = link.source; const target = link.target; const sourceX = source.x + 150; const sourceY = source.y + 150; const targetX = target.x + 150; const targetY = target.y; ctx.beginPath(); ctx.moveTo(sourceX, sourceY); ctx.bezierCurveTo( sourceX, sourceY + 50, targetX, targetY - 50, targetX, targetY ); ctx.stroke(); }); ctx.restore(); } // 自动调整视图以显示所有节点 function autoFitView() { // 获取所有节点的边界 let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; nodes.forEach(node => { minX = Math.min(minX, node.x); maxX = Math.max(maxX, node.x + 300); minY = Math.min(minY, node.y); maxY = Math.max(maxY, node.y + 180); // 更新为新的节点高度 }); // 计算内容尺寸 const contentWidth = maxX - minX; const contentHeight = maxY - minY; // 获取容器尺寸 const containerWidth = tablesContainer.clientWidth; const containerHeight = tablesContainer.clientHeight; // 计算合适的缩放比例 const scaleX = containerWidth / (contentWidth + 100); const scaleY = containerHeight / (contentHeight + 100); const newScale = Math.min(scaleX, scaleY, 1); // 计算中心点偏移 const centerX = (minX + maxX) / 2; const centerY = (minY + maxY) / 2; const offsetX = (containerWidth / 2) - (centerX * newScale); const offsetY = (containerHeight / 2) - (centerY * newScale); // 应用新的变换 transform.k = newScale; transform.x = offsetX; transform.y = offsetY; updateView(); // 调整完成后显示节点 nodesContainer.style.opacity = '1'; nodesContainer.style.transition = 'opacity 0.3s ease'; } // 初始布局 updateView(); // 使用requestAnimationFrame确保DOM已完全渲染 requestAnimationFrame(() => { autoFitView(); }); // 交互逻辑 let dragStart = { x: 0, y: 0 }; tablesContainer.addEventListener('mousedown', e => { if (e.target === tablesContainer || e.target === canvas) { dragStart = { x: e.clientX - transform.x, y: e.clientY - transform.y }; tablesContainer.style.cursor = 'grabbing'; } }); tablesContainer.addEventListener('mousemove', e => { if (dragStart.x || dragStart.y) { transform.x = e.clientX - dragStart.x; transform.y = e.clientY - dragStart.y; updateView(); } }); tablesContainer.addEventListener('mouseup', () => { dragStart = { x: 0, y: 0 }; tablesContainer.style.cursor = 'grab'; }); tablesContainer.addEventListener('wheel', e => { e.preventDefault(); const prevK = transform.k; const newK = Math.max(0.1, Math.min(3, transform.k * (e.deltaY < 0 ? 1.5 : 0.5))); const mx = e.clientX - tablesContainer.getBoundingClientRect().left; const my = e.clientY - tablesContainer.getBoundingClientRect().top; transform.x = mx - (mx - transform.x) * (newK / prevK); transform.y = my - (my - transform.y) * (newK / prevK); transform.k = newK; updateView(); }); tablesContainer.addEventListener('contextmenu', (e) => { e.preventDefault(); return false; }); window.addEventListener('resize', () => { updateView(); autoFitView(); }); // 点击遮罩层关闭属性窗口 attrModalMask.addEventListener('click', (e) => { if (e.target === attrModalMask) { attrModalMask.style.display = 'none'; } }); } // 创建按钮 function createButton(text, action) { const btn = document.createElement('div'); btn.className = 'custom-btn'; const link = document.createElement('a'); link.className = 'StyledLink-kjrCJO gvhEJs StyledInlineButton-fyUImi djGvpx WrapInlineButton-nnTTR kUBFEP Link-qfJUS dtwGsR'; link.style.cssText = 'cursor: pointer; color: rgb(51, 139, 255);'; link.textContent = text; link.addEventListener('click', action); btn.appendChild(link); return btn; } // 序号功能 let sequenceNumber = 1; function resetSequenceNumber() { sequenceNumber = 1; } function createSequenceSpan() { const span = document.createElement('span'); span.textContent = sequenceNumber++; span.className = 'spanNum'; return span; } function addSequenceNumbers() { resetSequenceNumber(); const trElements = document.querySelectorAll('tbody tr.StyledBodyRowTr-kSBvgt'); trElements.forEach(tr => { const lastTd = tr.lastElementChild; if (lastTd && !lastTd.querySelector('.spanNum')) { lastTd.insertBefore(createSequenceSpan(), lastTd.firstChild); } }); } // 行点击高亮功能 function changeTextColorToRed(tr) { Array.from(tr.children).forEach(td => { td.style.color = 'red'; }); } function restoreTextColor(tr) { Array.from(tr.children).forEach(td => { td.style.color = ''; }); } function addClickListeners() { const trElements = document.querySelectorAll('tbody tr.StyledBodyRowTr-kSBvgt'); trElements.forEach(tr => { tr.addEventListener('click', function (event) { // 清除之前可能存在的红色文本 const allTrElements = document.querySelectorAll('tbody tr.StyledBodyRowTr-kSBvgt'); allTrElements.forEach(tr => { restoreTextColor(tr); }); // 改变当前tr内所有文本的颜色为红色 changeTextColorToRed(tr); }); }); } // 调整列表布局样式 function updateProductDisplayStatus() { if (toolVisibleColumnIndex === null) { if (!initColumnIndexes()) { log('无法初始化列索引,可见性检查中止'); return false; } } let shouldInitialize = false; const rows = document.querySelectorAll('tr.StyledBodyRowTr-kSBvgt'); // 获取表格的colgroup const table = document.querySelector('table.StyledTable-diJSpn.irqLUa'); const colgroup = table?.querySelector('colgroup'); const cols = colgroup?.querySelectorAll('col'); // 计算需要隐藏的列数 let hiddenColumnCount = 0; const columnsToHide = [ productStatusColumnIndex, publishStatusColumnIndex, idColumnIndex, modelColumnIndex, productCodeColumnIndex, baseMaterialColumnIndex, materialColumnIndex ].filter(index => index !== null && index !== undefined); hiddenColumnCount = columnsToHide.length; // 隐藏表头中的相关列 const headerRow = document.querySelector('.StyledTable-diJSpn > thead:nth-child(2) > tr'); if (headerRow) { columnsToHide.forEach(colIndex => { const header = headerRow.querySelector(`th:nth-child(${colIndex})`); if (header) header.style.display = 'none'; }); } // 设置列宽度 if (cols && hiddenColumnCount > 0) { const totalCols = cols.length; const visibleCols = totalCols - hiddenColumnCount; // 隐藏指定的列 for (let i = totalCols - 1; i >= visibleCols; i--) { if (cols[i]) { cols[i].style.width = '0px'; cols[i].style.minWidth = '0px'; } } // 定义列宽配置 const columnWidths = { 1: { width: '260px', minWidth: '260px' }, 2: { width: '140px', minWidth: '140px' }, 3: { width: '180px', minWidth: '180px' }, 4: { width: '120px', minWidth: '120px' }, 5: { width: '80px', minWidth: '80px' }, 6: { width: '70px', minWidth: '70px' } }; // 应用预定义的列宽 Object.entries(columnWidths).forEach(([index, styles]) => { const colIndex = parseInt(index); if (cols[colIndex] && colIndex < visibleCols) { Object.assign(cols[colIndex].style, styles); } }); // 处理倒数第二和倒数第三可见列 const specialColumns = [ { index: visibleCols - 1, styles: { width: '0px', minWidth: '0px', display: 'none' } }, { index: visibleCols - 2, styles: { width: '0px', minWidth: '0px', display: 'none' } } ]; specialColumns.forEach(({ index, styles }) => { if (cols[index]) { Object.assign(cols[index].style, styles); } }); } // 处理每一行 rows.forEach(async row => { // 可见性高亮逻辑保持不变... const visibilityCell = row.querySelector(`td:nth-child(${toolVisibleColumnIndex})`); if (!visibilityCell) return; const visibilityText = visibilityCell.textContent.trim(); const targetDiv = row.querySelector('td:nth-child(2) > div:nth-child(1) > div:nth-child(1)'); if (!targetDiv) return; targetDiv.classList.remove('visible-highlight', 'invisible-highlight', 'transparent-highlight'); if (visibilityText === '可见') { targetDiv.classList.add('visible-highlight'); shouldInitialize = true; } else if (visibilityText === '不可见') { targetDiv.classList.add('invisible-highlight'); shouldInitialize = true; } else { targetDiv.classList.add('transparent-highlight'); } // 获取商品ID const idCell = row.querySelector(`td:nth-child(${idColumnIndex})`); if (!idCell) return; const actualElement = idCell.querySelector('span, div') || idCell; const currentId = (actualElement.textContent || '').trim(); if (!currentId) return; // 1. 将状态信息和ID移动到品牌系列列 if (brandSeriesColumnIndex && idColumnIndex) { const brandSeriesTd = row.querySelector(`td:nth-child(${brandSeriesColumnIndex})`); const idTd = row.querySelector(`td:nth-child(${idColumnIndex})`); // 可选列 const productStatusTd = productStatusColumnIndex ? row.querySelector(`td:nth-child(${productStatusColumnIndex})`) : null; const publishStatusTd = publishStatusColumnIndex ? row.querySelector(`td:nth-child(${publishStatusColumnIndex})`) : null; if (brandSeriesTd && idTd) { if (brandSeriesTd.dataset.processed === 'true') return; const brandSeriesDiv = brandSeriesTd.querySelector('div') || brandSeriesTd; const idDiv = idTd.querySelector('div') || idTd; // 获取内容 const idText = (idDiv.querySelector('.StyledContentCopy-bdGJSR.kZSaGD') || idDiv).textContent.trim(); let productStatusText = ''; if (productStatusTd) { const productStatusDiv = productStatusTd.querySelector('div') || productStatusTd; productStatusText = (productStatusDiv.querySelector('.StyledContentCopy-bdGJSR.kZSaGD') || productStatusDiv).textContent.trim(); } let publishStatusText = ''; if (publishStatusTd) { const publishStatusDiv = publishStatusTd.querySelector('div') || publishStatusTd; publishStatusText = (publishStatusDiv.querySelector('.StyledContentCopy-bdGJSR.kZSaGD') || publishStatusDiv).textContent.trim(); } // 创建容器 const containerDiv = document.createElement('div'); containerDiv.style.display = 'flex'; containerDiv.style.flexDirection = 'column'; containerDiv.style.gap = '4px'; // 添加品牌系列内容 const brandSeriesContainer = document.createElement('div'); brandSeriesContainer.innerHTML = brandSeriesDiv.innerHTML; containerDiv.appendChild(brandSeriesContainer); // 添加商品ID const idContainer = document.createElement('div'); idContainer.style.color = '#666'; idContainer.textContent = `${idText}`; containerDiv.appendChild(idContainer); // 添加商品状态(如果有内容) if (productStatusText) { const productStatusContainer = document.createElement('div'); productStatusContainer.style.color = '#666'; productStatusContainer.textContent = `状态: ${productStatusText}`; containerDiv.appendChild(productStatusContainer); } // 添加发布状态(如果有内容) if (publishStatusText) { const publishStatusContainer = document.createElement('div'); publishStatusContainer.style.color = '#666'; publishStatusContainer.textContent = `发布: ${publishStatusText}`; containerDiv.appendChild(publishStatusContainer); } // 更新品牌系列列 brandSeriesTd.innerHTML = ''; brandSeriesTd.appendChild(containerDiv); brandSeriesTd.dataset.processed = 'true'; // 隐藏原始列 if (productStatusTd) productStatusTd.style.display = 'none'; if (publishStatusTd) publishStatusTd.style.display = 'none'; idTd.style.display = 'none'; } } // 2. 将型号和产品编码移动到自定义编码列 if (customCodeColumnIndex && (modelColumnIndex || productCodeColumnIndex)) { const customCodeTd = row.querySelector(`td:nth-child(${customCodeColumnIndex})`); const modelTd = modelColumnIndex ? row.querySelector(`td:nth-child(${modelColumnIndex})`) : null; const productCodeTd = productCodeColumnIndex ? row.querySelector(`td:nth-child(${productCodeColumnIndex})`) : null; if (customCodeTd) { if (customCodeTd.dataset.processed === 'true') return; const customCodeDiv = customCodeTd.querySelector('div') || customCodeTd; // 获取内容 let modelText = ''; if (modelTd) { const modelDiv = modelTd.querySelector('div') || modelTd; modelText = (modelDiv.querySelector('.StyledContentCopy-bdGJSR.kZSaGD') || modelDiv).textContent.trim(); } let productCodeText = ''; if (productCodeTd) { const productCodeDiv = productCodeTd.querySelector('div') || productCodeTd; productCodeText = (productCodeDiv.querySelector('.StyledContentCopy-bdGJSR.kZSaGD') || productCodeDiv).textContent.trim(); } // 创建容器 const containerDiv = document.createElement('div'); containerDiv.style.display = 'flex'; containerDiv.style.flexDirection = 'column'; containerDiv.style.gap = '4px'; // 添加自定义编码原始内容 const customCodeContainer = document.createElement('div'); customCodeContainer.innerHTML = customCodeDiv.innerHTML; containerDiv.appendChild(customCodeContainer); // 添加型号(如果有内容) if (modelText) { const modelContainer = document.createElement('div'); modelContainer.style.color = '#666'; modelContainer.textContent = `型号: ${modelText}`; containerDiv.appendChild(modelContainer); } // 添加产品编码(如果有内容) if (productCodeText) { const productCodeContainer = document.createElement('div'); productCodeContainer.style.color = '#666'; productCodeContainer.textContent = `编码: ${productCodeText}`; containerDiv.appendChild(productCodeContainer); } // 添加对接编码(单独一行) try { const dockCodeResponse = await fetch(`https://www.kujiale.com/editor/api/site/param/bizproperty/editordata/query?obsBrandGoodId=${currentId}`); const dockCodeData = await dockCodeResponse.json(); const dockCodeEntry = dockCodeData.d?.find(entry => entry.name === "对接编码"); const dockCode = dockCodeEntry ? dockCodeEntry.value : "未定义"; const dockCodeContainer = document.createElement('div'); dockCodeContainer.style.color = '#666'; dockCodeContainer.textContent = `对接: ${dockCode}`; containerDiv.appendChild(dockCodeContainer); } catch (error) { console.error('获取对接编码失败:', error); } // 更新自定义编码列 customCodeTd.innerHTML = ''; customCodeTd.appendChild(containerDiv); customCodeTd.dataset.processed = 'true'; // 隐藏原始列 if (modelTd) modelTd.style.display = 'none'; if (productCodeTd) productCodeTd.style.display = 'none'; } } // 3. 将基材和材质移动到渲染分类列 if (renderCategoryColumnIndex && (baseMaterialColumnIndex || materialColumnIndex)) { const renderCategoryTd = row.querySelector(`td:nth-child(${renderCategoryColumnIndex})`); const baseMaterialTd = baseMaterialColumnIndex ? row.querySelector(`td:nth-child(${baseMaterialColumnIndex})`) : null; const materialTd = materialColumnIndex ? row.querySelector(`td:nth-child(${materialColumnIndex})`) : null; if (renderCategoryTd) { if (renderCategoryTd.dataset.processed === 'true') return; const renderCategoryDiv = renderCategoryTd.querySelector('div') || renderCategoryTd; // 获取内容 let baseMaterialText = ''; if (baseMaterialTd) { const baseMaterialDiv = baseMaterialTd.querySelector('div') || baseMaterialTd; baseMaterialText = (baseMaterialDiv.querySelector('.StyledContentCopy-bdGJSR.kZSaGD') || baseMaterialDiv).textContent.trim(); } let materialText = ''; if (materialTd) { const materialDiv = materialTd.querySelector('div') || materialTd; materialText = (materialDiv.querySelector('.StyledContentCopy-bdGJSR.kZSaGD') || materialDiv).textContent.trim(); } // 创建容器 const containerDiv = document.createElement('div'); containerDiv.style.display = 'flex'; containerDiv.style.flexDirection = 'column'; containerDiv.style.gap = '4px'; // 添加渲染分类原始内容 const renderCategoryContainer = document.createElement('div'); renderCategoryContainer.innerHTML = renderCategoryDiv.innerHTML; containerDiv.appendChild(renderCategoryContainer); // 添加基材(如果有内容) if (baseMaterialText) { const baseMaterialContainer = document.createElement('div'); baseMaterialContainer.style.color = '#666'; baseMaterialContainer.textContent = `基材: ${baseMaterialText}`; containerDiv.appendChild(baseMaterialContainer); } // 添加材质(如果有内容) if (materialText) { const materialContainer = document.createElement('div'); materialContainer.style.color = '#666'; materialContainer.textContent = `材质: ${materialText}`; containerDiv.appendChild(materialContainer); } // 更新渲染分类列 renderCategoryTd.innerHTML = ''; renderCategoryTd.appendChild(containerDiv); renderCategoryTd.dataset.processed = 'true'; // 隐藏原始列 if (baseMaterialTd) baseMaterialTd.style.display = 'none'; if (materialTd) materialTd.style.display = 'none'; } } }); return shouldInitialize; } // 修改后的按钮添加逻辑 function addButtons() { if (idColumnIndex === null && !initColumnIndexes()) { log('无法初始化列索引,按钮注入中止'); return; } // 确保属性窗口已初始化 initAttributeModal(); document.querySelectorAll('tr.StyledBodyRowTr-kSBvgt').forEach(row => { // 跳过已经处理过的行 if (row.dataset.buttonsAdded === 'true') return; const visibilityCell = row.querySelector(`td:nth-child(${toolVisibleColumnIndex})`); if (!visibilityCell) return; const visibilityText = visibilityCell.textContent.trim(); // 只在"可见"或"不可见"时添加按钮 if (visibilityText !== '可见' && visibilityText !== '不可见') { return; } const targetTd1 = row.querySelector(`td:nth-child(2)`); if (!targetTd1) return; // 清除可能存在的旧按钮 const existingButtons = targetTd1.querySelectorAll('.custom-btn'); existingButtons.forEach(btn => btn.remove()); // 添加新按钮 targetTd1.appendChild(createButton('更新', (e) => { e.preventDefault(); e.stopPropagation(); const row = e.target.closest('tr.StyledBodyRowTr-kSBvgt'); const idCell = row.querySelector(`td:nth-child(${idColumnIndex})`); const actualElement = idCell.querySelector('span, div') || idCell; const currentId = (actualElement.textContent || '').trim(); if (currentId) window.open(`https://www.kujiale.com/vc/editor/globalvariable?tooltype=cabinet¤tTab=model-DAG&bgId=${encodeURIComponent(currentId)}`, '_blank'); })); targetTd1.appendChild(createButton('关联', (e) => { e.preventDefault(); e.stopPropagation(); const row = e.target.closest('tr.StyledBodyRowTr-kSBvgt'); const idCell = row.querySelector(`td:nth-child(${idColumnIndex})`); const actualElement = idCell.querySelector('span, div') || idCell; const currentId = (actualElement.textContent || '').trim(); if (currentId) window.open(`https://www.kujiale.com/pub/saas/brandgoods/group/list?obsBrandGoodsId=${encodeURIComponent(currentId)}`, '_blank'); })); targetTd1.appendChild(createButton('属性', async (e) => { e.preventDefault(); e.stopPropagation(); const row = e.target.closest('tr.StyledBodyRowTr-kSBvgt'); const idCell = row.querySelector(`td:nth-child(${idColumnIndex})`); const currentId = (idCell.textContent || '').trim(); if (currentId) { await getData(currentId); } })); targetTd1.appendChild(createButton('结构', async (e) => { e.preventDefault(); e.stopPropagation(); tablesContainer.innerHTML = `
加载数据中...
`; modalMask.style.display = 'block'; const row = e.target.closest('tr.StyledBodyRowTr-kSBvgt'); const idCell = row.querySelector(`td:nth-child(${idColumnIndex})`); const actualElement = idCell.querySelector('span, div') || idCell; const currentId = (actualElement.textContent || '').trim(); if (currentId) { setSize('90%', '90%'); log(`开始获取节点数据,初始ID: ${currentId}`); const data = await getAllNodes(currentId); log('所有节点数据:', data); drawGraph(data); } })); // 添加"快速编辑"按钮 targetTd1.appendChild(createButton('编辑', (e) => { e.preventDefault(); e.stopPropagation(); const row = e.target.closest('tr.StyledBodyRowTr-kSBvgt'); const items = row.querySelectorAll(`td:nth-last-child(2) div a.Link-qfJUS.dtwGsR`); items.forEach(function (item) { if (item.textContent.trim() === '快速编辑') { item.click(); } }); })); // 添加"编辑模型"按钮 targetTd1.appendChild(createButton('打开', (e) => { e.preventDefault(); e.stopPropagation(); const row = e.target.closest('tr.StyledBodyRowTr-kSBvgt'); const items = row.querySelectorAll(`td:nth-last-child(2) div a.Link-qfJUS.dtwGsR`); items.forEach(function (item) { if (item.textContent.trim() === '编辑模型') { item.click(); } }); })); // 标记为已处理 row.dataset.buttonsAdded = 'true'; }); } // 修改后的初始化函数 function initialize() { // 每次初始化前重置列索引 idColumnIndex = null; toolVisibleColumnIndex = null; brandSeriesColumnIndex = null; productStatusColumnIndex = null; publishStatusColumnIndex = null; if (!initColumnIndexes()) { console.log('必要列未找到,已提示用户'); return; } // 更新可见性状态(原有逻辑不变) if (updateProductDisplayStatus()) { // 添加按钮和事件监听(原有逻辑不变) addButtons(); addClickListeners(); // 3. 渐变显示表格主体 const tbody = document.querySelector('table.StyledTable-diJSpn.irqLUa tbody'); if (tbody) { // 先重置display属性(如果之前被隐藏) tbody.style.display = ''; // 使用setTimeout确保浏览器有机会重绘 setTimeout(() => { tbody.classList.add('show'); // 添加show类触发渐变效果 }, 10); } } } // 观察器配置 const observer = new MutationObserver((mutations) => { // 检查是否有新的表格行被添加 const hasNewRows = mutations.some(mutation => { return mutation.addedNodes && Array.from(mutation.addedNodes).some(node => { return node.nodeType === 1 && ( node.matches('tr.StyledBodyRowTr-kSBvgt') || node.querySelector('tr.StyledBodyRowTr-kSBvgt') ); }); }); if (hasNewRows || document.querySelector('tr.StyledBodyRowTr-kSBvgt')) { // 延迟执行以确保DOM完全加载 setTimeout(() => { updateTabInfo(); initialize(); }, 300); } }); // 启动观察 - 扩大观察范围 observer.observe(document.body, { childList: true, subtree: true, attributes: false, characterData: false }); // 初始执行 if (document.readyState === 'complete') { if (updateProductDisplayStatus()) { initialize(); } } else { window.addEventListener('load', () => { if (updateProductDisplayStatus()) { initialize(); } }); } })();