From 7a7a9759cafe7a2358bb5f4916cda0cd6091563d Mon Sep 17 00:00:00 2001
From: aaron <>
Date: Sun, 10 Aug 2025 12:20:27 +0800
Subject: [PATCH] first commit
---
.env.example | 11 +
.gitignore | 94 ++++++
README.md | 117 +++++++
package.json | 24 ++
public/admin.html | 116 +++++++
public/css/admin.css | 455 +++++++++++++++++++++++++++
public/css/spinner.css | 6 +
public/css/style.css | 611 +++++++++++++++++++++++++++++++++++++
public/images/image01.jpg | Bin 0 -> 416731 bytes
public/index.html | 163 ++++++++++
public/js/admin.js | 443 +++++++++++++++++++++++++++
public/js/main.js | 369 ++++++++++++++++++++++
public/manual-payment.html | 222 ++++++++++++++
public/success.html | 159 ++++++++++
server.js | 384 +++++++++++++++++++++++
15 files changed, 3174 insertions(+)
create mode 100644 .env.example
create mode 100644 .gitignore
create mode 100644 README.md
create mode 100644 package.json
create mode 100644 public/admin.html
create mode 100644 public/css/admin.css
create mode 100644 public/css/spinner.css
create mode 100644 public/css/style.css
create mode 100644 public/images/image01.jpg
create mode 100644 public/index.html
create mode 100644 public/js/admin.js
create mode 100644 public/js/main.js
create mode 100644 public/manual-payment.html
create mode 100644 public/success.html
create mode 100644 server.js
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..e4e243a
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,11 @@
+# 环境变量配置文件
+# UPay 配置
+UPAY_APP_ID=E7c4dss9
+UPAY_APP_SECRET=Hwc56INsabRau2yn
+
+# 数据库配置
+DB_PATH=./database/shop.db
+
+# 服务器配置
+PORT=3000
+NODE_ENV=development
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d4218e6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,94 @@
+# Dependencies
+node_modules/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Coverage directory used by tools like istanbul
+coverage/
+
+# Dependency directories
+jspm_packages/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# Environment variables
+.env
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# Database files
+*.db
+*.sqlite
+database/*.db
+
+# Logs
+logs/
+*.log
+
+# Runtime data
+tmp/
+temp/
+
+# macOS
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# Windows
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+
+# Linux
+*~
+
+# Editor directories and files
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+
+# OS generated files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# Payment config files (if any)
+config/payment-keys.json
+config/secrets.json
+payment-config.json
+
+# Backup files
+*.bak
+*.backup
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..eca666a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,117 @@
+# USDT 支付商城
+
+这是一个基于 Node.js 和 UPay API 的 USDT 支付商城系统。
+
+## 功能特性
+
+- 📱 现代化响应式设计
+- 💰 USDT 加密货币支付
+- 🛒 简洁的购买流程
+- 📦 订单管理系统
+- 🔒 安全的支付处理
+- 📊 实时支付状态跟踪
+
+## 技术栈
+
+- **后端**: Node.js + Express
+- **数据库**: SQLite3
+- **支付**: UPay API (USDT支付)
+- **前端**: 原生 JavaScript + CSS3
+- **样式**: CSS Grid + Flexbox
+
+## 安装和运行
+
+1. 克隆项目并安装依赖:
+```bash
+npm install
+```
+
+2. 配置 UPay API:
+```bash
+# 设置环境变量
+export UPAY_APP_ID=your-upay-app-id
+export UPAY_APP_SECRET=your-upay-app-secret
+```
+
+3. 启动服务器:
+```bash
+# 开发模式
+npm run dev
+
+# 生产模式
+npm start
+```
+
+4. 访问 http://localhost:3000
+
+## 项目结构
+
+```
+myusdtshop/
+├── server.js # 主服务器文件
+├── package.json # 项目配置
+├── database/ # SQLite 数据库文件
+├── public/ # 前端静态文件
+│ ├── index.html # 主页面
+│ ├── css/
+│ │ └── style.css # 样式文件
+│ ├── js/
+│ │ └── main.js # JavaScript 逻辑
+│ └── images/ # 图片资源
+```
+
+## API 接口
+
+- `GET /api/products` - 获取产品信息
+- `POST /api/orders` - 创建订单
+- `POST /api/payment/create` - 创建支付
+- `POST /api/payment/callback` - 支付回调
+- `GET /api/orders/:order_id` - 获取订单状态
+
+## 使用说明
+
+### 配置 UPay
+
+1. 在 [UPay](https://upay.ink) 注册商户账户
+2. 获取 App ID 和 App Secret
+3. 设置环境变量或修改 server.js 中的配置
+
+### 自定义产品
+
+修改 server.js 中的 `PRODUCTS` 对象:
+
+```javascript
+const PRODUCTS = {
+ 'your-product-id': {
+ name: '您的产品名称',
+ price: 99.99,
+ description: '产品描述'
+ }
+};
+```
+
+### 支付流程
+
+1. 用户选择产品和数量
+2. 填写收货信息
+3. 创建订单
+4. 跳转到支付页面完成 USDT 支付
+5. 系统通过回调自动确认支付状态
+
+## UPay 集成特性
+
+- 支持 USDT 直接转账到商户钱包
+- 实时支付状态回调通知
+- MD5 签名验证确保安全
+- 支持多种支付状态处理
+
+## 安全注意事项
+
+- 请勿将 App Secret 提交到版本控制
+- 生产环境请使用 HTTPS
+- 定期备份数据库
+- 验证所有支付回调签名
+
+## 许可证
+
+ISC License
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..dda5dd5
--- /dev/null
+++ b/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "usdt-shop",
+ "version": "1.0.0",
+ "description": "USDT Payment Product Sales Website",
+ "main": "server.js",
+ "scripts": {
+ "start": "node server.js",
+ "dev": "nodemon server.js"
+ },
+ "dependencies": {
+ "express": "^4.18.2",
+ "sqlite3": "^5.1.6",
+ "axios": "^1.6.0",
+ "cors": "^2.8.5",
+ "body-parser": "^1.20.2",
+ "crypto": "^1.0.1"
+ },
+ "devDependencies": {
+ "nodemon": "^3.0.1"
+ },
+ "keywords": ["usdt", "payment", "shop", "nowpayments"],
+ "author": "Aaron",
+ "license": "ISC"
+}
\ No newline at end of file
diff --git a/public/admin.html b/public/admin.html
new file mode 100644
index 0000000..e10344b
--- /dev/null
+++ b/public/admin.html
@@ -0,0 +1,116 @@
+
+
+
+
+
+ 订单管理系统
+ 管理所有订单信息和发货状态
+
+
+
+
+
总订单数
+ 0
+
+
+
已支付未发货
+ 0
+
+
+
已发货
+ 0
+
+
+
+
+
+
+
+
+
+
+ | 订单号 |
+ 客户信息 |
+ 产品 |
+ 金额 |
+ 支付状态 |
+ 发货状态 |
+ 创建时间 |
+ 操作 |
+
+
+
+
+ | 加载中... |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/css/admin.css b/public/css/admin.css
new file mode 100644
index 0000000..f071409
--- /dev/null
+++ b/public/css/admin.css
@@ -0,0 +1,455 @@
+/* 订单管理页面样式 */
+
+/* 管理员导航 - 已移除 */
+
+/* 统计卡片 */
+.stats-section {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 20px;
+ margin-bottom: 30px;
+}
+
+.stat-card {
+ background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
+ padding: 25px;
+ border-radius: 15px;
+ text-align: center;
+ border: 1px solid #444;
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
+ position: relative;
+ overflow: hidden;
+}
+
+.stat-card::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 3px;
+ background: linear-gradient(90deg, #ffd700, #ffed4a);
+}
+
+.stat-card h3 {
+ color: #b0b0b0;
+ font-size: 1.1em;
+ margin-bottom: 10px;
+ font-weight: 500;
+}
+
+.stat-card span {
+ color: #ffd700;
+ font-size: 2.2em;
+ font-weight: bold;
+ display: block;
+ text-shadow: 0 0 20px rgba(255, 215, 0, 0.3);
+}
+
+/* 订单表格区域 */
+.orders-section {
+ background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
+ border-radius: 15px;
+ padding: 30px;
+ border: 1px solid #444;
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
+}
+
+.section-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 25px;
+ padding-bottom: 15px;
+ border-bottom: 1px solid #333;
+ flex-wrap: wrap;
+ gap: 15px;
+}
+
+.section-header h2 {
+ color: #ffffff;
+ font-size: 1.5em;
+ margin: 0;
+}
+
+.header-controls {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ flex-wrap: wrap;
+}
+
+.search-box {
+ display: flex;
+ gap: 10px;
+}
+
+.search-box input {
+ padding: 10px 15px;
+ background: #0a0a0a;
+ border: 2px solid #444;
+ border-radius: 8px;
+ color: #e0e0e0;
+ width: 250px;
+ font-size: 14px;
+}
+
+.search-box input:focus {
+ outline: none;
+ border-color: #ffd700;
+ box-shadow: 0 0 15px rgba(255, 215, 0, 0.2);
+}
+
+.search-btn {
+ padding: 10px 18px;
+ background: linear-gradient(135deg, #ffd700, #ffed4a);
+ color: #000;
+ border: none;
+ border-radius: 8px;
+ cursor: pointer;
+ font-weight: bold;
+ transition: all 0.3s ease;
+}
+
+.search-btn:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 5px 15px rgba(255, 215, 0, 0.3);
+}
+
+.section-header select {
+ padding: 10px 15px;
+ background: #0a0a0a;
+ border: 2px solid #444;
+ border-radius: 8px;
+ color: #e0e0e0;
+ font-size: 14px;
+ min-width: 120px;
+}
+
+.section-header select:focus {
+ outline: none;
+ border-color: #ffd700;
+}
+
+/* 表格容器 */
+.orders-table-container {
+ overflow-x: auto;
+ background: #0a0a0a;
+ border-radius: 10px;
+ border: 1px solid #333;
+}
+
+.orders-table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: 14px;
+}
+
+.orders-table th {
+ background: linear-gradient(145deg, #2d2d2d, #3d3d3d);
+ color: #ffd700;
+ padding: 15px 12px;
+ text-align: left;
+ font-weight: bold;
+ border-bottom: 2px solid #444;
+ position: sticky;
+ top: 0;
+ z-index: 10;
+}
+
+.orders-table td {
+ padding: 12px;
+ border-bottom: 1px solid #333;
+ color: #e0e0e0;
+ vertical-align: middle;
+}
+
+.orders-table tbody tr {
+ transition: background-color 0.3s ease;
+}
+
+.orders-table tbody tr:hover {
+ background-color: rgba(255, 215, 0, 0.05);
+}
+
+.loading {
+ text-align: center;
+ color: #b0b0b0;
+ font-style: italic;
+ padding: 50px !important;
+}
+
+/* 状态标签 */
+.status-badge {
+ display: inline-block;
+ padding: 4px 10px;
+ border-radius: 12px;
+ font-size: 12px;
+ font-weight: bold;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.status-pending {
+ background: rgba(255, 193, 7, 0.2);
+ color: #ffc107;
+ border: 1px solid #ffc107;
+}
+
+.status-finished {
+ background: rgba(40, 167, 69, 0.2);
+ color: #28a745;
+ border: 1px solid #28a745;
+}
+
+.status-shipped {
+ background: rgba(0, 123, 255, 0.2);
+ color: #007bff;
+ border: 1px solid #007bff;
+}
+
+.status-completed {
+ background: rgba(108, 117, 125, 0.2);
+ color: #6c757d;
+ border: 1px solid #6c757d;
+}
+
+.status-failed {
+ background: rgba(220, 53, 69, 0.2);
+ color: #dc3545;
+ border: 1px solid #dc3545;
+}
+
+/* 操作按钮 */
+.action-btn {
+ padding: 6px 12px;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 12px;
+ font-weight: bold;
+ margin-right: 5px;
+ margin-bottom: 4px;
+ transition: all 0.3s ease;
+ display: inline-block;
+}
+
+.btn-copy {
+ background: linear-gradient(135deg, #3498db, #2980b9);
+ color: #fff;
+ border: 1px solid #3498db;
+}
+
+.btn-copy:hover {
+ background: linear-gradient(135deg, #2980b9, #1f639a);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(52, 152, 219, 0.4);
+}
+
+.btn-ship {
+ background: linear-gradient(135deg, #ffd700, #ffed4a);
+ color: #000;
+ border: 1px solid #ffd700;
+}
+
+.btn-ship:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(255, 215, 0, 0.4);
+}
+
+/* 订单详情模态框 */
+.order-detail-content {
+ color: #e0e0e0;
+}
+
+.detail-section {
+ margin-bottom: 25px;
+ padding: 20px;
+ background: linear-gradient(145deg, #0a0a0a, #1a1a1a);
+ border-radius: 10px;
+ border: 1px solid #333;
+}
+
+.detail-section h4 {
+ color: #ffd700;
+ margin-bottom: 15px;
+ font-size: 1.1em;
+ padding-bottom: 8px;
+ border-bottom: 1px solid #333;
+}
+
+.detail-row {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ padding: 8px 0;
+}
+
+.detail-row:last-child {
+ margin-bottom: 0;
+}
+
+.detail-label {
+ font-weight: bold;
+ color: #b0b0b0;
+}
+
+.detail-value {
+ color: #e0e0e0;
+}
+
+/* 发货表单 */
+.shipping-form .form-group {
+ margin-bottom: 20px;
+}
+
+.shipping-form label {
+ display: block;
+ margin-bottom: 8px;
+ color: #ffffff;
+ font-weight: 600;
+}
+
+.shipping-form input,
+.shipping-form select,
+.shipping-form textarea {
+ width: 100%;
+ padding: 12px;
+ background: #0a0a0a;
+ border: 2px solid #444;
+ border-radius: 8px;
+ color: #e0e0e0;
+ font-size: 14px;
+}
+
+.shipping-form input:focus,
+.shipping-form select:focus,
+.shipping-form textarea:focus {
+ outline: none;
+ border-color: #ffd700;
+ box-shadow: 0 0 15px rgba(255, 215, 0, 0.2);
+}
+
+.form-actions {
+ display: flex;
+ gap: 15px;
+ justify-content: flex-end;
+ margin-top: 25px;
+}
+
+.btn-primary {
+ padding: 12px 25px;
+ background: linear-gradient(135deg, #ffd700, #ffed4a);
+ color: #000;
+ border: none;
+ border-radius: 8px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.btn-primary:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(255, 215, 0, 0.4);
+}
+
+.btn-secondary {
+ padding: 12px 25px;
+ background: linear-gradient(145deg, #333, #444);
+ color: #e0e0e0;
+ border: 1px solid #555;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.btn-secondary:hover {
+ background: linear-gradient(145deg, #444, #555);
+ transform: translateY(-2px);
+}
+
+/* 复制按钮样式 */
+.copy-btn {
+ background: none;
+ border: none;
+ color: #ffd700;
+ cursor: pointer;
+ font-size: 12px;
+ margin-left: 8px;
+ padding: 2px 4px;
+ border-radius: 3px;
+ transition: all 0.3s ease;
+ opacity: 0.7;
+}
+
+.copy-btn:hover {
+ opacity: 1;
+ background: rgba(255, 215, 0, 0.1);
+ transform: scale(1.1);
+}
+
+/* 复制成功提示 */
+.copy-toast {
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ background: linear-gradient(135deg, #00ff88, #00cc6a);
+ color: #000;
+ padding: 12px 20px;
+ border-radius: 8px;
+ font-weight: bold;
+ font-size: 14px;
+ z-index: 9999;
+ box-shadow: 0 8px 25px rgba(0, 255, 136, 0.3);
+ animation: slideIn 0.3s ease-out;
+}
+
+@keyframes slideIn {
+ from {
+ transform: translateX(100%);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+ .stats-section {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .section-header {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .header-controls {
+ justify-content: space-between;
+ }
+
+ .search-box input {
+ width: 180px;
+ }
+
+ .orders-table {
+ font-size: 12px;
+ }
+
+ .orders-table th,
+ .orders-table td {
+ padding: 8px 6px;
+ }
+
+ .action-btn {
+ padding: 4px 8px;
+ font-size: 11px;
+ }
+
+ .copy-btn {
+ font-size: 10px;
+ margin-left: 4px;
+ }
+}
\ No newline at end of file
diff --git a/public/css/spinner.css b/public/css/spinner.css
new file mode 100644
index 0000000..3142828
--- /dev/null
+++ b/public/css/spinner.css
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/public/css/style.css b/public/css/style.css
new file mode 100644
index 0000000..acd1164
--- /dev/null
+++ b/public/css/style.css
@@ -0,0 +1,611 @@
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Arial', 'Microsoft YaHei', sans-serif;
+ line-height: 1.6;
+ color: #e0e0e0;
+ background: #0a0a0a;
+ min-height: 100vh;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+main {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 40px;
+ align-items: start;
+ position: relative;
+}
+
+/* 订单管理按钮 */
+.admin-floating-btn {
+ position: fixed;
+ top: 30px;
+ right: 30px;
+ z-index: 1000;
+ background: linear-gradient(135deg, #ffd700, #ffed4a);
+ color: #000;
+ border: none;
+ border-radius: 50px;
+ padding: 12px 25px;
+ font-size: 14px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ box-shadow: 0 4px 15px rgba(255, 215, 0, 0.3);
+}
+
+.admin-floating-btn:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 8px 25px rgba(255, 215, 0, 0.5);
+}
+
+/* 产品卡片 */
+.product-section {
+ background: linear-gradient(145deg, #1a1a1a 0%, #2d2d2d 100%);
+ border-radius: 20px;
+ padding: 30px;
+ box-shadow:
+ 0 20px 40px rgba(0, 0, 0, 0.4),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ border: 1px solid #333;
+}
+
+.product-card {
+ text-align: center;
+}
+
+.product-image {
+ width: 100%;
+ height: 280px;
+ background: linear-gradient(135deg, #333 0%, #444 100%);
+ border-radius: 15px;
+ margin-bottom: 25px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ border: 2px solid #444;
+ position: relative;
+}
+
+.product-image::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(45deg, transparent 49%, rgba(255, 215, 0, 0.1) 50%, transparent 51%);
+ pointer-events: none;
+}
+
+.product-image img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ object-position: center;
+ border-radius: 10px;
+}
+
+.product-info h2 {
+ color: #ffffff;
+ margin-bottom: 15px;
+ font-size: 2em;
+ font-weight: 600;
+}
+
+.product-description {
+ color: #b0b0b0;
+ margin-bottom: 25px;
+ line-height: 1.6;
+ font-size: 1.1em;
+}
+
+.price {
+ font-size: 2.2em;
+ font-weight: bold;
+ margin-bottom: 20px;
+ background: linear-gradient(45deg, #ffd700, #ffed4a);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ text-shadow: 0 0 20px rgba(255, 215, 0, 0.3);
+}
+
+.price .currency,
+.price .unit {
+ font-size: 0.7em;
+ color: #888;
+}
+
+/* 订单表单 */
+.order-section {
+ background: linear-gradient(145deg, #1a1a1a 0%, #2d2d2d 100%);
+ border-radius: 20px;
+ padding: 30px;
+ box-shadow:
+ 0 20px 40px rgba(0, 0, 0, 0.4),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ border: 1px solid #333;
+}
+
+.form-group {
+ margin-bottom: 25px;
+}
+
+.form-group label {
+ display: block;
+ margin-bottom: 8px;
+ font-weight: 600;
+ color: #ffffff;
+ font-size: 1.1em;
+}
+
+.form-group input,
+.form-group textarea {
+ width: 100%;
+ padding: 15px;
+ border: 2px solid #444;
+ border-radius: 10px;
+ font-size: 16px;
+ background: #0a0a0a;
+ color: #e0e0e0;
+ transition: all 0.3s ease;
+}
+
+.form-group input:focus,
+.form-group textarea:focus {
+ outline: none;
+ border-color: #ffd700;
+ box-shadow: 0 0 20px rgba(255, 215, 0, 0.2);
+ background: #1a1a1a;
+}
+
+.form-group input::placeholder,
+.form-group textarea::placeholder {
+ color: #666;
+}
+
+/* 数量控制 */
+.quantity-controls {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin-bottom: 20px;
+ justify-content: center;
+}
+
+.quantity-controls button {
+ width: 45px;
+ height: 45px;
+ border: 2px solid #ffd700;
+ background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
+ color: #ffd700;
+ border-radius: 50%;
+ font-size: 20px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-weight: bold;
+}
+
+.quantity-controls button:hover {
+ background: linear-gradient(145deg, #ffd700, #ffed4a);
+ color: #000;
+ transform: scale(1.05);
+ box-shadow: 0 8px 20px rgba(255, 215, 0, 0.3);
+}
+
+.quantity-controls input {
+ width: 80px;
+ text-align: center;
+ margin: 0;
+ font-weight: bold;
+ font-size: 18px;
+}
+
+.total-price {
+ font-size: 1.3em;
+ font-weight: bold;
+ text-align: center;
+ padding: 15px;
+ background: linear-gradient(145deg, #0a0a0a, #1a1a1a);
+ border-radius: 10px;
+ border: 2px solid #333;
+ background: linear-gradient(45deg, #ffd700, #ffed4a);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+/* 按钮 */
+.order-btn {
+ width: 100%;
+ padding: 18px;
+ background: linear-gradient(135deg, #ffd700 0%, #ffed4a 100%);
+ color: #000;
+ border: none;
+ border-radius: 12px;
+ font-size: 18px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ position: relative;
+ overflow: hidden;
+}
+
+.order-btn::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;
+}
+
+.order-btn:hover::before {
+ left: 100%;
+}
+
+.order-btn:hover {
+ transform: translateY(-3px);
+ box-shadow: 0 15px 35px rgba(255, 215, 0, 0.4);
+}
+
+.order-btn:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ transform: none;
+}
+
+/* 模态框 */
+.modal {
+ position: fixed;
+ z-index: 1000;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.8);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ backdrop-filter: blur(5px);
+}
+
+.modal-content {
+ background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
+ padding: 0;
+ border-radius: 20px;
+ width: 90%;
+ max-width: 500px;
+ max-height: 90vh;
+ overflow: hidden;
+ border: 1px solid #444;
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
+}
+
+.modal-header {
+ background: linear-gradient(135deg, #ffd700 0%, #ffed4a 100%);
+ color: #000;
+ padding: 25px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.modal-header h3 {
+ margin: 0;
+ font-size: 1.4em;
+ font-weight: bold;
+}
+
+.close {
+ color: #000;
+ font-size: 28px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: opacity 0.3s;
+}
+
+.close:hover {
+ opacity: 0.7;
+}
+
+.modal-body {
+ padding: 30px;
+ background: #1a1a1a;
+}
+
+.order-summary {
+ margin-bottom: 30px;
+}
+
+.order-summary h4 {
+ color: #ffffff;
+ margin-bottom: 20px;
+ font-size: 1.3em;
+ font-weight: 600;
+}
+
+.summary-item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 12px;
+ padding: 10px 0;
+ border-bottom: 1px solid #333;
+ color: #e0e0e0;
+}
+
+.summary-item:last-child {
+ border-bottom: none;
+ font-weight: bold;
+ color: #ffd700;
+ font-size: 1.1em;
+}
+
+.payment-section {
+ text-align: center;
+ padding: 25px;
+ background: linear-gradient(145deg, #0a0a0a, #1a1a1a);
+ border-radius: 12px;
+ border: 1px solid #333;
+}
+
+.payment-section p {
+ color: #b0b0b0;
+ margin-bottom: 20px;
+ font-size: 1.1em;
+}
+
+.pay-btn {
+ background: linear-gradient(135deg, #ffd700, #ffed4a);
+ color: #000;
+ border: none;
+ padding: 15px 35px;
+ border-radius: 10px;
+ font-size: 16px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+.pay-btn:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 10px 25px rgba(255, 215, 0, 0.4);
+}
+
+/* 支付状态 */
+.payment-status {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: #0a0a0a;
+ z-index: 2000;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.status-content {
+ text-align: center;
+ padding: 50px;
+ background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
+ border-radius: 20px;
+ border: 1px solid #444;
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
+}
+
+.status-icon {
+ width: 100px;
+ height: 100px;
+ margin: 0 auto 30px;
+}
+
+.loading-spinner {
+ width: 100px;
+ height: 100px;
+ border: 6px solid #333;
+ border-top: 6px solid #ffd700;
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+.status-content h3 {
+ color: #ffffff;
+ margin-bottom: 15px;
+ font-size: 2em;
+}
+
+.status-content p {
+ color: #b0b0b0;
+ margin-bottom: 30px;
+ font-size: 1.2em;
+}
+
+.order-info {
+ background: linear-gradient(145deg, #0a0a0a, #1a1a1a);
+ padding: 25px;
+ border-radius: 12px;
+ margin-bottom: 30px;
+ border: 1px solid #333;
+}
+
+.order-info p {
+ margin-bottom: 12px;
+ color: #e0e0e0;
+ font-size: 1.1em;
+}
+
+.status-btn {
+ background: linear-gradient(135deg, #ffd700, #ffed4a);
+ color: #000;
+ border: none;
+ padding: 15px 35px;
+ border-radius: 10px;
+ font-size: 16px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+.status-btn:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 10px 25px rgba(255, 215, 0, 0.4);
+}
+
+/* 成功/失败图标 */
+.success-icon {
+ color: #00ff88;
+ font-size: 100px;
+ text-shadow: 0 0 30px rgba(0, 255, 136, 0.5);
+}
+
+.error-icon {
+ color: #ff4757;
+ font-size: 100px;
+ text-shadow: 0 0 30px rgba(255, 71, 87, 0.5);
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+ main {
+ grid-template-columns: 1fr;
+ gap: 30px;
+ }
+
+ .product-section,
+ .order-section {
+ padding: 25px;
+ }
+
+ .modal-content {
+ width: 95%;
+ margin: 10px;
+ }
+
+ .modal-body {
+ padding: 25px;
+ }
+
+ .status-content {
+ padding: 30px;
+ margin: 20px;
+ }
+
+ .admin-floating-btn {
+ top: 20px;
+ right: 20px;
+ padding: 10px 20px;
+ font-size: 12px;
+ }
+}
+
+/* 管理员登录表单样式 */
+.login-form .form-group {
+ margin-bottom: 20px;
+}
+
+.login-form label {
+ display: block;
+ margin-bottom: 8px;
+ color: #ffffff;
+ font-weight: 600;
+}
+
+.login-form input {
+ width: 100%;
+ padding: 12px 15px;
+ background: #0a0a0a;
+ border: 2px solid #444;
+ border-radius: 8px;
+ color: #e0e0e0;
+ font-size: 16px;
+ transition: all 0.3s ease;
+}
+
+.login-form input:focus {
+ outline: none;
+ border-color: #ffd700;
+ box-shadow: 0 0 15px rgba(255, 215, 0, 0.2);
+ background: #1a1a1a;
+}
+
+.login-form .form-actions {
+ display: flex;
+ gap: 15px;
+ justify-content: flex-end;
+ margin-top: 25px;
+}
+
+.login-form .btn-primary {
+ padding: 12px 25px;
+ background: linear-gradient(135deg, #ffd700, #ffed4a);
+ color: #000;
+ border: none;
+ border-radius: 8px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+.login-form .btn-primary:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 20px rgba(255, 215, 0, 0.4);
+}
+
+.login-form .btn-secondary {
+ padding: 12px 25px;
+ background: linear-gradient(145deg, #333, #444);
+ color: #e0e0e0;
+ border: 1px solid #555;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+}
+
+.login-form .btn-secondary:hover {
+ background: linear-gradient(145deg, #444, #555);
+ transform: translateY(-2px);
+}
+
+.error-message {
+ color: #ff4757;
+ font-size: 14px;
+ margin-top: 10px;
+ padding: 8px 12px;
+ background: rgba(255, 71, 87, 0.1);
+ border: 1px solid #ff4757;
+ border-radius: 6px;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/public/images/image01.jpg b/public/images/image01.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..14ebe9f93f2f6cc43146ba491517a1ef75f243a3
GIT binary patch
literal 416731
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