# 智步楼梯灯AI订单助手 v1.8 升级部署方案

## 项目信息确认

| 项目 | 信息 |
|------|------|
| **项目名称** | 智步楼梯灯AI订单助手 |
| **当前版本** | v1.7 |
| **升级版本** | v1.8 |
| **本地路径** | `/home/maocai/.openclaw/workspace/tools/stair-order/` (待确认) |
| **FRP端口** | 本地端口 → 阿里云7008端口 |
| **访问地址** | https://tools.we-smart.cn/stair-order/ |
| **Nginx配置** | `/etc/nginx/conf.d/tools.conf` |

---

## v1.8 版本更新内容

### 主要修复
1. **订单导出换行问题修复** - 使用 `\r\n` 换行符，确保Excel正常显示
2. **添加BOM头** - 解决中文乱码问题
3. **CSV特殊字符转义** - 处理逗号、引号等特殊字符

### 新增功能
1. **多格式导出支持** - CSV、Excel、文本格式
2. **导出选项下拉菜单** - 更友好的用户界面

---

## 部署步骤

### 步骤1：确认本地项目路径

请确认本地项目路径，通常是：
```bash
# 可能的路径
/home/maocai/.openclaw/workspace/tools/stair-order/
/root/.openclaw/workspace/tools/stair-order/
/www/tools/stair-order/
```

### 步骤2：备份 v1.7 版本

```bash
# 进入项目目录
cd /home/maocai/.openclaw/workspace/tools/stair-order/

# 备份 v1.7
mv stair-order stair-order-v1.7-backup

# 或者复制一份
 cp -r stair-order stair-order-v1.7-backup-$(date +%Y%m%d)
```

### 步骤3：创建 v1.8 版本

```bash
# 创建新版本目录
mkdir stair-order-v1.8

# 复制 v1.7 文件到新版本
cp -r stair-order-v1.7-backup/* stair-order-v1.8/

# 进入新版本目录
cd stair-order-v1.8
```

### 步骤4：修改导出功能代码

找到导出功能的JavaScript文件（通常是 `app.js` 或 `export.js`），替换为以下代码：

