Files
lgp-wx-new/pages/cart/cart.vue
2026-06-05 14:06:20 +08:00

507 lines
11 KiB
Vue
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.
<template>
<view class="container">
<!-- Header: 极简大气与详情页保持一致 -->
<view class="page-header">
<view class="header-content">
<view class="title-group">
<text class="header-title">我的清单</text>
<text class="header-subtitle">My COLLECTIONS</text>
</view>
<view class="header-badges">
<text class="count-badge">共计: {{ lists.length }}</text>
</view>
</view>
</view>
<!-- List Content -->
<scroll-view class="list-content" scroll-y @scrolltolower="loadMore">
<view v-if="lists.length > 0" class="list-wrapper">
<view
v-for="(item, index) in lists"
:key="index"
class="list-card animate-slide-in"
:style="{ animationDelay: index * 0.05 + 's' }"
@tap="goToDetail(item)"
>
<!-- 1. 卡片顶部工具栏日期 + 删除 -->
<!-- 彻底移除了 u-swipe-action解决编译报错 -->
<view class="card-top-bar">
<view class="top-left">
<u-icon name="calendar" color="#999" size="14"></u-icon>
<text class="date-text">{{ item.created_at }}</text>
</view>
<!-- 显性删除按钮更直观防误触 -->
<view class="delete-btn" @tap.stop="handleDelete(index, item.id)">
<u-icon name="trash" color="#ccc" size="18"></u-icon>
</view>
</view>
<!-- 2. 卡片主体内容 -->
<view class="card-body">
<view class="body-left">
<text class="item-name">{{ item.name }}</text>
<view class="item-remark" v-if="item.remark">
<text class="remark-line"></text>
<text class="remark-text">{{ item.remark }}</text>
</view>
<view class="item-remark placeholder" v-else>
<text class="remark-text">暂无备注信息</text>
</view>
</view>
<!-- 右侧数量展示更有设计感 -->
<view class="body-right">
<text class="count-label">商品数</text>
<text class="count-num">{{ item.count < 10 ? '0' + item.count : item.count }}</text>
</view>
</view>
<!-- 3. 底部装饰条 / 进入指引 -->
<view class="card-footer">
<text class="footer-status">查看详情</text>
<u-icon name="arrow-right" color="#B4854D" size="12"></u-icon>
</view>
</view>
</view>
<view class="empty-state" v-else>
<image src="/static/images/empty.png" mode="widthFix" class="empty-img"></image>
<text class="empty-text">您还没有创建任何清单</text>
<text class="empty-sub">点击下方按钮开始创建</text>
</view>
<!-- 底部垫高 -->
<view style="height: 180rpx;"></view>
</scroll-view>
<!-- Create Button (Floating) -->
<view class="fab-container">
<view class="create-btn" @tap="showCreateModal" hover-class="btn-hover">
<u-icon name="plus" color="#fff" size="18"></u-icon>
<text>新建清单</text>
</view>
</view>
<!-- Create List Modal -->
<u-modal
:show="showModal"
:title="false"
:showCancelButton="true"
cancelText="取消"
confirmText="创建"
confirmColor="#B4854D"
@confirm="createList"
@cancel="cancelCreate"
class="custom-modal"
>
<view class="modal-content">
<view class="modal-header-deco">
<text class="modal-title">新建清单</text>
<text class="modal-sub">创建新的选品组合</text>
</view>
<u-form :model="formData" ref="uForm" :errorType="['message']">
<u-form-item prop="name" class="modal-input-item">
<u-input
v-model="formData.name"
placeholder="清单名称"
border="bottom"
class="custom-input"
/>
</u-form-item>
<u-form-item prop="remark" class="modal-input-item">
<u-input
v-model="formData.remark"
placeholder="备注信息 (选填)"
border="bottom"
class="custom-input"
/>
</u-form-item>
</u-form>
</view>
</u-modal>
<!-- Loading -->
<u-loading-page :loading="isLoading" bgColor="rgba(255,255,255,0.9)" color="#B4854D" loadingText="加载中..."></u-loading-page>
</view>
</template>
<script>
import {createCartApi, deleteCartApi, getCartListApi} from "@/api/page/cart";
export default {
data() {
return {
isLoading: false,
showModal: false,
formData: {
name: '',
remark: ''
},
// swipeOptions 已移除,不再需要
lists: []
}
},
onShow() {
this.getList();
},
methods: {
navigateBack() {
uni.navigateBack()
},
showCreateModal() {
this.showModal = true
},
cancelCreate() {
this.showModal = false
this.formData = { name: '', remark: '' }
},
getList() {
getCartListApi().then((res) => {
this.lists = res
})
},
createList() {
if (!this.formData.name) {
uni.showToast({
title: '请输入清单名称',
icon: 'none'
})
return
}
createCartApi(this.formData).then((res) => {
this.showModal = false
this.formData = { name: '', remark: '' }
uni.showToast({
title: '已创建',
icon: 'success'
})
this.getList();
})
},
goToDetail(item) {
uni.navigateTo({
url: `/pages/cart/detail?id=${item.id}`
})
},
loadMore() {
// 暂无更多逻辑
},
handleDelete(index, id) {
uni.showModal({
title: '删除确认',
content: '确定要删除这个清单吗?此操作不可恢复。',
confirmText: '删除',
confirmColor: '#B4854D',
cancelColor: '#999',
success: (res) => {
if (res.confirm) {
deleteCartApi(id).then(() => {
this.lists.splice(index, 1)
uni.showToast({
title: '已删除',
icon: 'none'
})
})
}
}
})
}
}
}
</script>
<style lang="scss">
/* 核心Border-box 全局应用,防止布局错位 */
view, scroll-view, text, image {
box-sizing: border-box;
}
.container {
min-height: 100vh;
width: 100%;
background-color: #F7F8FA; /* 高级灰背景 */
display: flex;
flex-direction: column;
}
/* 动画 */
@keyframes slideInUp {
from { opacity: 0; transform: translateY(30rpx); }
to { opacity: 1; transform: translateY(0); }
}
.animate-slide-in {
animation: slideInUp 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
}
/* Header */
.page-header {
width: 100%;
background: #fff;
padding: 50rpx 40rpx 30rpx;
position: relative;
z-index: 10;
border-bottom: 1rpx solid rgba(0,0,0,0.03);
}
.header-content {
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.header-title {
font-size: 48rpx;
font-weight: 300;
color: #1A1A1A;
letter-spacing: 2rpx;
margin-bottom: 8rpx;
display: block;
font-family: serif;
}
.header-subtitle {
font-size: 18rpx;
color: #B4854D;
letter-spacing: 6rpx;
font-weight: 600;
text-transform: uppercase;
display: block;
}
.count-badge {
font-size: 20rpx;
color: #999;
letter-spacing: 1rpx;
font-family: Arial, sans-serif;
}
/* List Content */
.list-content {
flex: 1;
width: 100%;
padding: 30rpx;
}
/* --- 核心卡片样式 --- */
.list-card {
background: #fff;
margin-bottom: 30rpx;
border-radius: 12rpx;
box-shadow: 0 10rpx 40rpx rgba(0,0,0,0.04);
overflow: hidden;
border: 1rpx solid rgba(0,0,0,0.02);
display: flex;
flex-direction: column;
}
/* Top Bar */
.card-top-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 30rpx;
border-bottom: 1rpx solid #F9F9F9;
}
.top-left {
display: flex;
align-items: center;
gap: 12rpx;
}
.date-text {
font-size: 22rpx;
color: #999;
letter-spacing: 1rpx;
font-family: Arial, sans-serif;
}
.delete-btn {
padding: 10rpx;
margin-right: -10rpx; /* 增加点击热区修正视觉位置 */
}
/* Card Body */
.card-body {
padding: 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.body-left {
flex: 1;
padding-right: 30rpx;
}
.item-name {
font-size: 36rpx;
font-weight: 500;
color: #222;
margin-bottom: 16rpx;
display: block;
font-family: serif;
}
.item-remark {
display: flex;
align-items: center;
gap: 10rpx;
}
.remark-line {
width: 20rpx;
height: 2rpx;
background-color: #B4854D;
}
.remark-text {
font-size: 24rpx;
color: #888;
font-style: italic;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 300rpx;
}
.placeholder .remark-text {
color: #ddd;
}
/* 右侧数量区 */
.body-right {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-left: 30rpx;
border-left: 1rpx dashed #eee;
}
.count-label {
font-size: 18rpx; /* 微调字体大小 */
color: #ccc;
letter-spacing: 2rpx;
margin-bottom: 4rpx;
}
.count-num {
font-size: 48rpx;
font-weight: 400; /* 数字细一点更高级 */
color: #B4854D;
font-family: 'Times New Roman', serif;
line-height: 1;
}
/* Card Footer */
.card-footer {
background: #FDFDFD;
padding: 16rpx 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1rpx solid #F9F9F9;
}
.footer-status {
font-size: 20rpx;
color: #B4854D;
letter-spacing: 2rpx;
font-weight: 600;
}
/* FAB */
.fab-container {
position: fixed;
bottom: 60rpx;
left: 0;
right: 0;
display: flex;
justify-content: center;
pointer-events: none;
z-index: 20;
}
.create-btn {
pointer-events: auto;
background: #222; /* 纯黑背景更显奢华 */
color: #B4854D; /* 金色文字 */
padding: 28rpx 70rpx;
border-radius: 60rpx;
display: flex;
align-items: center;
gap: 16rpx;
font-size: 26rpx;
font-weight: 600;
letter-spacing: 2rpx;
box-shadow: 0 20rpx 40rpx rgba(0,0,0,0.2);
transition: all 0.2s;
border: 1rpx solid #333;
}
.btn-hover {
transform: translateY(2rpx);
box-shadow: 0 10rpx 20rpx rgba(0,0,0,0.15);
}
/* Empty State */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 200rpx;
}
.empty-img {
width: 200rpx;
opacity: 0.8;
margin-bottom: 40rpx;
filter: grayscale(100%); /* 图片黑白化 */
}
.empty-text {
font-size: 30rpx;
color: #666;
font-weight: 500;
margin-bottom: 12rpx;
}
.empty-sub {
font-size: 24rpx;
color: #ccc;
letter-spacing: 1rpx;
}
/* Modal Styling - 极简风 */
.modal-content {
padding: 50rpx 30rpx 30rpx;
}
.modal-header-deco {
text-align: center;
margin-bottom: 60rpx;
}
.modal-title {
display: block;
font-size: 40rpx;
font-weight: 300;
color: #333;
letter-spacing: 4rpx;
margin-bottom: 10rpx;
}
.modal-sub {
display: block;
font-size: 24rpx;
color: #999;
}
.custom-input {
padding: 20rpx 0 !important;
}
</style>