积分详情,成长值详情都完成

This commit is contained in:
linbin 2025-08-01 18:23:11 +08:00
parent e6ef4c05df
commit efc51486d5
7 changed files with 894 additions and 498 deletions

View File

@ -1,258 +1,242 @@
# 信息管理系统原型项目
# 信息管理系统演示项目开发约束
## 🚨 核心开发约束(必须严格遵守)
## 🎯 项目定位
**这是一个纯演示项目**,重点在于展示清晰的布局设计和流畅的交互体验。项目不包含实际的业务功能,所有数据均为模拟数据,主要用于:
- 界面原型展示
## 🚨 核心架构约束(必须严格遵守)
### CSS内嵌原则 - 项目核心约束
**所有页面专用CSS必须内嵌到对应的HTML文件中**
#### ✅ 强制要求
1. **CSS内容集成** - 每个页面的专用样式必须写在页面HTML底部的`<style>`标签中
2. **禁止独立CSS文件** - 不允许在css/目录创建页面专用的CSS文件
3. **一文件原则** - 每个页面的HTML、CSS必须在同一个文件中
4. **即时加载** - 页面打开时样式立即生效,无延迟无闪烁
#### ❌ 严禁事项
- **禁止创建独立CSS文件** - 任何页面专用样式都不能单独存储为.css文件
- **禁止JavaScript动态加载CSS** - 不允许在JS中动态创建link标签加载CSS
- **禁止外部样式依赖** - 页面不能依赖外部CSS文件才能正常显示
### 文件分离原则
1. **HTML内容必须独立存储** - 所有页面内容存储在 `pages/` 目录的独立HTML文件中
2. **CSS样式必须独立存储** - 所有样式存储在 `css/` 目录的独立CSS文件中
3. **JavaScript功能必须独立存储** - 所有页面功能存储在 `js/` 目录的独立JS文件中
1. **HTML内容独立存储** - 所有页面内容存储在 `pages/` 目录的独立HTML文件中
2. **JavaScript功能独立存储** - 所有页面功能存储在 `js/` 目录的独立JS文件中
3. **CSS样式内嵌存储** - 所有页面样式内嵌在对应HTML文件的底部
### 严禁事项 ❌
- **禁止在JavaScript中硬编码HTML内容** - 任何HTML标记都不能出现在JS文件中
- **禁止在JavaScript中硬编码CSS样式** - 任何CSS样式都不能出现在JS文件中
- **禁止在HTML中编写大段JavaScript代码** - 仅允许简单的事件调用
- **禁止随意创建新文件** - 优先编辑现有文件,必须创建时需遵循规范
- **禁止破坏现有架构模式** - 必须遵循动态加载和模块化原则
### 必须遵循 ✅
- **所有页面内容存储在pages/目录**
- **所有页面样式存储在css/目录**
- **所有页面功能存储在js/目录**
- **JavaScript仅处理逻辑通过fetch加载HTML和CSS**
- **每个JavaScript模块必须包含初始化函数**
- **使用中文界面文本**
- **遵循文件命名和结构约定**
## 项目概述
这是一个传统的中文信息管理系统原型采用纯HTML/CSS/JavaScript技术栈实现左侧菜单栏 + 中央tab展示区域的经典布局。项目专注于演示系统架构和交互流程严格遵循内容、样式、逻辑三分离原则。
## 文件结构规范
## 📁 标准文件结构
```
merchant/
├── index.html # 主框架页面
├── styles.css # 全局样式文件
├── script.js # 核心JavaScript逻辑
├── css/ # 专用样式目录
│ ├── coupon-modal.css # 优惠券弹窗样式
│ └── ... # 其他专用样式
├── styles.css # 全局通用样式(框架样式)
├── script.js # 核心框架逻辑
├── js/ # 页面功能模块目录
│ ├── level-settings.js # 等级设置页面功能
│ ├── level-edit.js # 等级编辑页面功能
│ └── ... # 其他页面功能
│ ├── feature-name.js # 页面功能逻辑
│ └── ...
├── pages/ # 页面内容目录
│ ├── level-settings.html # 等级设置页面
│ ├── coupon-modal.html # 优惠券弹窗内容
│ └── ... # 其他页面内容
└── CLAUDE.md # 项目文档
│ ├── feature-name.html # 页面内容+内嵌CSS
│ └── ...
└── CLAUDE.md # 本项目文档
```
## 开发流程规范
## 🛠️ 开发流程规范
### 1. 添加新功能的标准流程
### 1. 新增页面的标准流程
#### Step 1: 创建HTML内容文件
#### Step 1: 创建HTML文件(必需)
```bash
# 在pages/目录创建页面内容
# 在pages/目录创建页面文件
pages/feature-name.html
```
#### Step 2: 创建CSS样式文件如需要
```bash
# 在css/目录创建专用样式
css/feature-name.css
#### Step 2: HTML文件标准结构
```html
<!-- 页面内容区域 -->
<div class="page-content">
<!-- 页面HTML结构 -->
<h2>页面标题</h2>
<!-- 其他页面内容 -->
</div>
<!-- 页面专用样式(必需) -->
<style>
/* 页面专用CSS样式 */
.page-content {
/* 样式定义 */
}
/* 其他样式规则 */
</style>
```
#### Step 3: 创建JavaScript功能文件
#### Step 3: 创建JavaScript文件(可选)
```bash
# 在js/目录创建功能逻辑
# 在js/目录创建功能文件
js/feature-name.js
```
#### Step 4: JavaScript模块标准结构
#### Step 4: JavaScript文件标准结构
```javascript
// js/feature-name.js
/**
* 功能模块名称
* 页面功能模块
* 功能描述
*/
// 页面初始化函数(必需)
function initFeatureName() {
console.log('功能模块已初始化');
// 如果需要CSS动态加载
loadFeatureCSS();
// 其他初始化逻辑
}
// 加载专用CSS如需要
function loadFeatureCSS() {
if (!document.getElementById('featureCSS')) {
const link = document.createElement('link');
link.id = 'featureCSS';
link.rel = 'stylesheet';
link.href = 'css/feature-name.css';
document.head.appendChild(link);
}
console.log('页面已初始化');
// 初始化逻辑不包含CSS加载
}
// 功能函数
function someFunction() {
// 功能实现,仅处理逻辑
// 需要HTML时使用fetch加载
// 功能实现
}
// 暴露到全局作用域供HTML调用
window.someFunction = someFunction;
// 页面清理函数(可选)
function cleanupFeatureName() {
// 清理事件监听器等
}
```
### 2. 动态内容加载规范
### 2. CSS样式处理规范
#### HTML内容加载
#### 内嵌CSS标准写法
```html
<style>
/* 页面名称专用样式 */
/* 主要布局样式 */
.main-container {
display: flex;
flex-direction: column;
gap: 20px;
}
/* 组件样式 */
.component-card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* 交互样式 */
.btn:hover {
background-color: #0056b3;
}
/* 响应式样式 */
@media (max-width: 768px) {
.main-container {
padding: 10px;
}
}
</style>
```
#### CSS组织原则
1. **样式分组** - 按布局、组件、交互、响应式分组编写
2. **注释清晰** - 每个样式区块添加注释说明
3. **命名规范** - 使用语义化的CSS类名
4. **优先级管理** - 避免使用!important合理利用CSS优先级
### 3. 页面集成规范
#### 动态加载页面内容
```javascript
// 正确的HTML加载方式
async function loadHTMLContent() {
// 正确的页面加载方式
async function loadPageHTML() {
try {
const response = await fetch('pages/content.html');
const response = await fetch('pages/feature-name.html');
const htmlContent = await response.text();
document.getElementById('container').innerHTML = htmlContent;
// 页面加载完成CSS自动生效
} catch (error) {
console.error('加载失败:', error);
console.error('页面加载失败:', error);
}
}
```
#### CSS样式加载
```javascript
// 正确的CSS加载方式
function loadCSS(cssFile, id) {
if (!document.getElementById(id)) {
const link = document.createElement('link');
link.id = id;
link.rel = 'stylesheet';
link.href = `css/${cssFile}`;
document.head.appendChild(link);
}
}
```
## 🎨 样式系统规范
### 3. 文件命名规范
- **页面文件**: `pages/功能名称.html` (kebab-case)
- **样式文件**: `css/功能名称.css` (kebab-case)
- **脚本文件**: `js/功能名称.js` (kebab-case)
- **初始化函数**: `init[功能名称CamelCase]()`
- **CSS ID**: `功能名称CSS` (CamelCase)
### 全局样式职责
- `styles.css`: 仅包含框架级别的通用样式
- 基础reset样式
- 通用组件样式(按钮、表单等)
- 布局框架样式
- 公共工具类
## 架构特点
### 页面样式职责
- 每个页面HTML中的`<style>`
- 该页面特有的布局样式
- 页面内组件的专用样式
- 页面内的交互效果样式
- 该页面的响应式适配样式
### 三分离原则
1. **内容层(HTML)**: 存储页面结构和内容,不包含样式和逻辑
2. **表现层(CSS)**: 存储样式定义,不包含内容和逻辑
3. **逻辑层(JavaScript)**: 存储交互逻辑通过API加载内容和样式
### 样式冲突防范
1. **命名空间** - 为页面特有样式使用特殊前缀
2. **作用域控制** - 样式选择器尽量具体化
3. **优先级管理** - 页面样式优先级高于全局样式
### 动态加载机制
- **按需加载**: 只有需要时才加载对应的HTML、CSS、JS
- **智能缓存**: 避免重复加载已加载的资源
- **错误处理**: 完整的加载失败降级方案
- **自动初始化**: 自动调用页面对应的初始化函数
## 📐 UI设计原则
### 模块化管理
- **独立开发**: 每个功能模块可独立开发和维护
- **标准接口**: 统一的初始化和清理函数接口
- **全局暴露**: 需要在HTML中调用的函数暴露到window对象
### 布局设计
- **响应式优先** - 所有页面必须支持移动端适配
- **弹性布局** - 使用Flexbox和Grid进行布局
- **统一间距** - 使用统一的间距系统8px基础单位
- **清晰层次** - 通过间距、颜色、字体建立清晰的信息层次
## 核心功能
### 左侧菜单系统
- 一级菜单:主功能模块入口
- 二级菜单:具体功能页面,支持展开/收起
- 互斥展开:同时只能展开一个子菜单
### 中央Tab系统
- 多页面管理支持同时打开多个页面tab
- 防重复打开相同页面直接激活已存在tab
- 智能关闭关闭当前tab时自动激活相邻tab
## 开发示例
### 弹窗功能示例
以优惠券弹窗为例,展示标准的三分离开发模式:
1. **HTML内容** (`pages/coupon-modal.html`)
```html
<div id="couponModal" class="modal-overlay">
<div class="modal-content">
<!-- 弹窗内容结构 -->
</div>
</div>
```
2. **CSS样式** (`css/coupon-modal.css`)
### 色彩系统
```css
.modal-overlay {
/* 弹窗样式定义 */
}
/* 主色调 */
--primary-color: #2563eb; /* 主色 */
--primary-hover: #1d4ed8; /* 主色悬停 */
--success-color: #10b981; /* 成功色 */
--danger-color: #ef4444; /* 危险色 */
--warning-color: #f59e0b; /* 警告色 */
/* 中性色 */
--text-primary: #1f2937; /* 主要文本 */
--text-secondary: #6b7280; /* 次要文本 */
--border-color: #e5e7eb; /* 边框色 */
--background-gray: #f9fafb; /* 灰色背景 */
```
3. **JavaScript逻辑** (`js/level-edit.js`)
```javascript
async function showCouponModal(level) {
// 加载CSS
loadCouponModalCSS();
// 加载HTML
const response = await fetch('pages/coupon-modal.html');
const modalHtml = await response.text();
document.body.insertAdjacentHTML('beforeend', modalHtml);
}
```
### 交互设计
- **视觉反馈** - 所有可交互元素必须有悬停效果
- **加载状态** - 异步操作需要显示加载状态
- **错误处理** - 操作失败要有明确的错误提示
- **操作确认** - 重要操作需要用户确认
## 样式系统
## 📋 开发检查清单
### 全局样式
- `styles.css`: 基础框架样式
- 主题色彩:深蓝色主调,蓝色高亮
### 模块样式
- 每个功能模块可有独立的CSS文件
- 按需动态加载,避免样式冲突
- 使用有意义的CSS类名
## 技术要求
### 运行环境
```bash
# 必须使用HTTP服务器(fetch API要求)
python -m http.server 8000
# 或
npx serve .
```
### 浏览器兼容性
- Chrome 60+ (支持fetch API和ES6 async/await)
- Firefox 55+
- Safari 12+
- Edge 79+
## 项目目标
此项目是快速原型系统,用于演示传统管理系统的布局和交互流程。严格遵循内容、样式、逻辑分离原则,为团队协作和后续开发提供清晰的技术基础。
## 开发检查清单
在开发任何功能前,请确认:
- [ ] 是否创建了独立的HTML文件存储内容
- [ ] 是否创建了独立的CSS文件存储样式
- [ ] JavaScript中是否避免了硬编码HTML和CSS
- [ ] 是否使用fetch API动态加载内容和样式
- [ ] 是否包含了初始化函数?
- [ ] 是否将需要调用的函数暴露到全局作用域?
### 新增页面前检查
- [ ] 是否按照HTML+CSS内嵌结构创建
- [ ] 是否避免了创建独立的CSS文件
- [ ] 页面样式是否完整内嵌在HTML底部
- [ ] JavaScript中是否避免了CSS加载逻辑
- [ ] 文件命名是否遵循kebab-case规范
- [ ] 是否使用了中文界面文本?
**记住:内容、样式、逻辑三分离是本项目的核心原则,违反此原则的代码不被接受。**
## 🎪 演示项目特殊说明
### 数据处理
- **全部使用模拟数据** - 所有数据都在JavaScript中硬编码
- **无后端依赖** - 不需要任何服务器端支持
- **本地存储** - 可以使用localStorage模拟数据持久化
### 功能实现
- **视觉优先** - 重视视觉效果而非功能完整性
- **交互完整** - 确保用户操作有完整的反馈流程
- **流程演示** - 关键业务流程要能完整演示
### 扩展准备
- **模块化设计** - 每个页面独立,便于后续扩展
- **数据结构清晰** - 模拟数据结构接近真实业务数据
- **接口预留** - 为未来对接真实API预留接口
---
**记住这是一个演示项目重点在于清晰的视觉呈现和流畅的交互体验。CSS内嵌是本项目的核心架构原则必须严格遵守。**

View File

@ -1,123 +0,0 @@
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background: white;
border-radius: 8px;
width: 400px;
max-width: 90vw;
max-height: 90vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #eee;
}
.modal-header h3 {
margin: 0;
font-size: 18px;
color: #333;
}
.modal-close {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #999;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.modal-close:hover {
color: #333;
}
.modal-body {
padding: 20px;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 20px;
border-top: 1px solid #eee;
}
.form-group {
margin-bottom: 16px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #333;
}
.required {
color: #e74c3c;
margin-right: 4px;
}
.input-with-dropdown {
position: relative;
display: flex;
}
.input-with-dropdown .form-input {
flex: 1;
padding-right: 40px;
}
.dropdown-btn {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
color: #666;
font-size: 12px;
}
.btn-secondary {
background-color: #f8f9fa;
color: #6c757d;
border: 1px solid #dee2e6;
}
.btn-secondary:hover {
background-color: #e9ecef;
}
.btn-primary {
background-color: #007bff;
color: white;
border: 1px solid #007bff;
}
.btn-primary:hover {
background-color: #0056b3;
}

View File

@ -198,8 +198,6 @@ function addCoupon(level) {
// 显示优惠券添加弹窗
async function showCouponModal(level) {
try {
// 加载CSS样式
loadCouponModalCSS();
// 加载HTML内容
const response = await fetch('pages/coupon-modal.html');
@ -217,16 +215,6 @@ async function showCouponModal(level) {
}
}
// 加载优惠券弹窗CSS
function loadCouponModalCSS() {
if (!document.getElementById('couponModalCSS')) {
const link = document.createElement('link');
link.id = 'couponModalCSS';
link.rel = 'stylesheet';
link.href = 'css/coupon-modal.css';
document.head.appendChild(link);
}
}
// 关闭优惠券弹窗
function closeCouponModal() {

View File

@ -303,7 +303,312 @@ function getMemberData(memberId) {
return mockMembers[memberId] || null;
}
/**
* 显示成长值详情弹窗
* @param {string} changeTime - 变化时间
* @param {string} changeValue - 变化值
* @param {string} relatedOrder - 关联订单
*/
function showGrowthDetail(changeTime, changeValue, relatedOrder) {
const modal = document.getElementById('growthDetailModal');
const content = document.getElementById('growthDetailContent');
if (!modal || !content) return;
// 根据是否有关联订单生成不同的内容
let detailContent = '';
if (relatedOrder && relatedOrder !== '无') {
// 有关联订单的情况
detailContent = `
<div class="detail-section">
<div class="detail-label">变化原因:</div>
<div class="detail-value">订单消费</div>
</div>
<div class="detail-section">
<div class="detail-label">变化时间:</div>
<div class="detail-value">${changeTime}</div>
</div>
<div class="detail-section">
<div class="detail-label">成长值增加:</div>
<div class="detail-value positive">${changeValue}</div>
</div>
<div class="detail-section">
<div class="detail-label">订单编号:</div>
<div class="detail-value">${relatedOrder}</div>
</div>
<div class="detail-section">
<div class="detail-label">订单总金额:</div>
<div class="detail-value">¥${generateOrderAmount()}</div>
</div>
<div class="detail-section">
<div class="detail-label">订单时间:</div>
<div class="detail-value">${changeTime}</div>
</div>
<div class="detail-section">
<div class="detail-label">订单归属据点:</div>
<div class="detail-value">${getRandomStore()}</div>
</div>
<div class="detail-section">
<div class="detail-label">成长值受化:</div>
<div class="detail-value positive">${changeValue}</div>
</div>
`;
} else {
// 无关联订单的情况(系统奖励)
const reason = getSystemRewardReason();
detailContent = `
<div class="detail-section">
<div class="detail-label">变化原因:</div>
<div class="detail-value">${reason}</div>
</div>
<div class="detail-section">
<div class="detail-label">变化时间:</div>
<div class="detail-value">${changeTime}</div>
</div>
<div class="detail-section">
<div class="detail-label">成长值增加:</div>
<div class="detail-value positive">${changeValue}</div>
</div>
<div class="detail-section">
<div class="detail-description">${getRewardDescription(reason)}</div>
</div>
`;
}
content.innerHTML = detailContent;
modal.style.display = 'flex';
// 添加点击背景关闭功能
modal.onclick = function(e) {
if (e.target === modal) {
closeGrowthDetailModal();
}
};
}
/**
* 关闭成长值详情弹窗
*/
function closeGrowthDetailModal() {
const modal = document.getElementById('growthDetailModal');
if (modal) {
modal.style.display = 'none';
}
}
/**
* 生成随机订单金额
* @returns {string} 订单金额
*/
function generateOrderAmount() {
const amounts = ['270.54', '156.88', '89.99', '345.20', '128.50', '298.76', '199.99', '78.30'];
return amounts[Math.floor(Math.random() * amounts.length)];
}
/**
* 获取随机店铺
* @returns {string} 店铺名称
*/
function getRandomStore() {
const stores = ['美食餐厅', '时尚服装店', '数码电子城', '家居生活馆', '运动健身店'];
return stores[Math.floor(Math.random() * stores.length)];
}
/**
* 获取系统奖励原因
* @returns {string} 奖励原因
*/
function getSystemRewardReason() {
const reasons = ['生日奖励', '签到奖励', '活动奖励', '推荐奖励', '完善资料奖励'];
return reasons[Math.floor(Math.random() * reasons.length)];
}
/**
* 获取奖励描述
* @param {string} reason - 奖励原因
* @returns {string} 奖励描述
*/
function getRewardDescription(reason) {
const descriptions = {
'生日奖励': '会员生日当天系统自动发放的生日礼品成长值',
'签到奖励': '会员连续签到获得的成长值奖励',
'活动奖励': '参与平台活动获得的成长值奖励',
'推荐奖励': '成功推荐新会员注册获得的成长值奖励',
'完善资料奖励': '完善个人资料信息获得的成长值奖励'
};
return descriptions[reason] || '系统自动发放的成长值奖励';
}
/**
* 显示积分详情弹窗
* @param {string} changeTime - 变化时间
* @param {string} changeValue - 变化值
* @param {string} relatedOrder - 关联订单
*/
function showPointsDetail(changeTime, changeValue, relatedOrder) {
const modal = document.getElementById('pointsDetailModal');
const content = document.getElementById('pointsDetailContent');
if (!modal || !content) return;
// 根据变化值和关联订单生成不同的内容
let detailContent = '';
if (relatedOrder && relatedOrder !== '无' && !relatedOrder.includes('兑换')) {
// 有关联订单的情况(订单获得积分)
detailContent = `
<div class="detail-section">
<div class="detail-label">变化原因:</div>
<div class="detail-value">订单消费</div>
</div>
<div class="detail-section">
<div class="detail-label">变化时间:</div>
<div class="detail-value">${changeTime}</div>
</div>
<div class="detail-section">
<div class="detail-label">积分变动:</div>
<div class="detail-value ${changeValue.startsWith('+') ? 'positive' : 'negative'}">${changeValue}</div>
</div>
<div class="detail-section">
<div class="detail-label">订单编号:</div>
<div class="detail-value">${relatedOrder}</div>
</div>
<div class="detail-section">
<div class="detail-label">订单总金额:</div>
<div class="detail-value">¥${generateOrderAmount()}</div>
</div>
<div class="detail-section">
<div class="detail-label">订单时间:</div>
<div class="detail-value">${changeTime}</div>
</div>
<div class="detail-section">
<div class="detail-label">订单归属据点:</div>
<div class="detail-value">${getRandomStore()}</div>
</div>
<div class="detail-section">
<div class="detail-label">积分受化:</div>
<div class="detail-value ${changeValue.startsWith('+') ? 'positive' : 'negative'}">${changeValue}</div>
</div>
`;
} else if (relatedOrder && (relatedOrder.includes('兑换'))) {
// 积分消耗的情况(兑换商品/优惠券)
const exchangeType = relatedOrder.includes('商品') ? '商品' : '优惠券';
const exchangeItem = getRandomExchangeItem(exchangeType);
detailContent = `
<div class="detail-section">
<div class="detail-label">变化原因:</div>
<div class="detail-value">${relatedOrder}</div>
</div>
<div class="detail-section">
<div class="detail-label">变化时间:</div>
<div class="detail-value">${changeTime}</div>
</div>
<div class="detail-section">
<div class="detail-label">积分变动:</div>
<div class="detail-value ${changeValue.startsWith('+') ? 'positive' : 'negative'}">${changeValue}</div>
</div>
<div class="detail-section">
<div class="detail-label">兑换${exchangeType}:</div>
<div class="detail-value">${exchangeItem}</div>
</div>
<div class="detail-section">
<div class="detail-label">兑换数量:</div>
<div class="detail-value">1</div>
</div>
<div class="detail-section">
<div class="detail-description">使用${Math.abs(parseInt(changeValue))}积分兑换${exchangeType}兑换成功后积分将被扣除且不可退还</div>
</div>
`;
} else {
// 无关联订单的情况(系统奖励)
const reason = getPointsRewardReason();
detailContent = `
<div class="detail-section">
<div class="detail-label">变化原因:</div>
<div class="detail-value">${reason}</div>
</div>
<div class="detail-section">
<div class="detail-label">变化时间:</div>
<div class="detail-value">${changeTime}</div>
</div>
<div class="detail-section">
<div class="detail-label">积分变动:</div>
<div class="detail-value ${changeValue.startsWith('+') ? 'positive' : 'negative'}">${changeValue}</div>
</div>
<div class="detail-section">
<div class="detail-description">${getPointsRewardDescription(reason)}</div>
</div>
`;
}
content.innerHTML = detailContent;
modal.style.display = 'flex';
// 添加点击背景关闭功能
modal.onclick = function(e) {
if (e.target === modal) {
closePointsDetailModal();
}
};
}
/**
* 关闭积分详情弹窗
*/
function closePointsDetailModal() {
const modal = document.getElementById('pointsDetailModal');
if (modal) {
modal.style.display = 'none';
}
}
/**
* 获取随机兑换商品
* @param {string} type - 兑换类型商品/优惠券
* @returns {string} 兑换物品名称
*/
function getRandomExchangeItem(type) {
if (type === '商品') {
const items = ['精美水杯', '品牌T恤', '蓝牙耳机', '保温饭盒', '无线充电器', '护肤礼盒'];
return items[Math.floor(Math.random() * items.length)];
} else {
const coupons = ['满100减20优惠券', '8折通用优惠券', '满200减50优惠券', '新品9折优惠券', '免运费券'];
return coupons[Math.floor(Math.random() * coupons.length)];
}
}
/**
* 获取积分奖励原因
* @returns {string} 奖励原因
*/
function getPointsRewardReason() {
const reasons = ['签到奖励', '完成任务', '评价奖励', '邀请好友', '活动奖励', '每日任务'];
return reasons[Math.floor(Math.random() * reasons.length)];
}
/**
* 获取积分奖励描述
* @param {string} reason - 奖励原因
* @returns {string} 奖励描述
*/
function getPointsRewardDescription(reason) {
const descriptions = {
'签到奖励': '连续签到获得的积分奖励,每日签到可获得不同数量的积分',
'完成任务': '完成平台指定任务获得的积分奖励',
'评价奖励': '对购买商品进行评价后获得的积分奖励',
'邀请好友': '成功邀请好友注册并消费后获得的积分奖励',
'活动奖励': '参与平台活动获得的积分奖励',
'每日任务': '完成每日任务目标获得的积分奖励'
};
return descriptions[reason] || '系统自动发放的积分奖励';
}
// 暴露全局函数
window.viewMemberDetail_Detail = viewMemberDetail_Detail;
window.switchDetailTab = switchDetailTab;
window.closeMemberDetailTab = closeMemberDetailTab;
window.closeMemberDetailTab = closeMemberDetailTab;
window.showGrowthDetail = showGrowthDetail;
window.closeGrowthDetailModal = closeGrowthDetailModal;
window.showPointsDetail = showPointsDetail;
window.closePointsDetailModal = closePointsDetailModal;

View File

@ -36,4 +36,130 @@
<button class="btn btn-primary" onclick="confirmAddCoupon()">确认添加</button>
</div>
</div>
</div>
</div>
<style>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background: white;
border-radius: 8px;
width: 400px;
max-width: 90vw;
max-height: 90vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #eee;
}
.modal-header h3 {
margin: 0;
font-size: 18px;
color: #333;
}
.modal-close {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #999;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.modal-close:hover {
color: #333;
}
.modal-body {
padding: 20px;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 20px;
border-top: 1px solid #eee;
}
.form-group {
margin-bottom: 16px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #333;
}
.required {
color: #e74c3c;
margin-right: 4px;
}
.input-with-dropdown {
position: relative;
display: flex;
}
.input-with-dropdown .form-input {
flex: 1;
padding-right: 40px;
}
.dropdown-btn {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
color: #666;
font-size: 12px;
}
.btn-secondary {
background-color: #f8f9fa;
color: #6c757d;
border: 1px solid #dee2e6;
}
.btn-secondary:hover {
background-color: #e9ecef;
}
.btn-primary {
background-color: #007bff;
color: white;
border: 1px solid #007bff;
}
.btn-primary:hover {
background-color: #0056b3;
}
</style>

View File

@ -325,4 +325,129 @@
.level-edit-table th:nth-child(7) { width: 80px; } /* 开启生日优惠券 */
.level-edit-table th:nth-child(8) { width: 100px; } /* 生日优惠券操作 */
.level-edit-table th:nth-child(9) { width: 80px; } /* 开启生日双倍积分 */
/* 优惠券弹窗样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background: white;
border-radius: 8px;
width: 400px;
max-width: 90vw;
max-height: 90vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #eee;
}
.modal-header h3 {
margin: 0;
font-size: 18px;
color: #333;
}
.modal-close {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #999;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.modal-close:hover {
color: #333;
}
.modal-body {
padding: 20px;
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 20px;
border-top: 1px solid #eee;
}
.form-group {
margin-bottom: 16px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #333;
}
.required {
color: #e74c3c;
margin-right: 4px;
}
.input-with-dropdown {
position: relative;
display: flex;
}
.input-with-dropdown .form-input {
flex: 1;
padding-right: 40px;
}
.dropdown-btn {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
color: #666;
font-size: 12px;
}
.btn-secondary {
background-color: #f8f9fa;
color: #6c757d;
border: 1px solid #dee2e6;
}
.btn-secondary:hover {
background-color: #e9ecef;
}
.btn-primary {
background-color: #007bff;
color: white;
border: 1px solid #007bff;
}
.btn-primary:hover {
background-color: #0056b3;
}
</style>

View File

@ -72,122 +72,39 @@
<td>2025-07-24 17:20</td>
<td class="positive">+35</td>
<td>ORD9296</td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showGrowthDetail('2025-07-24 17:20', '+35', 'ORD9296'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-07-12 17:20</td>
<td class="positive">+100</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showGrowthDetail('2025-07-12 17:20', '+100', '无'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-07-10 17:20</td>
<td class="positive">+100</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showGrowthDetail('2025-07-10 17:20', '+100', '无'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-06-29 17:20</td>
<td class="positive">+20</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showGrowthDetail('2025-06-29 17:20', '+20', '无'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-06-17 17:20</td>
<td class="positive">+55</td>
<td>ORD2063</td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showGrowthDetail('2025-06-17 17:20', '+55', 'ORD2063'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-06-02 17:20</td>
<td class="positive">+20</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-20 17:20</td>
<td class="positive">+81</td>
<td>ORD5387</td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-16 17:20</td>
<td class="positive">+100</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-10 17:20</td>
<td class="positive">+50</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-04 17:20</td>
<td class="positive">+100</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-25 17:20</td>
<td class="positive">+100</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-18 17:20</td>
<td class="positive">+50</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-16 17:20</td>
<td class="positive">+20</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-04 17:20</td>
<td class="positive">+20</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-01 17:20</td>
<td class="positive">+10</td>
<td>ORD3911</td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-03-24 17:20</td>
<td class="positive">+20</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-03-10 17:20</td>
<td class="positive">+95</td>
<td>ORD8321</td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-02-28 17:20</td>
<td class="positive">+100</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-02-18 17:20</td>
<td class="positive">+100</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-02-04 17:20</td>
<td class="positive">+20</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showGrowthDetail('2025-06-02 17:20', '+20', '无'); return false;">详情</a></td>
</tr>
</tbody>
</table>
</div>
@ -218,110 +135,39 @@
<td>2025-07-24 17:20</td>
<td class="positive">+25</td>
<td>ORD9296</td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showPointsDetail('2025-07-24 17:20', '+25', 'ORD9296'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-07-20 15:30</td>
<td class="negative">-50</td>
<td>兑换商品</td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showPointsDetail('2025-07-20 15:30', '-50', '兑换商品'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-07-12 17:20</td>
<td class="positive">+80</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showPointsDetail('2025-07-12 17:20', '+80', '无'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-07-10 17:20</td>
<td class="positive">+60</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showPointsDetail('2025-07-10 17:20', '+60', '无'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-06-29 17:20</td>
<td class="positive">+15</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showPointsDetail('2025-06-29 17:20', '+15', '无'); return false;">详情</a></td>
</tr>
<tr>
<td>2025-06-25 14:20</td>
<td class="negative">-100</td>
<td>兑换优惠券</td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-06-17 17:20</td>
<td class="positive">+45</td>
<td>ORD2063</td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-06-02 17:20</td>
<td class="positive">+15</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-20 17:20</td>
<td class="positive">+65</td>
<td>ORD5387</td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-16 17:20</td>
<td class="positive">+80</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-12 10:30</td>
<td class="negative">-30</td>
<td>兑换商品</td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-10 17:20</td>
<td class="positive">+40</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-05-04 17:20</td>
<td class="positive">+80</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-25 17:20</td>
<td class="positive">+70</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-18 17:20</td>
<td class="positive">+35</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-16 17:20</td>
<td class="positive">+15</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-04 17:20</td>
<td class="positive">+15</td>
<td></td>
<td><a href="#" class="detail-link">详情</a></td>
</tr>
<tr>
<td>2025-04-01 17:20</td>
<td class="positive">+8</td>
<td>ORD3911</td>
<td><a href="#" class="detail-link">详情</a></td>
<td><a href="#" class="detail-link" onclick="showPointsDetail('2025-06-25 14:20', '-100', '兑换优惠券'); return false;">详情</a></td>
</tr>
</tbody>
</table>
</div>
@ -337,6 +183,36 @@
</div>
</div>
<!-- 成长值详情弹窗 -->
<div id="growthDetailModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-header">
<h3>成长值详情</h3>
<button class="modal-close" onclick="closeGrowthDetailModal()">&times;</button>
</div>
<div class="modal-content">
<div id="growthDetailContent">
<!-- 动态内容将在这里显示 -->
</div>
</div>
</div>
</div>
<!-- 积分详情弹窗 -->
<div id="pointsDetailModal" class="modal-overlay" style="display: none;">
<div class="modal-container">
<div class="modal-header">
<h3>积分详情</h3>
<button class="modal-close" onclick="closePointsDetailModal()">&times;</button>
</div>
<div class="modal-content">
<div id="pointsDetailContent">
<!-- 动态内容将在这里显示 -->
</div>
</div>
</div>
</div>
<style>
/* 会员详情页面样式 */
@ -642,6 +518,108 @@
background: #f3f4f6;
}
/* 成长值详情弹窗样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-container {
background: white;
border-radius: 8px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
max-width: 500px;
width: 90%;
max-height: 80vh;
overflow: hidden;
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
border-bottom: 1px solid #e5e7eb;
background: #f9fafb;
}
.modal-header h3 {
margin: 0;
color: #1f2937;
font-size: 18px;
font-weight: 600;
}
.modal-close {
background: none;
border: none;
font-size: 24px;
color: #6b7280;
cursor: pointer;
padding: 4px;
border-radius: 4px;
transition: all 0.2s ease;
}
.modal-close:hover {
background: #f3f4f6;
color: #374151;
}
.modal-content {
padding: 20px;
overflow-y: auto;
max-height: calc(80vh - 80px);
}
.detail-section {
margin-bottom: 16px;
}
.detail-section:last-child {
margin-bottom: 0;
}
.detail-label {
font-size: 14px;
color: #6b7280;
margin-bottom: 4px;
font-weight: 500;
}
.detail-value {
font-size: 16px;
color: #1f2937;
font-weight: 600;
margin-bottom: 12px;
}
.detail-value.positive {
color: #059669;
}
.detail-value.negative {
color: #dc2626;
}
.detail-description {
font-size: 14px;
color: #6b7280;
line-height: 1.5;
background: #f9fafb;
padding: 12px;
border-radius: 6px;
border-left: 3px solid #e5e7eb;
}
/* 响应式设计 */
@media (max-width: 768px) {
.member-info-content {
@ -676,5 +654,18 @@
gap: 12px;
align-items: flex-start;
}
.modal-container {
margin: 20px;
width: calc(100% - 40px);
}
.modal-header {
padding: 16px;
}
.modal-content {
padding: 16px;
}
}
</style>