make a note with window.open function

本文提供了两个关于MSDN及JavaScript的重要资源链接。第一个链接来自MSDN官方文档,可能涉及Windows编程、.NET Framework等内容。第二个链接则为JavaScript常见问题解答,有助于开发者解决JavaScript编程中遇到的问题。
[url]http://msdn.microsoft.com/en-us/library/ms536651%28VS.85%29.aspx[/url]
[url]http://www.javascripter.net/faq/openinga.htm[/url]
Facets 3 User Guide Version 3.5.0 NOTICE OF PROPRIETARY PROPERTY: THIS DOCUMENT AND THE INFORMATION CONTAINED HEREIN IS THE PROPRIETARY PROPERTY OF APPLE INC. THE POSSESSOR AGREES TO THE FOLLOWING: (I) TO MAINTAIN THIS DOCUMENT IN CONFIDENCE, (II) NOT TO REPRODUCE OR COPY IT, (III) NOT TO REVEAL OR PUBLISH IT IN WHOLE OR IN PART, (IV) ALL RIGHTS RESERVED. ACCESS TO THIS DOCUMENT AND THE INFORMATION CONTAINED HEREIN IS GOVERNED BY THE TERMS OF THE MFi LICENSE AGREEMENT. ALL OTHER USE SHALL BE AT APPLE'S SOLE DISCRETION.  DeveloperTable of Contents Introduction ....................................................................................................3 Important Information .................................................................................................3 General Requirements ....................................................................................4 Quick Start .....................................................................................................5 ATS Integration ...............................................................................................6 CaptureKit Agent Installation ......................................................................................6 Switching the ATS Version ..........................................................................................6 Viewing the ATS Trace Window ..................................................................................6 Test Plans .......................................................................................................7 Downloading the Test Plan ..........................................................................................7 Test Plan Versioning ....................................................................................................7 Required Test Cases ...................................................................................................7 Managing Product and Test Plans ...............................................................................7 Experimental Features ................................................................................................8 Exporting and Importing .......................................................................................8 Sandbox Mode ......................................................................................................8 Performing a Test Run .....................................................................................9 Test Run ......................................................................................................................9 Test Suites .................................................................................................................10 Test Case Contents ...................................................................................................10 Results .......................................................................................................................12 Failing a Test Case ...............................................................................................12 Editing Results .....................................................................................................12 Blocking a Step or Test Case ...............................................................................12 Uploading Test Results..............................................................................................13 Test Suite Features........................................................................................14 Migrate Test Suites Created in Facets 3.2 and Older ................................................14 Duplicate Test Suites .................................................................................................14 Copy a Test Suite s Test Case IDs .............................................................................14 My Suites and All Runs UI .........................................................................................15 Providing Feedback to Apple .........................................................................16 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 1 of 18Internet Connection.......................................................................................17 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 2 of 18Introduction Facets was redesigned to introduce a new workflow for running CarPlay functional tests. This new version of Facets enables: • Integration with MFi Certification Hub (MCH) to: • Retrieve Product Plan and Sample information (removing the need for the Test Plan Configuration from Facets 2) • Select, download, and update CarPlay test plans • Upload test results throughout the testing process • Control which test results are used in the certification submission to Apple • Improved test execution efficiency with more protocol validation Unlike Facets 2, Facets 3 does not use a document to record test results; this means users can run tests without needing to share a .facets file. Additionally, since the test plan is downloaded from MCH, the app no longer needs to be updated to change test plans. Important Information Facets 2 documents are not compatible with Facets 3. Both versions may need to be used until the transition to Facets 3 is complete. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 3 of 18General Requirements • Access to MFi Certification Hub (MCH) with MFi Program credentials • Product Plan with MCH records: • Configuration Record in Approved state • CarPlay Functional Tests Facets 3 record with all Sample Questionnaire fields completed • Mac running macOS Sonoma 14.2.1 or later • ATS (Accessory Test System) version 8 or later 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 4 of 18Quick Start 1. Install desired ATS (version 8 or later) 2. Install CaptureKit Agent (see CaptureKit Agent Installation below) 3. Launch Facets 3 4. Sign in with MFi credentials 5. Add Product Plan to be tested 6. Select and run test cases from the Test Plan 7. Once test run is complete, upload results to MCH 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 5 of 18ATS Integration Unlike Facets 2, Facets 3 communicates with the ATS application that is already installed on the Mac. To enable this, CaptureKit Agent must be installed (see CaptureKit Agent Installation). In Facets 3 users choose their desired capture type (e.g. Wireless CarPlay), ATS will then select the first available capture device. In most cases, the same capture can be used between multiple test cases. If users have multiple ATS installations on their computer, CaptureKit Agent needs to be installed from the desired version (see Switching ATS Version). CaptureKit Agent Installation Prior to using Facets 3, users must run the CaptureKit Agent installer in ATS by following these instructions: 1. Install the desired ATS (version 8 or later) 2. Launch ATS 3. In the ATS menu bar perform: Utilities > Install CaptureKit Agent (or similar) 4. Perform an ATS capture with accessory to ensure all dependencies are installed and up- to-date Switching the ATS Version To switch which ATS performs the Facets capture, repeat the CaptureKit Agent Installation steps from the desired ATS. Viewing the ATS Trace Window Users can choose to see the ATS trace window to appear during Facets test execution. This selection can be changed in Settings > Open ATS Window, and is enabled by default. Once enabled, the ATS trace window will open behind the Facets window and will close automatically. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 6 of 18Test Plans MFi credentials are required to add a Product Plan and download the test cases for a given Sample. Downloading the Test Plan After signing in, add a Product Plan to download its samples and corresponding Test Plan. Changes to the Configuration Record or Sample Questionnaire on MCH require updating the Product Plan in Facets. See Managing Product and Test Plans for more information. Test Plan Versioning Facets 3 has an improved Test Plan versioning system to customize which test cases are needed for a specific Product Plan. Test Plans are versioned according to the corresponding CarPlay spec version. For example, if the Product Plan is developing against Accessory Interface Specification CarPlay Addendum R5, expect the latest Test Plan version v5.x.y to be downloaded. Required Test Cases The Product Plan's Configuration Record and Sample Questionnaire on MCH determine which test cases are required (and supported) for the specific Sample under test. Unsupported test cases are not shown. Required test cases are indicated with a red asterisk (*). Additional information is shown under the info icon ( ), mainly to indicate if the test case version is incompatible with the Product Plan. Managing Product and Test Plans The Product Plan > Manage Product Plans… menu item will open the Manage Plans window. This provides the following functionality: • Retrieve latest Product Plan details from MCH with the "Update" button • Review the Release Notes of a Test Plan and copy the relevant content • Download new Test Plan versions • New Test Plans are automatically downloaded and will be denoted with a blue dot ( ) • Modify the Test Plan version for a given Product Plan. It is recommended to update to the latest spec-aligned version. This only impacts the version used locally in Facets 3. Note that this may result in submissions being rejected if the version is not suitable. • Delete downloaded items. Make sure to upload test results first. Facets automatically checks for Product Plan changes updates when signing-in after 8 hours. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 7 of 18Experimental Features The following features allow users to browse and run test cases but their results cannot be uploaded to MCH. Exporting and Importing In the Manage Plans window, Product Plan details can be exported and then imported by a different user. This allows users without a network connection to view and run test cases. Results cannot be uploaded to MCH. Sandbox Mode Sandbox Mode can be used to browse all test cases of any Test Plan version. Tests can be run but many steps will not function properly as they depend on Configuration Record and Sample Questionnaire information. Results cannot be uploaded. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 8 of 18Performing a Test Run Individual test cases or a Test Suite can be run via the toolbar, menu bar, or context menu. Test Run Initiating a test opens the "Create Test Run" window where users can configure their test run: • Test Run can be renamed • Test cases can be re-ordered When starting the run, a separate Test Run window will appear. This is where users perform test cases in the configured sequence. A Test Run can be stopped at any time and only results for completed test cases will be saved. Results are stored under "Ad-hoc Runs" in the sidebar. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 9 of 18Test Suites A Test Suite is a user-created collection of test cases. It can be created via the toolbar item or via context menu when selecting multiple test cases in the Test Plan view. Test Suites are only saved locally. Run results from a suite are located beneath the Test Suite in the "My Suites" section of the sidebar. See Test Suites Features for more information. Test Case Contents A test case contains the following components: • Test case ID, title, and description • Metrics gathered by ATS such as the wired CarPlay connection time • ATS rule errors where certain rule errors can cause the test case to fail • Sequence of steps • Blocks of repeated steps • Sample information used by steps 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 10 of 18Each step can contain the following components: ComponentDescription Step IDIdentifier used to refer to the step, appearing in the ATS trace to indicate when the step started and stopped CaptureInstructs the user to start an ATS capture Provides a choice of captures Can be configured to allow continuing the existing capture Once complete, the ATS trace is attached and can be opened InstructInstructs the user to perform a manual action VerifyPrompts the user to make an assertion on the expected test behavior Configured to fail depending on the answer Answer can be changed after the fact PromptPrompts the user to make a selection from the presented options AttachmentPrompts the user to attach one or more files MonitorUses ATS trace to perform protocol validation Receives a specific ATS event Can set variables for later use Can perform multiple programmatic assertions If Condition evaluated programmatically to enable a step 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 11 of 18Results Once a test case is complete, it will report a status of either Passed, Failed, or Blocked. Test results can be found in the Runs section, this list only shows locally saved content. Selecting a Test Run will show additional metadata, including if it was uploaded to MCH. Deleting a Test Run will remove it from the local file system; uploaded results will not be impacted. Failing a Test Case When steps fail, the test case also fails. These results should be uploaded to MCH; users select which test results to submit and failing results can be useful for tracking system health and regression testing. Editing Results For certain types of steps, like a "verify" step, the user can change their answer during test execution. This can be useful if the wrong selection was accidentally made. If a step can impact subsequent steps, it cannot be edited. A test case can also be reset to start over, during the test case or immediately after the test executed. Blocking a Step or Test Case A failure can be marked as "blocked". This can be used to communicate the inability to make a test assertion. If a step is marked as blocking the test case, the remainder of the test case is skipped. Step failures can be unblocked if the rest of the test case was not impacted. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 12 of 18Uploading Test Results When completing or stopping a test run, Facets will offer the option to "Upload Now" or "Upload Later". Users must be logged in to use the "Upload Now" option. It is recommended to upload all valid results even if they contain failures. The upload status is shown as follows: • Results have been uploaded. Click on "View Results in MCH " in the run to open results in your web browser. •Pending result upload. User must be signed in and have a network connection. •"Upload Later" was selected. To upload, click on the run and press the "Upload" button. •Result upload failed. See run for more details. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 13 of 18Test Suite Features As of Facets 3.3, all new Test Suites will be saved to only the specific testable record (Test Result or Audit) in which it was created. This is a change from earlier versions of Facets, where Test Suites were globally applied to all testable records a user had downloaded. Facets 3.3 also introduces enhancements to Test Suites, outlined below. Migrate Test Suites Created in Facets 3.2 and Older Facets 3.3 includes a utility to migrate a user s existing Test Suites to conform to the new structure in version 3.3. The utility will create a copy of each existing suite to each testable record downloaded at the time. Users then have the choice to keep or delete the copied suites. Deleting a suite will remove it from the selected testable record only. Duplicate Test Suites Users can copy a Test Suite to another testable record within the same PPID, or create additional copies of a suite in the same testable record. To do so, select the Test Suite under "My Suites" in the sidebar, Control-click to show the context menu, and select "Duplicate To…". Copy a Test Suite s Test Case IDs Users can copy all Test Case IDs in a suite to their pasteboard. To do so, select the Test Suite under "My Suites" in the sidebar, Control-click to show the context menu, and select "Copy Test Case IDs". The IDs are saved as a plain text string that can be pasted into any text editor or into the "Create Test Suite" screen. The "Create Test Suite" screen includes a field to provide copied Test Case IDs. Pasting Test Case IDs will automatically select those tests to be included in the new suite. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 14 of 18My Suites and All Runs UI Test Suites, their run results, and a results summary are collected together under "My Suites" in the sidebar. Run results are displayed beneath the suite in which the result was generated. A summary screen called "All Runs" is also displayed beneath a suite. This screen lists the results of all runs executed from the suite, plus a chart showing latest Pass/Fail/Blocked results for the suite. The chart will always reflect the latest execution. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 15 of 18Providing Feedback to Apple Report issues with Facets or its integration with ATS or Certification test cases to https:// feedbackassistant.apple.com using the “MFi Technologies” option. For app or test case issues, you may include the following: • Screenshot or screen recording displaying the issue • Saved ATS trace displaying the issue • Link to an MCH result upload that includes the issue • Log collected as soon as the issue occurred, by running the following in Terminal: sudo sysdiagnose If results are failing to upload to MCH, include the following information: • Time of upload attempt (including timezone) • MFi account username (email) • Testable record address (URL to the Test Result or Audit record in MCH) 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 16 of 18Internet Connection Facets 3 uses port 80 to communicate with the following addresses: • https://auth-assistant.apple.com • https://mficertificationhub.apple.com • https://flipper.apple.com 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 17 of 18 Apple Inc. Copyright © 2025 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer or device for personal use only and to print copies of documentation for personal use provided that the documentation contains Apple’s copyright notice. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-branded products. Apple Inc. One Apple Park Way Cupertino, CA 95014 408-996-1010 Apple is a trademark of Apple Inc., registered in the U.S. and other countries. APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED “AS IS,” AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT, ERROR OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. Some jurisdictions do not allow the exclusion of implied warranties or liability, so the above exclusion may not apply to you. 2025-06-24 | Copyright © 2025 Apple Inc. All Rights Reserved. Page 18 of 18 帮我翻译上面的文章
11-14
Homework 4: Binocular Stereo November 6, 2025 Due Date: November 27, by 23:59 Introduction In this project, you will implement a stereo matching algorithm for rectified stereo pairs. For simplicity, you will work under the assumption that the image planes of the two cameras are parallel to each other and to the baseline. The project requires implementing algorithms to compute disparity maps from stereo image pairs and visualizing depth maps. To see examples of disparity maps, run python main.py --tasks 0 to visualize the com￾parison of disparity map generated by cv2.StereoBM and the ground truth. 1 Basic Stereo Matching Algorithm (60 pts.) 1.1 Disparity Map Computation (30 pts.) Implement the function task1 compute disparity map simple() to return the disparity map of a given stereo pair. The function takes the reference image and the second image as inputs, along with the following hyperparameters: • window size: the size of the window used for matching. • disparity range: the minimum and maximum disparity value to search. • matching function: the function used for computing the matching cost. The function should implement a simple window-based stereo matching algorithm, as out￾lined in the Basic Stereo Matching Algorithm section in lecture slides 08: For each pixel in the first (reference) image, examine the corresponding scanline (in our case, the same row) in the second image to search for a best-matching window. The output should be a disparity map with respect to the first (reference) image. Note that you should also manage to record the running time of your code, which should be included in the report. 1.2 Hyperparameter Settings and Report (30 pts.) Set hyperparameters in function task1 simple disparity() to get the best performance. You can try different window sizes, disparity ranges, and matching functions. The comparison of your generated disparity maps and the ground truth maps can be visualized (or saved) by calling function visualize disparity map(). 1 Computer Vision (2025 fall) Homework 4 After finishing the implementation, you can run python main.py --tasks 1 to generate disparity maps with different settings and save them in the output folder. According to the comparison of your disparity maps and ground truth maps under different settings, report and discuss • How does the running time depend on window size, disparity range, and matching function? • Which window size works the best for different matching functions? • What is the maximum disparity range that makes sense for the given stereo pair? • Which matching function may work better for the given stereo pair? With the results above • Discuss the trade-offs between different hyperparameters on quality and time. • Choose the best hyperparameters and show the corresponding disparity map. • Compare the best disparity map with the ground truth map, discuss the differences and limitations of basic stereo matching. 2 Depth from Disparity (25 pts.) 2.1 Pointcloud Visualization (20 pts.) Implement task2 compute depth map() to convert a disparity map to a depth map, and task2 visualize pointcloud() to save the depth map as pointcloud in ply format for visual￾ization (recommended using MeshLab). For depth map computation, follow the Depth from Disparity part in slides 08. You should try to estimate proper depth scaling constants baseline and focal length to get a better performance. The depth of a pixel p can be formulated as: depth(p) = focal length × baseline disparity(p) (1) For pointcloud conversion, the x and y coordinates of a point should match pixel coordinates in the reference image, and the z coordinate shoule be set to the depth value. You should also set the color of the points to the color of the corresponding pixels the reference image. For better performance, you may need to exclude some outliers in the pointcloud. After finishing the implementation, you can run python main.py --tasks 02 to generate a ply file using the disparity map generated with cv2.StereoBM, saved in the output folder. By modifying the settings of the hyperparameters in task1 simple disparity() and run￾ning python main.py --tasks 12, you can generate pointclouds with your implemented stereo matching algorithm under different settings and they will be saved in the output folder. 2 Computer Vision (2025 fall) Homework 4 2.2 Report (5 pts.) Include in your report and compare the results of the pointclouds generated with • disparity map computed using cv2.StereoBM • disparity map computed using your implemented algorithm under optimal settings you found in task 1. 3 Stereo Matching with Dynamic Programming (15 pts.) 3.1 Algorithm Implementation (10 pts.) Incorporate non-local constraints into your algorithm to improve the quality of the disparity map. Specifically, you are to implement the function task3 compute disparity map dp() with dynamic programming algorithms. You may refer to the Stereo Matching with Dynamic Programming section in lecture slides 08. Note that you should also manage to record the running time of your code, which should be included in the report. After finishing the implementation, you can run python main.py --tasks 3 to generate the disparity map and save it in the output folder. You can also run python main.py --tasks 23 to simultaneously generate pointclouds. 3.2 Report (5 pts.) Report the running time, the disparity map, and the pointcloud generated with dynamic programming algorithm. Compare the results with basic stereo matching algorithm. Submission Requirements • Due date of this homework is November 27, by 23:59. Late submission is acceptable but with a penalty of 10% per day. • Zip your code, report, and all the visualization results (including disparity maps and the pointclouds) into a single file named StuID YourName HW4.zip. A wrong naming format may lead to a penalty of 10%. Make sure that the zip file can be unzipped under Windows. • For the code, it should run without errors and can reproduce the results in your report. If you use artificial intelligence tools to help generate codes, explain in your report of (1) how you use them, and (2) the details of implementation in your own words. If your code simultaneously (1) is suspected to be generated by AI tools, and (2) cannot run properly, you may get a penalty of 100%. • For the report, either Chinese or English is acceptable. Please submit a single PDF file, which can be exported from LATEX, Word, MarkDown, or any other text editor. You may get a penalty of 10% if the file format is not correct. 3 Computer Vision (2025 fall) Homework 4 Hints Here are some supplemental materials: • cv2.StereoBM: https://docs.opencv.org/4.x/d9/dba/classcv_1_1StereoBM.html • cv2.StereoBeliefPropagation: https://docs.opencv.org/4.x/de/d7a/classcv_1_1cuda _1_1StereoBeliefPropagation.html
11-28
/* 公共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('系统初始化完成'); }; 按照我的逻辑将删除添加修复好
08-08
(function (event) { event = event || document; let rgba = { r: 0, g: 0, b: 0, a: 1 }, hsb = { h: 0, s: 100, b: 100 }; let Initial = null, setTime = null, throttle = null; function ColorTool(str) { ColorTool.prototype.Ele = { body: document.querySelector('body'), main: document.querySelector('.main'), sample: document.querySelector('.sample'), ColorToolContainer: document.querySelector('.ColorToolContainer'), PanelContainer: document.querySelector('.PanelContainer'), panelCanvas: document.querySelector('#panelCanvas'), DotOne: document.querySelector('.DotOne'), Discoloration: document.querySelector('.Discoloration'), DotTwo: document.querySelector('.DotTwo'), input: document.querySelectorAll('input'), ControlButton: document.querySelector('.control>button'), LeftAndRightlSpan: document.querySelectorAll('.LeftAndRight>span'), InputBoxOne: document.querySelector('.InputBoxOne'), InputBoxTwo: document.querySelector('.InputBoxTwo'), InputBoxThree: document.querySelector('.InputBoxThree'), getColor: document.querySelector(".getColor"), constant: 0 }; Initial = str; return new ColorTool.prototype.init(str); } ColorTool.prototype.init = function (str) { ColorTool.prototype.initANDsetColor(str); ColorTool.prototype.getColorFun(); return this; } ColorTool.prototype.init.prototype = ColorTool.prototype; ColorTool.prototype.then = function (parameter) { ColorTool.prototype.then.prototype.thenFun = parameter; } ColorTool.setColor = function (str) { if (ColorTool.prototype.initANDsetColor) { ColorTool.prototype.initANDsetColor(str); } else { throw new Error('未调用ColorTool函数'); } } ColorTool.prototype.getColorFun = function () { if ('EyeDropper' in window) { // 判断是否支持这个api const eyeDropper = new EyeDropper(); // 创建对象 ColorTool.prototype.Ele.getColor.addEventListener('click', async () => { ColorTool.prototype.Ele.body.style.cssText = 'width:30px;height:30px;min-width:auto;min-height:auto;display:none;'; ColorTool.prototype.Ele.main.style.display = 'none'; await new Promise(resolve => setTimeout(resolve, 60)); try { const ColorResult = await eyeDropper.open();// 取得吸取结果 ColorTool.setColor(ColorResult.sRGBHex);// 取得颜色并设置颜色 chrome.storage.local.get({ history: [] }, data => { const hist = data.history; hist.unshift(ColorResult.sRGBHex); if (hist.length > 20) hist.pop(); chrome.storage.local.set({ history: hist }, () => { ColorTool.prototype.Ele.main.style.display = 'block'; ColorTool.prototype.Ele.body.style.cssText = 'width: 100vw;min-width: 256px;height:100vh;min-height: 329px;display:flex;'; }); }); } catch (e) { console.log( '%c%s', 'border: 1px solid white;border-radius: 5px;padding: 2px 5px;color: white;font-weight: bold;background-color: #ab5a5a;', '发生了一些意外!\nSomething unexpected happened!'); } }); } } ColorTool.prototype.initANDsetColor = function (str) { if (str.match(/rgb\(|\Rgb\(/g) && str.match(/\)|\);/g) && str.match(/,/g)) { if (str.match(/,/g).length === 2) { str = str.replace(/rgb\(|\Rgb\(/g, '').replace(/\)|\);/g, ''); let strArr = str.split(','); ColorTool.prototype.Ele.input[1].value = parseInt(strArr[0]); ColorTool.prototype.Ele.input[2].value = parseInt(strArr[1]); ColorTool.prototype.Ele.input[3].value = parseInt(strArr[2]); ColorTool.prototype.RgbInput(); } } else { ColorTool.prototype.Ele.input[0].value = str; ColorTool.prototype.HexInput(); } ColorTool.prototype.EventCollection(); } ColorTool.prototype.hsbToRgb = function (hsb) { var rgb = {}; var h = hsb.h; var s = hsb.s * 255 / 100; var v = hsb.b * 255 / 100; if (s == 0) { rgb.r = rgb.g = rgb.b = v; } else { var t1 = v; var t2 = (255 - s) * v / 255; var t3 = (t1 - t2) * (h % 60) / 60; if (h === 360) h = 0; if (h < 60) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3 } else if (h < 120) { rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3 } else if (h < 180) { rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3 } else if (h < 240) { rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3 } else if (h < 300) { rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3 } else if (h < 360) { rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3 } else { rgb.r = 0; rgb.g = 0; rgb.b = 0 } } return { r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b) }; } ColorTool.prototype.rgbToHex = function (rgb) { var hex = [ rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16) ]; hex.map(function (str, i) { if (str.length == 1) { hex[i] = '0' + str; } }); return hex.join(''); } ColorTool.prototype.hexToRgb = function (hex) { var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16); return { r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF) }; } ColorTool.prototype.hexToHsb = function (hex) { return this.rgbToHsb(this.hexToRgb(hex)); } ColorTool.prototype.rgbToHsb = function (rgb) { var hsb = { h: 0, s: 0, b: 0 }; var min = Math.min(rgb.r, rgb.g, rgb.b); var max = Math.max(rgb.r, rgb.g, rgb.b); var delta = max - min; hsb.b = max; hsb.s = max != 0 ? 255 * delta / max : 0; if (hsb.s != 0) { if (rgb.r == max) hsb.h = (rgb.g - rgb.b) / delta; else if (rgb.g == max) hsb.h = 2 + (rgb.b - rgb.r) / delta; else hsb.h = 4 + (rgb.r - rgb.g) / delta; } else hsb.h = -1; hsb.h *= 60; if (hsb.h < 0) hsb.h += 360; hsb.s *= 100 / 255; hsb.b *= 100 / 255; return hsb; } ColorTool.prototype.rgbToHsl = function (rgb) { var HslArray = { h: rgb.r / 255, s: rgb.g / 255, l: rgb.b / 255 }; var max = Math.max(HslArray.h, HslArray.s, HslArray.l); var min = Math.min(HslArray.h, HslArray.s, HslArray.l); var difference = max - min; var hsl = { h: 0, s: 0, l: 0 }; if (max == min) { hsl.h = 0; } else if (max == HslArray.h && HslArray.s >= HslArray.l) { hsl.h = 60 * (HslArray.s - HslArray.l) / difference; } else if (max == HslArray.h && HslArray.s < HslArray.l) { hsl.h = 60 * (HslArray.s - HslArray.l) / difference + 360; } else if (max == HslArray.s) { hsl.h = 60 * (HslArray.l - HslArray.h) / difference + 120; } else if (max == HslArray.l) { hsl.h = 60 * (HslArray.h - HslArray.s) / difference + 240; } var sum = max + min; hsl.l = sum / 2; if (hsl.l == 0 || max == min) { hsl.s = 0; } else if (0 < hsl.l && hsl.l <= 0.5) { hsl.s = difference / sum; } else { hsl.s = difference / (2 - sum); } hsl.h = Math.round(hsl.h); return hsl; } ColorTool.prototype.hslToRgb = function (H = 0, S = 0, L = 0) { S /= 100; L /= 100; let CXM = { C: (1 - Math.abs(2 * L - 1)) * S, X: ((1 - Math.abs(2 * L - 1)) * S) * (1 - Math.abs(((H / 60) % 2) - 1)), M: L - ((1 - Math.abs(2 * L - 1)) * S) / 2 } let vRGB = [] if (H >= 0 && H < 60) { vRGB.push(CXM.C, CXM.X, 0) } else if (H >= 60 && H < 120) { vRGB.push(CXM.X, CXM.C, 0) } else if (H >= 120 && H < 180) { vRGB.push(0, CXM.C, CXM.X) } else if (H >= 180 && H < 240) { vRGB.push(0, CXM.X, CXM.C) } else if (H >= 240 && H < 300) { vRGB.push(CXM.X, 0, CXM.C) } else if (H >= 300 && H < 360) { vRGB.push(CXM.C, 0, CXM.X) } const [vR, vG, vB] = vRGB let RGB = { r: Math.round(255 * (vR + CXM.M)), g: Math.round(255 * (vG + CXM.M)), b: Math.round(255 * (vB + CXM.M)) } return RGB } ColorTool.prototype.setValue = function (rgb) { ColorTool.prototype.Ele.input[0].value = "#" + this.rgbToHex(rgb); ColorTool.prototype.Ele.input[1].value = rgb.r; ColorTool.prototype.Ele.input[2].value = rgb.g; ColorTool.prototype.Ele.input[3].value = rgb.b; let hsl = ColorTool.prototype.rgbToHsl(rgb); ColorTool.prototype.Ele.input[4].value = hsl.h; ColorTool.prototype.Ele.input[5].value = Math.round(hsl.s * 100) + "%"; ColorTool.prototype.Ele.input[6].value = Math.round(hsl.l * 100) + "%"; } ColorTool.prototype.changeColor = function () { let rgb = this.hsbToRgb(hsb); this.setValue(rgb); rgba.r = rgb.r; rgba.g = rgb.g; rgba.b = rgb.b; localStorage.setItem("ColorToolStorage", "#" + this.rgbToHex(rgb)); ColorTool.prototype.Ele.sample.style.backgroundColor = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgba.a + ')'; if (!(rgb.r >= 196 && rgb.g >= 196 && rgb.b >= 196)) { document.documentElement.style.setProperty('--MyColor', 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgba.a + ')'); } clearTimeout(throttle); throttle = setTimeout(function () { if (ColorTool.prototype.thenFunExistence('rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')')) { ColorTool.prototype.then.prototype.thenFun('rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')'); } clearTimeout(throttle); }, 36); } ColorTool.prototype.thenFunExistence = function (ColorData) { if (ColorTool.prototype.then.prototype.thenFun) { return true; } else { clearTimeout(setTime); setTime = setTimeout(function () { //延时防止调用thenFun时发生越界 if (ColorTool.prototype.thenFunExistence(ColorData)) { ColorTool.prototype.then.prototype.thenFun(ColorData); } clearTimeout(setTime); }, 5); } return false; } ColorTool.prototype.PanelCalculation = function (x, y) { let MaxLeft = Math.max(0, Math.min(x, 216)); let MaxTop = Math.max(0, Math.min(y, 124)); hsb.s = 100 * MaxLeft / 216; hsb.b = 100 * (124 - MaxTop) / 124; this.changeColor(); } ColorTool.prototype.PanelColor = function (ColorData) { let canvas = ColorTool.prototype.Ele.panelCanvas; if (canvas && canvas.getContext) { let ctx = canvas.getContext("2d"); // 底色填充,也就是(举例红色)到白色 let gradientBase = ctx.createLinearGradient(3, 0, 216, 0); gradientBase.addColorStop(1, ColorData); gradientBase.addColorStop(0, "rgba(255,255,255,1)"); ctx.fillStyle = gradientBase; ctx.fillRect(0, 0, 216, 124); // 第二次填充,黑色到透明 let gradientScreen = ctx.createLinearGradient(0, 3, 0, 124); gradientScreen.addColorStop(0, "transparent"); gradientScreen.addColorStop(1, "rgba(0,0,0,1)"); ctx.fillStyle = gradientScreen; ctx.fillRect(0, 0, 216, 124); } } ColorTool.prototype.BarCalculation = function (x) { let Left = Math.max(0, Math.min(x, 216)); hsb.h = 360 * Left / 216; let rgb = this.hsbToRgb({ h: hsb.h, s: 100, b: 100 }); ColorTool.prototype.PanelColor('rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgba.a + ')'); this.changeColor(); // rgba.a = X / elem_width;//调透明度的 } ColorTool.prototype.panel = function (event) { ColorTool.prototype.Ele.DotOne.style.top = (event.offsetY - (ColorTool.prototype.Ele.DotOne.offsetHeight / 2)) + "px"; ColorTool.prototype.Ele.DotOne.style.left = (event.offsetX - (ColorTool.prototype.Ele.DotOne.offsetWidth / 2)) + "px"; ColorTool.prototype.PanelCalculation(event.offsetX, event.offsetY); } ColorTool.prototype.DiscolorationFun = function (event) { ColorTool.prototype.Ele.DotTwo.style.left = (event.offsetX - (ColorTool.prototype.Ele.DotTwo.offsetWidth / 2)) + "px"; ColorTool.prototype.BarCalculation(event.offsetX); } ColorTool.prototype.DotOneFun = function (event) { ColorTool.prototype.Ele.PanelContainer.removeEventListener("click", ColorTool.prototype.panel); let DotOneTop = event.offsetY > 0 ? event.offsetY : 0; let DotOneLeft = event.offsetX > 0 ? event.offsetX : 0; document.onmousemove = function (e) { e.preventDefault(); let PanelContainerWidth = ColorTool.prototype.Ele.PanelContainer.clientWidth; let PanelContainerHeight = ColorTool.prototype.Ele.PanelContainer.clientHeight; let OneTop = e.clientY - (ColorTool.prototype.Ele.ColorToolContainer.offsetTop + DotOneTop); let OneLeft = e.clientX - (ColorTool.prototype.Ele.ColorToolContainer.offsetLeft + DotOneLeft); OneTop = OneTop <= -(ColorTool.prototype.Ele.DotOne.offsetHeight / 2) ? -(ColorTool.prototype.Ele.DotOne.offsetHeight / 2) + 1 : OneTop; OneTop = OneTop >= (PanelContainerHeight - (ColorTool.prototype.Ele.DotOne.offsetHeight / 2)) ? (PanelContainerHeight - (ColorTool.prototype.Ele.DotOne.offsetHeight / 2)) : OneTop; OneLeft = OneLeft <= -(ColorTool.prototype.Ele.DotOne.offsetWidth / 2) ? -(ColorTool.prototype.Ele.DotOne.offsetWidth / 2) : OneLeft; OneLeft = OneLeft >= (PanelContainerWidth - (ColorTool.prototype.Ele.DotOne.offsetWidth / 2)) ? (PanelContainerWidth - (ColorTool.prototype.Ele.DotOne.offsetWidth / 2)) : OneLeft; ColorTool.prototype.Ele.DotOne.style.top = OneTop + "px"; ColorTool.prototype.Ele.DotOne.style.left = OneLeft + "px"; ColorTool.prototype.PanelCalculation((e.clientX - ColorTool.prototype.Ele .ColorToolContainer.offsetLeft), (e.clientY - ColorTool.prototype.Ele.ColorToolContainer.offsetTop)); } document.onmouseup = function (e) { document.onmousemove = null; document.onmouseup = null; let delayed = setTimeout(function () { ColorTool.prototype.Ele.PanelContainer.addEventListener('click', ColorTool.prototype.panel); clearTimeout(delayed); }, 10); } } ColorTool.prototype.DotTwoFun = function (event) { ColorTool.prototype.Ele.Discoloration.removeEventListener("click", ColorTool.prototype .DiscolorationFun); let DotTwoLeft = event.offsetX > 0 ? event.offsetX : 0; document.onmousemove = function (e) { e.preventDefault(); let TwoLeft = e.clientX - (ColorTool.prototype.Ele.ColorToolContainer.offsetLeft + DotTwoLeft); let DiscolorationWidth = ColorTool.prototype.Ele.Discoloration.clientWidth; TwoLeft = TwoLeft <= -(ColorTool.prototype.Ele.DotTwo.offsetWidth / 2) ? -(ColorTool.prototype.Ele.DotTwo.offsetWidth / 2) : TwoLeft; TwoLeft = TwoLeft >= (DiscolorationWidth - (ColorTool.prototype.Ele.DotTwo.offsetWidth / 2)) ? (DiscolorationWidth - (ColorTool.prototype.Ele.DotTwo.offsetWidth / 2)) : TwoLeft; ColorTool.prototype.Ele.DotTwo.style.left = TwoLeft + "px"; ColorTool.prototype.BarCalculation(e.clientX - ColorTool.prototype.Ele.ColorToolContainer .offsetLeft); } document.onmouseup = function (e) { document.onmousemove = null; document.onmouseup = null; let delayed = setTimeout(function () { ColorTool.prototype.Ele.Discoloration.addEventListener('click', ColorTool .prototype.DiscolorationFun); clearTimeout(delayed); }, 10); } } ColorTool.prototype.setDistance = function (hsb) { ColorTool.prototype.Ele.DotOne.style.top = parseInt(((100 - hsb.b) * 124 / 100) - (ColorTool.prototype.Ele.DotOne.offsetHeight / 2)) + "px"; ColorTool.prototype.Ele.DotOne.style.left = parseInt((hsb.s * 216 / 100) - (ColorTool.prototype.Ele.DotOne.offsetWidth / 2)) + "px"; ColorTool.prototype.Ele.DotTwo.style.left = parseInt((hsb.h / 360 * 216) - (ColorTool.prototype.Ele.DotTwo.offsetWidth / 2)) + "px"; this.PanelCalculation(hsb.s * 216 / 100, (100 - hsb.b) * 124 / 100); this.BarCalculation(hsb.h / 360 * 216); } ColorTool.prototype.SpecialSymbol = function (str) { var pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>《》/?~!@#¥……&*()——|{}【】‘;:”“'。,、? ]"); if (pattern.test(str)) { return true; } return false; } ColorTool.prototype.HexInput = function (Blur) { let ColorToolThis = ColorTool.prototype; if (!ColorTool.prototype.Ele.input[0].value) { return null; } if (ColorTool.prototype.Ele.input[0].value[0] !== "#") { ThisValuePro = "#" + ColorTool.prototype.Ele.input[0].value; } else { ThisValuePro = ColorTool.prototype.Ele.input[0].value.substring(1); } if (!ColorToolThis.SpecialSymbol(ThisValuePro)) { if (ThisValuePro.length === 6) { ColorToolThis.setDistance(ColorToolThis.hexToHsb(ColorTool.prototype.Ele.input[0].value)); } else if (Blur) { if (ThisValuePro.length === 3) { let NewValue = ThisValuePro[0] + ThisValuePro[0] + ThisValuePro[1] + ThisValuePro[1] + ThisValuePro[ 2] + ThisValuePro[2]; ColorToolThis.setDistance(ColorToolThis.hexToHsb(NewValue)); } } } } ColorTool.prototype.RgbInput = function (event) { let ColorToolThis = ColorTool.prototype; if (!ColorToolThis.SpecialSymbol(ColorToolThis.Ele.input[1].value) && !ColorToolThis .SpecialSymbol(ColorToolThis.Ele.input[2].value) && !ColorToolThis.SpecialSymbol(ColorToolThis.Ele.input[3].value)) { if (parseInt(ColorToolThis.Ele.input[1].value) >= 0 && parseInt(ColorToolThis.Ele.input[2] .value) >= 0 && parseInt(ColorToolThis.Ele.input[3].value) >= 0) { if (parseInt(ColorToolThis.Ele.input[1].value) <= 255 && parseInt(ColorToolThis.Ele.input[2] .value) <= 255 && parseInt(ColorToolThis.Ele.input[3] .value) <= 255) { ColorToolThis.setDistance(ColorToolThis.rgbToHsb({ r: parseInt(ColorToolThis.Ele.input[1].value), g: parseInt(ColorToolThis.Ele.input[2].value), b: parseInt(ColorToolThis.Ele.input[3].value) })); } } } ColorTool.prototype.hslToRgb(0, 100, 50); } ColorTool.prototype.HslInput = function (event) { let ColorToolThis = ColorTool.prototype; if (!ColorToolThis.SpecialSymbol(ColorToolThis.Ele.input[4].value) && !ColorToolThis .SpecialSymbol(ColorToolThis.Ele.input[5].value) && !ColorToolThis.SpecialSymbol(ColorToolThis.Ele.input[6].value)) { if (parseInt(ColorToolThis.Ele.input[4].value) >= 0 && parseInt(ColorToolThis.Ele.input[5] .value) >= 0 && parseInt(ColorToolThis.Ele.input[6].value) >= 0) { if (parseInt(ColorToolThis.Ele.input[4].value) <= 360 && parseInt(ColorToolThis.Ele.input[5] .value) <= 100 && parseInt(ColorToolThis.Ele.input[6] .value) <= 100) { ColorToolThis.setDistance( ColorToolThis.rgbToHsb( ColorTool.prototype.hslToRgb( parseInt(ColorToolThis.Ele.input[4].value), parseInt(ColorToolThis.Ele.input[5].value), parseInt(ColorToolThis.Ele.input[6].value) ) ) ); } } } } ColorTool.prototype.NoneOrFlex = function (constant) { ColorTool.prototype.Ele.InputBoxOne.style.display = "none"; ColorTool.prototype.Ele.InputBoxTwo.style.display = "none"; ColorTool.prototype.Ele.InputBoxThree.style.display = "none"; if (constant === 0) { ColorTool.prototype.Ele.InputBoxOne.style.display = "block"; } else if (constant === 1) { ColorTool.prototype.Ele.InputBoxTwo.style.display = "flex"; } else { ColorTool.prototype.Ele.InputBoxThree.style.display = "flex"; } } ColorTool.prototype.EventCollection = function () { ColorTool.prototype.Ele.PanelContainer.addEventListener('click', ColorTool.prototype.panel); ColorTool.prototype.Ele.Discoloration.addEventListener('click', ColorTool.prototype .DiscolorationFun); ColorTool.prototype.Ele.DotOne.addEventListener('mousedown', ColorTool.prototype.DotOneFun); ColorTool.prototype.Ele.DotTwo.addEventListener('mousedown', ColorTool.prototype.DotTwoFun); ColorTool.prototype.Ele.input[0].addEventListener('input', function () { ColorTool.prototype.HexInput(false) }); ColorTool.prototype.Ele.input[0].addEventListener('blur', function () { ColorTool.prototype.HexInput(true) }); ColorTool.prototype.Ele.input[1].addEventListener('input', ColorTool.prototype.RgbInput); ColorTool.prototype.Ele.input[2].addEventListener('input', ColorTool.prototype.RgbInput); ColorTool.prototype.Ele.input[3].addEventListener('input', ColorTool.prototype.RgbInput); ColorTool.prototype.Ele.input[4].addEventListener('input', ColorTool.prototype.HslInput); ColorTool.prototype.Ele.input[5].addEventListener('input', ColorTool.prototype.HslInput); ColorTool.prototype.Ele.input[6].addEventListener('input', ColorTool.prototype.HslInput); ColorTool.prototype.Ele.ControlButton.addEventListener('click', function () { ColorTool.prototype.init(Initial); }); ColorTool.prototype.Ele.LeftAndRightlSpan[0].addEventListener('click', function () { ColorTool.prototype.Ele.constant = --ColorTool.prototype.Ele.constant >= 0 ? --ColorTool.prototype.Ele.constant : 1; ColorTool.prototype.NoneOrFlex(++ColorTool.prototype.Ele.constant); }); ColorTool.prototype.Ele.LeftAndRightlSpan[1].addEventListener('click', function () { ColorTool.prototype.Ele.constant = ++ColorTool.prototype.Ele.constant <= 2 ? ++ColorTool.prototype.Ele.constant : 1; ColorTool.prototype.NoneOrFlex(--ColorTool.prototype.Ele.constant); }); } event.ColorTool = ColorTool; })(window);把它改写成类
09-25
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值