Skill: bondli/store-order-query (version 1.0.0)

--- name: store-order-query description: query store order information from database --- # Store Order Query Skill ## 技能描述 这是一个通过连接MySQL数据库查询店铺订单的 Skill。当用户询问店铺订单情况时(如"查询今天店铺订单"、"今天的订单怎么样"、"店铺经营情况"),使用此 Skill 连接数据库查询订单数据,并生成分析报告。 ## 使用场景 - 用户想查询特定时间段的订单数据 - 用户想了解店铺经营状况 - 用户想分析订单中的商品销售情况 - 用户想查看支付方式分布 ## 工作流程 ### step1. 检查配置文件 首先检查是否存在数据库配置文件 `~/openclaw-skill-data/store-order-query/config.json`。 **如果配置文件不存在**,需要询问用户以下信息: - MySQL数据库主机地址 - 数据库端口（默认3306） - 数据库名称 - 数据库用户名 - 数据库密码 然后基于 `config.example.json` 创建 `config.json` 文件。 ### step2. 解析用户查询意图 从用户的查询中提取: - **时间范围**: 今天、昨天、最近7天、最近30天等 - **查询维度**: 订单量、金额、商品、支付方式等 如果用户说"今天",则查询当天的订单数据。 ### step3. 执行查询脚本 调用以下命令查询订单数据，传递参数： - `--date-range`: 时间范围 (today/yesterday/last7days/last30days 或 custom) - `--start-date`: 开始日期 (YYYY-MM-DD 格式，可选) - `--end-date`: 结束日期 (YYYY-MM-DD 格式，可选) ``` node dist/index.js --date-range today ``` 脚本会： 1. 读取配置文件连接MySQL数据库 2. 查询Order表获取订单数据 3. 根据订单号查询OrderItems表获取商品信息 4. 将数据保存到 `~/openclaw-skill-data/store-order-query/orders_data.json` ### step4. 分析数据并生成报告 调用以下命令分析订单数据并生成报告： ``` node dist/analyze-orders.js ``` 脚本会： 1. 读取 `~/openclaw-skill-data/store-order-query/orders_data.json` 2. 进行数据分析（订单量、总金额、支付方式分布、商品分析等） 3. 生成 Markdown 格式的报告保存到 `~/openclaw-skill-data/store-order-query/order_report.md` ### 5. 呈现报告 读取生成的报告文件,向用户展示分析结果。 ## 配置文件格式 `~/openclaw-skill-data/store-order-query/config.json` 示例: ```json { "database": { "type": "mysql", "host": "localhost", "port": 3306, "database": "shop_db", "user": "root", "password": "your_password" }, "tables": { "orders": "Order", "order_items": "OrderItems" }, "fields": { "orders": { "id": "orderSn", "created_at": "createdAt", "total_amount": "orderActualAmount", "payment_method": "payType", "status": "orderStatus" }, "order_items": { "order_id": "orderSn", "product_name": "name", "sku": "sku", "quantity": "counts", "price": "actualPrice" } } } ``` ## 数据库表结构 ### Order 表（订单表） | 字段 | 类型 | 说明 | |------|------|------| | orderSn | VARCHAR(50) | 订单号(主键) | | createdAt | DATETIME | 创建时间 | | orderActualAmount | DECIMAL(10,2) | 订单实际金额 | | payType | VARCHAR(50) | 支付方式 | | orderStatus | VARCHAR(20) | 订单状态 | ### OrderItems 表（订单商品表） | 字段 | 类型 | 说明 | |------|------|------| | id | INT | 主键ID | | orderSn | VARCHAR(50) | 订单号(外键) | | name | VARCHAR(200) | 商品名称 | | sku | VARCHAR(100) | SKU | | counts | INT | 数量 | | actualPrice | DECIMAL(10,2) | 实际价格 | ## 注意事项 1. 确保已在根目录安装依赖：`pnpm install` 2. 配置文件包含敏感信息，不要将其提交到公共仓库 3. 首次使用时需要配置数据库信息 4. 确保MySQL数据库用户有读取Order和OrderItems表的权限 5. 生成的报告会保存在 output 目录中,可以重复查看 ## 错误处理 - 如果数据库连接失败,提示用户检查配置信息 - 如果查询结果为空,提示用户该时间段没有订单数据 - 如果表或字段不存在,提示用户检查配置文件中的字段映射

path: README.md
content: # Store Order Query Skill

