From c287650fbb46d303211d49be3edb20231060b32e Mon Sep 17 00:00:00 2001 From: qingfeng1121 Date: Mon, 12 Jan 2026 13:56:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=B7=AF=E7=94=B1):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=92=8C=E8=81=8A=E5=A4=A9=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit style(页脚): 更新版权信息和样式,添加链接和响应式设计 style(全局样式): 引入CSS变量,统一设计系统 refactor(主页面): 使用CSS变量优化样式,提升可维护性 style(购物车): 应用CSS变量,优化交互效果和动画 feat(头部导航): 增强用户信息展示和搜索类型切换动画 feat(聊天页面): 新增聊天功能界面,支持用户列表和消息交互 feat(用户信息): 重构用户信息页面,添加订单状态和功能菜单 --- src/Route/route.ts | 13 + src/Style/App.css | 107 ++- src/Views/Cart.vue | 162 ++--- src/Views/Chat.vue | 703 ++++++++++++++++++ src/Views/User/User.vue | 1353 +++++++++++++++++++++++++++++++++++ src/Views/User/Userinfo.vue | 904 ++++++++++++++++++++++- src/Views/footer.vue | 86 ++- src/Views/herde.vue | 502 +++++++++++-- src/Views/main.vue | 75 +- 9 files changed, 3685 insertions(+), 220 deletions(-) create mode 100644 src/Views/Chat.vue create mode 100644 src/Views/User/User.vue diff --git a/src/Route/route.ts b/src/Route/route.ts index 800bad4..513b5a2 100644 --- a/src/Route/route.ts +++ b/src/Route/route.ts @@ -7,6 +7,8 @@ import Search from '../Views/Search.vue' import ProductDetail from '../Views/product/productdetil.vue' import Cart from '../Views/Cart.vue' import Order from '../Views/Order.vue' +import User from '../Views/User/User.vue' +import Chat from '../Views/Chat.vue' @@ -41,6 +43,17 @@ const routes = [ name: 'order', component: Order }, + { + path: '/user', + name: 'user', + component: User + }, + { + path: '/chat', + name: 'chat', + component: Chat + }, + ] const router = createRouter({ diff --git a/src/Style/App.css b/src/Style/App.css index da10fdf..fb69a0e 100644 --- a/src/Style/App.css +++ b/src/Style/App.css @@ -1,13 +1,112 @@ /* 全局样式 */ body { height: 100%; - padding: 0 20px; + padding: 0 var(--spacing-lg); + background-color: var(--bg-color); + font-family: var(--font-family); + font-size: var(--font-size-base); + color: var(--text-primary); + margin: 0; } a { text-decoration: none; - color: #000; - font-size: 16px; + color: var(--text-primary); + font-size: var(--font-size-base); font-weight: bold; - transition: all 0.3s ease-in-out; + transition: all var(--transition-normal); +} + +a:hover { + color: var(--primary-color); +} +:root { + /* 主色调 */ + --primary-color: #ff5000; + --primary-hover: #ff7a45; + --primary-active: #ff3a00; + --primary-light: rgba(255, 80, 0, 0.05); + --primary-light-rgb: 255, 80, 0; + + /* 辅助色 */ + --secondary-color: #1890ff; + --secondary-hover: #40a9ff; + --success-color: #52c41a; + --success-light: #f6ffed; + --warning-color: #faad14; + --warning-light: #fff7e6; + --error-color: #ff4d4f; + --error-light: #fff2f0; + + /* 登录按钮渐变色 */ + --login-gradient-start: #667eea; + --login-gradient-end: #764ba2; + + /* 中性色 */ + --bg-color: #f5f5f5; + --bg-light: #fafafa; + --bg-primary-light: #fff5f5; + --bg-primary-lighter: #fff0f0; + --bg-primary-lightest: #fff0e8; + --card-bg: #ffffff; + --text-primary: #333333; + --text-dark: #2d3436; + --text-secondary: #666666; + --text-tertiary: #999999; + --border-color: #e0e0e0; + --border-light: #e8e8e8; + + /* 字体 */ + --font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + --font-size-xs: 12px; + --font-size-sm: 14px; + --font-size-base: 16px; + --font-size-lg: 18px; + --font-size-xl: 20px; + --font-size-2xl: 24px; + --font-size-3xl: 32px; + --font-size-4xl: 36px; + + /* 间距 */ + --spacing-xs: 4px; + --spacing-sm: 8px; + --spacing-md: 16px; + --spacing-lg: 24px; + --spacing-xl: 32px; + --spacing-xxl: 40px; + + /* 圆角 */ + --border-radius-sm: 4px; + --border-radius-md: 8px; + --border-radius-lg: 12px; + --border-radius-xl: 16px; + --border-radius-2xl: 24px; + --border-radius-3xl: 28px; + --border-radius-full: 50%; + + /* 阴影 */ + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); + --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.12); + --shadow-xl: 0 6px 20px rgba(0, 0, 0, 0.15); + --shadow-2xl: 0 12px 32px rgba(0, 0, 0, 0.2); + + /* 过渡 */ + --transition-fast: 0.2s ease; + --transition-normal: 0.3s ease; + --transition-slow: 0.5s ease; + --transition-transform: 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); + + /* 搜索框相关 */ + --search-height: 52px; + --search-radius: 28px; + + /* 消息相关 */ + --message-radius: 18px; + + /* 输入框相关 */ + --input-bg: #f9fafb; + --input-error: #ef4444; + --error-bg: #fee2e2; + --error-text: #dc2626; } diff --git a/src/Views/Cart.vue b/src/Views/Cart.vue index 2e920ac..f663363 100644 --- a/src/Views/Cart.vue +++ b/src/Views/Cart.vue @@ -263,24 +263,24 @@ const removeItem = (id: number) => { #cart { width: 100%; min-height: 100vh; - background: linear-gradient(135deg, #f5f5f5 0%, #fafafa 100%); - padding: 20px; + background: linear-gradient(135deg, var(--bg-color) 0%, var(--bg-light) 100%); + padding: var(--spacing-md); } .cart-container { max-width: 1400px; margin: 0 auto; - background: linear-gradient(135deg, #ffffff 0%, #fafafa 100%); - border-radius: 16px; - box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08); + background: linear-gradient(135deg, var(--card-bg) 0%, var(--bg-light) 100%); + border-radius: var(--border-radius-xl); + box-shadow: var(--shadow-md); overflow: hidden; - border: 1px solid #f0f0f0; + border: 1px solid var(--border-color); } .cart-header { - padding: 20px 40px; - border-bottom: 3px solid #f0f0f0; - background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); + padding: var(--spacing-md) var(--spacing-xxl); + border-bottom: 3px solid var(--border-color); + background: linear-gradient(135deg, var(--card-bg) 0%, var(--bg-light) 100%); display: block; align-items: center; position: relative; @@ -294,7 +294,7 @@ const removeItem = (id: number) => { left: -100%; width: 100%; height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 80, 0, 0.05), transparent); + background: linear-gradient(90deg, transparent, var(--primary-light), transparent); transition: left 0.6s ease; } @@ -303,94 +303,94 @@ const removeItem = (id: number) => { } .cart-title { - font-size: 32px; + font-size: var(--font-size-3xl); font-weight: 800; - color: #2d3436; + color: var(--text-dark); margin: 0; display: flex; align-items: center; - gap: 15px; + gap: var(--spacing-md); position: relative; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); + transition: all var(--transition-transform); } .cart-title:hover { - color: #ff5000; - transform: translateX(8px); - text-shadow: 0 4px 8px rgba(255, 80, 0, 0.2); + color: var(--primary-color); + transform: translateX(var(--spacing-sm)); + text-shadow: 0 4px 8px rgba(var(--primary-light-rgb), 0.2); } .cart-title i { - font-size: 36px; - color: #ff5000; - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); + font-size: var(--font-size-4xl); + color: var(--primary-color); + transition: all var(--transition-transform); } .cart-title:hover i { transform: rotate(10deg) scale(1.2); - filter: drop-shadow(0 2px 6px rgba(255, 80, 0, 0.3)); + filter: drop-shadow(0 2px 6px rgba(var(--primary-light-rgb), 0.3)); } .filter-buttons { - margin-top: 20px; + margin-top: var(--spacing-md); display: flex; - gap: 20px; + gap: var(--spacing-md); position: relative; } .filter-btn { - padding: 12px 36px; - border-radius: 28px; - font-size: 15px; + padding: var(--spacing-sm) var(--spacing-xxl); + border-radius: var(--border-radius-3xl); + font-size: var(--font-size-sm); font-weight: 600; - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - border: 2px solid #e0e0e0; - background: linear-gradient(135deg, #ffffff 0%, #fafafa 100%); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transition: all var(--transition-transform); + border: 2px solid var(--border-color); + background: linear-gradient(135deg, var(--card-bg) 0%, var(--bg-light) 100%); + box-shadow: var(--shadow-md); letter-spacing: 0.5px; } .filter-btn.active { - background: linear-gradient(135deg, #ff5000 0%, #ff6b00 100%); - border-color: #ff5000; + background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-hover) 100%); + border-color: var(--primary-color); color: #ffffff; - box-shadow: 0 6px 20px rgba(255, 80, 0, 0.35); + box-shadow: 0 6px 20px rgba(var(--primary-light-rgb), 0.35); transform: translateY(-2px); } .filter-btn:not(.active):hover { - border-color: #ff5000; - color: #ff5000; - background: linear-gradient(135deg, #fff5f5 0%, #fff0f0 100%); - box-shadow: 0 4px 16px rgba(255, 80, 0, 0.15); + border-color: var(--primary-color); + color: var(--primary-color); + background: linear-gradient(135deg, var(--bg-primary-light) 0%, var(--bg-primary-lighter) 100%); + box-shadow: 0 4px 16px rgba(var(--primary-light-rgb), 0.15); transform: translateY(-2px); } .filter-btn:active { transform: translateY(0); - box-shadow: 0 2px 8px rgba(255, 80, 0, 0.2); + box-shadow: 0 2px 8px rgba(var(--primary-light-rgb), 0.2); } .cart-list { - padding: 20px 40px; + padding: var(--spacing-md) var(--spacing-xxl); min-height: 400px; } .cart-item { display: flex; align-items: center; - padding: 15px; - background: linear-gradient(135deg, #ffffff 0%, #fafafa 100%); - border-radius: 24px; - margin-bottom: 30px; - border: 2px solid #f5f5f5; - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08); + padding: var(--spacing-md); + background: linear-gradient(135deg, var(--card-bg) 0%, var(--bg-light) 100%); + border-radius: var(--border-radius-2xl); + margin-bottom: var(--spacing-xl); + border: 2px solid var(--border-color); + transition: all var(--transition-transform); + box-shadow: var(--shadow-md); position: relative; overflow: hidden; - gap: 30px; + gap: var(--spacing-xl); animation: float 6s ease-in-out infinite; } @@ -406,55 +406,55 @@ const removeItem = (id: number) => { width: 26px; height: 26px; cursor: pointer; - accent-color: #ff5000; - transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); + accent-color: var(--primary-color); + transition: all var(--transition-transform); position: relative; - border-radius: 6px; - background-color: #ffffff; - border: 2px solid #e0e0e0; + border-radius: var(--border-radius-md); + background-color: var(--card-bg); + border: 2px solid var(--border-color); } .checkbox-input:hover { transform: scale(1.2); - box-shadow: 0 0 0 10px rgba(255, 80, 0, 0.12); - border-color: #ff5000; + box-shadow: 0 0 0 10px rgba(var(--primary-light-rgb), 0.12); + border-color: var(--primary-color); } .checkbox-input:checked { - box-shadow: 0 0 0 8px rgba(255, 80, 0, 0.25); - border-color: #ff5000; + box-shadow: 0 0 0 8px rgba(var(--primary-light-rgb), 0.25); + border-color: var(--primary-color); animation: checkbox-pulse 0.4s ease; } .checkbox-input:focus { outline: none; - box-shadow: 0 0 0 6px rgba(255, 80, 0, 0.2); - border-color: #ff5000; + box-shadow: 0 0 0 6px rgba(var(--primary-light-rgb), 0.2); + border-color: var(--primary-color); } @keyframes checkbox-pulse { 0% { - box-shadow: 0 0 0 4px rgba(255, 80, 0, 0.2); + box-shadow: 0 0 0 4px rgba(var(--primary-light-rgb), 0.2); } 50% { - box-shadow: 0 0 0 12px rgba(255, 80, 0, 0.1); + box-shadow: 0 0 0 12px rgba(var(--primary-light-rgb), 0.1); } 100% { - box-shadow: 0 0 0 8px rgba(255, 80, 0, 0.25); + box-shadow: 0 0 0 8px rgba(var(--primary-light-rgb), 0.25); } } .cart-item-img-container { width: 150px; height: 150px; - border-radius: 20px; + border-radius: var(--border-radius-xl); overflow: hidden; - border: 3px solid #f0f0f0; + border: 3px solid var(--border-color); flex-shrink: 0; - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); + transition: all var(--transition-transform); position: relative; - background: linear-gradient(135deg, #fafafa 0%, #ffffff 100%); - box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1); + background: linear-gradient(135deg, var(--bg-light) 0%, var(--card-bg) 100%); + box-shadow: var(--shadow-lg); } .cart-item-img-container::after { @@ -464,10 +464,10 @@ const removeItem = (id: number) => { left: 0; right: 0; bottom: 0; - border-radius: 20px; + border-radius: var(--border-radius-xl); border: 3px solid transparent; - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - background: linear-gradient(135deg, rgba(255, 80, 0, 0.08) 0%, rgba(255, 80, 0, 0.03) 100%); + transition: all var(--transition-transform); + background: linear-gradient(135deg, rgba(var(--primary-light-rgb), 0.08) 0%, rgba(var(--primary-light-rgb), 0.03) 100%); opacity: 0; } @@ -478,21 +478,21 @@ const removeItem = (id: number) => { left: -50%; width: 200%; height: 200%; - background: linear-gradient(45deg, transparent, rgba(255, 80, 0, 0.1), transparent); + background: linear-gradient(45deg, transparent, rgba(var(--primary-light-rgb), 0.1), transparent); transform: rotate(45deg); - transition: all 0.6s ease; + transition: all var(--transition-slow); opacity: 0; } .cart-item:hover .cart-item-img-container { - border-color: #ff5000; + border-color: var(--primary-color); transform: scale(1.1) translateY(-4px); - box-shadow: 0 12px 32px rgba(255, 80, 0, 0.2); + box-shadow: 0 12px 32px rgba(var(--primary-light-rgb), 0.2); } .cart-item:hover .cart-item-img-container::after { - border-color: #ff5000; - box-shadow: 0 0 0 8px rgba(255, 80, 0, 0.2); + border-color: var(--primary-color); + box-shadow: 0 0 0 8px rgba(var(--primary-light-rgb), 0.2); opacity: 1; } @@ -524,9 +524,9 @@ const removeItem = (id: number) => { } .cart-item-name { - font-size: 18px; + font-size: var(--font-size-lg); font-weight: 700; - color: #333; + color: var(--text-primary); margin: 0; overflow: hidden; /* 限制显示两行 */ @@ -535,15 +535,15 @@ const removeItem = (id: number) => { -webkit-line-clamp: 5; -webkit-box-orient: vertical; line-height: 1.5; - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); + transition: all var(--transition-transform); position: relative; letter-spacing: 0.5px; } .cart-item:hover .cart-item-name { - color: #ff5000; - transform: translateX(8px); - text-shadow: 0 2px 6px rgba(255, 80, 0, 0.2); + color: var(--primary-color); + transform: translateX(var(--spacing-sm)); + text-shadow: 0 2px 6px rgba(var(--primary-light-rgb), 0.2); } .cart-item-name::after { diff --git a/src/Views/Chat.vue b/src/Views/Chat.vue new file mode 100644 index 0000000..614d09c --- /dev/null +++ b/src/Views/Chat.vue @@ -0,0 +1,703 @@ + + + + + + \ No newline at end of file diff --git a/src/Views/User/User.vue b/src/Views/User/User.vue new file mode 100644 index 0000000..b30379c --- /dev/null +++ b/src/Views/User/User.vue @@ -0,0 +1,1353 @@ + + + + + + diff --git a/src/Views/User/Userinfo.vue b/src/Views/User/Userinfo.vue index 05ec47c..11a7009 100644 --- a/src/Views/User/Userinfo.vue +++ b/src/Views/User/Userinfo.vue @@ -2,28 +2,902 @@ \ No newline at end of file + + + + + \ No newline at end of file diff --git a/src/Views/footer.vue b/src/Views/footer.vue index 6cc4d20..2806889 100644 --- a/src/Views/footer.vue +++ b/src/Views/footer.vue @@ -6,7 +6,19 @@ @@ -59,7 +71,7 @@ const productLists = ref([ \ No newline at end of file diff --git a/src/Views/herde.vue b/src/Views/herde.vue index 48d09ca..0c22e26 100644 --- a/src/Views/herde.vue +++ b/src/Views/herde.vue @@ -5,8 +5,14 @@ @@ -14,11 +20,15 @@
- + - 首页 - - + 首页 + +
@@ -31,30 +41,23 @@
    -
  • 宝贝
  • -
  • 店铺
  • +
  • 宝贝
  • +
  • 店铺
- +
- +
- +
搜索 @@ -100,7 +103,7 @@ const searchValue = ref('') const showHistory = ref(false) // 标志:是否正在清空历史记录 const isClearingHistory = ref(false) -// 标志:是否在搜索界面 +// 控制搜索框是否显示 const booleanSearch = ref(true) // 路由事件 router.beforeEach((to, from, next) => { @@ -109,7 +112,7 @@ router.beforeEach((to, from, next) => { } console.log(to.name) // 如果在商品页面 隐藏搜索框 - if (to.name === 'productDetail') { + if (to.name === 'productDetail' || to.name === 'chat') { booleanSearch.value = false } else { booleanSearch.value = true @@ -173,15 +176,56 @@ const onInputBlur = () => { }, 200) } +// 当前搜索类型 +const currentSearchType = ref('宝贝') + // 设置搜索类型 -const setSearchType = (type: string) => { +const setSearchType = (type: string, event: MouseEvent) => { const typeItems = document.querySelectorAll('.search-type-item') - typeItems.forEach(item => { - item.classList.remove('active') - }) - // 添加active类到点击的元素 - // event?.currentTarget?.classList.add('active') - console.log('搜索类型:', type) + // 找到当前活跃的元素 + const currentActiveItem = document.querySelector('.search-type-item.active') + // 保存点击的元素引用 + const clickedTarget = event.currentTarget as HTMLElement + + // 为当前活跃的元素添加消失动画 + if (currentActiveItem && currentActiveItem !== clickedTarget) { + if (currentSearchType.value === '宝贝' && type === '店铺') { + // 宝贝 -> 店铺:宝贝元素从左往右消失 + currentActiveItem.classList.add('animate-right-out') + } else if (currentSearchType.value === '店铺' && type === '宝贝') { + // 店铺 -> 宝贝:店铺元素从右往左消失 + currentActiveItem.classList.add('animate-left-out') + } + + // 等待消失动画完成后再继续 + setTimeout(() => { + // 移除所有元素的类 + typeItems.forEach(item => { + item.classList.remove('active', 'animate-left', 'animate-right', 'animate-left-out', 'animate-right-out') + }) + + // 添加active类到点击的元素 + if (clickedTarget) { + // 判断切换方向 + if (currentSearchType.value === '宝贝' && type === '店铺') { + // 宝贝 -> 店铺:从左往右出现 + clickedTarget.classList.add('active', 'animate-right') + } else if (currentSearchType.value === '店铺' && type === '宝贝') { + // 店铺 -> 宝贝:从右往左出现 + clickedTarget.classList.add('active', 'animate-left') + } else { + // 默认动画 + clickedTarget.classList.add('active') + } + currentSearchType.value = type + } + console.log('搜索类型:', type) + + }, 300) + } else { + // 如果点击的是当前活跃的元素,直接返回 + return + } } // 清除搜索输入 @@ -226,8 +270,8 @@ const rightMenu = [ \ No newline at end of file