Files
shop-platform/docs/readme.md

14 KiB
Raw Permalink Blame History

说明

基本概念

店铺和门店的关系可以从不同角度来理解,让我为您详细解释:

🏪 店铺 vs 门店:概念解析

1. 从层级关系理解

店铺(总店/品牌店)

graph TD
    A[品牌总部/总店] --> B1[门店A]
    A --> B2[门店B]
    A --> B3[门店C]
    A --> B4[线上店铺]

    B1 --> C1[分店A-1]
    B1 --> C2[分店A-2]
    B2 --> C3[分店B-1]

店铺特征:

  • 管理层面:品牌、总部、总店的概念
  • 业务范围:可能包含多个物理门店和线上渠道
  • 功能定位:战略决策、品牌管理、供应链控制

门店(分店/实体店)

graph LR
    A[门店] --> B[具体营业场所]
    A --> C[固定地址]
    A --> D[面对面服务]

门店特征:

  • 物理存在:有具体的营业场所和地址
  • 服务范围:服务特定区域客户
  • 运营独立:相对独立的日常运营

2. 从业务模式区分

维度 店铺Shop 门店Store
存在形式 可虚拟可实体 必须是实体
数量关系 1个店铺可有多门店 1个门店属于1个店铺
管理范围 品牌、战略、标准 日常运营、客户服务
系统关系 总部系统、ERP POS系统、库存管理

3. 实际业务场景

场景1连锁品牌

店铺(总店)
├── 北京门店(朝阳区店)
├── 上海门店(浦东店)
├── 广州门店(天河店)
└── 线上官方店铺

场景2电商+实体结合

店铺(品牌旗舰店)
├── 天猫官方店铺(线上)
├── 京东官方店铺(线上)
├── 线下体验门店(实体)
└── 微信小程序店铺(线上)

场景3单店经营

店铺 = 门店(合二为一)
└── 既是品牌也是具体营业点

💼 在智能客服系统中的数据建模

1. 数据库设计

-- 店铺表(总店/品牌)
CREATE TABLE shops (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,        -- 店铺名称
    brand_name VARCHAR(100),           -- 品牌名称
    type ENUM('single', 'chain', 'online'), -- 店铺类型
    status ENUM('active', 'inactive'),
    created_at TIMESTAMP
);

-- 门店表(分店/实体店)
CREATE TABLE stores (
    id INT PRIMARY KEY AUTO_INCREMENT,
    shop_id INT,                       -- 所属店铺
    name VARCHAR(100) NOT NULL,        -- 门店名称
    address TEXT,                      -- 具体地址
    phone VARCHAR(20),
    manager_id INT,                    -- 店长
    business_hours JSON,               -- 营业时间
    latitude DECIMAL(10, 8),          -- 纬度
    longitude DECIMAL(11, 8),          -- 经度
    status ENUM('open', 'closed', 'maintenance'),
    FOREIGN KEY (shop_id) REFERENCES shops(id)
);

-- 员工表(关联门店)
CREATE TABLE staff (
    id INT PRIMARY KEY AUTO_INCREMENT,
    store_id INT,                      -- 所属门店
    name VARCHAR(50),
    role ENUM('manager', 'assistant', 'cashier'),
    phone VARCHAR(20),
    FOREIGN KEY (store_id) REFERENCES stores(id)
);

2. 业务逻辑实现

// 店铺管理类
class ShopManager {
    constructor() {
        this.shops = new Map();
        this.stores = new Map();
    }

    // 创建店铺
    createShop(shopData) {
        const shop = {
            id: this.generateId(),
            name: shopData.name,
            brand: shopData.brand,
            type: shopData.type || 'single',
            stores: [], // 下属门店
            createdAt: new Date(),
            status: 'active'
        };

        this.shops.set(shop.id, shop);
        return shop;
    }

    // 添加门店到店铺
    addStoreToShop(shopId, storeData) {
        const shop = this.shops.get(shopId);
        if (!shop) throw new Error('店铺不存在');

        const store = {
            id: this.generateId(),
            shopId: shopId,
            name: storeData.name,
            address: storeData.address,
            contact: storeData.contact,
            coordinates: storeData.coordinates,
            businessHours: storeData.businessHours,
            staff: [],
            createdAt: new Date()
        };

        shop.stores.push(store.id);
        this.stores.set(store.id, store);

        return store;
    }

    // 根据位置查找最近门店
    findNearestStore(shopId, userLocation) {
        const shop = this.shops.get(shopId);
        if (!shop) return null;

        let nearestStore = null;
        let minDistance = Infinity;

        shop.stores.forEach(storeId => {
            const store = this.stores.get(storeId);
            if (store && store.status === 'open') {
                const distance = this.calculateDistance(
                    userLocation,
                    store.coordinates
                );

                if (distance < minDistance) {
                    minDistance = distance;
                    nearestStore = store;
                }
            }
        });

        return nearestStore;
    }

    // 计算距离(简化版)
    calculateDistance(loc1, loc2) {
        const R = 6371; // 地球半径公里
        const dLat = this.deg2rad(loc2.lat - loc1.lat);
        const dLon = this.deg2rad(loc2.lon - loc1.lon);

        const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
                 Math.cos(this.deg2rad(loc1.lat)) * Math.cos(this.deg2rad(loc2.lat)) *
                 Math.sin(dLon/2) * Math.sin(dLon/2);

        const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        return R * c;
    }

    deg2rad(deg) {
        return deg * (Math.PI/180);
    }
}

3. 在智能客服中的对话逻辑

// 店铺门店相关的对话处理
class StoreDialogHandler {
    constructor(shopManager) {
        this.shopManager = shopManager;
    }