通过连接MySQL数据库实现 **查询店铺订单** 的 OpenClaw Skill。

该 Skill 会读取数据库配置信息，连接MySQL数据库进行订单数据查询，最后对数据进行呈现和分析。

## 功能特性

- 专为MySQL数据库设计
- 支持实际业务表结构（Order、OrderItems）
- 多种查询时间范围：今天、昨天、最近7天、最近30天、自定义日期
- 自动生成详细的 Markdown 分析报告
- 订单数据、商品销售、SKU分析全面覆盖

## 交互形态

1. 用户输入查询诉求（如："查询今天店铺订单"、"今天的订单怎么样"）
2. Agent 检查是否有配置文件，如无则引导用户配置数据库信息
3. Agent 执行查询脚本获取订单数据
4. Agent 执行分析脚本生成报告并展示给用户

## 快速开始

### 1. 配置数据库

复制 `config.example.json` 为 `config.json`，并修改数据库配置：

```bash
cp config.example.json config.json
```

编辑 `config.json`，填入你的MySQL数据库信息：

```json
{
  "database": {
    "type": "mysql",
    "host": "localhost",
    "port": 3306,
    "database": "shop_db",
    "user": "root",
    "password": "your_password"
  },
  "tables": {
    "orders": "Order",
    "order_items": "OrderItems"
  },
  "fields": {
    "orders": {
      "id": "orderSn",
      "created_at": "createdAt",
      "total_amount": "orderActualAmount",
      "payment_method": "payType",
      "status": "orderStatus"
    },
    "order_items": {
      "order_id": "orderSn",
      "product_name": "name",
      "sku": "sku",
      "quantity": "counts",
      "price": "actualPrice"
    }
  }
}
```

### 2. 测试数据库（可选）

如果你想快速测试，可以使用提供的示例数据库脚本：

```bash
mysql -u root -p < scripts/example_database.sql
```

这会创建 `Order` 和 `OrderItems` 表，并插入一些测试数据。

### 3. 查询订单

```bash
# 查询今天的订单
pnpm run query -- --date-range today

# 查询昨天的订单
pnpm run query -- --date-range yesterday

# 查询最近7天的订单
pnpm run query -- --date-range last7days

# 查询自定义日期范围
pnpm run query -- --date-range custom --start-date 2024-01-01 --end-date 2024-01-31
```

### 4. 生成分析报告

```bash
pnpm run analyze
```

**一键查询并分析：**

```bash
pnpm run query-today
```

报告将保存到 `output/order_report.md`。

## 生成的数据

1. **订单原始数据** (`output/orders_data.json`)
   - 符合查询条件的订单数据
   - 关联的商品信息

2. **分析报告** (`output/order_report.md`)
   - 总体概况：订单量、总金额、平均订单金额、商品总数
   - 支付方式分布
   - 订单状态分布
   - 热销商品 TOP 10
   - SKU 销售分析（尺码、颜色等）

## 目录结构

```
store-order-query/
├── SKILL.md                    # Skill 定义文件
├── README.md                   # 使用说明
├── package.json                # 依赖配置
├── tsconfig.json               # TypeScript 配置
├── config.example.json         # 配置文件示例
├── config.json                 # 实际配置文件（需自行创建）
├── src/
│   ├── index.ts                # 订单查询入口
│   └── analyze-orders.ts       # 数据分析入口
├── scripts/
│   └── example_database.sql   # 示例数据库脚本
└── output/                     # 输出目录（自动创建）
    ├── orders_data.json        # 订单原始数据
    └── order_report.md         # 分析报告
```

## 数据库表结构

### Order 表（订单表）

```sql
CREATE TABLE `Order` (
    `orderSn` VARCHAR(50) PRIMARY KEY COMMENT '订单号',
    `createdAt` DATETIME NOT NULL COMMENT '创建时间',
    `orderActualAmount` DECIMAL(10, 2) NOT NULL COMMENT '订单实际金额',
    `payType` VARCHAR(50) COMMENT '支付方式',
    `orderStatus` VARCHAR(20) COMMENT '订单状态',
    INDEX `idx_createdAt` (`createdAt`)
);
```

### OrderItems 表（订单商品表）