```javascript
// ============================================
// 智步楼梯灯AI订单助手 v1.8 - 导出功能
// 更新日期：2026-04-21
// 更新内容：修复CSV换行问题，支持多格式导出
// ============================================

// 当前订单数据（全局变量）
let currentOrderData = null;

// 设置当前订单数据
function setOrderData(orderData) {
    currentOrderData = orderData;
}

// 导出订单为CSV格式
function exportOrderToCSV(orderData) {
    if (!orderData) {
        alert('请先创建订单');
        return;
    }
    
    // CSV表头
    const headers = ['楼层', '踏步编号', '尺寸(mm)', '数量', '备注'];
    
    // 构建CSV内容 - 使用 \r\n 确保Windows和Mac都能正常换行
    let csvContent = '\uFEFF'; // 添加BOM，确保中文不乱码
    csvContent += headers.join(',') + '\r\n'; // 表头换行
    
    // 添加数据行
    orderData.items.forEach(item => {
        const row = [
            escapeCSV(item.floor),
            escapeCSV(item.stepNumber),
            escapeCSV(item.size),
            item.quantity || 1,
            escapeCSV(item.note)
        ];
        csvContent += row.join(',') + '\r\n'; // 每行数据换行
    });
    
    // 添加空行和订单汇总信息
    csvContent += '\r\n'; // 空行
    csvContent += '订单信息,\r\n';
    csvContent += `订单编号,${escapeCSV(orderData.orderId)}\r\n`;
    csvContent += `客户名称,${escapeCSV(orderData.customerName)}\r\n`;
    csvContent += `联系电话,${escapeCSV(orderData.phone)}\r\n`;
    csvContent += `订单日期,${escapeCSV(orderData.date)}\r\n`;
    csvContent += `总数量,${orderData.totalQuantity}\r\n`;
    csvContent += `总金额,${orderData.totalAmount}\r\n`;
    
    // 创建并下载文件
    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
    const link = document.createElement('a');
    const url = URL.createObjectURL(blob);
    link.setAttribute('href', url);
    link.setAttribute('download', `楼梯灯订单_${orderData.orderId}_${formatDate(new Date())}.csv`);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
}

// 导出为Excel格式
function exportOrderToExcel(orderData) {
    if (!orderData) {
        alert('请先创建订单');
        return;
    }
    
    // 检查是否引入了SheetJS
    if (typeof XLSX === 'undefined') {
        // 如果没有引入SheetJS，提示用户或自动切换到CSV
        alert('Excel导出需要引入SheetJS库，将为您导出CSV格式');
        exportOrderToCSV(orderData);
        return;
    }
    
    // 构建工作表数据
    const wsData = [
        ['智步楼梯灯订单'], // 标题
        [], // 空行
        ['楼层', '踏步编号', '尺寸(mm)', '数量', '备注'] // 表头
    ];
    
    // 添加数据行
    orderData.items.forEach(item => {
        wsData.push([
            item.floor || '',
            item.stepNumber || '',
            item.size || '',
            item.quantity || 1,
            item.note || ''
        ]);
    });
    
    // 添加空行和订单信息
    wsData.push([]);
    wsData.push(['订单信息']);
    wsData.push(['订单编号', orderData.orderId]);
    wsData.push(['客户名称', orderData.customerName]);
    wsData.push(['联系电话', orderData.phone]);
    wsData.push(['订单日期', orderData.date]);
    wsData.push(['总数量', orderData.totalQuantity]);
    wsData.push(['总金额', orderData.totalAmount]);
    
    // 创建工作簿
    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.aoa_to_sheet(wsData);
    
    // 设置列宽
    ws['!cols'] = [
        {wch: 10}, // 楼层
        {wch: 12}, // 踏步编号
        {wch: 15}, // 尺寸
        {wch: 8},  // 数量
        {wch: 20}  // 备注
    ];
    
    // 添加工作表到工作簿
    XLSX.utils.book_append_sheet(wb, ws, '订单详情');
    
    // 下载文件
    XLSX.writeFile(wb, `楼梯灯订单_${orderData.orderId}_${formatDate(new Date())}.xlsx`);
}

// 导出为文本格式
function exportOrderToText(orderData) {
    if (!orderData) {
        alert('请先创建订单');
        return;
    }
    
    let textContent = '';
    
    // 标题
    textContent += '================================\r\n';
    textContent += '      智步楼梯灯订单\r\n';
    textContent += '================================\r\n\r\n';
    
    // 订单信息
    textContent += '【订单信息】\r\n';
    textContent += `订单编号：${orderData.orderId}\r\n`;
    textContent += `客户名称：${orderData.customerName}\r\n`;
    textContent += `联系电话：${orderData.phone}\r\n`;
    textContent += `订单日期：${orderData.date}\r\n\r\n`;
    
    // 产品明细
    textContent += '【产品明细】\r\n';
    textContent += '--------------------------------\r\n';
    textContent += '楼层  |  踏步编号  |  尺寸(mm)  |  数量  |  备注\r\n';
    textContent += '--------------------------------\r\n';
    
    orderData.items.forEach(item => {
        textContent += `${(item.floor || '').padEnd(6)}|  `;
        textContent += `${(item.stepNumber || '').padEnd(10)}|  `;
        textContent += `${(item.size || '').padEnd(12)}|  `;
        textContent += `${(item.quantity || 1).toString().padEnd(6)}|  `;
        textContent += `${item.note || ''}\r\n`;
    });
    
    textContent += '--------------------------------\r\n\r\n';
    
    // 汇总
    textContent += '【订单汇总】\r\n';
    textContent += `总数量：${orderData.totalQuantity} 套\r\n`;
    textContent += `总金额：¥${orderData.totalAmount}\r\n\r\n`;
    
    // 备注
    textContent += '【备注】\r\n';
    textContent += `${orderData.remark || '无'}\r\n\r\n`;
    
    textContent += '================================\r\n';
    textContent += '智步智能照明 www.we-smart.cn\r\n';
    textContent += '================================\r\n';
    
    // 下载文件
    const blob = new Blob([textContent], { type: 'text/plain;charset=utf-8;' });
    const link = document.createElement('a');
    const url = URL.createObjectURL(blob);
    link.setAttribute('href', url);
    link.setAttribute('download', `楼梯灯订单_${orderData.orderId}_${formatDate(new Date())}.txt`);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
}

// 辅助函数：处理CSV特殊字符
function escapeCSV(value) {
    if (value === null || value === undefined) return '';
    value = String(value);
    // 如果包含逗号、引号或换行符，需要用引号包裹
    if (value.includes(',') || value.includes('"') || value.includes('\n') || value.includes('\r')) {
        // 将引号替换为两个引号
        value = value.replace(/"/g, '""');
        return `"${value}"`;
    }
    return value;
}

// 辅助函数：格式化日期
function formatDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}${month}${day}`;
}

