From 3c065b99fb13f868987086953bab1c431525dd33 Mon Sep 17 00:00:00 2001 From: RockYang Date: Sat, 30 Aug 2025 16:27:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E4=BB=98=E6=A8=A1=E5=9D=97=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/core/types/order.go | 5 +- api/handler/admin/admin_handler.go | 13 - api/handler/admin/product_handler.go | 15 +- api/handler/order_handler.go | 14 +- api/handler/payment_handler.go | 54 +-- api/main.go | 1 + api/service/migration_service.go | 12 + api/service/payment/wxpay_service.go | 1 + api/store/model/order.go | 2 +- api/store/model/product.go | 20 +- api/utils/strings.go | 14 +- web/src/assets/css/member.scss | 491 ++++++++++++++++++++++----- web/src/components/UserOrder.vue | 2 +- web/src/views/ChatPlus.vue | 6 +- web/src/views/Member.vue | 288 +++++++++------- web/src/views/admin/Order.vue | 21 +- web/src/views/admin/Product.vue | 19 +- 17 files changed, 661 insertions(+), 317 deletions(-) diff --git a/api/core/types/order.go b/api/core/types/order.go index 41096d37..39d7c8c4 100644 --- a/api/core/types/order.go +++ b/api/core/types/order.go @@ -11,9 +11,8 @@ type OrderStatus int const ( OrderNotPaid = OrderStatus(0) - OrderScanned = OrderStatus(1) // 已扫码 - OrderPaidSuccess = OrderStatus(2) - OrderPaidFailed = OrderStatus(3) + OrderPaidSuccess = OrderStatus(2) // 已支付 + OrderPaidFailed = OrderStatus(3) // 已关闭 ) type OrderRemark struct { diff --git a/api/handler/admin/admin_handler.go b/api/handler/admin/admin_handler.go index 6cc60e9d..002096ae 100644 --- a/api/handler/admin/admin_handler.go +++ b/api/handler/admin/admin_handler.go @@ -81,19 +81,6 @@ func (h *ManagerHandler) Login(c *gin.Context) { return } - // if h.App.SysConfig.Base.EnabledVerify { - // var check bool - // if data.X != 0 { - // check = h.captcha.SlideCheck(data) - // } else { - // check = h.captcha.Check(data) - // } - // if !check { - // resp.ERROR(c, "请先完人机验证") - // return - // } - // } - var manager model.AdminUser res := h.DB.Model(&model.AdminUser{}).Where("username = ?", data.Username).First(&manager) if res.Error != nil { diff --git a/api/handler/admin/product_handler.go b/api/handler/admin/product_handler.go index 333ccc76..2202fa6f 100644 --- a/api/handler/admin/product_handler.go +++ b/api/handler/admin/product_handler.go @@ -15,9 +15,10 @@ import ( "geekai/store/vo" "geekai/utils" "geekai/utils/resp" + "time" + "github.com/gin-gonic/gin" "gorm.io/gorm" - "time" ) type ProductHandler struct { @@ -43,9 +44,7 @@ func (h *ProductHandler) Save(c *gin.Context) { Id uint `json:"id"` Name string `json:"name"` Price float64 `json:"price"` - Discount float64 `json:"discount"` Enabled bool `json:"enabled"` - Days int `json:"days"` Power int `json:"power"` CreatedAt int64 `json:"created_at"` } @@ -55,12 +54,10 @@ func (h *ProductHandler) Save(c *gin.Context) { } item := model.Product{ - Name: data.Name, - Price: data.Price, - Discount: data.Discount, - Days: data.Days, - Power: data.Power, - Enabled: data.Enabled} + Name: data.Name, + Price: data.Price, + Power: data.Power, + Enabled: data.Enabled} item.Id = data.Id if item.Id > 0 { item.CreatedAt = time.Unix(data.CreatedAt, 0) diff --git a/api/handler/order_handler.go b/api/handler/order_handler.go index 1dc8d08e..bcdea2d4 100644 --- a/api/handler/order_handler.go +++ b/api/handler/order_handler.go @@ -15,7 +15,6 @@ import ( "geekai/store/vo" "geekai/utils" "geekai/utils/resp" - "time" "github.com/gin-gonic/gin" "gorm.io/gorm" @@ -96,17 +95,8 @@ func (h *OrderHandler) Query(c *gin.Context) { return } - counter := 0 - for { - time.Sleep(time.Second) - var item model.Order - h.DB.Where("order_no = ?", orderNo).First(&item) - if counter >= 15 || item.Status == types.OrderPaidSuccess || item.Status != order.Status { - order.Status = item.Status - break - } - counter++ - } + var item model.Order + h.DB.Where("order_no = ?", orderNo).First(&item) resp.SUCCESS(c, gin.H{"status": order.Status}) } diff --git a/api/handler/payment_handler.go b/api/handler/payment_handler.go index 5d0eeeb8..4069f3bf 100644 --- a/api/handler/payment_handler.go +++ b/api/handler/payment_handler.go @@ -9,7 +9,6 @@ package handler import ( "embed" - "errors" "fmt" "geekai/core" "geekai/core/middleware" @@ -77,17 +76,14 @@ func (h *PaymentHandler) RegisterRoutes() { // 支付回调接口(公开) rg.POST("notify/alipay", h.AlipayNotify) - rg.GET("notify/geek", h.GeekPayNotify) - rg.POST("notify/wechat", h.WechatPayNotify) + rg.GET("notify/epay", h.EPayNotify) + rg.POST("notify/wxpay", h.WxpayNotify) // 需要用户登录的接口 rg.Use(middleware.UserAuthMiddleware(h.App.Config.Session.SecretKey, h.App.Redis)) { - rg.POST("create", h.Pay) + rg.POST("create", h.CreateOrder) } - - // 同步订单状态 - h.StartSyncOrders() } func (h *PaymentHandler) StartSyncOrders() { @@ -116,10 +112,11 @@ func (h *PaymentHandler) SyncOrders() error { } for _, order := range orders { - // 超时15分钟的订单,直接标记为已关闭 + //超时15分钟的订单,直接标记为已关闭 if time.Now().After(order.CreatedAt.Add(time.Minute * 15)) { h.DB.Model(&model.Order{}).Where("id", order.Id).Update("checked", true) - return errors.New("订单超时") + logger.Errorf("订单超时:%v", order) + continue } // 查询订单状态 var res payment.OrderInfo @@ -127,18 +124,22 @@ func (h *PaymentHandler) SyncOrders() error { case payment.PayChannelEpay: res, err = h.epayService.Query(order.OrderNo) if err != nil { - return fmt.Errorf("error with query order info: %v", err) + logger.Errorf("error with query order info: %v", err) + continue } // 微信支付 case payment.PayChannelWX: res, err = h.wxpayService.Query(order.OrderNo) + logger.Debugf("微信支付订单状态:%+v", res) if err != nil { - return fmt.Errorf("error with query order info: %v", err) + logger.Errorf("error with query order info: %v", err) + continue } case payment.PayChannelAL: res, err = h.alipayService.Query(order.OrderNo) if err != nil { - return fmt.Errorf("error with query order info: %v", err) + logger.Errorf("error with query order info: %v", err) + continue } } @@ -148,24 +149,26 @@ func (h *PaymentHandler) SyncOrders() error { "checked": true, "status": types.OrderPaidFailed, }) - return errors.New("订单已关闭") + logger.Errorf("订单已关闭:%v", order) + continue } // 订单未支付,不处理,继续轮询 if !res.Success() { - return nil + continue } // 订单支付成功 err = h.paySuccess(res) if err != nil { - return fmt.Errorf("error with deal order: %v", err) + logger.Errorf("error with deal order: %v", err) + continue } } return nil } -func (h *PaymentHandler) Pay(c *gin.Context) { +func (h *PaymentHandler) CreateOrder(c *gin.Context) { var data struct { PayWay string `json:"pay_way,omitempty"` // 支付方式:支付宝,微信 Pid int `json:"pid,omitempty"` @@ -210,7 +213,7 @@ func (h *PaymentHandler) Pay(c *gin.Context) { if h.config.WxPay.Domain != "" { data.Domain = h.config.WxPay.Domain } - notifyURL = fmt.Sprintf("%s/api/payment/notify/wechat", data.Domain) + notifyURL = fmt.Sprintf("%s/api/payment/notify/wxpay", data.Domain) payURL, err = h.wxpayService.Pay(payment.PayRequest{ OutTradeNo: orderNo, TotalFee: fmt.Sprintf("%d", int(amount*100)), @@ -230,7 +233,7 @@ func (h *PaymentHandler) Pay(c *gin.Context) { if h.config.Epay.Domain != "" { data.Domain = h.config.Epay.Domain } - notifyURL = fmt.Sprintf("%s/api/payment/notify/geek", data.Domain) + notifyURL = fmt.Sprintf("%s/api/payment/notify/epay", data.Domain) params := payment.PayRequest{ OutTradeNo: orderNo, Subject: product.Name, @@ -280,7 +283,7 @@ func (h *PaymentHandler) Pay(c *gin.Context) { if h.config.Epay.Domain != "" { data.Domain = h.config.Epay.Domain } - notifyURL = fmt.Sprintf("%s/api/payment/notify/geek", data.Domain) + notifyURL = fmt.Sprintf("%s/api/payment/notify/epay", data.Domain) params := payment.PayRequest{ OutTradeNo: orderNo, Subject: product.Name, @@ -309,7 +312,6 @@ func (h *PaymentHandler) Pay(c *gin.Context) { // 创建订单 remark := types.OrderRemark{ - Days: product.Days, Power: product.Power, Name: product.Name, Price: product.Price, @@ -377,7 +379,7 @@ func (h *PaymentHandler) paySuccess(info payment.OrderInfo) error { order.Status = types.OrderPaidSuccess order.TradeNo = info.TradeId order.Checked = true - err = h.DB.Updates(&order).Error + err = h.DB.Debug().Updates(&order).Error if err != nil { return fmt.Errorf("error with update order info: %v", err) } @@ -418,14 +420,14 @@ func (h *PaymentHandler) AlipayNotify(c *gin.Context) { c.String(http.StatusOK, "success") } -// GeekPayNotify 支付异步回调 -func (h *PaymentHandler) GeekPayNotify(c *gin.Context) { +// EPayNotify 易支付支付异步回调 +func (h *PaymentHandler) EPayNotify(c *gin.Context) { var params = make(map[string]string) for k := range c.Request.URL.Query() { params[k] = c.Query(k) } - logger.Infof("收到GeekPay订单支付回调:%+v", params) + logger.Infof("收到易支付订单支付回调:%+v", params) // 检查支付状态, 如果未支付,则返回成功 if params["trade_status"] != "TRADE_SUCCESS" { c.String(http.StatusOK, "success") @@ -456,8 +458,8 @@ func (h *PaymentHandler) GeekPayNotify(c *gin.Context) { c.String(http.StatusOK, "success") } -// WechatPayNotify 微信商户支付异步回调 -func (h *PaymentHandler) WechatPayNotify(c *gin.Context) { +// WxpayNotify 微信商户支付异步回调 +func (h *PaymentHandler) WxpayNotify(c *gin.Context) { err := c.Request.ParseForm() if err != nil { c.String(http.StatusOK, "fail") diff --git a/api/main.go b/api/main.go index 71c2221e..8d3e9cd3 100644 --- a/api/main.go +++ b/api/main.go @@ -303,6 +303,7 @@ func main() { }), fx.Invoke(func(s *core.AppServer, h *handler.PaymentHandler) { h.RegisterRoutes() + h.StartSyncOrders() }), fx.Invoke(func(s *core.AppServer, h *admin.ProductHandler) { h.RegisterRoutes() diff --git a/api/service/migration_service.go b/api/service/migration_service.go index 1288af95..223963bf 100644 --- a/api/service/migration_service.go +++ b/api/service/migration_service.go @@ -118,6 +118,18 @@ func (s *MigrationService) TableMigration() { if s.db.Migrator().HasColumn(&model.ChatModel{}, "description") { s.db.Migrator().DropColumn(&model.ChatModel{}, "description") } + if s.db.Migrator().HasColumn(&model.Product{}, "discount") { + s.db.Migrator().DropColumn(&model.Product{}, "discount") + } + if s.db.Migrator().HasColumn(&model.Product{}, "days") { + s.db.Migrator().DropColumn(&model.Product{}, "days") + } + if s.db.Migrator().HasColumn(&model.Product{}, "app_url") { + s.db.Migrator().DropColumn(&model.Product{}, "app_url") + } + if s.db.Migrator().HasColumn(&model.Product{}, "url") { + s.db.Migrator().DropColumn(&model.Product{}, "url") + } } // 迁移配置数据 diff --git a/api/service/payment/wxpay_service.go b/api/service/payment/wxpay_service.go index fc4e100a..89ca27a9 100644 --- a/api/service/payment/wxpay_service.go +++ b/api/service/payment/wxpay_service.go @@ -74,6 +74,7 @@ func (s *WxPayService) Pay(params PayRequest) (string, error) { bm.Set("total", utils.IntValue(params.TotalFee, 0)). Set("currency", "CNY") }) + logger.Debugf("wxpay params: %+v", bm) if params.Device == "mobile" { bm.SetBodyMap("scene_info", func(bm gopay.BodyMap) { bm.Set("payer_client_ip", params.ClientIP) diff --git a/api/store/model/order.go b/api/store/model/order.go index 3fc2a06b..7fb5ce72 100644 --- a/api/store/model/order.go +++ b/api/store/model/order.go @@ -17,7 +17,7 @@ type Order struct { Amount float64 `gorm:"column:amount;type:decimal(10,2);not null;default:0.00;comment:订单金额" json:"amount"` Status types.OrderStatus `gorm:"column:status;type:tinyint(1);not null;default:0;comment:订单状态(0:待支付,1:已扫码,2:支付成功)" json:"status"` Remark string `gorm:"column:remark;type:varchar(255);not null;comment:备注" json:"remark"` - PayTime int64 `gorm:"column:pay_time;type:int;comment:支付时间" json:"pay_time"` + PayTime int64 `gorm:"column:pay_time;type:int(11);comment:支付时间" json:"pay_time"` PayWay string `gorm:"column:pay_way;type:varchar(20);not null;comment:支付方式" json:"pay_way"` Channel string `gorm:"column:channel;type:varchar(30);not null;comment:支付类型渠道:支付宝,微信,聚合支付"` // 支付类型渠道 CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"` diff --git a/api/store/model/product.go b/api/store/model/product.go index f1bcc744..1278ecbb 100644 --- a/api/store/model/product.go +++ b/api/store/model/product.go @@ -6,19 +6,15 @@ import ( // Product 充值产品 type Product struct { - Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + Id uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"` Name string `gorm:"column:name;type:varchar(30);not null;comment:名称" json:"name"` - Price float64 `gorm:"column:price;type:decimal(10,2);not null;default:0.00;comment:价格" json:"price"` - Discount float64 `gorm:"column:discount;type:decimal(10,2);not null;default:0.00;comment:优惠金额" json:"discount"` - Days int `gorm:"column:days;type:smallint;not null;default:0;comment:延长天数" json:"days"` - Power int `gorm:"column:power;type:int;not null;default:0;comment:增加算力值" json:"power"` - Enabled bool `gorm:"column:enabled;type:tinyint(1);not null;default:0;comment:是否启动" json:"enabled"` - Sales int `gorm:"column:sales;type:int;not null;default:0;comment:销量" json:"sales"` - SortNum int `gorm:"column:sort_num;type:tinyint;not null;default:0;comment:排序" json:"sort_num"` - CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"` - UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;not null" json:"updated_at"` - AppUrl string `gorm:"column:app_url;type:varchar(255);comment:App跳转地址" json:"app_url"` - Url string `gorm:"column:url;type:varchar(255);comment:跳转地址" json:"url"` + Price float64 `gorm:"column:price;type:decimal(10,2);not null;default:0.00;comment:价格" json:"price"` + Power int `gorm:"column:power;type:int;not null;default:0;comment:增加算力值" json:"power"` + Enabled bool `gorm:"column:enabled;type:tinyint(1);not null;default:0;comment:是否启动" json:"enabled"` + Sales int `gorm:"column:sales;type:int;not null;default:0;comment:销量" json:"sales"` + SortNum int `gorm:"column:sort_num;type:tinyint;not null;default:0;comment:排序" json:"sort_num"` + CreatedAt time.Time `gorm:"column:created_at;type:datetime;not null" json:"created_at"` + UpdatedAt time.Time `gorm:"column:updated_at;type:datetime;not null" json:"updated_at"` } func (m *Product) TableName() string { diff --git a/api/utils/strings.go b/api/utils/strings.go index 0538163d..1e198a59 100644 --- a/api/utils/strings.go +++ b/api/utils/strings.go @@ -17,8 +17,9 @@ import ( "time" "unicode" - "golang.org/x/crypto/sha3" rand2 "math/rand" + + "golang.org/x/crypto/sha3" ) // RandString generate rand string with specified length @@ -72,7 +73,16 @@ func Str2stamp(str string) int64 { return 0 } - layout := "2006-01-02 15:04:05" + var layout string + if strings.Contains(str, "T") { + layout = "2006-01-02T15:04:05-07:00" + } else { + if len(str) < 12 { + str = str + " 00:00:00" + } + layout = "2006-01-02 15:04:05" + } + t, err := time.ParseInLocation(layout, str, time.Local) if err != nil { return 0 diff --git a/web/src/assets/css/member.scss b/web/src/assets/css/member.scss index db37e31b..83cf9593 100644 --- a/web/src/assets/css/member.scss +++ b/web/src/assets/css/member.scss @@ -81,7 +81,8 @@ width: 100%; height: 100%; z-index: 0; - background: url('data:image/svg+xml;utf8,') no-repeat center/cover; + background: url('data:image/svg+xml;utf8,') + no-repeat center/cover; opacity: 0.08; pointer-events: none; } @@ -99,115 +100,259 @@ } .list-box { + .product-col { + animation: fadeInUp 0.6s ease-out; + animation-fill-mode: both; + + &:nth-child(1) { + animation-delay: 0.1s; + } + &:nth-child(2) { + animation-delay: 0.2s; + } + &:nth-child(3) { + animation-delay: 0.3s; + } + &:nth-child(4) { + animation-delay: 0.4s; + } + &:nth-child(5) { + animation-delay: 0.5s; + } + &:nth-child(6) { + animation-delay: 0.6s; + } + } + .product-item { - // border: 1px solid #666666; - background-color: var(--chat-bg); - border-radius: 6px; + background: linear-gradient(135deg, var(--panel-bg) 0%, var(--chat-bg) 100%); + border-radius: 16px; overflow: hidden; cursor: pointer; - transition: all 0.3s ease; /* 添加过渡效果 */ - margin-bottom: 20px; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + margin-bottom: 24px; + border: 1px solid rgba(255, 255, 255, 0.1); + position: relative; - .image-container { - display: flex; - justify-content: center; + .product-header { + position: relative; - .el-image { - padding: 6px; - - .el-image__inner { - border-radius: 10px; - } - } - } - - .product-title { - display: flex; - padding: 10px; - - .name { - width: 100%; - text-align: center; - font-size: 16px; - font-weight: bold; - color: var(--el-color-primary); - } - } - - .product-info { - padding: 10px 20px; - font-size: 14px; - color: #999999; - - .info-line { - display: flex; - width: 100%; - padding: 5px 0; - - .label { - display: flex; - width: 100%; - } - - .price, .expire, calls { - display: flex; - width: 90px; - justify-content: right; - } - - .discount { - color: #f56c6c; - font-size: 20px; - } - - .expire { - color: #409eff; - } - - .power { - color: #f2cb51; - } - } - - .pay-way { - padding: 10px 0; + .image-container { + position: relative; display: flex; justify-content: center; - flex-wrap: wrap; + padding: 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - .el-button { - margin: 10px 5px 0 5px; - height: 32px; - filter: none; + .el-image { + width: 80px; + height: 80px; + border-radius: 50%; + overflow: hidden; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); + transition: transform 0.3s ease; - .icon-alipay, .icon-wechat-pay { - color: #ffffff; + &:hover { + transform: scale(1.1); } - .icon-qq { - color: #15a6e8; - font-size: 24px; + } + + .image-overlay { + position: absolute; + top: 10px; + right: 10px; + + .vip-badge { + background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%); + color: #333; + padding: 4px 12px; + border-radius: 20px; + font-size: 12px; + font-weight: bold; + box-shadow: 0 4px 12px rgba(255, 215, 0, 0.4); + animation: pulse 2s infinite; } - .icon-jd-pay { - color: var(--text-theme-color); - font-size: 24px; + } + } + + .product-title { + padding: 20px 20px 0; + text-align: center; + + .name { + font-size: 20px; + font-weight: 700; + color: var(--text-theme-color); + margin: 0 0 8px 0; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + } + + .description { + font-size: 14px; + color: var(--text-secondary-color, #666); + margin: 0; + line-height: 1.4; + } + } + } + + .product-content { + padding: 20px; + + .price-section { + text-align: center; + margin-bottom: 20px; + + .price-info { + display: flex; + align-items: baseline; + justify-content: center; + margin-bottom: 8px; + + .currency { + font-size: 18px; + color: #f56c6c; + font-weight: 600; + margin-right: 2px; } - .icon-douyin { - color: #0a0a0a; - font-size: 22px; + + .price-value { + font-size: 32px; + font-weight: 800; + color: #f56c6c; + line-height: 1; } - .icon-paypal { + + .price-unit { font-size: 14px; - color: #009cde; + color: var(--text-secondary-color, #666); + margin-left: 4px; + } + } + + .original-price { + font-size: 12px; + color: #999; + text-decoration: line-through; + } + } + + .features-list { + .feature-item { + display: flex; + align-items: center; + margin-bottom: 8px; + font-size: 14px; + color: var(--text-secondary-color, #666); + + i { + color: #67c23a; + margin-right: 8px; + font-size: 16px; + } + } + } + } + + .product-actions { + padding: 0 20px 20px; + + .payment-buttons { + display: flex; + gap: 12px; + + .payment-btn { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 12px 16px; + border: none; + border-radius: 12px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; + transform: translateZ(0); + + &::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient( + 90deg, + transparent, + rgba(255, 255, 255, 0.2), + transparent + ); + transition: left 0.5s; + } + + &:hover::before { + left: 100%; + } + + &:active { + transform: translateY(1px) scale(0.98); + } + + i { + font-size: 18px; + transition: transform 0.3s ease; + } + + span { + font-weight: 600; + transition: transform 0.3s ease; + } + + &:hover { + i, + span { + transform: scale(1.05); + } + } + + &.wechat-btn { + background: linear-gradient(135deg, #07c160 0%, #06ad56 100%); + color: white; + box-shadow: 0 4px 16px rgba(7, 193, 96, 0.3); + + &:hover { + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(7, 193, 96, 0.4); + background: linear-gradient(135deg, #06ad56 0%, #07c160 100%); + } + } + + &.alipay-btn { + background: linear-gradient(135deg, #1677ff 0%, #0e5fd8 100%); + color: white; + box-shadow: 0 4px 16px rgba(22, 119, 255, 0.3); + + &:hover { + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(22, 119, 255, 0.4); + background: linear-gradient(135deg, #0e5fd8 0%, #1677ff 100%); + } } } } } &:hover { - // box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* 添加阴影效果 */ - transform: translateY(-10px); /* 向上移动10像素 */ - box-shadow: 0 0 10px var(--shadow-color); - background-color: var(--hover-deep-color); + transform: translateY(-8px); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15); + border-color: rgba(102, 126, 234, 0.3); } } } @@ -234,4 +379,168 @@ font-weight: 700; } } -} \ No newline at end of file +} + +// 添加动画效果 +@keyframes pulse { + 0%, + 100% { + transform: scale(1); + opacity: 1; + } + 50% { + transform: scale(1.05); + opacity: 0.8; + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +// 响应式优化 +@media (max-width: 768px) { + .member { + .inner { + .product-box { + .list-box { + .el-col { + width: 100% !important; + margin-bottom: 16px; + } + + .product-item { + .product-header { + .image-container { + padding: 16px; + + .el-image { + width: 60px; + height: 60px; + } + } + + .product-title { + padding: 16px 16px 0; + + .name { + font-size: 18px; + } + } + } + + .product-content { + padding: 16px; + + .price-section { + .price-info { + .price-value { + font-size: 28px; + } + } + } + } + + .product-actions { + padding: 0 16px 16px; + + .payment-buttons { + flex-direction: column; + gap: 8px; + + .payment-btn { + padding: 10px 14px; + } + } + } + } + } + } + } + } +} + +@media (max-width: 480px) { + .member { + .inner { + padding: 10px 0 10px 10px; + + .product-box { + padding: 0 10px; + + .list-box { + .product-item { + margin-bottom: 16px; + + .product-header { + .image-container { + padding: 12px; + + .el-image { + width: 50px; + height: 50px; + } + } + + .product-title { + padding: 12px 12px 0; + + .name { + font-size: 16px; + } + + .description { + font-size: 12px; + } + } + } + + .product-content { + padding: 12px; + + .price-section { + .price-info { + .price-value { + font-size: 24px; + } + + .currency { + font-size: 16px; + } + } + } + + .features-list { + .feature-item { + font-size: 12px; + } + } + } + + .product-actions { + padding: 0 12px 12px; + + .payment-buttons { + .payment-btn { + padding: 8px 12px; + font-size: 12px; + + i { + font-size: 16px; + } + } + } + } + } + } + } + } + } +} diff --git a/web/src/components/UserOrder.vue b/web/src/components/UserOrder.vue index 2923eb9d..eef50bf8 100644 --- a/web/src/components/UserOrder.vue +++ b/web/src/components/UserOrder.vue @@ -18,7 +18,7 @@ {{ scope.row.remark && scope.row.remark.power }} - + - -