```sql
CREATE TABLE `OrderItems` (
    `id` INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
    `orderSn` VARCHAR(50) NOT NULL COMMENT '订单号',
    `name` VARCHAR(200) NOT NULL COMMENT '商品名称',
    `sku` VARCHAR(100) COMMENT 'SKU',
    `counts` INT NOT NULL COMMENT '数量',
    `actualPrice` DECIMAL(10, 2) NOT NULL COMMENT '实际价格',
    INDEX `idx_orderSn` (`orderSn`)
);
```

## Scripts

| 命令 | 说明 |
|------|------|
| `pnpm run query` | 运行查询脚本 |
| `pnpm run analyze` | 运行分析脚本 |
| `pnpm run query-today` | 一键查询今天的订单并分析 |

## 技术栈

- **Node.js**: 运行环境（>= 18）
- **TypeScript**: 开发语言
- **mysql2**: MySQL 数据库驱动

## 注意事项

1. **数据库权限**：确保数据库用户有读取 Order 和 OrderItems 表的权限
2. **安全性**：配置文件包含敏感信息，请勿提交到公共仓库，已添加到 `.gitignore`
3. **日期字段**：确保 `createdAt` 字段是 DATETIME 类型，支持 `DATE()` 函数
4. **字段映射**：如果你的表结构不同，请修改 `config.json` 中的字段映射

## 常见问题

### Q: 数据库连接失败？

检查：
1. MySQL 服务是否启动
2. 配置文件中的用户名和密码是否正确
3. 数据库名称是否存在
4. 端口号是否正确（默认 3306）

### Q: 查询结果为空？

检查：
1. 日期范围是否正确
2. 数据库中是否有该时间段的数据
3. Order 表中 `createdAt` 字段是否有值

### Q: 字段不匹配错误？

检查 `config.json` 中的字段映射是否与实际表结构一致。

---

**作者**: liwentao
**仓库**: https://github.com/bondli/my-claw-skills.git


path: config.example.json
content: {
  "database": {
    "type": "mysql",
    "host": "localhost",
    "port": 3306,
    "database": "shop_db",
    "user": "root",
    "password": "your_password"
  },
  "tables": {
    "orders": "Order",
    "order_items": "OrderItems"
  },
  "fields": {
    "orders": {
      "id": "orderSn",
      "created_at": "createdAt",
      "total_amount": "orderActualAmount",
      "payment_method": "payType",
      "status": "orderStatus"
    },
    "order_items": {
      "order_id": "orderSn",
      "product_name": "name",
      "sku": "sku",
      "quantity": "counts",
      "price": "actualPrice"
    }
  }
}


path: package.json
content: {
  "name": "@bondli-skills/store-order-query",
  "version": "1.0.2",
  "description": "通过连接MySQL数据库查询店铺订单的 OpenClaw Skill",
  "type": "module",
  "main": "dist/index.js",
  "files": [
    "dist",
    "SKILL.md",
    "README.md",
    "config.example.json"
  ],
  "keywords": [
    "order",
    "query",
    "mysql",
    "analysis"
  ],
  "dependencies": {
    "mysql2": "^3.6.0"
  },
  "license": "MIT"
}


path: dist/analyze-orders.d.ts
content: import type { OrdersData, Analysis } from "./types.js";
export declare function analyzeOrders(data: OrdersData): Analysis;
export declare function generateReport(analysis: Analysis): string;
//# sourceMappingURL=analyze-orders.d.ts.map

path: dist/types.js
content: export {};
//# sourceMappingURL=types.js.map

path: dist/types.d.ts
content: export interface DBConfig {
    host: string;
    port: number;
    user: string;
    [REDACTED_SECRET];
    database: string;
}
export interface FieldsConfig {
    orders: Record<string, string>;
    order_items: Record<string, string>;
}
export interface Config {
    database: DBConfig;
    tables: {
        orders: string;
        order_items: string;
    };
    fields: FieldsConfig;
}
export interface OrderItem {
    order_id: string;
    product_name: string;
    sku: string;
    quantity: number;
    price: number;
}
export interface Order {
    order_id: string;
    created_at: string;
    total_amount: number;
    payment_method: string;
    status: string;
    items?: OrderItem[];
}
export interface OrderItemAnalysis {
    product_name?: string;
    sku?: string;
    quantity?: number;
    price?: number;
}
export interface OrderAnalysis {
    total_amount?: number;
    payment_method?: string;
    status?: string;
    items?: OrderItemAnalysis[];
}
export interface OrdersData {
    date_range: {
        start: string;
        end: string;
    };
    orders: OrderAnalysis[];
}
export interface SKUDetail {
    quantity: number;
    revenue: number;
    product_name: string;
}
export interface Analysis {
    date_range: {
        start: string;
        end: string;
    };
    total_orders: number;
    total_amount: number;
    avg_order_amount: number;
    total_items: number;
    payment_methods: Record<string, number>;
    status_distribution: Record<string, number>;
    products: Record<string, number>;
    sku_analysis: Record<string, SKUDetail>;
}
//# sourceMappingURL=types.d.ts.map