    // 处理用户查询
    handleStoreQuery(userMessage, userContext) {
        const intent = this.detectIntent(userMessage);

        switch(intent) {
            case 'find_nearest':
                return this.handleFindNearest(userMessage, userContext);

            case 'store_hours':
                return this.handleStoreHours(userMessage, userContext);

            case 'store_contact':
                return this.handleStoreContact(userMessage, userContext);

            case 'all_stores':
                return this.handleAllStores(userMessage, userContext);

            default:
                return this.handleGeneralQuery(userMessage, userContext);
        }
    }

    // 查找最近门店
    handleFindNearest(userMessage, userContext) {
        const location = this.extractLocation(userMessage);
        const shopId = userContext.currentShopId;

        if (!location) {
            return {
                type: 'request_location',
                message: '请问您当前在哪个位置?我可以帮您查找最近的门店。',
                options: ['使用当前位置', '手动输入地址']
            };
        }

        const nearestStore = this.shopManager.findNearestStore(shopId, location);

        if (nearestStore) {
            return {
                type: 'store_info',
                message: `离您最近的门店是:${nearestStore.name}`,
                data: {
                    store: nearestStore,
                    distance: this.calculateDistance(location, nearestStore.coordinates),
                    estimatedTime: this.estimateTravelTime(nearestStore.coordinates, location)
                },
                actions: [
                    { text: '查看详情', action: 'show_store_detail' },
                    { text: '导航前往', action: 'navigate_to_store' },
                    { text: '联系门店', action: 'contact_store' }
                ]
            };
        } else {
            return {
                type: 'no_store_found',
                message: '在您附近没有找到我们的门店,建议您尝试线上服务或查看其他区域的门店。',
                alternatives: this.findAlternativeStores(shopId)
            };
        }
    }

    // 处理营业时间查询
    handleStoreHours(userMessage, userContext) {
        const storeName = this.extractStoreName(userMessage);
        const store = this.findStoreByName(storeName, userContext.currentShopId);

        if (store) {
            const hours = store.businessHours;
            const currentStatus = this.getCurrentStatus(store);

            return {
                type: 'business_hours',
                message: `${store.name}的营业时间:${this.formatBusinessHours(hours)}`,
                data: {
                    store: store,
                    currentStatus: currentStatus,
                    todayHours: this.getTodayHours(hours)
                }
            };
        }
    }
}

4. 响应消息模板

// 店铺门店信息响应模板
const StoreResponseTemplates = {
    // 门店列表响应
    storeList: (stores, options = {}) => {
        return {
            type: 'store_list',
            layout: 'card',
            title: options.title || '我们的门店',
            items: stores.map(store => ({
                title: store.name,
                description: store.address,
                image: store.image,
                meta: {
                    distance: store.distance ? `${store.distance}km` : '',
                    status: store.status === 'open' ? '营业中' : '休息中',
                    hours: store.businessHours ? '查看营业时间' : ''
                },
                actions: [
                    { text: '导航', action: 'navigate', data: { storeId: store.id } },
                    { text: '电话', action: 'call', data: { phone: store.phone } },
                    { text: '详情', action: 'detail', data: { storeId: store.id } }
                ]
            })),
            quickReplies: [
                '找最近的门店',
                '查看所有门店',
                '联系客服'
            ]
        };
    },

    // 单个门店详情
    storeDetail: (store) => {
        return {
            type: 'store_detail',
            layout: 'detail',
            title: store.name,
            sections: [
                {
                    title: '📍 地址',
                    content: store.address,
                    action: { type: 'map', data: store.coordinates }
                },
                {
                    title: '📞 联系方式',
                    content: store.phone,
                    action: { type: 'call', data: store.phone }
                },
                {
                    title: '🕒 营业时间',
                    content: formatBusinessHours(store.businessHours),
                    action: { type: 'hours', data: store.businessHours }
                },
                {
                    title: '👥 门店服务',
                    content: store.services.join('、'),
                    action: { type: 'services', data: store.services }
                }
            ],
            actions: [
                { text: '分享门店', action: 'share' },
                { text: '收藏门店', action: 'favorite' },
                { text: '投诉建议', action: 'feedback' }
            ]
        };
    },

    // 营业时间响应
    businessHours: (store, currentStatus) => {
        return {
            type: 'business_hours',
            message: `**${store.name}**\n\n` +
                    `当前状态:**${currentStatus}**\n\n` +
                    `营业时间:\n${formatBusinessHours(store.businessHours)}`,
            quickActions: [
                { text: '明天营业时间', action: 'tomorrow_hours' },
                { text: '节假日安排', action: 'holiday_hours' },
                { text: '联系确认', action: 'confirm_hours' }
            ]
        };
    }
};

// 工具函数
function formatBusinessHours(hours) {
    if (!hours) return '暂无信息';

    const days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
    return days.map((day, index) => {
        const dayHours = hours[index] || hours['default'];
        return `${day}: ${dayHours || '休息'}`;
    }).join('\n');
}

🎯 总结:店铺与门店的关系

核心关系

  1. 包含关系店铺包含门店1:N
  2. 品牌关系:店铺是品牌,门店是落地实体
  3. 管理关系:店铺管理门店的标准和运营

在智能客服中的应用

  • 用户说"我要找店铺" → 理解为品牌/总店概念
  • 用户说"找最近的门店" → 理解为具体营业点
  • 用户说"你们店在哪里" → 需要区分是指品牌还是具体门店

数据处理建议

// 在客服系统中这样区分:
const customerQuery = {
    "找苹果店": { type: "shop", brand: "apple" },
    "找朝阳区的苹果店": { type: "store", brand: "apple", location: "朝阳区" },
    "线上店铺": { type: "online_shop" },
    "实体门店": { type: "physical_store" }
};

这样的区分让智能客服能够更精准地理解用户意图,提供更准确的店铺/门店信息服务。