// 切换导出菜单显示/隐藏
function toggleExportMenu() {
    const menu = document.getElementById('exportMenu');
    if (menu) {
        menu.style.display = menu.style.display === 'none' ? 'block' : 'none';
    }
}

// 点击其他地方关闭菜单
document.addEventListener('click', function(event) {
    const dropdown = document.querySelector('.export-dropdown');
    const menu = document.getElementById('exportMenu');
    if (dropdown && menu && !dropdown.contains(event.target)) {
        menu.style.display = 'none';
    }
});

// 版本信息
const APP_VERSION = '1.8';
const APP_NAME = '智步楼梯灯AI订单助手';

// 页面加载完成后显示版本信息
document.addEventListener('DOMContentLoaded', function() {
    console.log(`${APP_NAME} v${APP_VERSION} 已加载`);
    
    // 更新页面标题中的版本号
    const versionElement = document.getElementById('app-version');
    if (versionElement) {
        versionElement.textContent = `v${APP_VERSION}`;
    }
});
```

### 步骤5：添加导出按钮HTML

在HTML文件中添加导出按钮（通常在订单展示区域）：

```html
<!-- 导出选项下拉菜单 -->
<div class="export-dropdown">
    <button class="export-btn" onclick="toggleExportMenu()">
        📥 导出订单
        <span class="arrow">▼</span>
    </button>
    <div class="export-options" id="exportMenu" style="display: none;">
        <button onclick="exportOrderToCSV(currentOrderData); toggleExportMenu();">
            📄 导出为CSV
        </button>
        <button onclick="exportOrderToExcel(currentOrderData); toggleExportMenu();">
            📊 导出为Excel
        </button>
        <button onclick="exportOrderToText(currentOrderData); toggleExportMenu();">
            📝 导出为文本
        </button>
    </div>
</div>

<!-- 样式 -->
<style>
.export-dropdown {
    position: relative;
    display: inline-block;
    margin: 10px 0;
}

.export-btn {
    background: #1890ff;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    display: flex;
    align-items: center;
    gap: 5px;
}

.export-btn:hover {
    background: #40a9ff;
}

.export-btn .arrow {
    font-size: 12px;
    margin-left: 5px;
}

.export-options {
    position: absolute;
    top: 100%;
    left: 0;
    background: white;
    min-width: 160px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
    border-radius: 4px;
    z-index: 1000;
    margin-top: 5px;
    overflow: hidden;
}

.export-options button {
    display: block;
    width: 100%;
    padding: 10px 15px;
    border: none;
    background: white;
    text-align: left;
    cursor: pointer;
    font-size: 14px;
    transition: background 0.2s;
}

.export-options button:hover {
    background: #f5f5f5;
}
</style>

