Files
medical-mall/doc_mall/consumer/sql/07_create_chat_rooms.sql

140 lines
5.1 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =====================================================================================
-- 4. 创建聊天会话表 (ml_chat_rooms)
-- 用于优化聊天列表查询性能,维护用户与商家的会话状态
-- 依赖表: public.ak_users, public.ml_chat_messages
-- =====================================================================================
-- 1. 创建表结构
CREATE TABLE IF NOT EXISTS public.ml_chat_rooms (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES public.ak_users(id) ON DELETE CASCADE, -- 消费者ID
merchant_id UUID NOT NULL, -- 商家ID/店铺ID
shop_name VARCHAR(100), -- 缓存店铺名称
shop_logo TEXT, -- 缓存店铺Logo
last_message TEXT, -- 最后一条消息内容预览
last_message_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), -- 最后一条消息时间
unread_count INTEGER DEFAULT 0, -- 未读消息数
is_top BOOLEAN DEFAULT FALSE, -- 是否置顶
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- 确保同一个用户和同一个商家只有一个会话
UNIQUE(user_id, merchant_id)
);
COMMENT ON TABLE public.ml_chat_rooms IS '聊天会话列表表';
-- 2. 开启 RLS
ALTER TABLE public.ml_chat_rooms ENABLE ROW LEVEL SECURITY;
-- 3. RLS 策略
-- 策略:用户只能查自己的会话
CREATE POLICY ml_chat_rooms_select_policy ON public.ml_chat_rooms
FOR SELECT USING (
auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id)
);
-- 策略:允许插入(通常由触发器或后端逻辑维护)
CREATE POLICY ml_chat_rooms_insert_policy ON public.ml_chat_rooms
FOR INSERT WITH CHECK (
auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id)
);
-- 策略:允许更新(如清除未读数)
CREATE POLICY ml_chat_rooms_update_policy ON public.ml_chat_rooms
FOR UPDATE USING (
auth.uid() = (SELECT auth_id FROM public.ak_users WHERE id = user_id)
);
-- =====================================================================================
-- 4. 触发器函数:自动维护会话列表
-- =====================================================================================
CREATE OR REPLACE FUNCTION public.handle_new_chat_message()
RETURNS TRIGGER AS $$
DECLARE
v_user_id UUID;
v_merchant_id UUID;
v_shop_name TEXT;
v_shop_logo TEXT;
v_is_from_user BOOLEAN;
v_count_inc INTEGER;
BEGIN
-- 确定谁是用户,谁是商家
-- 假设 is_from_user 为 true 时sender_id 是用户receiver_id 是商家
-- 假设 is_from_user 为 false 时sender_id 是商家receiver_id 是用户
v_is_from_user := NEW.is_from_user;
IF v_is_from_user THEN
v_user_id := NEW.sender_id;
v_merchant_id := NEW.receiver_id;
v_count_inc := 0; -- 用户自己发的,未读数不变
ELSE
v_user_id := NEW.receiver_id;
v_merchant_id := NEW.sender_id;
v_count_inc := 1; -- 商家发的,用户未读数 +1
END IF;
-- 尝试更新用户的会话
UPDATE public.ml_chat_rooms
SET
last_message = NEW.content,
last_message_at = NEW.created_at,
updated_at = NOW(),
unread_count = unread_count + v_count_inc
WHERE user_id = v_user_id AND merchant_id = v_merchant_id;
-- 如果没有更新到任何行(说明会话不存在),则插入新会话
IF NOT FOUND THEN
-- 尝试从 ml_shops 表获取店铺信息(如果有的话)
BEGIN
SELECT shop_name, shop_logo INTO v_shop_name, v_shop_logo
FROM public.ml_shops
WHERE merchant_id = v_merchant_id
LIMIT 1;
EXCEPTION WHEN OTHERS THEN
-- 忽略错误,使用默认值
v_shop_name := '未知店铺';
v_shop_logo := '';
END;
-- 如果没查到,给个默认名
IF v_shop_name IS NULL THEN
v_shop_name := '店铺 ' || substr(v_merchant_id::text, 1, 8);
END IF;
INSERT INTO public.ml_chat_rooms (
user_id,
merchant_id,
last_message,
last_message_at,
unread_count,
shop_name,
shop_logo
)
VALUES (
v_user_id,
v_merchant_id,
NEW.content,
NEW.created_at,
v_count_inc,
v_shop_name,
v_shop_logo
);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- 5. 创建触发器
DROP TRIGGER IF EXISTS on_chat_message_inserted ON public.ml_chat_messages;
CREATE TRIGGER on_chat_message_inserted
AFTER INSERT ON public.ml_chat_messages
FOR EACH ROW
EXECUTE FUNCTION public.handle_new_chat_message();