优化数据库初始化,新增用户收货地址表以支持多地址管理;更新章节页面和我的页面,整合底部导航组件,提升用户体验;调整小程序设置页面,增加收货地址管理功能,优化样式与布局。
This commit is contained in:
@@ -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({
|
||||
|
||||
112
app/api/user/addresses/[id]/route.ts
Normal file
112
app/api/user/addresses/[id]/route.ts
Normal 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 })
|
||||
}
|
||||
}
|
||||
68
app/api/user/addresses/route.ts
Normal file
68
app/api/user/addresses/route.ts
Normal 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 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user