path: dist/index.js
content: import fs from "fs";
import path from "path";
import mysql from "mysql2/promise";
const baseDir = path.join(process.env.HOME || "~", "/openclaw-skill-data/store-order-query/");
const configPath = path.join(baseDir, "config.json");
const dataFile = path.join(baseDir, "orders_data.json");
function loadConfig() {
    // 确保目录存在
    if (!fs.existsSync(baseDir)) {
        try {
            fs.mkdirSync(baseDir, { recursive: true });
            console.log(`已创建配置目录: ${baseDir}`);
        }
        catch (error) {
            console.error(`创建配置目录失败: ${error.message}`);
            process.exit(1);
        }
    }
    if (!fs.existsSync(configPath)) {
        console.error("错误: 配置文件不存在");
        console.error(`配置文件路径: ${configPath}`);
        console.error("\n请执行以下命令创建配置文件:");
        // 获取当前技能的根目录
        const skillRoot = path.join(path.dirname(new URL(import.meta.url).pathname), "..");
        const examplePath = path.join(skillRoot, "config.example.json");
        console.error(`\n  cp ${examplePath} ${configPath}`);
        console.error("\n然后编辑配置文件填入你的数据库信息");
        process.exit(1);
    }
    return JSON.parse(fs.readFileSync(configPath, "utf-8"));
}
function getDateRange(rangeType, startDate, endDate) {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    if (rangeType === "today") {
        return { start: today, end: today };
    }
    else if (rangeType === "yesterday") {
        const yesterday = new Date(today);
        yesterday.setDate(yesterday.getDate() - 1);
        return { start: yesterday, end: yesterday };
    }
    else if (rangeType === "last7days") {
        const start = new Date(today);
        start.setDate(start.getDate() - 6);
        return { start, end: today };
    }
    else if (rangeType === "last30days") {
        const start = new Date(today);
        start.setDate(start.getDate() - 29);
        return { start, end: today };
    }
    else if (rangeType === "custom" && startDate && endDate) {
        return { start: new Date(startDate), end: new Date(endDate) };
    }
    return { start: today, end: today };
}
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}`;
}
export async function connectMySQL(config) {
    try {
        const connection = await mysql.createConnection({
            host: config.host,
            port: config.port,
            user: config.user,
            [REDACTED_SECRET],
            database: config.database
        });
        console.log("数据库连接成功");
        return connection;
    }
    catch (error) {
        console.error("MySQL 连接失败:", error.message);
        throw error;
    }
}
export async function queryOrders(connection, config, startDate, endDate) {
    const { tables, fields } = config;
    const ordersFields = fields.orders;
    const startDateStr = formatDate(startDate);
    const endDateStr = formatDate(endDate);
    const orderSQL = `
    SELECT 
      \`${ordersFields.id}\` as order_id,
      \`${ordersFields.created_at}\` as created_at,
      \`${ordersFields.total_amount}\` as total_amount,
      \`${ordersFields.payment_method}\` as payment_method,
      \`${ordersFields.status}\` as status
    FROM \`${tables.orders}\`
    WHERE DATE(\`${ordersFields.created_at}\`) >= ? 
      AND DATE(\`${ordersFields.created_at}\`) <= ?
    ORDER BY \`${ordersFields.created_at}\` DESC
  `;
    const [orders] = await connection.query(orderSQL, [startDateStr, endDateStr]);
    console.log(`查询到 ${orders.length} 条订单记录`);
    if (orders.length > 0) {
        const orderIds = orders.map(order => order.order_id);
        const itemsFields = fields.order_items;
        const placeholders = orderIds.map(() => "?").join(",");
        const itemsSQL = `
      SELECT 
        \`${itemsFields.order_id}\` as order_id,
        \`${itemsFields.product_name}\` as product_name,
        \`${itemsFields.sku}\` as sku,
        \`${itemsFields.quantity}\` as quantity,
        \`${itemsFields.price}\` as price
      FROM \`${tables.order_items}\`
      WHERE \`${itemsFields.order_id}\` IN (${placeholders})
    `;
        const [items] = await connection.query(itemsSQL, orderIds);
        console.log(`查询到 ${items.length} 条商品记录`);
        const itemsByOrder = {};
        items.forEach(item => {
            if (!itemsByOrder[item.order_id]) {
                itemsByOrder[item.order_id] = [];
            }
            itemsByOrder[item.order_id].push(item);
        });
        orders.forEach(order => {
            order.items = itemsByOrder[order.order_id] || [];
        });
    }
    return orders;
}
function saveData(orders, startDate, endDate) {
    if (!fs.existsSync(baseDir)) {
        fs.mkdirSync(baseDir, { recursive: true });
    }
    const data = {
        query_date: new Date().toISOString(),
        date_range: { start: formatDate(startDate), end: formatDate(endDate) },
        orders,
    };
    fs.writeFileSync(dataFile, JSON.stringify(data, null, 2), "utf-8");
    console.log(`数据已保存到: ${dataFile}`);
}
function parseArgs() {
    const args = process.argv.slice(2);
    const options = { dateRange: "today", startDate: null, endDate: null };
    for (let i = 0; i < args.length; i++) {
        if (args[i] === "--date-range" && i + 1 < args.length) {
            options.dateRange = args[i + 1];
            i++;
        }
        else if (args[i] === "--start-date" && i + 1 < args.length) {
            options.startDate = args[i + 1];
            i++;
        }
        else if (args[i] === "--end-date" && i + 1 < args.length) {
            options.endDate = args[i + 1];
            i++;
        }
    }
    return options;
}
async function main() {
    let connection;
    try {
        const options = parseArgs();
        const config = loadConfig();
        const { start, end } = getDateRange(options.dateRange, options.startDate, options.endDate);
        console.log(`查询日期范围: ${formatDate(start)} 至 ${formatDate(end)}`);
        connection = await connectMySQL(config.database);
        const orders = await queryOrders(connection, config, start, end);
        saveData(orders, start, end);
        console.log("查询完成!");
    }
    catch (error) {
        console.error("执行失败:", error.message);
        process.exit(1);
    }
    finally {
        if (connection) {
            await connection.end();
        }
    }
}
main();
//# sourceMappingURL=index.js.map

