PageSourceSearch

https://cdn2.zcqtz.com/static/index/js/index_qp.js

js zcqtz.com collected 2026-10-07 21:07:30 UTC 13,745 bytes, 398 lines download raw bytes

1function handleTabChange(id, index) {
2  const tabs = document.getElementById(id).querySelectorAll(".tab-item");
3  const contents = document.getElementById(id).querySelectorAll(".tab-content");
4  tabs.forEach((o) => {
5    o.classList.remove("active");
6  });
7  tabs[index].classList.add("active");
8  contents.forEach((o) => {
9    o.classList.add("hidden");
10  });
11  contents[index].classList.remove("hidden");
12}
13
14function handleTabChangecountry(id, index) {
15  const tabs = document.getElementById(id).querySelectorAll(".tab-item-country");
16  const contents = document.getElementById(id).querySelectorAll(".tab-content-country");
17  tabs.forEach((o) => {
18    o.classList.remove("active");
19  });
20  tabs[index].classList.add("active");
21  contents.forEach((o) => {
22    o.classList.add("hidden");
23  });
24  contents[index].classList.remove("hidden");
25}
26
27function changeMobileMenu(isShow) {
28  const mobileMenu = document.getElementById("mobile-menu");
29  isShow
30    ? mobileMenu.classList.remove("hidden")
31    : mobileMenu.classList.add("hidden");
32}
33function changeMenuDirection(idx) {
34  const mobileMenu = document.getElementById("mobile-menu");
35  const submenu = mobileMenu.querySelectorAll(".submenu");
36  const icon = mobileMenu.querySelectorAll(".turn-arrow");
37  if (idx >= 0 && idx < submenu.length && idx < icon.length) {
38    const isRotated = icon[idx].classList.toggle("rotate-180");
39    submenu[idx].classList.toggle("hidden", !isRotated);
40  }
41}
42
43document.addEventListener("DOMContentLoaded", function () {
44  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy-load"));
45  if ("IntersectionObserver" in window) {
46    let lazyImageObserver = new IntersectionObserver(function (entries, observer) {
47      entries.forEach(function (entry) {
48        if (entry.isIntersecting) {
49          let lazyImage = entry.target;
50          lazyImage.src = lazyImage.dataset.src;
51          lazyImage.classList.remove("lazy-load");
52          lazyImageObserver.unobserve(lazyImage);
53        }
54      });
55    });
56
57    lazyImages.forEach(function (lazyImage) {
58      lazyImageObserver.observe(lazyImage);
59    });
60  } else {
61    // 处理不支持IntersectionObserver的情况
62    lazyImages.forEach(function (lazyImage) {
63      lazyImage.src = lazyImage.dataset.src;
64      lazyImage.classList.remove("lazy-load");
65    });
66  }
67});
68
69document.addEventListener('DOMContentLoaded', function() {
70  const lazyBackgrounds = document.querySelectorAll('.lazy-background');
71  const observer = new IntersectionObserver((entries, observer) => {
72    entries.forEach(entry => {
73      if (entry.isIntersecting) {
74        const bg = entry.target.dataset.src;
75        entry.target.style.backgroundImage = `url(${bg})`;
76        observer.unobserve(entry.target);
77      }
78    });
79  });
80
81  lazyBackgrounds.forEach(background => {
82    observer.observe(background);
83  });
84});
85
86
87
88
89
90document.addEventListener("DOMContentLoaded", function() {
91  // 定义核心元素
92  const caidanBtn = document.querySelector('.icon-caidan');
93  const closeBtn = document.querySelector('.btn-close');
94  const offcanvasEl = document.querySelector('.offcanvas');
95  
96  // 遮罩层创建函数
97  function createBackdrop() {
98      // 先检查是否已存在遮罩层,避免重复创建
99      const existingBackdrop = document.querySelector('.offcanvas-backdrop');
100      if (existingBackdrop) return;
101      
102      // 创建遮罩层元素
103      const backdrop = document.createElement('div');
104      backdrop.className = 'offcanvas-backdrop fade show';
105      
106      // 将遮罩层插入到offcanvas的同级位置(下方)
107      if (offcanvasEl && offcanvasEl.parentNode) {
108          offcanvasEl.parentNode.insertBefore(backdrop, offcanvasEl.nextSibling);
109      }
110  }
111  
112  // 遮罩层移除函数
113  function removeBackdrop() {
114      const backdrop = document.querySelector('.offcanvas-backdrop');
115      if (backdrop) {
116          backdrop.remove();
117      }
118  }
119  
120  // 确保核心元素存在再绑定事件
121  if (offcanvasEl) {
122      // 点击菜单按钮:显示offcanvas + 创建遮罩层
123      if (caidanBtn) {
124          caidanBtn.addEventListener('click', function() {
125              offcanvasEl.classList.add('show');
126              createBackdrop();
127              
128              // 可选:点击遮罩层也关闭(常见交互需求)
129              const backdrop = document.querySelector('.offcanvas-backdrop');
130              if (backdrop) {
131                  backdrop.addEventListener('click', function() {
132                      offcanvasEl.classList.remove('show');
133                      removeBackdrop();
134                  });
135              }
136          });
137      }
138      
139      // 点击关闭按钮:隐藏offcanvas + 移除遮罩层
140      if (closeBtn) {
141          closeBtn.addEventListener('click', function() {
142              offcanvasEl.classList.remove('show');
143              removeBackdrop();
144          });
145      }
146  }
147});
148
149
150
151
152
153// 全局变量:存储成功/失败图标路径(已填写实际路径)
154const ICONS = {
155  success: 'https://cdn2.zcqtz.com/qp/static/index/img/success-icon.webp',
156  error: 'https://cdn2.zcqtz.com/qp/static/index/img/error-icon.webp'
157};
158
159// 全局变量:管理错误浮层和定时器,确保单次只显示一个浮层
160let currentErrorTip = null;
161let errorTipTimer = null;
162
163// 全局配置:接口地址(可根据实际项目修改)
164const API_CONFIG = {
165  formSubmitUrl: '/Api/insertGeneralFilingInfo' // 真实表单提交接口地址
166};
167
168/**
169* 表单提交主函数
170* @param {string|number} index - 表单索引(用于区分多个表单)
171*/
172function sub_msg(index = '') {
173
174  // 根据索引拼接表单元素ID后缀(适配多个表单)
175  const suffix = index !== '' ? `_${index}` : '';
176  const nameEl = document.getElementById(`name_fast${suffix}`);
177  const mobileEl = document.getElementById(`mobile_fast${suffix}`);
178  const contentEl = document.getElementById(`message_fast${suffix}`);
179
180  // 清除历史错误提示和定时器
181  clearErrorTips();
182
183  // 1. 表单校验逻辑(顺序校验,只提示第一个错误)
184  // 验证姓名(必填)
185  if (!nameEl.value.trim()) {
186      showErrorTip(nameEl, '请输入您的称呼');
187      return;
188  }
189  // 验证手机号(必填+格式)
190  const mobileReg = /^1[3-9]\d{9}$/;
191  if (!mobileEl.value.trim()) {
192      showErrorTip(mobileEl, '请输入手机号码');
193      return;
194  } else if (!mobileReg.test(mobileEl.value.trim())) {
195      showErrorTip(mobileEl, '请输入正确的手机号码');
196      return;
197  }
198  // 验证留言(必填)
199  if (!contentEl.value.trim()) {
200      showErrorTip(contentEl, '请输入您的留言');
201      return;
202  }
203
204  // 2. 整理表单提交数据
205  const formData = {
206      name: nameEl.value.trim(),
207      mobile: mobileEl.value.trim(),
208      content: contentEl.value.trim(),
209      current_url: window.location.href,
210      formIndex: index // 可选:传递表单索引,便于后端区分多表单
211  };
212
213  // 3. 调用原生AJAX提交表单(替换原模拟提交)
214  submitFormByAjax(formData)
215      .then(() => {
216          // 提交成功:显示成功弹窗+重置表单
217          showResultModal(true, '提交成功!我们会尽快与您联系');
218          nameEl.value = '';
219          mobileEl.value = '';
220          contentEl.value = '';
221      })
222      .catch(errorMsg => {
223          // 提交失败:显示失败弹窗(提示具体错误信息)
224          showResultModal(false, errorMsg || '提交失败,请稍后重试');
225      });
226}
227
228/**
229* 原生AJAX表单提交(核心接口请求逻辑)
230* @param {Object} formData - 表单数据(name/mobile/content)
231* @returns {Promise} - 提交结果(成功resolve/失败reject)
232*/
233function submitFormByAjax(formData) {
234  return new Promise((resolve, reject) => {
235      // 1. 创建XMLHttpRequest对象(兼容现代浏览器+IE6+)
236      let xhr;
237      if (window.XMLHttpRequest) {
238          xhr = new XMLHttpRequest();
239      } else {
240          xhr = new ActiveXObject('Microsoft.XMLHTTP');
241      }
242
243      // 2. 初始化请求(POST方式,接口地址,异步)
244      xhr.open('POST', API_CONFIG.formSubmitUrl, true);
245
246      // 3. 设置请求头(表单提交默认格式:application/x-www-form-urlencoded)
247      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
248      // 可选:若接口需要认证,添加Token请求头(根据实际需求修改)
249      // xhr.setRequestHeader('Authorization', 'Bearer ' + getToken());
250
251      // 4. 设置超时时间(5秒,避免请求长期挂起)
252      xhr.timeout = 5000;
253
254      // 5. 监听请求状态变化(处理响应)
255      xhr.onreadystatechange = function() {
256          // readyState=4:请求完成;status=200~299:HTTP状态码成功
257          if (xhr.readyState === 4) {
258              try {
259                  // 解析接口返回的JSON数据(假设后端返回JSON格式)
260                  const response = JSON.parse(xhr.responseText);
261                  // 按后端约定判断成功/失败(示例:code=200为成功)
262                  if (response.code === 200) {
263                      resolve(); // 成功:触发then回调
264                  } else {
265                      // 失败:传递后端返回的错误信息(如"手机号已存在")
266                      reject(response.message || '接口返回错误');
267                  }
268              } catch (error) {
269                  // 非JSON格式响应(如服务器错误页面),提示解析失败
270                  reject('接口响应格式错误,请联系技术支持');
271              }
272          }
273      };
274
275      // 6. 监听网络错误(如断网、跨域未配置等)
276      xhr.onerror = function() {
277          reject('网络异常,请检查网络连接后重试');
278      };
279
280      // 7. 监听请求超时
281      xhr.ontimeout = function() {
282          reject('请求超时,请稍后重试');
283      };
284
285      // 8. 处理表单数据(转为URL编码格式:name=张三&mobile=13800138000)
286      const paramStr = Object.keys(formData)
287          .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(formData[key])}`)
288          .join('&');
289
290      // 9. 发送请求(POST请求数据放在请求体中)
291      xhr.send(paramStr);
292  });
293}
294
295/**
296* 显示错误提示浮层(表单校验失败时调用)
297* @param {HTMLElement} element - 关联的输入框元素
298* @param {string} message - 错误提示文本
299*/
300function showErrorTip(element, message) {
301  // 先清除已存在的错误浮层和定时器
302  clearErrorTips();
303
304  // 1. 创建错误浮层元素(依赖外部CSS类:error-tip-1)
305  const tip = document.createElement('div');
306  tip.className = 'error-tip-1';
307  tip.textContent = message;
308
309  // 2. 计算浮层位置(优先显示在输入框下方,空间不足则右侧)
310  const elementRect = element.getBoundingClientRect();
311  if (window.innerHeight - elementRect.bottom > 4) {
312      // 下方空间足够:显示在正下方
313      tip.style.top = '0';
314      tip.style.right = '0';
315      tip.style.marginTop = '3px';
316  } else {
317      // 下方空间不足:显示在右侧
318      tip.style.left = '100%';
319      tip.style.top = '50%';
320      tip.style.transform = 'translateY(-50%)';
321      tip.style.marginLeft = '10px';
322  }
323
324  // 3. 添加浮层到输入框父容器(确保父容器相对定位)
325  const parent = element.parentElement;
326  parent.appendChild(tip);
327  currentErrorTip = tip;
328
329  // 4. 3秒后自动清除浮层
330  errorTipTimer = setTimeout(() => {
331      clearErrorTips();
332  }, 3000);
333}
334
335/**
336* 清除错误提示(浮层+定时器)
337*/
338function clearErrorTips() {
339  // 清除当前浮层
340  if (currentErrorTip) {
341      currentErrorTip.remove();
342      currentErrorTip = null;
343  }
344  // 清除自动消失定时器
345  if (errorTipTimer) {
346      clearTimeout(errorTipTimer);
347      errorTipTimer = null;
348  }
349}
350
351/**
352* 显示提交结果弹窗(成功/失败通用)
353* @param {boolean} isSuccess - 是否提交成功
354* @param {string} message - 弹窗提示文本
355*/
356function showResultModal(isSuccess, message) {
357  // 1. 创建遮罩层(依赖外部CSS类:result-overlay)
358  const overlay = document.createElement('div');
359  overlay.className = 'result-overlay';
360
361  // 2. 创建弹窗容器(依赖外部CSS类:result-modal)
362  const modal = document.createElement('div');
363  modal.className = 'result-modal';
364
365  // 3. 组装弹窗内容(图标+文本+按钮)
366  // 3.1 结果图标
367  const icon = document.createElement('img');
368  icon.className = 'result-modal-icon';
369  icon.src = isSuccess ? ICONS.success : ICONS.error;
370  icon.alt = isSuccess ? '提交成功' : '提交失败';
371
372  // 3.2 提示文本
373  const text = document.createElement('p');
374  text.className = 'result-modal-text';
375  text.textContent = message;
376
377  // 3.3 关闭按钮
378  const btn = document.createElement('button');
379  btn.className = 'result-modal-btn';
380  btn.textContent = '确定';
381  btn.onclick = () => overlay.remove(); // 点击关闭弹窗
382
383  // 4. 渲染弹窗到页面
384  modal.appendChild(icon);
385  modal.appendChild(text);
386  modal.appendChild(btn);
387  overlay.appendChild(modal);
388  document.body.appendChild(overlay);
389}
390
391// 可选:若需要Token认证,可添加获取Token的辅助函数(根据实际登录逻辑修改)
392// function getToken() {
393//     return localStorage.getItem('userToken') || '';
394// }
395
396
397
398

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.