/* 公共js文件
创建时间:2025-3-21
说明:该文件包含项目中多个页面共用的功能逻辑,如登录验证、提示弹窗、全选控制、删除功能、表单验证等
*/
// 定义基础接口URL,作为所有AJAX请求的前缀
let url = 'http://bas.zuniquex.cn';
// 从sessionStorage中获取登录页存储的用户账号和密码(JSON字符串转对象)
let proof = JSON.parse(sessionStorage.getItem('userAccount'));
let password = JSON.parse(sessionStorage.getItem('password'));
// 定义标志变量,用于控制输入框事件的处理逻辑(如避免重复触发)
let flag = true;
// 定义全局变量editId,用于存储当前正在编辑的项的ID(如编辑表格数据时标记当前行)
let editId;
// 定义全局变量isValid,用于标记表单验证的合法性(true为合法)
let isValid = true;
// 登录状态检查:如果当前页面不是登录页,且未获取到用户信息,则提示未登录并跳转到登录页
if (!window.location.href.includes('login')) {
if (proof == null) {
showError("用户未登录");
setTimeout(function () {
window.location.replace('./login.html');
localStorage.clear(); // 清除本地存储数据
sessionStorage.clear(); // 清除会话存储数据(避免残留登录信息)
}, 1000);
}
}
// 锁屏状态检查:如果当前页面不是锁屏页,且检测到锁屏状态(lock=1),则跳转到锁屏页
let lockVal = sessionStorage.getItem('lock');
if (!window.location.href.includes('lock')) {
if (lockVal == 1) {
window.location.replace('./lock.html');
}
}
// 错误提示函数:显示指定元素的错误信息(用于表单字段级别的错误提示)
// 参数:errorId(错误提示元素的选择器)、errorMessage(错误信息内容)
function errorTips(errorId, errorMessage) {
$(errorId).css("display", "block"); // 显示错误提示
$(errorId).html(errorMessage); // 设置错误信息内容
}
// 成功弹窗函数:显示全局成功提示弹窗,1秒后自动隐藏
function showSuccess(message) {
$(".successText").html(message); // 设置成功信息内容
$("#success").css('display', 'flex'); // 显示弹窗
setTimeout(function () {
$("#success").css('display', 'none'); // 1秒后隐藏
}, 1000);
}
// 失败弹窗函数:显示全局失败提示弹窗,1秒后自动隐藏
function showError(message) {
$(".errorText").html(message); // 设置失败信息内容
$("#error").css('display', 'flex'); // 显示弹窗
setTimeout(function () {
$("#error").css('display', 'none'); // 1秒后隐藏
}, 1000);
}
// 星星综合评分功能
let currentRating = 0; // 记录当前选中的评分(星级)
$(document).ready(function () {
// 鼠标悬浮星星时:临时更新星级显示(未点击确认)
$('.star').on('mouseover', function () {
const value = $(this).data('value'); // 获取当前星星代表的分值(如1-5)
updateStars(value); // 更新星星显示状态
});
// 鼠标移出星星时:恢复为当前已确认的评分
$('.star').on('mouseout', function () {
updateStars(currentRating);
});
// 点击星星时:确认评分并更新当前选中状态
$('.star').on('click', function () {
currentRating = $(this).data('value'); // 更新当前评分
updateStars(currentRating); // 更新星星显示
});
});
// 更新星星显示的函数:根据评分值设置星星的选中/悬浮状态
function updateStars(rating) {
$('.star').each(function () {
const value = $(this).data('value'); // 获取当前星星的分值
// 如果星星分值<=评分,则添加选中和悬浮类;否则移除
value <= rating ? $(this).addClass('selected').removeClass('hover') : $(this).removeClass('selected');
// 鼠标悬浮效果补充(控制hover类)
value <= rating ? $(this).addClass('hover') : $(this).removeClass('hover');
});
}
// 文本域计数器:实时显示输入长度,并在超过限制时变色
function updateCount() {
let currentLength = $('#description').val().length; // 获取文本域当前输入长度
Count.textContent = `${currentLength}/200`; // 显示"当前长度/最大长度"
// 超过200字时文字变红,否则恢复默认颜色
currentLength > 200 ? $('#Count').css('color', 'red') : $('#Count').css('color', '#505050');
}
// 全局变量:存储图片链接(单图和多图)
let img_url = null; // 单张图片的链接
let imgUrls = []; // 多张图片的链接数组(如轮播图)
// 处理图片上传(支持单图和多图)
// 参数statue:true为单图上传,false为多图上传
function upload(statue) {
// 多图上传时限制最多4张
if (!statue) {
if (imgUrls.length >= 4) {
showError('最多只能上传4张图片');
return; // 超过数量则阻止上传
}
}
// 构建表单数据(根据单图/多图选择不同的表单)
let pic_data = new FormData(statue ? $("#myForm")[0] : $("#myForms")[0]);
// 发送AJAX上传请求
$.ajax({
url: url + '/api/common/upload', // 上传接口地址
type: 'POST',
data: pic_data,
dataType: 'json',
cache: false, // 不缓存
processData: false, // 不对数据进行处理(FormData需保持原样)
contentType: false, // 不设置Content-Type(由浏览器自动处理)
success: function (res) {
if (res.code == 1) { // 上传成功(假设code=1为成功)
if (statue) { // 单张图片上传
img_url = res.data.url; // 存储图片链接
$("#pic").attr("src", url + img_url); // 显示上传的图片
$('#img_error').hide(); // 隐藏错误提示
isValid = true; // 标记表单验证合法
} else { // 多张图片上传
let pic_url = res.data.url; // 获取图片链接
imgUrls.push(pic_url); // 添加到数组
bannerRender(imgUrls); // 重新渲染多图展示区
// 多图至少上传2张时隐藏错误提示
if (imgUrls.length >= 2) {
$('#banner_error').hide();
isValid = true;
}
}
} else {
// 上传失败处理
$('#pic').html("<p>上传失败,请重试。</p>");
}
},
error: function (err) {
console.error('请求失败: ', err.status, err.responseText);
showError("请求失败,请稍后再试"); // 提示请求失败
}
});
}
// 轮播图渲染函数:根据图片数组生成HTML并显示
function bannerRender(img) {
$('#imgContainer').empty(); // 清空容器
// 限制最多4张图片
if (img.length > 4) {
showError('最多上传4张');
return;
}
let str = ''; // 拼接HTML字符串
for (let i = 0; i < img.length; i++) {
// 判断图片链接是否已包含基础URL,避免重复拼接
if (img[i].includes(url)) {
str += `
<div class="imgContainer"data-index="${i}">
<img src="${img[i]}" alt="" class="picture"/>
<div class="closeButton" onclick="imgRemove(${i})">
<img src="./img/cha.png" alt="" class="deleteImg"/>
</div>
</div>
`;
} else {
str += `
<div class="imgContainer" data-index="${i}">
<img src="${url + img[i]}" alt="" class="picture" />
<div class="closeButton" onclick="imgRemove(${i})">
<img src="./img/cha.png" alt="" class="deleteImg"/>
</div>
</div>
`;
}
$('#imgContainer').append(str); // 追加到容器
str = ''; // 清空字符串,准备下一次循环
}
// 清空文件输入框(避免重复上传同一张图片)
$("#file").val("");
}
// 移除指定索引的图片:从数组中删除并重新渲染
function imgRemove(i) {
imgUrls.splice(i, 1); // 删除数组中索引为i的元素
bannerRender(imgUrls); // 重新渲染
}
// 图片预览相关变量
let scale = 1; // 缩放比例(初始为1)
let previewModal = document.getElementById("imagePreview"); // 预览弹窗容器
let previewImage = document.getElementById("previewImage"); // 预览图片元素
// 显示图片预览:设置图片地址并显示弹窗
function preview(imgUrl) {
previewImage.src = imgUrl; // 设置预览图片的src
previewModal.style.display = "flex"; // 显示弹窗
previewImage.style.transform = `scale(1)`; // 重置缩放
scale = 1; // 重置缩放比例
}
// 关闭图片预览:隐藏弹窗
function previewCancel() {
previewModal.style.display = "none";
}
// 为预览弹窗绑定鼠标滚轮事件:控制图片缩放
if (previewModal) {
previewModal.addEventListener("wheel", (event) => {
event.preventDefault(); // 阻止默认行为(避免页面滚动)
if (event.deltaY > 0) {
scale -= 0.1; // 滚轮向下滚动:缩小
} else if (event.deltaY < 0) {
scale += 0.1; // 滚轮向上滚动:放大
}
// 限制缩放范围(最小0.5倍,最大3倍)
scale = Math.max(0.5, Math.min(scale, 3));
// 应用缩放样式
previewImage.style.transform = `scale(${scale})`;
});
}
// 清空开始时间输入框
function startClear() {
$('#start_time').val('');
}
// 清空结束时间输入框
function endTime() {
$('#end_time').val('');
}
// 获取编辑器的文本内容(假设使用UE编辑器)
let content; // 存储编辑器内容的变量
function getContentTxt() {
content = ue.getContentTxt(); // 调用UE编辑器的方法获取纯文本内容
}
// 表单验证工具:检查表单字段是否为空
var FormCheck = {
// 初始化:绑定表单元素的事件
init: function () {
// 获取需要验证的元素(下拉框、文本域、输入框)
this.selects = document.querySelectorAll(".add_pop_select"); // 下拉框
this.textareas = document.querySelectorAll(".add_pop_textarea"); // 文本域
this.inputs = document.querySelectorAll(".add_pop_input"); // 输入框
// 绑定下拉框的change事件:值变化时验证
for (var i = 0; i < this.selects.length; i++) {
this.selects[i].addEventListener("change", function () {
FormCheck.checkOne(this);
});
}
// 绑定文本域的input事件:输入时验证
for (var j = 0; j < this.textareas.length; j++) {
this.textareas[j].addEventListener("input", function () {
FormCheck.checkOne(this);
});
}
// 绑定输入框的input事件:输入时验证
for (var k = 0; k < this.inputs.length; k++) {
this.inputs[k].addEventListener("input", function () {
FormCheck.checkOne(this);
});
}
},
// 检查单个元素:判断元素值是否为空
checkOne: function (el) {
var isValid = true;
// 下拉框验证:值为空则不合法
if (el.tagName === "SELECT") {
isValid = el.value !== "";
}
// 文本域验证:去除空格后为空则不合法
else if (el.tagName === "TEXTAREA") {
isValid = el.value.trim() !== "";
}
// 输入框验证:去除空格后为空则不合法
else if (el.tagName === "INPUT") {
isValid = el.value.trim() !== "";
}
// 显示/隐藏错误提示
this.showError(el, !isValid);
return isValid;
},
// 检查所有元素:验证表单中所有需要验证的字段
checkAll: function () {
var allValid = true;
// 获取所有需要验证的元素(下拉框、文本域、输入框)
var elements = document.querySelectorAll(
".add_pop_select, .add_pop_textarea, .add_pop_input"
);
// 逐个验证,只要有一个不合法则整体不合法
for (var i = 0; i < elements.length; i++) {
if (!this.checkOne(elements[i])) {
allValid = false;
}
}
return allValid;
},
// 显示/隐藏错误提示:根据验证结果控制错误提示的显示
showError: function (el, show) {
// 查找元素的父容器(.input_pop或note_content类)
var parent = el.closest(".input_pop,note_content");
if (!parent) return;
// 查找父容器中的.error类元素(错误提示框)
var errorBox = parent.querySelector(".error");
if (errorBox) {
errorBox.style.display = show ? "block" : "none"; // 显示或隐藏
}
},
};
// 页面加载完成后初始化表单验证
window.onload = function () {
FormCheck.init();
};
// 清空时间输入框并触发搜索
function timeClear() {
$('#start').val(''); // 清空开始时间
$('#end').val(''); // 清空结束时间
handleSearch(); // 调用搜索函数(假设该函数存在)
}
// 浏览量相关:初始值为1
let num = 1;
// 浏览量加减函数:state为true时加1,false时减1(最小为1)
function plus(state) {
if (state) {
num += 1; // 增加
$('#number').val(num); // 更新输入框显示
} else {
if ($('#number').val() > 1) { // 确保不小于1
num -= 1; // 减少
$('#number').val(num);
}
}
}
// 库存、好评、价格的初始值(均为1)
let stock = 1; // 库存
let acclaim = 1; // 好评
let priceNum = 1; // 价格
// 库存数量加减函数:state为true时加1,false时减1(最小为1)
function stockChange(state) {
if (state) {
stock++;
$("#amount").val(stock);
} else {
if (stock > 1) {
stock--;
$("#amount").val(stock);
}
}
}
// 价格数量加减函数:state为true时加1,false时减1(最小为1)
function priceChange(state) {
if (state) {
priceNum++;
$("#price").val(priceNum);
} else {
if (priceNum > 1) {
priceNum--;
$("#price").val(priceNum);
}
}
}
// 好评量数量加减函数:state为true时加1,false时减1(最小为1)
function acclaimChange(state) {
if (state) {
acclaim++;
$("#good_word").val(acclaim);
} else {
if (acclaim > 1) {
acclaim--;
$("#good_word").val(acclaim);
}
}
}
// 数量输入框事件:确保输入值不小于1
$('#price,#good_word,#number,#amount').on('input', function () {
// 价格输入框:小于1则强制设为1,否则更新变量
$('#price').val() < 1 ? $('#price').val('1') : priceNum = $('#price').val();
// 好评输入框:小于1则强制设为1,否则更新变量
$('#good_word').val() < 1 ? $('#good_word').val('1') : acclaim = $('#good_word').val();
// 浏览量输入框:小于1则强制设为1,否则更新变量
$('#number').val() < 1 ? $('#number').val('1') : number = $('#number').val();
// 库存输入框:小于1则强制设为1,否则更新变量
$('#amount').val() < 1 ? $('#amount').val('1') : stock = $('#amount').val();
})
// 订单状态分类数组(按状态存储订单数据)
let paymentRender = []; // 待付款订单
let accountPaid = []; // 已付款订单
let verification = []; // 已核销订单
let canceled = []; // 已取消订单
// 订单页面状态角标数量渲染:根据订单状态分类并更新角标数字
function markersRender(data) {
// 清空现有分类数据
paymentRender = [];
accountPaid = [];
verification = [];
canceled = [];
// 遍历订单数据,按状态分类
for (let i in data) {
if (data[i].status == 1) { // 状态1:待付款
paymentRender.push(data[i]);
} else if (data[i].status == 2) { // 状态2:已付款
accountPaid.push(data[i]);
} else if (data[i].status == 3) { // 状态3:已核销
verification.push(data[i]);
} else if (data[i].status == 4) { // 状态4:已取消
canceled.push(data[i]);
}
}
// 更新页面上的状态角标数字(若无数据则显示0)
$(".buy_num").eq(0).html(paymentRender.length || 0);
$(".payment_num").html(accountPaid.length || 0);
$(".write_num").html(verification.length || 0);
$(".cancelled_num").html(canceled.length || 0);
}
// 默认高亮"全部"状态按钮
$(".cancel").eq(0).css("background-color", "#eeeded");
// 订单状态点击事件:根据选择的状态过滤订单数据并重新渲染
function orderStatus(state) {
$(".cancel").css("background-color", ""); // 重置所有按钮的背景色
// 根据状态筛选数据(使用已分类的数组)
if (state == 1) { // 全部订单
$(".cancel").eq(0).css("background-color", "#eeeded"); // 高亮"全部"按钮
// 若有过滤后的数据则使用,否则使用原始分页数据
if (isFilteredDataEmpty) {
return; // 数据为空时不重新渲染
} else {
data = filteredData.length == 0 ? pageData : filteredData;
}
} else if (state == 2) { // 待付款
$(".not_buy").css("background-color", "#eeeded"); // 高亮对应按钮
data = paymentRender;
} else if (state == 3) { // 已付款
$(".payment").css("background-color", "#eeeded");
data = accountPaid;
} else if (state == 4) { // 已核销
$(".write_off").css("background-color", "#eeeded");
data = verification;
} else { // 已取消
$(".cancelled").css("background-color", "#eeeded");
data = canceled;
}
// 渲染筛选后的数据并初始化分页
render(data); // 假设render函数用于渲染订单列表
pages(0); // 假设pages函数用于初始化分页
}
// ====================== 公共删除模块(可直接调用) ======================
const DeleteControl = (function() {
// 私有配置
const config = {
deleteApi: '',
findItem: () => null,
afterDelete: () => {},
confirmMessage: null
};
// 初始化弹窗事件(绑定asd和zxc函数)
function initPopupEvents() {
// 取消按钮事件(对应弹窗onclick="asd()")
window.asd = () => {
const modal = document.querySelector('.paddle');
if (modal) modal.style.display = 'none';
};
// 确定按钮事件(对应弹窗onclick="zxc()")
window.zxc = () => {
const modal = document.querySelector('.paddle');
if (modal) {
const id = modal.getAttribute('data-delete-id');
if (id) executeDelete(id);
modal.style.display = 'none';
}
};
}
// 执行删除请求
function executeDelete(id) {
const targetItem = config.findItem(id);
if (!targetItem) return;
$.ajax({
type: "POST",
url: config.deleteApi,
data: { account: 'admin', password: '123456', id: id },
success: (res) => {
if (res.code === 1) {
showSuccess('删除成功');
removeNodeFromDataSource(id);
config.afterDelete();
} else {
showError('删除失败:' + (res.msg || '未知错误'));
}
},
error: (xhr) => {
console.error('删除请求失败', xhr);
showError('网络错误,删除失败');
}
});
}
// 从数据源移除节点
function removeNodeFromDataSource(id) {
const targetId = String(id);
const removeNodeById = (nodes) => {
if (!Array.isArray(nodes)) return [];
return nodes.filter(node => {
if (node.children) node.children = removeNodeById(node.children);
return String(node.id) !== targetId;
});
};
// 更新缓存数据
if (window.treeDataCache) {
window.treeDataCache = removeNodeById([...window.treeDataCache]);
}
if (window.originalTreeData) {
window.originalTreeData = removeNodeById([...window.originalTreeData]);
}
// 刷新分页
refreshPagination();
}
// 刷新分页
function refreshPagination() {
if (!window.pagination) return;
window.pagination = {
...window.pagination,
currentPage: 1,
totalRecords: window.treeDataCache?.length || 0,
totalPages: Math.ceil((window.treeDataCache?.length || 0) / window.pagination.pageSize),
currentData: [],
cache: {}
};
$('#pagination').empty();
if (window.initPaginationControl) initPaginationControl();
if (window.loadPageData) loadPageData(1);
}
// 公共API
return {
/**
* 初始化删除模块
* @param {Object} options 配置参数
* @param {string} options.deleteApi 删除接口地址
* @param {Function} options.findItem 根据ID查找数据的函数
* @param {Function} options.afterDelete 删除后的回调函数
* @param {Function} options.confirmMessage 自定义确认消息函数
*/
init(options) {
// 合并配置
Object.assign(config, options);
// 初始化弹窗事件
initPopupEvents();
console.log('删除模块初始化完成');
},
/**
* 触发删除流程(直接调用此方法)
* @param {string|number} id 要删除的数据ID
* @param {Event} event 事件对象(用于阻止冒泡)
*/
deleteItem(id, event) {
event?.stopPropagation();
const targetItem = config.findItem(id);
if (!targetItem) {
showError('目标数据不存在');
return;
}
// 生成确认消息
const confirmMsg = config.confirmMessage
? config.confirmMessage(targetItem)
: `确定要删除「${targetItem.name}」吗?`;
// 显示弹窗
const modal = document.querySelector('.paddle');
if (!modal) {
console.error('未找到删除弹窗(.paddle)');
return;
}
const hintElement = modal.querySelector('.hint h3') || document.getElementById('deleteHintText');
if (hintElement) hintElement.textContent = confirmMsg;
modal.style.display = 'flex';
modal.setAttribute('data-delete-id', id);
}
};
})();
// 自动暴露到全局(确保在公共文件中可直接调用)
window.DeleteControl = DeleteControl;
const IndustryFormPlugin = {
currentMode: 'add', // add/edit
currentParentId: null,
currentId: null,
openModal(mode, id, isSecondLevel = false) {
this.currentMode = mode;
this.currentId = id;
this.currentParentId = isSecondLevel ? id : null;
const modal = document.querySelector('.over');
const title = modal?.querySelector('.pops_title p');
const input = document.getElementById('industryNameInput');
const errorTip = document.getElementById('nameErrorTip');
// 重置表单(增加空值判断)
if (input) input.value = '';
if (errorTip) errorTip.style.display = 'none';
// 设置标题
if (title) {
title.textContent = mode === 'add'
? (isSecondLevel ? '新增二级行业' : '新增一级行业')
: '编辑行业';
}
// 编辑模式:加载数据
if (mode === 'edit' && id) {
const item = findIndustryById(id);
if (item && input) {
input.value = item.name || '';
}
}
// 显示弹窗
if (modal) modal.style.display = 'flex';
// 绑定按钮事件(优化绑定方式)
this.bindFormButtons();
},
bindFormButtons() {
const modal = document.querySelector('.over');
if (!modal) return;
// 移除旧事件(通过事件委托优化)
modal.removeEventListener('click', this.handleFormClick);
modal.addEventListener('click', this.handleFormClick.bind(this));
},
// 事件委托处理表单按钮点击(减少DOM操作)
handleFormClick(e) {
const modal = document.querySelector('.over');
if (e.target.closest('.confirm')) {
this.submitForm(); // 确认按钮
} else if (e.target.closest('.cancel')) {
modal.style.display = 'none'; // 取消按钮
}
},
submitForm() {
const input = document.getElementById('industryNameInput');
const errorTip = document.getElementById('nameErrorTip');
const name = input?.value.trim() || '';
// 验证
if (!name) {
if (errorTip) {
errorTip.textContent = '请输入行业名称';
errorTip.style.display = 'block';
}
return;
}
// 检查名称是否已存在
const nodes = window.originalTreeData || [];
const existing = findIndustryByName(name, nodes, this.currentMode === 'edit' ? this.currentId : null);
if (existing) {
if (errorTip) {
errorTip.textContent = '该行业名称已存在';
errorTip.style.display = 'block';
}
return;
}
// 提交数据
this.submitData(name);
},
submitData(name) {
// 构造提交数据
const data = {
account: 'admin',
password: '123456',
name: name
};
// 编辑模式需要ID
if (this.currentMode === 'edit') {
data.id = this.currentId;
}
// 新增二级行业需要父ID
else if (this.currentParentId) {
data.parent_id = this.currentParentId;
}
// 修复:接口地址变量冲突(原代码中url与全局变量重名)
const apiUrl = this.currentMode === 'add'
? url + '/fastapi/trade/add' // 全局url已定义,直接使用
: url + '/fastapi/trade/edit';
$.ajax({
type: 'POST',
url: apiUrl,
data: data,
success: (res) => {
if (res.code === 1) {
showSuccess(this.currentMode === 'add' ? '新增成功' : '编辑成功');
// 关闭弹窗
const modal = document.querySelector('.over');
if (modal) modal.style.display = 'none';
// 重新加载数据(增加延迟确保DOM更新)
setTimeout(resetData, 300);
} else {
showError((this.currentMode === 'add' ? '新增失败' : '编辑失败') + ': ' + (res.msg || '未知错误'));
}
},
error: (xhr) => {
console.error('提交失败', xhr);
showError('网络错误,操作失败');
}
});
}
};// AJAX 请求函数
function loadData(callback) {
$.ajax({
type: "POST",
url: url + '/fastapi/trade/index',
headers: {},
data: {
account: 'admin',
password: '123456'
},
success: function (res) {
console.log('数据加载成功', res);
if (res.code === 1) {
const treeData = res.data;
initNodeCheckedState(treeData);
window.treeDataCache = treeData;
window.originalTreeData = JSON.parse(JSON.stringify(treeData));
callback(treeData);
} else {
console.error('请求失败', res.msg);
callback(null);
showError('数据加载失败: ' + res.msg);
}
},
error: function (xhr) {
console.error('网络错误', xhr);
callback(null);
showError('网络错误,无法加载数据');
}
});
}
// 初始化节点选中状态
function initNodeCheckedState(nodes) {
if (!Array.isArray(nodes)) return;
nodes.forEach(node => {
node.checked = false;
if (node.children?.length) {
initNodeCheckedState(node.children);
}
});
}
// 分页核心变量对象
window.pagination = {
currentPage: 1,
pageSize: 5,
totalPages: 0,
totalRecords: 0,
currentData: [],
cache: {},
searchKeyword: ''
};
// 程序核心入口
function initPaginationData() {
loadData(function (treeData) {
if (treeData) {
initSearchEvent();
window.pagination.totalRecords = treeData.length;
window.pagination.totalPages = Math.ceil(window.pagination.totalRecords / window.pagination.pageSize);
initPaginationControl();
loadPageData(1);
}
});
// 事件委托处理按钮点击
document.addEventListener('click', (e) => {
const btn = e.target.closest('[data-action]');
if (!btn) return;
e.stopPropagation();
const action = btn.getAttribute('data-action');
const id = btn.getAttribute('data-id');
switch (action) {
case 'add-second':
IndustryFormPlugin.openModal('add', id, true);
break;
case 'edit':
IndustryFormPlugin.openModal('edit', id);
break;
case 'delete':
DeleteControl.deleteItem(id, e);
break;
}
});
}
// 弹窗控制变量和函数(删除相关)
let currentDeleteId = null;
let deleteMode = 'single';
// 重置数据(深度重置)
function resetData() {
window.treeDataCache = null;
window.originalTreeData = null;
window.pagination = {
currentPage: 1,
pageSize: 5,
totalPages: 0,
totalRecords: 0,
currentData: [],
cache: {},
searchKeyword: ''
};
initPaginationData();
resetSearch();
}
// 重置搜索(轻量重置)
function resetSearch() {
const refreshImg = document.querySelector('.renovate');
if (refreshImg) {
refreshImg.classList.add('rotating');
refreshImg.addEventListener('animationend', () => refreshImg.classList.remove('rotating'), { once: true });
}
window.pagination.searchKeyword = '';
$('.search_box').val('');
if (window.originalTreeData) {
window.treeDataCache = JSON.parse(JSON.stringify(window.originalTreeData));
initNodeCheckedState(window.treeDataCache);
window.pagination.totalRecords = window.treeDataCache.length;
window.pagination.totalPages = Math.ceil(window.pagination.totalRecords / window.pagination.pageSize);
window.pagination.currentPage = 1;
window.pagination.cache = {};
$('#pagination').empty();
initPaginationControl();
loadPageData(1);
}
}
// 从缓存的树形数据中查找指定ID的节点
function findIndustryById(targetId) {
// 优先从当前分页的缓存数据找,没有再从原始全量数据找
function findRecursive(nodes) {
if (!Array.isArray(nodes)) return null;
for (const node of nodes) {
if (String(node.id) === String(targetId)) {
return node;
}
if (node.children && node.children.length > 0) {
const foundInChildren = findRecursive(node.children);
if (foundInChildren) {
return foundInChildren;
}
}
}
return null;
}
// 先从当前分页缓存的currentData找
const foundInCurrent = findRecursive(window.pagination.currentData);
if (foundInCurrent) {
return foundInCurrent;
}
// 再从原始全量数据找
return findRecursive(window.originalTreeData);
}
// 根据名称递归查找行业节点
function findIndustryByName(targetName, nodes, excludeId = null) {
if (!Array.isArray(nodes)) return null;
for (const node of nodes) {
if (node.name.toLowerCase() === targetName.toLowerCase() && node.id !== excludeId) return node;
if (node.children?.length) {
const result = findIndustryByName(targetName, node.children, excludeId);
if (result) return result;
}
}
return null;
}
// 初始化分页控件
function initPaginationControl() {
$('#pagination').empty();
const totalPages = Math.max(1, window.pagination.totalPages);
new Page({
id: 'pagination',
pageTotal: totalPages,
pageAmount: window.pagination.pageSize,
dataTotal: window.pagination.totalRecords,
curPage: Math.min(window.pagination.currentPage, totalPages),
pageSize: 5,
showSkipInputFlag: true,
getPage: (page) => loadPageData(page)
});
}
// 初始化搜索事件
function initSearchEvent() {
$('#search').on('click', performSearch);
$('.search_box').on('keypress', (e) => {
if (e.which === 13) {
performSearch();
}
});
$('#refresh').on('click', resetSearch);
$('#reset').on('click', resetData);
}
// 执行搜索
function performSearch() {
const keyword = $('.search_box').val().trim().toLowerCase();
window.pagination.searchKeyword = keyword;
if (!keyword) {
showError('请输入搜索关键词');
return;
}
const filteredData = filterTreeData(window.originalTreeData, keyword);
window.treeDataCache = filteredData;
window.pagination.totalRecords = filteredData.length;
window.pagination.totalPages = Math.ceil(window.pagination.totalRecords / window.pagination.pageSize);
window.pagination.currentPage = 1;
window.pagination.cache = {};
$('#pagination').empty();
initPaginationControl();
loadPageData(1);
if (filteredData.length > 0) {
showSuccess(`搜索到 ${filteredData.length} 条匹配数据`);
} else {
showInfo('未搜索到匹配数据');
}
}
// 根据关键词筛选树形结构
function filterTreeData(nodes, keyword) {
if (!Array.isArray(nodes)) return [];
return nodes.reduce((result, node) => {
const isMatch = node.name.toLowerCase().includes(keyword) ||
(node.id && node.id.toString().includes(keyword));
let filteredChildren = node.children?.length ? filterTreeData(node.children, keyword) : [];
if (isMatch || filteredChildren.length) {
const newNode = { ...node, children: filteredChildren };
if (!isMatch && filteredChildren.length) newNode._expanded = true;
result.push(newNode);
}
return result;
}, []);
}
// 加载指定页数据
function loadPageData(page) {
const cacheKey = `page_${page}_${window.pagination.searchKeyword}`;
// 如果有缓存,直接使用缓存数据
if (window.pagination.cache[cacheKey]) {
window.pagination.currentPage = page;
window.pagination.currentData = window.pagination.cache[cacheKey];
renderCurrentPage();
return;
}
if (!window.treeDataCache) return;
// 计算分页数据范围
const startIndex = (page - 1) * window.pagination.pageSize;
const endIndex = startIndex + window.pagination.pageSize;
const pageData = window.treeDataCache.slice(startIndex, endIndex);
// 初始化展开状态
initExpandedState(pageData);
// 同步选中状态(关键修复:确保分页切换时选中状态正确)
syncCheckedState(pageData);
// 缓存当前页数据
window.pagination.cache[cacheKey] = pageData;
window.pagination.currentPage = page;
window.pagination.currentData = pageData;
// 渲染页面
renderCurrentPage();
}
// 同步选中状态(确保与全量数据一致)
function syncCheckedState(nodes) {
if (!Array.isArray(nodes) || !window.treeDataCache) return;
nodes.forEach(node => {
const fullNode = findIndustryById(node.id);
if (fullNode) {
node.checked = fullNode.checked;
}
if (node.children) {
syncCheckedState(node.children);
}
});
}
// 渲染当前页表格
function renderCurrentPage() {
const tableHtml = renderTable(window.pagination.currentData);
$('#dataTable').html(tableHtml || '<tr><td colspan="3" style="text-align:center">暂无数据</td></tr>');
}
// 初始化节点展开状态
function initExpandedState(nodes) {
if (!Array.isArray(nodes)) return;
nodes.forEach(item => {
if (item._expanded === undefined) item._expanded = false;
if (item.children?.length) initExpandedState(item.children);
});
}
// 递归生成树形结构的HTML
function renderTable(nodes, level = 0) {
let html = '';
if (!Array.isArray(nodes)) return html;
nodes.forEach(item => {
const Tag = level === 0 ? 'th' : 'td';
// 二级行业增加缩进,区分层级
const indent = level > 0 ? `<span style="margin-left: ${level * 20}px"></span>` : '';
const hasRealChildren = Array.isArray(item.children) && item.children.length > 0;
const rowClass = hasRealChildren ? 'parent-row' : '';
const iconSrc = hasRealChildren ? (item._expanded ? "./img/下箭头.png" : "./img/1右箭头.png") : "";
const rotateIcon = hasRealChildren && level === 0 ? `
<img src="${iconSrc}" alt="${item._expanded ? '折叠' : '展开'}" class="rotate-icon"
onclick="stopEventPropagation(event); toggleChildren(${item.id}, event)"
style="width:16px; height:16px; cursor:pointer; margin-right:5px;">
` : '';
// 操作按钮(一级和二级行业不同)
let actionButtons = level === 0 ? `
<div class="stair">
<button class="stair_addition" data-id="${item.id}" data-action="add-second" onclick="stopEventPropagation(event)">
<img src="./img/加号.png" alt="新增"><p>新增二级行业</p>
</button>
<button class="stair_compile" data-id="${item.id}" data-action="edit" onclick="stopEventPropagation(event)">
<img src="./img/编辑.png" alt="编辑"><p>编辑</p>
</button>
<button class="stair_delete" data-id="${item.id}" data-action="delete" onclick="stopEventPropagation(event)">
<img src="./img/删除.png" alt="删除"><p>删除</p>
</button>
</div>
` : `
<div class="stair">
<button class="stair_compile" data-id="${item.id}" data-action="edit" onclick="stopEventPropagation(event)">
<img src="./img/编辑.png" alt="编辑"><p>编辑</p>
</button>
<button class="stair_delete" data-id="${item.id}" data-action="delete" onclick="stopEventPropagation(event)">
<img src="./img/删除.png" alt="删除"><p>删除</p>
</button>
</div>
`;
// ID列内容(复选框+ID)
const idColumnContent = `
<div class="middlr_left">
<input type="checkbox" class="item-check" data-id="${item.id}"
onclick="stopEventPropagation(event); CheckboxControl.updateSingle(this, ${item.id})"
${item.checked ? 'checked' : ''}>
<p>${rotateIcon}${item.id}</p>
</div>
`;
// 名称列(高亮搜索关键词)
let displayName = item.name;
if (window.pagination.searchKeyword) {
const regex = new RegExp(`(${window.pagination.searchKeyword})`, 'gi');
displayName = item.name.replace(regex, '<span class="search-highlight">$1</span>');
}
// 拼接行HTML
html += `<tr class="${rowClass}" onclick="handleRowClick(${item.id}, event)">
<${Tag}>${idColumnContent}</${Tag}>
<${Tag}>${indent}${displayName}</${Tag}>
<${Tag} class="action-column">${actionButtons}</${Tag}>
</tr>`;
// 递归渲染子节点(二级行业)
if (hasRealChildren && item._expanded) {
html += renderTable(item.children, level + 1);
}
});
return html;
}
// 行点击事件(展开/折叠子节点)
function handleRowClick(id, event) {
event?.stopPropagation();
const $row = event && $(event.currentTarget);
if (!$row?.hasClass('parent-row') || !window.treeDataCache) return;
const toggleNode = (nodes) => {
for (const node of nodes) {
if (node.id == id) {
node._expanded = !node._expanded;
return true;
}
if (node.children && toggleNode(node.children)) return true;
}
return false;
};
// 切换展开状态
!toggleNode(window.pagination.currentData) && toggleNode(window.treeDataCache);
// 更新缓存
window.pagination.cache[`page_${window.pagination.currentPage}_${window.pagination.searchKeyword}`] = window.pagination.currentData;
// 重新渲染
renderCurrentPage();
}
// 切换子节点展开/折叠
function toggleChildren(id, event) {
handleRowClick(id, event);
}
// 阻止事件冒泡
function stopEventPropagation(event) {
if (!event) return;
event.stopPropagation();
event.cancelBubble = true;
}
// 复选框控制组件(修复分页全选问题)
const CheckboxControl = {
init() {
// 初始化全选功能
const selectAll = document.getElementById('selectAll');
if (selectAll) {
selectAll.addEventListener('click', (e) => {
this.selectAll(e.target.checked);
});
}
},
reset() {
document.querySelectorAll('.item-check').forEach(checkbox => {
checkbox.checked = false;
});
if (window.treeDataCache) {
initNodeCheckedState(window.treeDataCache);
}
const selectAll = document.getElementById('selectAll');
if (selectAll) selectAll.checked = false;
},
updateSingle(checkbox, id) {
const isChecked = checkbox.checked;
const updateNode = (nodes) => {
for (const node of nodes) {
if (node.id == id) {
node.checked = isChecked;
return true;
}
if (node.children && updateNode(node.children)) return true;
}
return false;
};
updateNode(window.treeDataCache);
this.updateSelectAllStatus();
},
selectAll(checked) {
// 1. 更新全量数据的选中状态
const updateAllNodes = (nodes) => {
if (!Array.isArray(nodes)) return;
nodes.forEach(node => {
node.checked = checked;
if (node.children) updateAllNodes(node.children);
});
};
if (window.treeDataCache) {
updateAllNodes(window.treeDataCache);
}
// 2. 更新所有分页缓存中的数据状态(关键修复)
const cache = window.pagination.cache;
for (const key in cache) {
if (cache.hasOwnProperty(key)) {
updateAllNodes(cache[key]);
}
}
// 3. 更新当前页DOM复选框状态
document.querySelectorAll('.item-check').forEach(checkbox => {
checkbox.checked = checked;
});
// 4. 更新全选框状态
const selectAll = document.getElementById('selectAll');
if (selectAll) selectAll.checked = checked;
},
updateSelectAllStatus() {
const selectAll = document.getElementById('selectAll');
if (!selectAll) return;
const checkboxes = document.querySelectorAll('.item-check');
let allChecked = true;
let hasCheckbox = false;
checkboxes.forEach(checkbox => {
hasCheckbox = true;
if (!checkbox.checked) allChecked = false;
});
selectAll.checked = hasCheckbox ? allChecked : false;
},
getCheckedIds() {
const ids = [];
const collectIds = (nodes) => {
if (!Array.isArray(nodes)) return;
nodes.forEach(node => {
if (node.checked) ids.push(node.id);
if (node.children) collectIds(node.children);
});
};
if (window.treeDataCache) collectIds(window.treeDataCache);
return ids;
}
};
window.onload = function () {
console.log('公共JS初始化');
FormCheck.init();
if (typeof initSearchEvent === 'function') initSearchEvent();
if (typeof initPaginationData === 'function') initPaginationData();
if (typeof CheckboxControl !== 'undefined' && CheckboxControl.init) CheckboxControl.init();
const batchDeleteBtn = document.getElementById('expurgate');
if (batchDeleteBtn) {
batchDeleteBtn.addEventListener('click', () => {
const checkedIds = CheckboxControl.getCheckedIds();
if (checkedIds.length === 0) {
showError('请先选择要删除的行业');
return;
}
openDeleteModal('batch');
});
}
const addFirstLevelBtn = document.getElementById('addition');
if (addFirstLevelBtn) {
addFirstLevelBtn.addEventListener('click', () => {
IndustryFormPlugin.openModal('add', null, false);
});
}
// 初始化删除模块
DeleteControl.init({
deleteApi: url + '/fastapi/trade/del', // 接口地址
findItem: findIndustryById, // 复用现有查找函数
afterDelete: function() {
// 删除成功后执行(如刷新列表、重置选择状态)
CheckboxControl.reset();
loadPageData(window.pagination.currentPage);
},
confirmMessage: function(item) {
// 自定义确认消息(可选)
return item.children?.length
? `删除「${item.name}」将同时删除其${item.children.length}个子分类,确定继续?`
: `确定删除「${item.name}」吗?`;
}
});
console.log('系统初始化完成');
};
按照我的逻辑将删除添加修复好
最新发布