chenkainan 2 months ago
parent
commit
a55d1e8b4c
  1. 3
      src/assets/css/common.css
  2. 46
      src/router/index.js
  3. 93
      src/views/User/Index.vue
  4. 272
      src/views/User/OrderDetail.vue
  5. 558
      src/views/User/OrderList.vue
  6. 309
      src/views/User/UserCenter.vue
  7. 131
      src/views/User/UserInfo.vue
  8. 112
      src/views/User/ViewHistory.vue

3
src/assets/css/common.css

@ -47,3 +47,6 @@ div {
display: flex;
flex-direction: column;
}
.normal-margin-bottom{
margin-bottom: 20px;
}

46
src/router/index.js

@ -82,25 +82,45 @@ const router = new Router({
// component: () => import('@/views/Checkout.vue')
// },
{
path: '/userCenter',
name: 'UserCenter',
meta: {
title: '个人中心 - 精品商城',
requireAuth: true,
keepAlive: false
},
path: '/User',
name: 'User',
// meta: { title: '个人中心 - 精品商城',requireAuth: true,keepAlive: false},
component: () => import('@/views/User/Index.vue'),
redirect: '/User/UserCenter',
children: [
{
path:'UserCenter',
name: "UserCenter",
// meta: {title: '个人中心 - 精品商城',keepAlive: false,},
component: ()=>import('@/views/User/UserCenter.vue')
},
{
path: 'orderList',
path: 'OrderList',
name: 'OrderList',
meta: {
title: '我的订单 - 精品商城',
requireAuth: true,
keepAlive: false
},
meta: { title: '我的订单 - 精品商城', keepAlive: false },
component: () => import('@/views/User/OrderList.vue')
},
{
path: 'UserInfo',
name: 'UserInfo',
meta: { title: '个人信息 - 精品商城', keepAlive: false },
component: () => import('@/views/User/UserInfo.vue')
},
{
path: 'ViewHistory',
name: 'ViewHistory',
meta: { title: '我的足迹 - 精品商城', keepAlive: false },
component: () => import('@/views/User/ViewHistory.vue')
},
],
},
{
path: '/OrderDetail',
name: 'OrderDetail',
meta: { title: '订单详情 - 精品商城', keepAlive: false },
component: () => import('@/views/User/OrderDetail.vue')
},
// {
// path: '/user/orders/:id',
// name: 'OrderDetail',

93
src/views/User/Index.vue

@ -0,0 +1,93 @@
<template>
<div class="bg">
<div class="left-container">
<router-link :class="['route-item',selectIndex==i?'active':'']" v-for="(item,i) in navList" :key="i" :to="item.path">{{ item.title }}</router-link>
</div>
<div class="right-container">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
data() {
return {
selectIndex: 0,
navList: [
{title: "个人中心",path:"/User/UserCenter"},
{title: '我的购物车',path:"" },
{title: '我的订单',path:"/User/OrderList" },
{title: '评价管理',path:"" },
{title: '我的发票',path:"" },
{title: '我的收藏' ,path:""},
{title: '我的足迹',path:"/User/ViewHistory" },
{title: '个人信息',path:"/User/UserInfo" },
{title: '账号设置',path:"" },
{title: '我的收货地址',path:"" }
]
}
},
watch: {
// $route
$route(to, from) {
let toPath = to.path.toLocaleLowerCase()
let index = this.navList.findIndex(x=>x.path.toLocaleLowerCase()== toPath)
if (index>=0) {
this.selectIndex = index
}
}
},
computed: {
},
created() {
let path = this.$route.path.toLocaleLowerCase()
let index = this.navList.findIndex(x=>x.path.toLocaleLowerCase()== path)
if (index>=0) {
this.selectIndex = index
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.bg{
display: flex;
}
.left-container{
width: 150px;
flex-shrink: 0;
display: flex;
flex-direction: column;
height: fit-content;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
.route-item{
padding: 10px;
cursor: pointer;
font-size: 14px;
&:hover{
background-color: #f9f9f9;
}
&.active{
background-color: #6a8a27;
color: #fff;
}
}
}
.right-container{
flex: 1;
width: 1px;
padding-left: 20px;
}
</style>

272
src/views/User/OrderDetail.vue

@ -0,0 +1,272 @@
<template>
<div class="bg">
<!-- 订单状态时间线 -->
<div class="normal-margin-bottom">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/User/UserCenter' }">个人中心</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: '/User/OrderList' }">我的订单</el-breadcrumb-item>
<el-breadcrumb-item> 订单详情</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="common-card normal-margin-bottom" style="padding: 20px 0;display: flex;">
<div class="order-status">
<div class="order-no">订单号: 209907091214560078 <el-button style="color: #999;" type="text" icon="el-icon-document-copy"></el-button></div>
<div class="status-title">
<i class="el-icon-time" style="color: #ff9800;font-size: 32px;"></i>
<span style="height: 24px;line-height: 24px;padding-left: 5px;">订单状态: 待付款</span>
</div>
<el-button type="primary" size="medium">在线付款</el-button>
<el-button type="text" size="small" style="padding: 0;">打印订单</el-button>
</div>
<div class="order-step">
<el-steps :active="2" align-center style="width: 100%;">
<el-step v-for="(item,i) in activities" :key="i">
<div class="process-title" slot="title">{{ item.status }}</div>
<div slot="icon">
<span v-if="i>=2">{{i+1}}</span>
<i v-else style="color: #fff;" class="el-icon-check"></i>
</div>
<div class="process-description" slot="description">{{ item.timestamp }}</div>
</el-step>
</el-steps>
</div>
</div>
<!-- 订单信息卡片 -->
<div class="common-card normal-margin-bottom order-info-card" style="display: flex;padding: 20px 0;">
<el-descriptions title="订单信息" :column="1">
<el-descriptions-item label="订单号">{{ orderInfo.orderNumber }}</el-descriptions-item>
<el-descriptions-item label="订单状态">{{ orderInfo.status }}</el-descriptions-item>
<el-descriptions-item label="下单时间">{{ orderInfo.orderTime }}</el-descriptions-item>
</el-descriptions>
<el-descriptions title="配送信息" :column="1">
<el-descriptions-item label="收货人">{{ deliveryInfo.receiver }}</el-descriptions-item>
<el-descriptions-item label="地址">{{ deliveryInfo.address }}</el-descriptions-item>
<el-descriptions-item label="手机号码">{{ deliveryInfo.phone }}</el-descriptions-item>
<el-descriptions-item label="配送方式">{{ deliveryInfo.deliveryMethod }}</el-descriptions-item>
<el-descriptions-item label="期望送达时间">{{ deliveryInfo.expectedDeliveryTime }}</el-descriptions-item>
</el-descriptions>
<el-descriptions title="支付信息" :column="1" style="border: none;">
<el-descriptions-item label="支付方式">{{ paymentInfo.paymentMethod }}</el-descriptions-item>
<el-descriptions-item label="支付状态">{{ paymentInfo.paymentStatus }}</el-descriptions-item>
<el-descriptions-item label="支付时间">{{ paymentInfo.paymentTime }}</el-descriptions-item>
</el-descriptions>
</div>
<!-- 商品列表 -->
<el-table :data="productList" style="width: 100%">
<el-table-column prop="name" label="商品名称" align="center">
<template slot-scope="{row}">
<div style="display: flex;align-items: center;">
<img :src="row.image" class="product-image" :alt="row.name"/>
<div>{{ row.name }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="spec" label="规格" align="center"></el-table-column>
<el-table-column prop="price" label="单价(元)" align="center" width="200"></el-table-column>
<el-table-column prop="quantity" label="数量" align="center" width="100"></el-table-column>
<el-table-column prop="subtotal" label="小计(元)" align="center" width="200">
<template slot-scope="{row}">
<div style="color: #ff1111;">{{ row.subtotal }}</div>
</template>
</el-table-column>
</el-table>
<!-- 订单总价 -->
<div class="common-card normal-margin-bottom total-card">
<el-descriptions :column="1">
<el-descriptions-item label="商品总价">{{ totalPrice.productTotal }}</el-descriptions-item>
<el-descriptions-item label="运费">{{ totalPrice.shippingFee }}</el-descriptions-item>
<el-descriptions-item label="实付款">
<span style="font-size: 16px;font-weight: bold;color: #ff1111;">{{ totalPrice.actualPayment }}</span>
</el-descriptions-item>
</el-descriptions>
</div>
</div>
</template>
<script>
export default {
name: 'OrderDetail',
data() {
return {
activities: [
{ status: '提交订单', timestamp: '2025-08-01 15:30:00' },
{ status: '支付成功', timestamp: '2025-08-01 15:35:00' },
{ status: '商家接单', timestamp: '2025-08-01 15:40:00' },
{ status: '商品出库', timestamp: '2025-08-01 16:00:00' },
{ status: '配送中', timestamp: '2025-08-01 16:30:00' },
{ status: '已完成', timestamp: '2025-08-01 17:00:00' }
],
orderInfo: {
orderNumber: '20250801123456',
status: '已完成',
orderTime: '2025-08-01 15:30:00'
},
deliveryInfo: {
receiver: '张三',
address: '北京市海淀区xxx街道xxx小区',
phone: '13800138000',
deliveryMethod: '快递',
expectedDeliveryTime: '2025-08-02'
},
paymentInfo: {
paymentMethod: '支付宝',
paymentStatus: '已支付',
paymentTime: '2025-08-01 15:35:00'
},
productList: [
{ name: '商品1', spec: '规格1', price: 100, quantity: 1, subtotal: 100,image: 'https://picsum.photos/200/200?random=1', },
{ name: '商品2', spec: '规格2', price: 200, quantity: 2, subtotal: 400,image: 'https://picsum.photos/200/200?random=1', }
],
totalPrice: {
productTotal: 500,
shippingFee: 0,
actualPayment: 500
}
};
},
computed: {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.bg{
display: flex;
flex-direction: column;
font-size: 14px;
}
.common-card{
width: 100%;
background-color: white;
padding: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
}
.order-status {
border-right: 1px solid #eee;
width: 350px;
height: 220px;
flex-shrink: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
.order-no{
color: #999;
.el-button{
width: fit-content;
margin: 0;
display: inline-block;
padding: 0;
}
}
.status-title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: bold;
}
.status-title i {
font-size: 24px;
}
.el-button {
width: 120px;
display: block;
margin: 0 auto;
}
}
.order-step{
flex: 1;
width: 1px;
padding: 0 20px;
display: flex;
align-items: center;
::v-deep .el-step__icon.is-text{
border: none;
width: 30px;
height: 30px;
border-radius: 50%;
background: #C0C4CC;
color: white;
}
::v-deep .el-step__line{
top: 13px;
}
::v-deep .el-step__line-inner{
border-color: #C0C4CC;
}
.process-title{
color:#666;
font-weight: bold;
font-size:14px;
margin-top: -70px;
}
.process-description{
color:#666;
font-size:12px;
margin-top: 45px;
}
::v-deep .is-finish .el-step__icon{
background: #67C23A;
}
}
.order-info-card{
display: flex;
::v-deep .el-descriptions{
flex: 1;
flex-shrink: 0;
border-right: 1px solid rgba(153,153,153, 0.1);
padding: 0 20px;
.el-descriptions-item__label{
width: 90px;
}
}
}
.product-image {
width: 80px;
height: 80px;
object-fit: cover;
margin-right: 15px;
border-radius: 4px;
}
.total-card{
margin-top: 20px;
background: #fafafa;
box-shadow: none;
::v-deep .el-descriptions__body{
background: none;
text-align: right;
.el-descriptions-item__label{
width: 90%;
text-align: right;
justify-content: flex-end;
}
.el-descriptions-item__content{
justify-content: flex-end;
}
}
}
</style>

558
src/views/User/OrderList.vue

@ -0,0 +1,558 @@
<template>
<div class="bg">
<el-tabs v-model="activeTab">
<el-tab-pane label="所有订单" name="all"></el-tab-pane>
<el-tab-pane label="待付款" name="pendingPayment"></el-tab-pane>
<el-tab-pane label="待发货" name="pendingDelivery"></el-tab-pane>
<el-tab-pane label="配送中" name="delivering"></el-tab-pane>
<el-tab-pane label="待评价" name="pendingReview"></el-tab-pane>
</el-tabs>
<div class="filter-bar">
<el-form :inline="true" :model="filterForm" size="small">
<el-form-item label="商品名称">
<el-input v-model="filterForm.goodsName" placeholder="请输入商品名称"></el-input>
</el-form-item>
<el-form-item label="订单编号">
<el-input v-model="filterForm.orderNo" placeholder="请输入订单编号"></el-input>
</el-form-item>
<el-form-item label="下单时间">
<el-date-picker v-model="filterForm.createTime" type="daterange" range-separator="" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
<el-form-item label="商家名称">
<el-input v-model="filterForm.merchantName" placeholder="请输入商家名称"></el-input>
</el-form-item>
<el-form-item label="交易状态">
<el-select v-model="filterForm.tradeStatus" placeholder="请选择" style="width: 200px;">
<el-option label="全部" value=""></el-option>
<el-option label="待付款" value="pendingPayment"></el-option>
<el-option label="待发货" value="pendingDelivery"></el-option>
<el-option label="配送中" value="delivering"></el-option>
<el-option label="已完成" value="completed"></el-option>
<el-option label="已取消" value="cancelled"></el-option>
</el-select>
</el-form-item>
<el-form-item label="完成时间">
<el-date-picker v-model="filterForm.createTime" type="daterange" range-separator="" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button style="background:#6a8a27;border: none;" type="primary" @click="search">搜索</el-button>
</el-form-item>
<el-form-item>
<el-button @click="reset">重置</el-button>
</el-form-item>
</el-form>
</div>
<div>
<div class="order-products" style="padding:0 20px;background: #f8f9fa; border-top: 1px solid #eee; border-bottom: 1px solid #eee;margin-bottom: 20px;">
<div class="product-item" >
<div class="product-details">
<div class="product-name">商品信息</div>
</div>
<div class="product-price">单价()</div>
<div class="product-quantity">数量</div>
<div class="product-total">小计()</div>
<!-- <div class="product-status">
<el-tag :type="getStatusTagType(product.status)" size="small">{{ getStatusText(product.status) }}</el-tag>
</div> -->
<div class="product-actions"></div>
</div>
</div>
<!-- 订单卡片 - 按商家合并商品 -->
<div class="order-card" v-for="order in filteredOrders" :key="order.id">
<!-- 订单头部 - 包含商家信息 -->
<div class="order-header flex-between">
<div style="display: flex;">
<div >订单号: {{ order.orderNo }}</div>
<div style="padding-left: 60px;">下单时间{{ order.createTime }}</div>
</div>
<div class="product-status">
<el-tag :type="getStatusTagType(order.status)" size="small">{{ getStatusText(order.status) }}</el-tag>
</div>
</div>
<!-- 订单商品列表 -->
<div class="order-products">
<div class="product-item" v-for="product in order.products" :key="product.id">
<img :src="product.image" class="product-image" :alt="product.name">
<div class="product-details">
<div class="product-name">{{ product.name }}</div>
<div class="product-spec">{{ product.spec }}</div>
</div>
<div class="product-price">¥{{ product.price.toFixed(2) }}</div>
<div class="product-quantity">x{{ product.quantity }}</div>
<div class="product-total">¥{{ (product.price * product.quantity).toFixed(2) }}</div>
<!-- <div class="product-status">
<el-tag :type="getStatusTagType(product.status)" size="small">{{ getStatusText(product.status) }}</el-tag>
</div> -->
<div class="product-actions">
<el-button type="text" size="mini"> 商品详情</el-button>
</div>
</div>
</div>
<!-- 订单底部 - 金额和操作 -->
<div class="order-footer">
<div class="order-summary">
<div class="order-amount">
合计: <strong>¥{{ order.totalAmount.toFixed(2) }}</strong> (含运费 ¥{{ order.freight.toFixed(2) }})
</div>
<!-- <div class="order-tips">
{{ order.products.length }}件商品
</div> -->
</div>
<div class="order-actions">
<el-button
type="text"
size="mini"
@click="viewOrderDetail(order.id)"
>订单详情</el-button>
<el-button
v-if="order.status === 'pendingPayment'"
type="primary"
size="mini"
@click="payOrder(order.id)"
>去付款</el-button>
<el-button
v-if="order.status === 'pendingDelivery'"
type="text"
size="mini"
@click="remindDelivery(order.id)"
>提醒发货</el-button>
<el-button
v-if="order.status === 'delivering'"
type="text"
size="mini"
@click="checkLogistics(order.id)"
>查看物流</el-button>
<el-button
v-if="order.status === 'completed' && !order.isReviewed"
type="text"
size="mini"
@click="gotoReview(order.id)"
>去评价</el-button>
</div>
</div>
</div>
<el-empty description="暂无订单" v-if="filteredOrders.length<=0"></el-empty>
<!-- 分页 -->
<div style="text-align: right; margin-top: 20px;">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[5, 10, 20]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="filteredOrders.length"
></el-pagination>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'OrderList',
data () {
return {
activeTab: 'all',
currentPage: 1,
pageSize: 10,
filterForm: {
goodsName: '',
orderNo: '',
createTime: '',
merchantName: '',
tradeStatus: ''
},
// -
orders: [
{
id: 1,
orderNo: '209907091214560078',
createTime: '2099-07-09 10:47:49',
status: 'pendingPayment',
totalAmount: 937,
freight: 15,
isReviewed: false,
merchant: {
id: 101,
name: '花艺生活馆',
isOfficial: true
},
products: [
{
id: 1001,
name: '深情挚爱/卡罗拉玫瑰',
image: 'https://picsum.photos/200/200?random=1',
spec: '卡罗拉玫瑰33枝',
price: 349,
quantity: 1,
status: 'pendingPayment'
},
{
id: 1002,
name: '精美包装纸',
image: 'https://picsum.photos/200/200?random=4',
spec: '粉色',
price: 38,
quantity: 2,
status: 'pendingPayment'
}
]
},
{
id: 2,
orderNo: '209907091214560079',
createTime: '2099-07-09 10:48:49',
status: 'pendingDelivery',
totalAmount: 199,
freight: 0,
isReviewed: false,
merchant: {
id: 102,
name: '北欧家居旗舰店',
isOfficial: true
},
products: [
{
id: 2001,
name: '北欧花艺素雅仿真花',
image: 'https://picsum.photos/200/200?random=2',
spec: '白色',
price: 199,
quantity: 1,
status: 'pendingDelivery'
}
]
},
{
id: 3,
orderNo: '209907091214560080',
createTime: '2099-07-09 10:49:49',
status: 'delivering',
totalAmount: 389,
freight: 10,
isReviewed: false,
merchant: {
id: 101,
name: '花艺生活馆',
isOfficial: true
},
products: [
{
id: 3001,
name: '香槟玫瑰+白玫瑰混搭',
image: 'https://picsum.photos/200/200?random=3',
spec: '混搭',
price: 389,
quantity: 1,
status: 'delivering'
}
]
}
]
}
},
computed: {
//
filteredOrders() {
let result = [...this.orders];
//
if (this.activeTab !== 'all') {
result = result.filter(order => order.status === this.activeTab);
}
//
if (this.filterForm.goodsName) {
const keyword = this.filterForm.goodsName.toLowerCase();
result = result.filter(order => {
return order.products.some(product =>
product.name.toLowerCase().includes(keyword)
);
});
}
//
if (this.filterForm.orderNo) {
result = result.filter(order =>
order.orderNo.includes(this.filterForm.orderNo)
);
}
//
if (this.filterForm.merchantName) {
const keyword = this.filterForm.merchantName.toLowerCase();
result = result.filter(order =>
order.merchant.name.toLowerCase().includes(keyword)
);
}
//
if (this.filterForm.tradeStatus) {
result = result.filter(order =>
order.status === this.filterForm.tradeStatus
);
}
return result;
}
},
methods: {
//
search() {
this.currentPage = 1; //
this.$message({
message: '搜索条件已应用',
type: 'info'
});
},
//
reset() {
this.filterForm = {
goodsName: '',
orderNo: '',
createTime: '',
merchantName: '',
tradeStatus: ''
};
this.activeTab = 'all';
this.currentPage = 1;
},
//
handleSizeChange(val) {
this.pageSize = val;
},
//
handleCurrentChange(val) {
this.currentPage = val;
},
//
getStatusText(status) {
const statusMap = {
pendingPayment: '待付款',
pendingDelivery: '待发货',
delivering: '配送中',
completed: '已完成',
cancelled: '已取消'
};
return statusMap[status] || status;
},
//
getStatusTagType(status) {
const typeMap = {
pendingPayment: 'warning',
pendingDelivery: 'info',
delivering: 'primary',
completed: 'success',
cancelled: 'danger'
};
return typeMap[status] || 'default';
},
//
payOrder(orderId) {
this.$message({
message: `订单 ${orderId} 去付款`,
type: 'info'
});
},
//
remindDelivery(orderId) {
this.$message({
message: `已提醒订单 ${orderId} 发货`,
type: 'success'
});
},
//
checkLogistics(orderId) {
this.$message({
message: `查看订单 ${orderId} 物流`,
type: 'info'
});
},
//
gotoReview(orderId) {
this.$message({
message: `去评价订单 ${orderId}`,
type: 'info'
});
},
//
viewOrderDetail(orderId) {
this.$message({
message: `查看订单 ${orderId} 详情`,
type: 'info'
});
}
}
}
</script>
<style lang="scss" scoped>
.bg{
display: flex;
flex-direction: column;
::v-deep .el-button--text {
color: #6a8a27;
}
::v-deep .el-tabs__item.is-active{
color: #6a8a27;
}
::v-deep .el-tabs__active-bar{
background-color: #6a8a27
}
::v-deep .el-tabs__item:hover{
color: #6a8a27;
}
}
.filter-bar {
margin-bottom: 20px;
}
/* 订单卡片样式 */
.order-card {
border: 1px solid #eee;
border-radius: 4px;
margin-bottom: 20px;
overflow: hidden;
}
/* 订单头部 - 包含商家信息 */
.order-header {
background-color: #f8f9fa;
padding: 12px 20px;
display: flex;
align-items: center;
border-bottom: 1px solid #eee;
color: #666;
font-size: 14px;
}
/* 订单商品列表 */
.order-products {
padding: 10px 20px;
}
.product-item {
display: flex;
align-items: center;
padding: 15px 0;
border-bottom: 1px dashed #eee;
font-size: 14px;
}
.product-item:last-child {
border-bottom: none;
}
.product-image {
width: 80px;
height: 80px;
object-fit: cover;
margin-right: 15px;
border-radius: 4px;
}
.product-details {
flex: 1;
}
.product-name {
color: #333;
margin-bottom: 5px;
}
.product-spec {
color: #999;
font-size: 12px;
}
.product-price {
width: 120px;
text-align: center;
color: #333;
}
.product-quantity {
width: 100px;
text-align: center;
color: #666;
}
.product-total {
width: 120px;
text-align: center;
color: #333;
font-weight: 500;
}
.product-status {
width: 150px;
text-align: center;
}
.product-actions {
width: 150px;
text-align: center;
}
/* 订单底部 - 金额和操作 */
.order-footer {
background-color: #f8f9fa;
padding: 15px 20px;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #eee;
}
.order-summary {
text-align: right;
}
.order-amount {
color: #333;
margin-bottom: 5px;
}
.order-amount strong {
color: #ff4d4f;
font-size: 16px;
}
.order-tips {
font-size: 12px;
color: #999;
}
.order-actions {
display: flex;
gap: 10px;
}
</style>

309
src/views/User/UserCenter.vue

@ -0,0 +1,309 @@
<template>
<div class="bg">
<div class="notice-bar" v-if="showNotice">
<div class="notice-bar__content">
<i class="el-icon-lightbulb"></i>
尊敬的采购人欢迎来到xxx平台您可以先完成下方的基础设置方便您更高效的采购
</div>
<div class="notice-bar__close" @click="showNotice = false">
<i class="el-icon-close"></i>
</div>
</div>
<!-- 快速设置卡片 -->
<el-card>
<el-row :gutter="20">
<el-col :xs="24" :sm="8" :md="8" v-for="(item,i) in headFun" :key="i">
<div class="feature-item" >
<div class="feature-icon">
<i :class="item.icon"></i>
</div>
<span class="feature-name">{{ item.title }}</span>
<el-button type="text" size="mini" style="margin-top: 5px;">去设置</el-button>
</div>
</el-col>
</el-row>
</el-card>
<!-- 个人信息卡片 -->
<el-card>
<div slot="header">个人信息</div>
<div class="user-info">
<img src="https://picsum.photos/id/1005/200/200" alt="用户头像" class="user-avatar">
<div class="user-details">
<div>
<div class="user-name">张三哥</div>
<div class="user-other-info">
ID: 200901071124
<el-button type="text" size="mini" @click="copyId">复制</el-button>
</div>
<div class="user-other-info">手机号: 138****5678</div>
</div>
<div class="login-info">
<div class="login-section">
<div class="login-section-title">当前登录信息</div>
<div class="login-detail">登录设备: Edge浏览器</div>
<div class="login-detail">登录地点: 中国广东深圳</div>
<div class="login-detail">登录时间: 2099-02-23 10:09:50</div>
</div>
<div class="login-section">
<div class="login-section-title">上次登录信息</div>
<div class="login-detail">登录设备: 微信小程序</div>
<div class="login-detail">登录地点: 中国广东深圳</div>
<div class="login-detail">登录时间: 2099-02-05 10:46:45</div>
</div>
</div>
</div>
<div>
<el-button type="primary" size="mini" style="background-color: #6a8a27;border: none;">
<i class="el-icon-edit"></i> 编辑个人信息
</el-button>
</div>
</div>
</el-card>
<!-- 订单管理卡片 -->
<div class="flex-center">
<el-card style="flex: 1;">
<div slot="header">我的议价</div>
<div class="feature-grid" >
<div class="feature-item" v-for="(item,i) in bargaining" :key="i">
<el-badge v-if="item.value" :value="item.value" type="danger" >
<div class="feature-icon"><i :class="item.icon"></i></div>
</el-badge>
<div v-else class="feature-icon"><i :class="item.icon"></i></div>
<span class="feature-name">{{ item.title }}</span>
</div>
</div>
</el-card>
<div style="width: 20px;flex-shrink: 0;"></div>
<el-card style="flex: 1;">
<div slot="header">我的订单</div>
<div class="feature-grid" >
<div class="feature-item" v-for="(item,i) in order" :key="i">
<el-badge v-if="item.value" :value="item.value" type="danger" >
<div class="feature-icon"><i :class="item.icon"></i></div>
</el-badge>
<div v-else class="feature-icon"><i :class="item.icon"></i></div>
<span class="feature-name">{{ item.title }}</span>
</div>
</div>
</el-card>
</div>
</div>
</template>
<script>
export default {
name: 'UserCenter',
data() {
return {
showNotice: true,
userId: '200901071124',
headFun: [
{icon: "el-icon-location", title: "设置收货地址", path: ""},
{icon: "el-icon-document", title: "设置发票抬头", path: ""},
{icon: "el-icon-user", title: "设置采购人信息", path: ""},
],
bargaining: [
{icon: "el-icon-time", title: "待回复", path: "", value: 2},
{icon: "el-icon-truck", title: "已取消", path: "", value: 2},
{icon: "el-icon-menu", title: "已成交", path: "", value: 2},
],
order: [
{icon: "el-icon-time", title: "待付款", path: "", value: 2},
{icon: "el-icon-truck", title: "未发货", path: "", value: 2},
{icon: "el-icon-menu", title: "全部订单", path: "", value: 2},
]
}
},
computed: {
},
created() {
},
methods: {
// ID
copyId() {
const input = document.createElement('input');
input.value = this.userId;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
this.$message({
message: 'ID已复制',
type: 'success'
});
}
}
}
</script>
<style lang="scss" scoped>
.bg{
display: flex;
flex-direction: column;
::v-deep .el-button--text {
color: #6a8a27;
}
}
/* 卡片通用样式 */
.el-card {
margin-bottom: 20px;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
border: none;
}
.el-card__header {
padding: 16px 20px;
border-bottom: 1px solid #f0f0f0;
background-color: #fff;
font-size: 16px;
font-weight: 500;
}
.el-card__body {
padding: 20px;
}
/* 通知栏样式 */
.notice-bar {
background-color: #fffbe6;
border: 1px solid #ffe58f;
padding: 12px 16px;
border-radius: 4px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
align-items: center;
color: #fa8c16;
font-size: 14px;
}
.notice-bar__content {
display: flex;
align-items: center;
}
.notice-bar__content i {
margin-right: 8px;
}
.notice-bar__close {
cursor: pointer;
transition: color 0.2s;
}
.notice-bar__close:hover {
color: #fa8c16;
}
/* 用户信息样式 */
.user-info {
display: flex;
align-items: flex-start;
padding: 10px 0;
}
.user-avatar {
width: 100px;
height: 100px;
border-radius: 50%;
margin-right: 20px;
border: 4px solid #f5f7fa;
}
.user-details {
flex: 1;
}
.user-name {
font-size: 20px;
font-weight: 500;
margin-bottom: 10px;
color: #1f2329;
}
.user-other-info {
color: #4e5969;
margin-bottom: 6px;
font-size: 14px;
}
/* 登录信息样式 */
.login-info {
display: flex;
padding-top: 20px;
}
.login-section {
flex: 1;
}
.login-section-title {
font-weight: 500;
margin-bottom: 10px;
color: #1f2329;
font-size: 15px;
}
.login-detail {
color: #4e5969;
font-size: 14px;
margin-bottom: 6px;
}
/* 功能图标区域 */
.feature-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
margin-top: 15px;
}
.feature-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 15px 10px;
border-radius: 6px;
transition: all 0.2s;
cursor: pointer;
}
.feature-item:hover {
background-color: #f5f7fa;
}
.feature-icon {
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
margin-bottom: 10px;
font-size: 20px;
color: #6a8a27;
background-color: rgba(106, 138, 39, 0.1);
}
.feature-name {
font-size: 14px;
color: #4e5969;
}
</style>

131
src/views/User/UserInfo.vue

@ -0,0 +1,131 @@
<template>
<div class="bg">
<el-card style="width: 100%;">
<div slot="header" class="clearfix">
<span>个人信息</span>
</div>
<div style="padding-right: 200px;">
<el-form :model="user" label-width="100px" size="small">
<el-form-item label="用户头像">
<el-upload class="avatar-uploader" action="#" :auto-upload="false"
:on-change="handleAvatarChange" :show-file-list="false">
<div style="position: relative;" v-if="user.avatar">
<img :src="user.avatar" class="avatar">
<div class="hover-tip">修改头像</div>
</div>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-form-item label="*昵称">
<el-input v-model="user.nickname" placeholder="请输入昵称"></el-input>
</el-form-item>
<el-form-item label="用户ID">
<el-input v-model="user.id" disabled>
<template slot="append">
<el-button @click="copyId">复制</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="user.gender">
<el-radio label="male">男性</el-radio>
<el-radio label="female">女性</el-radio>
<el-radio label="secret">保密</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="生日">
<el-date-picker type="date" placeholder="选择日期" v-model="user.birthday"
style="width: 100%;" value-format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
<el-form-item class="form-actions">
<el-button type="primary" @click="saveUser">保存</el-button>
<el-button @click="close">关闭</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
</div>
</template>
<script>
export default {
name: 'UserInfo',
data() {
return {
user: {
avatar: '',
nickname: '张三哥',
id: '209901071124',
gender: 'male',
birthday: ''
}
}
},
methods:{
handleAvatarChange(file) {
this.user.avatar = URL.createObjectURL(file.raw);
},
copyId() {
const input = document.createElement('input');
input.value = this.user.id;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
this.$message({
message: '用户ID已复制',
type: 'success'
});
},
saveUser() {
this.$message({
message: '保存成功',
type: 'success'
});
},
close() {
this.$message({
message: '已关闭',
type: 'info'
});
}
}
}
</script>
<style lang="scss" scoped>
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
::v-deep .avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar {
width: 100px;
height: 100px;
display: block;
}
.hover-tip{
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 20px;
text-align: center;
line-height: 20px;
font-size: 14px;
color: #fff;
background: rgba(0,0,0,0.5);
}
</style>

112
src/views/User/ViewHistory.vue

@ -0,0 +1,112 @@
<template>
<div class="bg">
<el-card style="width: 100%;">
<div slot="header" class="clearfix">
<span>个人信息</span>
<el-button style="float: right;color: #999;" type="text" icon="el-icon-delete">批量删除</el-button>
</div>
<el-checkbox-group v-model="checkList">
<div class="date-container" v-for="(item,i) in historyData" :key="i">
<div class="head-date">
{{ item.date }}
<span class="goods-num">{{item.goods.length}}件商品</span>
</div>
<div class="goods-container">
<div class="goods-item" v-for="(goods,itemI) in 15" :key="itemI">
<!-- <img class="goods-img" :src="goods.image">
<div class="goods-content">
<div class="price">{{ goods.price }}</div>
<div class="text-overflowRows">{{ goods.name }}</div>
</div> -->
<img class="goods-img" :src="item.goods[0].image">
<div class="goods-content">
<div class="price">{{ item.goods[0].price }}</div>
<div class="text-overflowRows">{{ item.goods[0].name }}</div>
</div>
<!-- <el-checkbox class="select-item" :label="itemI"></el-checkbox> -->
</div>
</div>
</div>
</el-checkbox-group>
</el-card>
</div>
</template>
<script>
export default {
name: 'UserInfo',
data() {
return {
historyData: [
{
date: "06.10",
goods: [{image: 'https://picsum.photos/300/200?random=1',price: 359,name: '产品标题产品标题'}],
}
],
checkList: [],
}
},
methods:{
}
}
</script>
<style lang="scss" scoped>
.date-container{
font-size: 14px;
}
.head-date{
font-size: 30px;
border-bottom: 1px solid #ddd;
padding-bottom: 10px;
// font-weight: bold;
.goods-num{
font-size: 14px;
font-weight: normal;
padding-left: 5px;
}
}
.goods-container{
padding: 20px 0;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
.goods-item{
width: 220px;
position: relative;
.goods-img{
height: 260px;
width: 100%;
border-radius: 4px;
object-fit: cover;
}
.goods-content{
padding: 10px 0;
height: 80px;
}
.price{
color: #ff1111;
font-size: 16px;
padding-bottom: 3px;
&::before{
content: "¥";
font-size: 14px;
}
}
}
}
.select-item{
position: absolute;
top: 5px;
left: 5px;
::v-deep .el-checkbox__label{
display: none;
}
}
</style>
Loading…
Cancel
Save