Files
ai_dianshang/miniprogram/pages/user/address/list/index.html
2025-11-17 13:32:54 +08:00

484 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>收货地址</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: #f5f5f5;
color: #333;
}
.header {
background: #fff;
padding: 16px;
border-bottom: 1px solid #eee;
position: sticky;
top: 0;
z-index: 100;
}
.header h1 {
font-size: 18px;
font-weight: 500;
text-align: center;
}
.container {
padding: 16px;
}
.address-list {
background: #fff;
border-radius: 8px;
overflow: hidden;
}
.address-item {
padding: 16px;
border-bottom: 1px solid #f0f0f0;
position: relative;
}
.address-item:last-child {
border-bottom: none;
}
.address-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.user-info {
font-size: 16px;
font-weight: 500;
}
.default-tag {
background: #ff6b35;
color: white;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
}
.address-detail {
color: #666;
line-height: 1.5;
margin-bottom: 12px;
}
.address-actions {
display: flex;
gap: 16px;
}
.action-btn {
background: none;
border: 1px solid #ddd;
padding: 6px 12px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
}
.action-btn:hover {
background: #f5f5f5;
}
.action-btn.primary {
background: #ff6b35;
color: white;
border-color: #ff6b35;
}
.action-btn.primary:hover {
background: #e55a2b;
}
.action-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.add-address {
position: fixed;
bottom: 20px;
right: 20px;
width: 56px;
height: 56px;
background: #ff6b35;
border: none;
border-radius: 50%;
color: white;
font-size: 24px;
cursor: pointer;
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
transition: all 0.2s;
}
.add-address:hover {
transform: scale(1.1);
box-shadow: 0 6px 16px rgba(255, 107, 53, 0.4);
}
.loading, .error, .empty {
text-align: center;
padding: 40px 20px;
color: #666;
}
.loading {
font-size: 16px;
}
.error {
color: #ff4757;
}
.empty {
color: #999;
}
.hidden {
display: none;
}
.toast {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 12px 24px;
border-radius: 4px;
z-index: 1000;
opacity: 0;
transition: opacity 0.3s;
}
.toast.show {
opacity: 1;
}
.test-controls {
position: fixed;
top: 10px;
right: 10px;
z-index: 1001;
display: flex;
gap: 8px;
}
.test-btn {
background: #007aff;
color: white;
border: none;
padding: 6px 12px;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="header">
<h1>收货地址</h1>
</div>
<div class="container">
<div id="loading" class="loading">
加载中...
</div>
<div id="error" class="error hidden">
加载失败,请重试
<br><br>
<button class="action-btn" onclick="loadAddresses()">重新加载</button>
</div>
<div id="empty" class="empty hidden">
暂无收货地址
<br><br>
<button class="action-btn primary" onclick="addAddress()">添加地址</button>
</div>
<div id="addressList" class="address-list hidden">
<!-- 地址列表将在这里动态生成 -->
</div>
</div>
<button class="add-address" onclick="addAddress()">+</button>
<div id="toast" class="toast"></div>
<!-- 测试控制按钮 -->
<div class="test-controls">
<button class="test-btn" onclick="generateTestToken()">生成Token</button>
<button class="test-btn" onclick="toggleMock()">切换模式</button>
</div>
<script>
// 配置
const config = {
apiBase: 'http://127.0.0.1:8080/api/v1',
useMock: false
};
// 全局变量
let addresses = [];
let isLoading = false;
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
// 自动设置测试token如果没有token的话
if (!getToken()) {
const testToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJ1c2VyIiwiaXNzIjoiZGlhbnNoYW5nIiwiZXhwIjoxNzYwMDMzMjg2LCJuYmYiOjE3NjAwMjYwODYsImlhdCI6MTc2MDAyNjA4Nn0.zCPYwDld_WDSwySyj62CWgk9xJnOUhUt3NbTc6kL4Zg';
localStorage.setItem('token', testToken);
console.log('自动设置测试token');
}
loadAddresses();
});
// 显示提示信息
function showToast(message) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 2000);
}
// 获取存储的token
function getToken() {
return localStorage.getItem('token') || '';
}
// 模拟微信请求
function wxRequest(options) {
return fetch(options.url, {
method: options.method || 'GET',
headers: {
'Authorization': `Bearer ${getToken()}`,
'Content-Type': 'application/json',
...options.header
},
body: options.data ? JSON.stringify(options.data) : undefined
}).then(response => {
return response.json().then(data => ({
statusCode: response.status,
data: data
}));
});
}
// 加载地址列表
async function loadAddresses() {
if (isLoading) return;
isLoading = true;
showLoading();
try {
if (config.useMock) {
// 使用模拟数据
await new Promise(resolve => setTimeout(resolve, 1000));
addresses = [
{
id: 1,
name: '张三',
phone: '13800138000',
provinceName: '北京市',
cityName: '北京市',
districtName: '朝阳区',
detailAddress: '三里屯街道工体北路8号',
isDefault: true
},
{
id: 2,
name: '李四',
phone: '13900139000',
provinceName: '上海市',
cityName: '上海市',
districtName: '黄浦区',
detailAddress: '南京东路100号',
isDefault: false
}
];
displayAddresses();
} else {
// 调用真实API
const res = await wxRequest({
url: `${config.apiBase}/users/addresses`,
method: 'GET'
});
if (res.statusCode === 200 && res.data.code === 200) {
addresses = res.data.data || [];
displayAddresses();
} else {
throw new Error(res.data.message || '获取地址列表失败');
}
}
} catch (error) {
console.error('加载地址列表失败:', error);
showError();
showToast('加载地址列表失败');
} finally {
isLoading = false;
}
}
// 显示加载状态
function showLoading() {
document.getElementById('loading').classList.remove('hidden');
document.getElementById('error').classList.add('hidden');
document.getElementById('empty').classList.add('hidden');
document.getElementById('addressList').classList.add('hidden');
}
// 显示错误状态
function showError() {
document.getElementById('loading').classList.add('hidden');
document.getElementById('error').classList.remove('hidden');
document.getElementById('empty').classList.add('hidden');
document.getElementById('addressList').classList.add('hidden');
}
// 显示地址列表
function displayAddresses() {
const loadingEl = document.getElementById('loading');
const errorEl = document.getElementById('error');
const emptyEl = document.getElementById('empty');
const listEl = document.getElementById('addressList');
loadingEl.classList.add('hidden');
errorEl.classList.add('hidden');
if (addresses.length === 0) {
emptyEl.classList.remove('hidden');
listEl.classList.add('hidden');
return;
}
listEl.innerHTML = addresses.map(address => `
<div class="address-item" data-id="${address.id}">
<div class="address-header">
<div class="user-info">
${address.name} ${address.phone}
</div>
${address.isDefault ? '<span class="default-tag">默认</span>' : ''}
</div>
<div class="address-detail">
${address.provinceName}${address.cityName}${address.districtName}${address.detailAddress}
</div>
<div class="address-actions">
<button class="action-btn" onclick="editAddress(${address.id})">编辑</button>
<button class="action-btn" onclick="deleteAddress(${address.id})">删除</button>
${!address.isDefault ? `<button class="action-btn primary" onclick="setDefault(${address.id})">设为默认</button>` : ''}
</div>
</div>
`).join('');
emptyEl.classList.add('hidden');
listEl.classList.remove('hidden');
}
// 添加地址
function addAddress() {
showToast('跳转到添加地址页面');
// 实际应用中这里应该跳转到添加地址页面
// window.location.href = '/pages/user/address/edit/index.html';
}
// 编辑地址
function editAddress(id) {
showToast(`编辑地址 ID: ${id}`);
// 实际应用中这里应该跳转到编辑地址页面
// window.location.href = `/pages/user/address/edit/index.html?id=${id}`;
}
// 删除地址
async function deleteAddress(id) {
if (!confirm('确定要删除这个地址吗?')) {
return;
}
try {
const res = await wxRequest({
url: `${config.apiBase}/users/addresses/${id}`,
method: 'DELETE'
});
if (res.statusCode === 200 && res.data.code === 200) {
showToast('删除成功');
// 从本地数组中移除
addresses = addresses.filter(addr => addr.id !== id);
displayAddresses();
} else {
throw new Error(res.data.message || '删除失败');
}
} catch (error) {
console.error('删除地址失败:', error);
showToast('删除失败');
}
}
// 设为默认地址
async function setDefault(id) {
try {
const res = await wxRequest({
url: `${config.apiBase}/users/addresses/${id}/default`,
method: 'PUT'
});
if (res.statusCode === 200 && res.data.code === 200) {
showToast('设置成功');
// 更新本地数据
addresses.forEach(addr => {
addr.isDefault = addr.id === id;
});
displayAddresses();
} else {
throw new Error(res.data.message || '设置失败');
}
} catch (error) {
console.error('设置默认地址失败:', error);
showToast('设置失败');
}
}
// 测试功能生成测试token
function generateTestToken() {
// 使用我们之前测试成功的token
const testToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX3R5cGUiOiJ1c2VyIiwiaXNzIjoiZGlhbnNoYW5nIiwiZXhwIjoxNzYwMDMzMjg2LCJuYmYiOjE3NjAwMjYwODYsImlhdCI6MTc2MDAyNjA4Nn0.zCPYwDld_WDSwySyj62CWgk9xJnOUhUt3NbTc6kL4Zg';
localStorage.setItem('token', testToken);
showToast('测试token已生成页面将自动刷新');
// 自动刷新页面以加载地址数据
setTimeout(() => {
loadAddresses();
}, 1000);
}
// 切换模拟模式
function toggleMock() {
config.useMock = !config.useMock;
showToast(`已切换到${config.useMock ? '模拟' : '真实API'}模式`);
loadAddresses();
}
</script>
</body>
</html>