响应式 支持手机和电脑




<!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>