<!-- 可选：引入SheetJS库（用于Excel导出） -->
<script src="https://cdn.sheetjs.com/xlsx-0.20.0/package/dist/xlsx.full.min.js"></script>
```

### 步骤6：更新版本号

在HTML文件中更新版本号显示：

```html
<!-- 在标题或页脚添加版本号 -->
<h1>智步楼梯灯AI订单助手 <span id="app-version">v1.8</span></h1>
```

### 步骤7：本地测试

```bash
# 启动本地服务器（根据实际技术栈调整）
# 如果是纯静态HTML
cd stair-order-v1.8
python3 -m http.server 8080

# 如果是Node.js
npm start
# 或
node server.js
```

访问 `http://localhost:8080` 测试导出功能是否正常。

### 步骤8：配置FRP穿透

确保FRP配置正确，将本地端口映射到阿里云：

```ini
# frpc.ini 配置示例
[stair-order-v1.8]
type = http
local_port = 8080  # 本地服务端口
custom_domains = tools.we-smart.cn
locations = /stair-order-v1.8
```

或者如果直接替换v1.7：
```ini
[stair-order]
type = http
local_port = 8080
custom_domains = tools.we-smart.cn
locations = /stair-order
```

### 步骤9：部署到阿里云

**方案A：并行部署（推荐，保留v1.7）**

```bash
# 登录阿里云
ssh root@8.138.219.128

# 进入网站目录
cd /var/www/zhibu/

# 创建v1.8目录
mkdir -p stair-order-v1.8

# 从本地复制文件（通过scp或git）
# scp -r /本地路径/stair-order-v1.8/* root@8.138.219.128:/var/www/zhibu/stair-order-v1.8/

# 或者如果FRP已配置，不需要复制，直接通过FRP访问
```

**方案B：直接替换v1.7**

```bash
# 登录阿里云
ssh root@8.138.219.128

cd /var/www/zhibu/

# 备份v1.7
cp -r stair-order stair-order-v1.7-backup

# 替换为v1.8
rm -rf stair-order
cp -r stair-order-v1.8 stair-order
```

### 步骤10：更新Nginx配置（如需要）

```bash
# 编辑Nginx配置
vim /etc/nginx/conf.d/tools.conf

# 确保配置正确
server {
    listen 80;
    server_name tools.we-smart.cn;
    
    location /stair-order {
        proxy_pass http://127.0.0.1:7008;  # FRP端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    # v1.8版本（并行部署时）
    location /stair-order-v1.8 {
        proxy_pass http://127.0.0.1:7009;  # 新的FRP端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

# 测试并重载Nginx
nginx -t
systemctl reload nginx
```

### 步骤11：验证部署

1. 访问 `https://tools.we-smart.cn/stair-order/`（v1.7）
2. 访问 `https://tools.we-smart.cn/stair-order-v1.8/`（v1.8，如果并行部署）
3. 创建测试订单
4. 点击导出按钮，验证换行是否正常

---

## 快速修复方案（如果只需要修复换行）

如果只需要快速修复v1.7的换行问题，而不需要创建v1.8：

```bash
# 登录阿里云
ssh root@8.138.219.128

cd /var/www/zhibu/stair-order

# 找到导出功能的JS文件
vim app.js  # 或 export.js

# 找到导出函数，修改以下关键行：
# 原来：
# const csv = "...\n...";
# 
# 改为：
# const csv = "\uFEFF...\r\n...";
```

---

## 需要您确认的信息

1. **本地项目路径**：`/home/maocai/.openclaw/workspace/tools/stair-order/` 是否正确？

2. **部署方式**：
   - 方案A：并行部署v1.8（保留v1.7）
   - 方案B：直接替换v1.7为v1.8

3. **FRP配置**：
   - 当前FRP端口是多少？
   - 是否需要为v1.8配置新的FRP端口？

4. **技术栈**：
   - 是纯静态HTML/CSS/JS吗？
   - 还是有Node.js后端？

请提供这些信息，我可以给您更精确的部署命令。
