html+js 实现生活缴费页面模板

响应式 支持手机和电脑

复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>生活缴费平台</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  
  <!-- Tailwind 配置 -->
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#165DFF',
            secondary: '#36BFFA',
            success: '#00B42A',
            warning: '#FF7D00',
            danger: '#F53F3F',
            neutral: {
              100: '#F2F3F5',
              200: '#E5E6EB',
              300: '#C9CDD4',
              400: '#86909C',
              500: '#4E5969',
              600: '#272E3B',
              700: '#1D2129',
            }
          },
          fontFamily: {
            inter: ['Inter', 'system-ui', 'sans-serif'],
          },
          boxShadow: {
            'card': '0 4px 20px rgba(0, 0, 0, 0.08)',
            'card-hover': '0 8px 30px rgba(0, 0, 0, 0.12)',
          }
        },
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    @layer utilities {
      .content-auto {
        content-visibility: auto;
      }
      .transition-all-300 {
        transition: all 300ms ease-in-out;
      }
      .bg-gradient-primary {
        background: linear-gradient(135deg, #165DFF 0%, #36BFFA 100%);
      }
      .text-balance {
        text-wrap: balance;
      }
    }
  </style>
</head>

<body class="font-inter bg-neutral-100 text-neutral-700 min-h-screen">
  <!-- 头部导航 -->
  <header class="bg-white shadow-sm sticky top-0 z-50">
    <div class="container mx-auto px-4 py-4 flex justify-between items-center">
      <div class="flex items-center space-x-2">
        <i class="fa fa-credit-card text-primary text-2xl"></i>
        <h1 class="text-xl font-bold text-neutral-700">生活缴费平台</h1>
      </div>
      <div class="flex items-center space-x-6">
        <button class="text-neutral-500 hover:text-primary transition-all-300">
          <i class="fa fa-bell-o"></i>
        </button>
        <button class="text-neutral-500 hover:text-primary transition-all-300">
          <i class="fa fa-user-o"></i>
        </button>
      </div>
    </div>
  </header>

  <!-- 主内容区 -->
  <main class="container mx-auto px-4 py-8 max-w-5xl">
    <!-- 步骤指示器 -->
    <div class="mb-10">
      <div class="flex justify-between items-center relative">
        <div class="absolute left-0 right-0 top-1/2 h-1 bg-neutral-200 -z-10"></div>
        <div class="absolute left-0 h-1 bg-primary transition-all duration-500" id="progress-bar" style="width: 0%; top: 1/2; z-10"></div>
        
        <div class="step-indicator flex flex-col items-center" data-step="1">
          <div class="w-10 h-10 rounded-full bg-primary text-white flex items-center justify-center mb-2">
            <i class="fa fa-map-marker"></i>
          </div>
          <span class="text-sm font-medium text-primary">选择城市</span>
        </div>
        
        <div class="step-indicator flex flex-col items-center" data-step="2">
          <div class="w-10 h-10 rounded-full bg-neutral-200 text-neutral-500 flex items-center justify-center mb-2">
            <i class="fa fa-list-alt"></i>
          </div>
          <span class="text-sm font-medium text-neutral-500">缴费类型</span>
        </div>
        
        <div class="step-indicator flex flex-col items-center" data-step="3">
          <div class="w-10 h-10 rounded-full bg-neutral-200 text-neutral-500 flex items-center justify-center mb-2">
            <i class="fa fa-search"></i>
          </div>
          <span class="text-sm font-medium text-neutral-500">查询</span>
        </div>
        
        <div class="step-indicator flex flex-col items-center" data-step="4">
          <div class="w-10 h-10 rounded-full bg-neutral-200 text-neutral-500 flex items-center justify-center mb-2">
            <i class="fa fa-file-text-o"></i>
          </div>
          <span class="text-sm font-medium text-neutral-500">账单</span>
        </div>
      </div>
    </div>

    <!-- 步骤内容区 -->
    <div class="bg-white rounded-xl shadow-card p-6 md:p-8 transition-all-300">
      <!-- 步骤1: 选择城市 -->
      <div id="step-1" class="step-content">
        <h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold text-neutral-700 mb-6">选择您的城市</h2>
        
        <div class="mb-6">
          <div class="relative">
            <input type="text" id="city-search" placeholder="搜索城市..." 
                  class="w-full px-4 py-3 rounded-lg border border-neutral-200 focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none transition-all-300">
            <i class="fa fa-search absolute right-4 top-1/2 -translate-y-1/2 text-neutral-400"></i>
          </div>
        </div>
        
        <div class="mb-6">
          <h3 class="text-neutral-500 font-medium mb-3">热门城市</h3>
          <div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-3" id="hot-cities">
            <!-- 城市将通过JS动态生成 -->
          </div>
        </div>
        
        <div>
          <h3 class="text-neutral-500 font-medium mb-3">按省份选择</h3>
          <div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3" id="provinces">
            <!-- 省份将通过JS动态生成 -->
          </div>
        </div>
        
        <div class="mt-8 flex justify-end">
          <button id="to-step-2" class="px-6 py-3 bg-primary text-white rounded-lg shadow-sm hover:bg-primary/90 transition-all-300 opacity-50 cursor-not-allowed">
            下一步 <i class="fa fa-arrow-right ml-1"></i>
          </button>
        </div>
      </div>

      <!-- 步骤2: 选择缴费类型 -->
      <div id="step-2" class="step-content hidden">
        <h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold text-neutral-700 mb-6">选择缴费类型</h2>
        
        <div class="mb-4 text-neutral-500">
          当前城市: <span id="selected-city-display" class="font-medium text-neutral-700">未选择</span>
        </div>
        
        <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-6" id="payment-types">
          <!-- 缴费类型将通过JS动态生成 -->
        </div>
        
        <div class="mt-8 flex justify-between">
          <button id="back-to-step-1" class="px-6 py-3 border border-neutral-200 text-neutral-600 rounded-lg hover:bg-neutral-50 transition-all-300">
            <i class="fa fa-arrow-left mr-1"></i> 上一步
          </button>
          <button id="to-step-3" class="px-6 py-3 bg-primary text-white rounded-lg shadow-sm hover:bg-primary/90 transition-all-300 opacity-50 cursor-not-allowed">
            下一步 <i class="fa fa-arrow-right ml-1"></i>
          </button>
        </div>
      </div>

      <!-- 步骤3: 查询页面 -->
      <div id="step-3" class="step-content hidden">
        <h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold text-neutral-700 mb-6">查询缴费信息</h2>
        
        <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
          <div>
            <p class="text-neutral-500 mb-1">城市</p>
            <p id="query-city" class="font-medium"></p>
          </div>
          <div>
            <p class="text-neutral-500 mb-1">缴费类型</p>
            <p id="query-type" class="font-medium"></p>
          </div>
        </div>
        
        <div id="query-form" class="space-y-4 mt-6">
          <!-- 查询表单将根据缴费类型动态生成 -->
        </div>
        
        <div class="mt-8 flex justify-between">
          <button id="back-to-step-2" class="px-6 py-3 border border-neutral-200 text-neutral-600 rounded-lg hover:bg-neutral-50 transition-all-300">
            <i class="fa fa-arrow-left mr-1"></i> 上一步
          </button>
          <button id="to-step-4" class="px-6 py-3 bg-primary text-white rounded-lg shadow-sm hover:bg-primary/90 transition-all-300">
            查询账单 <i class="fa fa-search ml-1"></i>
          </button>
        </div>
      </div>

      <!-- 步骤4: 账单页面 -->
      <div id="step-4" class="step-content hidden">
        <h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold text-neutral-700 mb-6">您的账单信息</h2>
        
        <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
          <div class="bg-neutral-50 p-4 rounded-lg">
            <p class="text-neutral-500 mb-1">城市</p>
            <p id="bill-city" class="font-medium"></p>
          </div>
          <div class="bg-neutral-50 p-4 rounded-lg">
            <p class="text-neutral-500 mb-1">缴费类型</p>
            <p id="bill-type" class="font-medium"></p>
          </div>
          <div class="bg-neutral-50 p-4 rounded-lg">
            <p class="text-neutral-500 mb-1">户号</p>
            <p id="bill-account" class="font-medium"></p>
          </div>
        </div>
        
        <div id="bills-container" class="space-y-6">
          <!-- 账单信息将通过JS动态生成 -->
        </div>
        
        <div class="mt-8 flex justify-between">
          <button id="back-to-step-3" class="px-6 py-3 border border-neutral-200 text-neutral-600 rounded-lg hover:bg-neutral-50 transition-all-300">
            <i class="fa fa-arrow-left mr-1"></i> 返回查询
          </button>
          <button id="pay-bill" class="px-8 py-3 bg-success text-white rounded-lg shadow-sm hover:bg-success/90 transition-all-300">
            立即缴费 <i class="fa fa-money ml-1"></i>
          </button>
        </div>
      </div>
    </div>
  </main>

  <!-- 页脚 -->
  <footer class="bg-white mt-12 py-8 border-t border-neutral-200">
    <div class="container mx-auto px-4 text-center text-neutral-500 text-sm">
      <p>©  生活缴费平台 版权所有</p>
      <p class="mt-2">客服热线: 400-***-4567</p>
    </div>
  </footer>

  <!-- 缴费成功弹窗 -->
  <div id="success-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
    <div class="bg-white rounded-xl p-8 max-w-md w-full mx-4 transform transition-all-300 scale-95 opacity-0" id="modal-content">
      <div class="text-center">
        <div class="w-16 h-16 bg-success/20 rounded-full flex items-center justify-center mx-auto mb-4">
          <i class="fa fa-check text-2xl text-success"></i>
        </div>
        <h3 class="text-xl font-bold text-neutral-700 mb-2">缴费成功</h3>
        <p class="text-neutral-500 mb-6">您已成功完成缴费,账单信息已更新</p>
        <button id="close-modal" class="w-full py-3 bg-primary text-white rounded-lg hover:bg-primary/90 transition-all-300">
          完成
        </button>
      </div>
    </div>
  </div>

  <script>
    // 模拟数据 - 城市和省份
    const cityData = {
      hotCities: ['北京', '上海', '广州', '深圳', '杭州', '成都', '武汉', '重庆', '南京', '西安', '苏州', '天津'],
      provinces: [
        { name: '北京市', cities: ['北京'] },
        { name: '上海市', cities: ['上海'] },
        { name: '广东省', cities: ['广州', '深圳', '珠海', '汕头', '佛山', '韶关'] },
        { name: '江苏省', cities: ['南京', '无锡', '徐州', '常州', '苏州', '南通'] },
        { name: '浙江省', cities: ['杭州', '宁波', '温州', '绍兴', '湖州', '嘉兴'] },
        { name: '四川省', cities: ['成都', '自贡', '攀枝花', '泸州', '德阳', '绵阳'] },
        { name: '山东省', cities: ['济南', '青岛', '淄博', '枣庄', '东营', '烟台'] },
        { name: '河南省', cities: ['郑州', '开封', '洛阳', '平顶山', '安阳', '鹤壁'] },
        { name: '湖北省', cities: ['武汉', '黄石', '十堰', '宜昌', '襄阳', '鄂州'] },
        { name: '湖南省', cities: ['长沙', '株洲', '湘潭', '衡阳', '邵阳', '岳阳'] },
        { name: '河北省', cities: ['石家庄', '唐山', '秦皇岛', '邯郸', '邢台', '保定'] },
        { name: '陕西省', cities: ['西安', '铜川', '宝鸡', '咸阳', '渭南', '延安'] }
      ]
    };

    // 模拟数据 - 缴费类型
    const paymentTypes = [
      { 
        id: 'water', 
        name: '水费', 
        icon: 'fa-tint', 
        color: '#165DFF',
        formFields: [
          { name: '户号', key: 'account', type: 'text', placeholder: '请输入水费户号' }
        ]
      },
      { 
        id: 'electricity', 
        name: '电费', 
        icon: 'fa-bolt', 
        color: '#FF7D00',
        formFields: [
          { name: '户号', key: 'account', type: 'text', placeholder: '请输入电费户号' },
          { name: '缴费单位', key: 'company', type: 'select', options: ['国家电网', '南方电网', '地方电力公司'] }
        ]
      },
      { 
        id: 'gas', 
        name: '燃气费', 
        icon: 'fa-fire', 
        color: '#F53F3F',
        formFields: [
          { name: '户号', key: 'account', type: 'text', placeholder: '请输入燃气费户号' },
          { name: '燃气公司', key: 'company', type: 'select', options: ['天然气公司', '液化气公司', '煤气公司'] }
        ]
      }
    ];

    // 模拟数据 - 账单信息
    function generateBills(account, type) {
      const months = ['1月', '2月', '3月', '4月', '5月', '6月'];
      const currentMonth = new Date().getMonth();
      
      return months.slice(0, currentMonth + 1).map((month, index) => {
        const year = new Date().getFullYear();
        const isPaid = index < currentMonth;
        let usage, amount;
        
        // 根据不同类型生成不同的用量和金额
        switch(type) {
          case 'water':
            usage = Math.floor(Math.random() * 10) + 5; // 5-15吨
            amount = (usage * 3.8).toFixed(2); // 每吨3.8元
            break;
          case 'electricity':
            usage = Math.floor(Math.random() * 100) + 50; // 50-150度
            amount = (usage * 0.58).toFixed(2); // 每度0.58元
            break;
          case 'gas':
            usage = Math.floor(Math.random() * 15) + 5; // 5-20立方米
            amount = (usage * 2.5).toFixed(2); // 每立方米2.5元
            break;
        }
        
        return {
          id: `bill-${index + 1}`,
          month: `${year}年${month}`,
          usage: usage,
          amount: amount,
          isPaid: isPaid,
          dueDate: isPaid ? `${year}年${month}15日` : `${year}年${months[currentMonth]}25日`
        };
      });
    }

    // 存储用户选择的数据
    const userSelections = {
      city: null,
      paymentType: null,
      formData: {}
    };

    // DOM元素
    const elements = {
      progressBar: document.getElementById('progress-bar'),
      stepIndicators: document.querySelectorAll('.step-indicator'),
      stepContents: document.querySelectorAll('.step-content'),
      hotCitiesContainer: document.getElementById('hot-cities'),
      provincesContainer: document.getElementById('provinces'),
      citySearch: document.getElementById('city-search'),
      selectedCityDisplay: document.getElementById('selected-city-display'),
      paymentTypesContainer: document.getElementById('payment-types'),
      queryCity: document.getElementById('query-city'),
      queryType: document.getElementById('query-type'),
      queryForm: document.getElementById('query-form'),
      billsContainer: document.getElementById('bills-container'),
      billCity: document.getElementById('bill-city'),
      billType: document.getElementById('bill-type'),
      billAccount: document.getElementById('bill-account'),
      successModal: document.getElementById('success-modal'),
      modalContent: document.getElementById('modal-content')
    };

    // 按钮
    const buttons = {
      toStep2: document.getElementById('to-step-2'),
      backToStep1: document.getElementById('back-to-step-1'),
      toStep3: document.getElementById('to-step-3'),
      backToStep2: document.getElementById('back-to-step-2'),
      toStep4: document.getElementById('to-step-4'),
      backToStep3: document.getElementById('back-to-step-3'),
      payBill: document.getElementById('pay-bill'),
      closeModal: document.getElementById('close-modal')
    };

    // 初始化页面
    function init() {
      renderHotCities();
      renderProvinces();
      renderPaymentTypes();
      setupEventListeners();
    }

    // 渲染热门城市
    function renderHotCities() {
      elements.hotCitiesContainer.innerHTML = '';
      
      cityData.hotCities.forEach(city => {
        const cityElement = document.createElement('button');
        cityElement.className = 'py-2 px-3 rounded-lg border border-neutral-200 hover:border-primary hover:text-primary transition-all-300 text-center';
        cityElement.textContent = city;
        cityElement.addEventListener('click', () => selectCity(city));
        
        elements.hotCitiesContainer.appendChild(cityElement);
      });
    }

    // 渲染省份
    function renderProvinces() {
      elements.provincesContainer.innerHTML = '';
      
      cityData.provinces.forEach(province => {
        const provinceElement = document.createElement('div');
        provinceElement.className = 'province-item';
        
        const provinceName = document.createElement('button');
        provinceName.className = 'text-left py-2 px-3 w-full rounded-lg border border-neutral-200 hover:border-primary hover:text-primary transition-all-300 flex justify-between items-center';
        provinceName.innerHTML = `${province.name} <i class="fa fa-chevron-down text-xs"></i>`;
        
        const citiesList = document.createElement('div');
        citiesList.className = 'cities-list mt-2 grid grid-cols-2 gap-2 hidden';
        
        province.cities.forEach(city => {
          const cityElement = document.createElement('button');
          cityElement.className = 'py-1 px-2 text-sm rounded border border-neutral-200 hover:border-primary hover:text-primary transition-all-300';
          cityElement.textContent = city;
          cityElement.addEventListener('click', () => selectCity(city));
          
          citiesList.appendChild(cityElement);
        });
        
        provinceName.addEventListener('click', () => {
          citiesList.classList.toggle('hidden');
          const icon = provinceName.querySelector('i');
          icon.classList.toggle('fa-chevron-down');
          icon.classList.toggle('fa-chevron-up');
        });
        
        provinceElement.appendChild(provinceName);
        provinceElement.appendChild(citiesList);
        elements.provincesContainer.appendChild(provinceElement);
      });
    }

    // 渲染缴费类型
    function renderPaymentTypes() {
      elements.paymentTypesContainer.innerHTML = '';
      
      paymentTypes.forEach(type => {
        const typeCard = document.createElement('div');
        typeCard.className = 'payment-type-card border border-neutral-200 rounded-xl p-6 text-center cursor-pointer hover:shadow-card-hover transition-all-300 hover:border-primary/30';
        typeCard.dataset.type = type.id;
        
        typeCard.innerHTML = `
          <div class="w-16 h-16 rounded-full mx-auto mb-4 flex items-center justify-center" style="background-color: ${type.color}20">
            <i class="fa ${type.icon} text-2xl" style="color: ${type.color}"></i>
          </div>
          <h3 class="font-medium text-lg">${type.name}</h3>
        `;
        
        typeCard.addEventListener('click', () => selectPaymentType(type));
        
        elements.paymentTypesContainer.appendChild(typeCard);
      });
    }

    // 渲染查询表单
    function renderQueryForm(type) {
      elements.queryForm.innerHTML = '';
      
      if (!type) return;
      
      type.formFields.forEach(field => {
        const fieldGroup = document.createElement('div');
        
        if (field.type === 'text') {
          fieldGroup.innerHTML = `
            <label for="${field.key}" class="block text-neutral-600 mb-1.5">${field.name}</label>
            <input type="${field.type}" id="${field.key}" 
                  class="w-full px-4 py-3 rounded-lg border border-neutral-200 focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none transition-all-300"
                  placeholder="${field.placeholder}" data-field="${field.key}">
          `;
        } else if (field.type === 'select') {
          let optionsHtml = '';
          field.options.forEach(option => {
            optionsHtml += `<option value="${option}">${option}</option>`;
          });
          
          fieldGroup.innerHTML = `
            <label for="${field.key}" class="block text-neutral-600 mb-1.5">${field.name}</label>
            <select id="${field.key}" 
                  class="w-full px-4 py-3 rounded-lg border border-neutral-200 focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none transition-all-300"
                  data-field="${field.key}">
              <option value="">请选择${field.name}</option>
              ${optionsHtml}
            </select>
          `;
        }
        
        elements.queryForm.appendChild(fieldGroup);
      });
      
      // 添加表单输入监听
      const formInputs = elements.queryForm.querySelectorAll('[data-field]');
      formInputs.forEach(input => {
        input.addEventListener('input', updateFormData);
      });
    }

    // 渲染账单信息
    function renderBills() {
      const { city, paymentType, formData } = userSelections;
      
      if (!city || !paymentType || !formData.account) return;
      
      elements.billCity.textContent = city;
      elements.billType.textContent = paymentType.name;
      elements.billAccount.textContent = formData.account;
      
      const bills = generateBills(formData.account, paymentType.id);
      elements.billsContainer.innerHTML = '';
      
      bills.forEach(bill => {
        const billCard = document.createElement('div');
        billCard.className = 'border border-neutral-200 rounded-xl p-6 transition-all-300 hover:shadow-card';
        
        const statusClass = bill.isPaid ? 'text-success' : 'text-danger';
        const statusText = bill.isPaid ? '已缴费' : '待缴费';
        const statusIcon = bill.isPaid ? 'fa-check-circle' : 'fa-exclamation-circle';
        
        let usageUnit = '';
        switch(paymentType.id) {
          case 'water': usageUnit = '吨'; break;
          case 'electricity': usageUnit = '度'; break;
          case 'gas': usageUnit = '立方米'; break;
        }
        
        billCard.innerHTML = `
          <div class="flex justify-between items-start mb-4">
            <h3 class="font-medium text-lg">${bill.month}账单</h3>
            <span class="flex items-center ${statusClass}">
              <i class="fa ${statusIcon} mr-1"></i> ${statusText}
            </span>
          </div>
          
          <div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-neutral-600">
            <div>
              <p class="text-sm text-neutral-500">用量</p>
              <p class="font-medium">${bill.usage} ${usageUnit}</p>
            </div>
            <div>
              <p class="text-sm text-neutral-500">金额</p>
              <p class="font-medium">¥${bill.amount}</p>
            </div>
            <div>
              <p class="text-sm text-neutral-500">${bill.isPaid ? '缴费日期' : '截止日期'}</p>
              <p class="font-medium">${bill.dueDate}</p>
            </div>
          </div>
          
          ${!bill.isPaid ? `
            <div class="mt-4 pt-4 border-t border-neutral-100 flex justify-end">
              <button class="pay-this-bill px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-all-300 text-sm"
                      data-amount="${bill.amount}" data-month="${bill.month}">
                立即支付 ¥${bill.amount}
              </button>
            </div>
          ` : ''}
        `;
        
        elements.billsContainer.appendChild(billCard);
      });
      
      // 添加单账单支付事件
      const payButtons = elements.billsContainer.querySelectorAll('.pay-this-bill');
      payButtons.forEach(button => {
        button.addEventListener('click', function() {
          const amount = this.dataset.amount;
          const month = this.dataset.month;
          showSuccessModal(amount, month);
        });
      });
    }

    // 切换步骤
    function goToStep(stepNumber) {
      // 更新进度条
      elements.progressBar.style.width = `${(stepNumber - 1) * 33.33}%`;
      
      // 更新步骤指示器
      elements.stepIndicators.forEach(indicator => {
        const indicatorStep = parseInt(indicator.dataset.step);
        const circle = indicator.querySelector('div');
        const text = indicator.querySelector('span');
        
        if (indicatorStep < stepNumber) {
          // 已完成的步骤
          circle.classList.remove('bg-neutral-200', 'text-neutral-500');
          circle.classList.add('bg-primary', 'text-white');
          text.classList.remove('text-neutral-500');
          text.classList.add('text-primary');
        } else if (indicatorStep === stepNumber) {
          // 当前步骤
          circle.classList.remove('bg-neutral-200', 'text-neutral-500');
          circle.classList.add('bg-primary', 'text-white');
          text.classList.remove('text-neutral-500');
          text.classList.add('text-primary');
        } else {
          // 未完成的步骤
          circle.classList.remove('bg-primary', 'text-white');
          circle.classList.add('bg-neutral-200', 'text-neutral-500');
          text.classList.remove('text-primary');
          text.classList.add('text-neutral-500');
        }
      });
      
      // 显示当前步骤内容,隐藏其他步骤
      elements.stepContents.forEach(content => {
        const contentStep = parseInt(content.id.split('-')[1]);
        if (contentStep === stepNumber) {
          content.classList.remove('hidden');
        } else {
          content.classList.add('hidden');
        }
      });
      
      // 滚动到顶部
      window.scrollTo({ top: 0, behavior: 'smooth' });
    }

    // 选择城市
    function selectCity(city) {
      userSelections.city = city;
      
      // 更新UI
      elements.selectedCityDisplay.textContent = city;
      
      // 重置之前的选择样式
      document.querySelectorAll('#hot-cities button, .cities-list button').forEach(btn => {
        btn.classList.remove('bg-primary/10', 'border-primary', 'text-primary');
      });
      
      // 设置当前选择样式
      const selectedBtn = Array.from(document.querySelectorAll('#hot-cities button, .cities-list button'))
        .find(btn => btn.textContent === city);
      if (selectedBtn) {
        selectedBtn.classList.add('bg-primary/10', 'border-primary', 'text-primary');
      }
      
      // 启用下一步按钮
      buttons.toStep2.classList.remove('opacity-50', 'cursor-not-allowed');
    }

    // 选择缴费类型
    function selectPaymentType(type) {
      userSelections.paymentType = type;
      
      // 重置之前的选择样式
      document.querySelectorAll('.payment-type-card').forEach(card => {
        card.classList.remove('border-primary', 'bg-primary/5');
      });
      
      // 设置当前选择样式
      const selectedCard = document.querySelector(`.payment-type-card[data-type="${type.id}"]`);
      if (selectedCard) {
        selectedCard.classList.add('border-primary', 'bg-primary/5');
      }
      
      // 启用下一步按钮
      buttons.toStep3.classList.remove('opacity-50', 'cursor-not-allowed');
    }

    // 更新表单数据
    function updateFormData() {
      const formInputs = elements.queryForm.querySelectorAll('[data-field]');
      formInputs.forEach(input => {
        userSelections.formData[input.dataset.field] = input.value;
      });
    }

    // 显示成功弹窗
    function showSuccessModal(amount, month) {
      elements.successModal.classList.remove('hidden');
      setTimeout(() => {
        elements.modalContent.classList.remove('scale-95', 'opacity-0');
        elements.modalContent.classList.add('scale-100', 'opacity-100');
      }, 10);
    }

    // 隐藏成功弹窗
    function hideSuccessModal() {
      elements.modalContent.classList.remove('scale-100', 'opacity-100');
      elements.modalContent.classList.add('scale-95', 'opacity-0');
      setTimeout(() => {
        elements.successModal.classList.add('hidden');
        // 刷新账单列表以反映缴费状态
        renderBills();
      }, 300);
    }

    // 设置事件监听器
    function setupEventListeners() {
      // 步骤切换按钮
      buttons.toStep2.addEventListener('click', () => {
        if (userSelections.city) {
          goToStep(2);
        }
      });
      
      buttons.backToStep1.addEventListener('click', () => goToStep(1));
      
      buttons.toStep3.addEventListener('click', () => {
        if (userSelections.paymentType) {
          elements.queryCity.textContent = userSelections.city;
          elements.queryType.textContent = userSelections.paymentType.name;
          renderQueryForm(userSelections.paymentType);
          goToStep(3);
        }
      });
      
      buttons.backToStep2.addEventListener('click', () => goToStep(2));
      
      buttons.toStep4.addEventListener('click', () => {
        renderBills();
        goToStep(4);
      });
      
      buttons.backToStep3.addEventListener('click', () => goToStep(3));
      
      buttons.payBill.addEventListener('click', () => {
        // 找到第一个未缴费的账单
        const firstUnpaidBill = elements.billsContainer.querySelector('.pay-this-bill');
        if (firstUnpaidBill) {
          const amount = firstUnpaidBill.dataset.amount;
          const month = firstUnpaidBill.dataset.month;
          showSuccessModal(amount, month);
        }
      });
      
      // 弹窗关闭按钮
      buttons.closeModal.addEventListener('click', hideSuccessModal);
      
      // 城市搜索
      elements.citySearch.addEventListener('input', (e) => {
        const searchTerm = e.target.value.toLowerCase();
        if (!searchTerm) {
          renderHotCities();
          return;
        }
        
        // 搜索所有城市
        const allCities = [...cityData.hotCities];
        cityData.provinces.forEach(province => {
          allCities.push(...province.cities);
        });
        
        // 去重并筛选
        const uniqueCities = [...new Set(allCities)];
        const filteredCities = uniqueCities.filter(city => 
          city.toLowerCase().includes(searchTerm)
        );
        
        // 显示搜索结果
        elements.hotCitiesContainer.innerHTML = '';
        if (filteredCities.length > 0) {
          filteredCities.forEach(city => {
            const cityElement = document.createElement('button');
            cityElement.className = 'py-2 px-3 rounded-lg border border-neutral-200 hover:border-primary hover:text-primary transition-all-300 text-center';
            cityElement.textContent = city;
            cityElement.addEventListener('click', () => selectCity(city));
            
            elements.hotCitiesContainer.appendChild(cityElement);
          });
        } else {
          elements.hotCitiesContainer.innerHTML = '<p class="col-span-full text-center text-neutral-500 py-4">未找到匹配的城市</p>';
        }
      });
    }

    // 初始化
    document.addEventListener('DOMContentLoaded', init);
  </script>
</body>
</html>
相关推荐
洛白白1 天前
Word文档中打勾和打叉的三种方法
经验分享·学习·word·生活·学习方法
码银2 天前
【python】基于 生活方式与健康数据预测数据集(Lifestyle and Health Risk Prediction)的可视化练习,附数据集源文件。
开发语言·python·生活
彷徨而立3 天前
【生活】感冒症状 没精神,恶寒,吃布洛芬有效果吗?
生活
彷徨而立3 天前
【生活】连花清瘟颗粒和布洛芬一起吃可以吗
生活
Jeff-Nolan4 天前
数据结构(c++版):二叉树的实现
生活
心态特好5 天前
解锁分布式唯一 ID:技术、实践与最佳方案
分布式·生活
weixin_lynhgworld6 天前
旧物新生,从二手回收小程序开启绿色生活
小程序·生活·旧物回收
互联网江湖7 天前
蓝桥杯出局,少儿编程的价值祛魅时刻?
人工智能·生活