优化数据库初始化,新增用户收货地址表以支持多地址管理;更新章节页面和我的页面,整合底部导航组件,提升用户体验;调整小程序设置页面,增加收货地址管理功能,优化样式与布局。

This commit is contained in:
乘风
2026-01-31 22:37:05 +08:00
parent 692397c997
commit c7b125535c
24 changed files with 1159 additions and 141 deletions

View File

@@ -154,6 +154,30 @@ export async function GET(request: NextRequest) {
results.push('✅ 创建system_config表')
}
// 6. 用户收货地址表(多地址,类似淘宝)
try {
await query('SELECT 1 FROM user_addresses LIMIT 1')
results.push('✅ user_addresses表已存在')
} catch (e) {
await query(`
CREATE TABLE IF NOT EXISTS user_addresses (
id VARCHAR(50) PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
name VARCHAR(50) NOT NULL,
phone VARCHAR(20) NOT NULL,
province VARCHAR(50) NOT NULL,
city VARCHAR(50) NOT NULL,
district VARCHAR(50) NOT NULL,
detail VARCHAR(200) NOT NULL,
is_default TINYINT(1) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`)
results.push('✅ 创建user_addresses表')
}
console.log('[DB Init] 数据库升级完成')
return NextResponse.json({

View File

@@ -0,0 +1,112 @@
/**
* 用户收货地址 - 单条详情 / 编辑 / 删除 / 设为默认
* GET: 详情
* PUT: 更新name, phone, detail 等;省/市/区可选)
* DELETE: 删除
*/
import { NextRequest, NextResponse } from 'next/server'
import { query } from '@/lib/db'
async function getOne(id: string) {
const rows = await query(
`SELECT id, user_id, name, phone, province, city, district, detail, is_default, created_at, updated_at
FROM user_addresses WHERE id = ?`,
[id]
) as any[]
if (!rows || rows.length === 0) return null
const r = rows[0]
return {
id: r.id,
userId: r.user_id,
name: r.name,
phone: r.phone,
province: r.province,
city: r.city,
district: r.district,
detail: r.detail,
isDefault: !!r.is_default,
fullAddress: `${r.province}${r.city}${r.district}${r.detail}`,
createdAt: r.created_at,
updatedAt: r.updated_at,
}
}
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
if (!id) {
return NextResponse.json({ success: false, message: '缺少地址 id' }, { status: 400 })
}
const item = await getOne(id)
if (!item) {
return NextResponse.json({ success: false, message: '地址不存在' }, { status: 404 })
}
return NextResponse.json({ success: true, item })
} catch (e) {
console.error('[Addresses] GET one error:', e)
return NextResponse.json({ success: false, message: '获取地址失败' }, { status: 500 })
}
}
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
if (!id) {
return NextResponse.json({ success: false, message: '缺少地址 id' }, { status: 400 })
}
const body = await request.json()
const { name, phone, province, city, district, detail, isDefault } = body
const existing = await query('SELECT user_id FROM user_addresses WHERE id = ?', [id]) as any[]
if (!existing || existing.length === 0) {
return NextResponse.json({ success: false, message: '地址不存在' }, { status: 404 })
}
const userId = existing[0].user_id
const updates = []
const values = []
if (name !== undefined) { updates.push('name = ?'); values.push(name.trim()) }
if (phone !== undefined) { updates.push('phone = ?'); values.push(phone.trim()) }
if (province !== undefined) { updates.push('province = ?'); values.push((province == null ? '' : String(province)).trim()) }
if (city !== undefined) { updates.push('city = ?'); values.push((city == null ? '' : String(city)).trim()) }
if (district !== undefined) { updates.push('district = ?'); values.push((district == null ? '' : String(district)).trim()) }
if (detail !== undefined) { updates.push('detail = ?'); values.push(detail.trim()) }
if (isDefault === true) {
await query('UPDATE user_addresses SET is_default = 0 WHERE user_id = ?', [userId])
updates.push('is_default = 1')
} else if (isDefault === false) {
updates.push('is_default = 0')
}
if (updates.length > 0) {
values.push(id)
await query(`UPDATE user_addresses SET ${updates.join(', ')}, updated_at = NOW() WHERE id = ?`, values)
}
const item = await getOne(id)
return NextResponse.json({ success: true, item, message: '更新成功' })
} catch (e) {
console.error('[Addresses] PUT error:', e)
return NextResponse.json({ success: false, message: '更新地址失败' }, { status: 500 })
}
}
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params
if (!id) {
return NextResponse.json({ success: false, message: '缺少地址 id' }, { status: 400 })
}
await query('DELETE FROM user_addresses WHERE id = ?', [id])
return NextResponse.json({ success: true, message: '删除成功' })
} catch (e) {
console.error('[Addresses] DELETE error:', e)
return NextResponse.json({ success: false, message: '删除地址失败' }, { status: 500 })
}
}

View File

@@ -0,0 +1,68 @@
/**
* 用户收货地址 - 列表与新建
* GET: 列表(需 userId
* POST: 新建(必填 userId, name, phone, detail省/市/区可选)
*/
import { NextRequest, NextResponse } from 'next/server'
import { query } from '@/lib/db'
import { randomUUID } from 'crypto'
export async function GET(request: NextRequest) {
try {
const userId = request.nextUrl.searchParams.get('userId')
if (!userId) {
return NextResponse.json({ success: false, message: '缺少 userId' }, { status: 400 })
}
const rows = await query(
`SELECT id, user_id, name, phone, province, city, district, detail, is_default, created_at, updated_at
FROM user_addresses WHERE user_id = ? ORDER BY is_default DESC, updated_at DESC`,
[userId]
) as any[]
const list = (rows || []).map((r) => ({
id: r.id,
userId: r.user_id,
name: r.name,
phone: r.phone,
province: r.province,
city: r.city,
district: r.district,
detail: r.detail,
isDefault: !!r.is_default,
fullAddress: `${r.province}${r.city}${r.district}${r.detail}`,
createdAt: r.created_at,
updatedAt: r.updated_at,
}))
return NextResponse.json({ success: true, list })
} catch (e) {
console.error('[Addresses] GET error:', e)
return NextResponse.json({ success: false, message: '获取地址列表失败' }, { status: 500 })
}
}
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { userId, name, phone, province, city, district, detail, isDefault } = body
if (!userId || !name || !phone || !detail) {
return NextResponse.json(
{ success: false, message: '缺少必填项userId, name, phone, detail' },
{ status: 400 }
)
}
const id = randomUUID().replace(/-/g, '').slice(0, 24)
const p = (v: string | undefined) => (v == null ? '' : String(v).trim())
if (isDefault) {
await query('UPDATE user_addresses SET is_default = 0 WHERE user_id = ?', [userId])
}
await query(
`INSERT INTO user_addresses (id, user_id, name, phone, province, city, district, detail, is_default)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[id, userId, name.trim(), phone.trim(), p(province), p(city), p(district), detail.trim(), isDefault ? 1 : 0]
)
return NextResponse.json({ success: true, id, message: '添加成功' })
} catch (e) {
console.error('[Addresses] POST error:', e)
return NextResponse.json({ success: false, message: '添加地址失败' }, { status: 500 })
}
}