path: dist/analyze-orders.js
content: import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const baseDir = path.join(process.env.HOME || "~", "/openclaw-skill-data/store-order-query/");
const dataFile = path.join(baseDir, "orders_data.json");
function loadOrdersData() {
    if (!fs.existsSync(dataFile)) {
        console.error("错误: 订单数据文件不存在,请先运行查询脚本");
        process.exit(1);
    }
    return JSON.parse(fs.readFileSync(dataFile, "utf-8"));
}
export function analyzeOrders(data) {
    const orders = data.orders;
    if (!orders || orders.length === 0) {
        return {
            date_range: data.date_range,
            total_orders: 0,
            total_amount: 0,
            avg_order_amount: 0,
            total_items: 0,
            payment_methods: {},
            status_distribution: {},
            products: {},
            sku_analysis: {}
        };
    }
    const totalOrders = orders.length;
    const totalAmount = orders.reduce((sum, order) => sum + parseFloat(String(order.total_amount || 0)), 0);
    const paymentMethods = {};
    const statusDistribution = {};
    const productsCounter = {};
    const skuDetails = {};
    let totalItems = 0;
    orders.forEach(order => {
        const paymentMethod = order.payment_method || "未知";
        paymentMethods[paymentMethod] = (paymentMethods[paymentMethod] || 0) + 1;
        const status = order.status || "未知";
        statusDistribution[status] = (statusDistribution[status] || 0) + 1;
        const items = order.items || [];
        items.forEach(item => {
            const productName = item.product_name || "未知商品";
            const sku = item.sku || "未知SKU";
            const quantity = parseInt(String(item.quantity || 0));
            const price = parseFloat(String(item.price || 0));
            productsCounter[productName] = (productsCounter[productName] || 0) + quantity;
            totalItems += quantity;
            if (!skuDetails[sku]) {
                skuDetails[sku] = { quantity: 0, revenue: 0, product_name: productName };
            }
            skuDetails[sku].quantity += quantity;
            skuDetails[sku].revenue += price * quantity;
        });
    });
    const topProducts = Object.fromEntries(Object.entries(productsCounter).sort((a, b) => b[1] - a[1]).slice(0, 10));
    const topSKUs = Object.fromEntries(Object.entries(skuDetails).sort((a, b) => b[1].quantity - a[1].quantity).slice(0, 20));
    return {
        date_range: data.date_range,
        total_orders: totalOrders,
        total_amount: totalAmount,
        avg_order_amount: totalOrders > 0 ? totalAmount / totalOrders : 0,
        total_items: totalItems,
        payment_methods: paymentMethods,
        status_distribution: statusDistribution,
        products: topProducts,
        sku_analysis: topSKUs
    };
}
export function generateReport(analysis) {
    const { start: startDate, end: endDate } = analysis.date_range;
    let report = `# 店铺订单分析报告\n\n## 查询时间范围\n**${startDate}** 至 **${endDate}**\n\n---\n\n## 总体概况\n\n| 指标 | 数值 |\n|------|------|\n| 订单总数 | **${analysis.total_orders}** 单 |\n| 订单总金额 | **¥${analysis.total_amount.toFixed(2)}** |\n| 平均订单金额 | **¥${analysis.avg_order_amount.toFixed(2)}** |\n| 商品总数 | **${analysis.total_items}** 件 |\n\n`;
    report += "---\n\n## 支付方式分布\n\n";
    if (Object.keys(analysis.payment_methods).length > 0) {
        report += "| 支付方式 | 订单数 | 占比 |\n|----------|--------|------|\n";
        Object.entries(analysis.payment_methods)
            .sort((a, b) => b[1] - a[1])
            .forEach(([method, count]) => {
            const pct = analysis.total_orders > 0 ? (count / analysis.total_orders * 100).toFixed(1) : "0";
            report += `| ${method} | ${count} | ${pct}% |\n`;
        });
    }
    else {
        report += "*暂无数据*\n";
    }
    report += "\n---\n\n## 热销商品 TOP 10\n\n";
    if (Object.keys(analysis.products).length > 0) {
        report += "| 排名 | 商品名称 | 销售数量 |\n|------|----------|----------|\n";
        let rank = 1;
        Object.entries(analysis.products).forEach(([product, quantity]) => {
            report += `| ${rank++} | ${product} | ${quantity} 件 |\n`;
        });
    }
    else {
        report += "*暂无数据*\n";
    }
    report += "\n---\n\n## SKU 销售分析 (前20)\n\n";
    if (Object.keys(analysis.sku_analysis).length > 0) {
        report += "| SKU | 商品名称 | 销售数量 | 销售额 |\n|-----|----------|----------|--------|\n";
        Object.entries(analysis.sku_analysis).forEach(([sku, details]) => {
            report += `| ${sku} | ${details.product_name} | ${details.quantity} 件 | ¥${details.revenue.toFixed(2)} |\n`;
        });
    }
    else {
        report += "*暂无数据*\n";
    }
    const now = new Date();
    const timestamp = now.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" });
    report += `\n---\n\n*报告生成时间: ${timestamp}*\n`;
    return report;
}
function saveReport(report) {
    if (!fs.existsSync(baseDir)) {
        fs.mkdirSync(baseDir, { recursive: true });
    }
    const reportFile = path.join(baseDir, "order_report.md");
    fs.writeFileSync(reportFile, report, "utf-8");
    console.log(`报告已保存到: ${reportFile}`);
}
function main() {
    const data = loadOrdersData();
    console.log("正在分析订单数据...");
    const analysis = analyzeOrders(data);
    console.log("正在生成报告...");
    const report = generateReport(analysis);
    saveReport(report);
    console.log("分析完成!");
    console.log(`\n订单总数: ${analysis.total_orders}`);
    console.log(`订单总金额: ¥${analysis.total_amount.toFixed(2)}`);
    console.log(`商品总数: ${analysis.total_items} 件`);
}
main();
//# sourceMappingURL=analyze-orders.js.map

path: dist/index.d.ts
content: import { type Connection } from "mysql2/promise";
import type { DBConfig, Config, Order } from "./types.js";
export declare function connectMySQL(config: DBConfig): Promise<Connection>;
export declare function queryOrders(connection: Connection, config: Config, startDate: Date, endDate: Date): Promise<Order[]>;
//# sourceMappingURL=index.d.ts.map

Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)