consumerm模块完成度90%,完善消费者和商家端数据库表,商品、聊天、订单数据对接好了supabase,和商家端对接了聊天功能,安卓端编译通过了css样式,剩余几个页面在处理函数规范问题

This commit is contained in:
cyh666666
2026-02-24 17:17:49 +08:00
parent e2f1dfb097
commit e606c597ca
174 changed files with 37917 additions and 4444 deletions

119
doc_mall/consumer/ed.md Normal file
View File

@@ -0,0 +1,119 @@
把roles/index.uvue 像 users/detail.uvue那样 使用supa 和 store,现在的使用方式幼替换interface 需要抽出来放到 admins/admintypes.uts并引入。
参考user-management的onResize处理大小屏的切换问题。
切换到小屏card-view的display還是none
超出界面還是需要上下滾動的
https://gitee.com/xiangyuecn/AreaCity-JsSpider-StatsGov
【在线测试和预览】省市区乡镇四级行政区划数据支持在线生成JSON、多级联动js
【在线测试和预览】ECharts Map四级下钻在线测试和预览+代码生成:坐标边界范围在线测试和预览;
【转换工具】AreaCity-Geo格式转换工具软件csv文件导入数据库坐标、边界范围转换支持转成sql、shp、geojson
【查询工具】AreaCity-Query-Geometry高性能的坐标数据、边界数据查询工具Java开源程序、带http查询接口内存占用低1秒可查1万个以上坐标对应的城市信息
数据下载
emqx ctl admins add akoo Hexiaoniu1!
node.js + fastify + postgres + kafka
在pages/sports的目录下创建老师和学生端的关于训练提升系统的页面用严格的uni-app-x的android能运行的模式使用supadb做aksupainstance完成数据交互部分。同时还需要兼顾 大屏和小屏的不同展现方式.
我们的i项目是uni-app-x不是uni-app.目前不支持 uni-easyinputuni-nav-baruni-data-selectuni-icons uni-datetime-picker。easyinput用input 代替uni-nav-bar先删除uni-data-select用picker-view代替uni-datetime-picker 用components/picker-date 或components/picker-time代替
supadb的使用方式是:
// supadb 表格组件实例引用
const rolesdb = ref<SupadbComponentPublicInstance | null>(null)
if( rolesdb.value!=null)
{
const rolesdbloaddata = rolesdb.value!!.loadData;
rolesdbloaddata({ clear: false })
}
要获取 後續數據用 emit('load', newValue) 獲取的數據;
## UTS-Android 兼容性开发规范
> 以下为 uni-app-x (UTS) Android 端开发常见注意事项与踩坑点,建议所有开发成员遵循:
Uts需要注意的几点
表单优先用form.
跟template交互的变量尽量用1维的变量
不要用foreach,不要用map,不要用safeget,只要utsjsonobject就好了
都用utsjsonobject 了把safeget 这些必要性不大的函数都去掉以utsjsonobject为核心
用for解析的数组最好用Array<type> .不要用简写[]
uts android不支持picker,用picker-view,或者uni.showactionsheet.一维的优先用uni.showactionsheet.
uts android不支持undefined
uts 中的变量声明使用 let 和 const不能使用 var。
uts 对判断只接受boolean类型所以要用 !==null之类的来判断空
uts不支持 Intersection Type is not supported.
uts 中,只适合转 type不适合使用 interface。因为 interface 在 kotlin 和 swift 中另有不同。
for 循环里面的i要指定类型为Int ,如for (let i:Int = 0; i < byteLen; i++)
||表示逻辑或,&&表示逻辑与,!表示逻辑非,??表示空值合并运算符当左侧为null或undefined时返回右侧值
uts在 if里面只接受 boolean类型的值不能是其他类型的值否则会报错。
Index Signature is not supported
uts不支持undefined类型undefined类型的变量会被当做null处理。
uts android对map的支持不够好用for这种方式来代替。
uts android 对类型要求比较严格对属性的推断也比较严格多重推断用as ...来确认类型,
css只支持部分属性不能使用复杂的选择器和伪类。
只支持display: flex;
不支持gap;
不支持 display:grid;
不支持 calc();
scroll-view 在 uni-app-x中不是用 scroll-y=true 。而是要用 direction="vertical"
不支持table,grid,grid-template-columns
property value `calc(33.33% - 10px)` is not supported for `min-width` (supported values are: `number`|`pixel`)
ts的 为空则使用默认值的语法在uts中不能用 ||,要用 ?? 来代替,但不要直接全部替换,因为逻辑与还是 ||。
uts android不支持!在变量前面的判断空方式,要用 != null 来代替。
picker-view的事件 UniPickerViewChangeEvent
css:
[APP-ANDROID] 不支持伪类选择器
[APP-IOS] 不支持伪类选择器
[APP-ANDROID] 不支持的单位: 'vh'
[APP-IOS] 不支持的单位: 'vh'
css不支持 gap;
WARNING: `backdrop-filter` is not a standard property name (may not be supported)
ERROR: Selector `.login-button[disabled]` is not supported. uvue only support classname selector
ERROR: property value `100%` is not supported for `min-height` (supported values are: `number`|`pixel`)
[plugin:uni:app-uvue-css] ERROR: property value `all` is not supported for `transition-property` (supported values are: `css property`)
用 utils/utis 下的 UTSJSONObject 做类型转换
时间获取用uni_modules/lime-date-time-picker
在script里面或者uts里面要用 import { tt } from '@/utils/i18nfun.uts',
uni-app-x的 android的setup模式下对顺序有要求 函数必须放在调用的函数之前,否则无法找到。
一般情况下尽可能用强类型模式uni_modules的情况下尽量把type定义到interface里面。
style property `white-space` is only supported on `<text>|<button>`. there is an error on `<view class="ak-charts-container chart-view">`.
教师端用户id: 7bf7378e-a027-473e-97ac-3460ed3f170a
学生端用户id: eed3824b-bba1-4309-8048-19d17367c084
https://ak3.oulog.com/storage/v1/object/public/
设备id : ak_devices.id :12345678-1234-5678-9abc-123456789012
以下是 UTS Android 兼容性开发要求的简明版,适合 agent/开发者快速理解和执行:
1. 表单优先用 form 组件。
2. 跟 template 交互的变量尽量用一维变量(不要嵌套对象)。
3. 不要用 forEach、map、safeget数组遍历用 for 循环,类型转换用 UTSJSONObject。
4. 数组类型建议写成 Array<Type>,不要用 Type[] 简写。
5. 不支持 undefined变量未赋值就是 null。
6. 变量声明只能用 let 或 const不能用 var。
7. 判断空要用 !== null不能用 !变量。
8. 只支持 type不建议用 interfaceinterface 在 kotlin/swift 下不兼容)。
9. for 循环的 i 必须写明类型let i: Int = 0。
10. 逻辑或用 ||,空值合并用 ??,不能混用。
11. if 判断只能是 boolean 类型。
12. 不支持索引签名Index Signature
13. 类型推断严格,必要时用 as Type 明确类型。
14. 不支持 Intersection Type。
15. picker 用 picker-view 或 uni.showActionSheet 替代,不支持原生 picker。
16. 样式只支持 display: flex不支持 gap、grid、calc()、伪类选择器等复杂 CSS。
17. scroll-view 用 direction="vertical"。
18. 不支持 table、grid、vh 单位、min-width: 100% 等。
19. 组件事件如 picker-view 用 UniPickerViewChangeEvent。
20. 时间选择用 uni_modules/lime-date-time-picker。
21. 类型转换建议用 utils/utis 下的 UTSJSONObject。
22. 在uts setup的android模式下调用的函数必须在调用之前定义
数据获取争取都用强类型方式查询或rpc查询用supa.from.executeAs<T>()方式返回的是result,resultdata一般可以 as Array<T>,按照这个方式处理应该简单直接。update,insert用execute()

View File

@@ -0,0 +1,139 @@
-- =====================================================================================
-- 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();

View File

@@ -0,0 +1,78 @@
-- =====================================================================================
-- 8. 修复聊天消息表 (ml_chat_messages) 的 RLS 策略
-- 解决 403 Forbidden 问题 (无法发送消息) 和无法获取聊天记录的问题
-- =====================================================================================
-- 1. 确保表存在 (如果尚未创建)
CREATE TABLE IF NOT EXISTS public.ml_chat_messages (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
sender_id UUID NOT NULL, -- 发送方ID (关联 ak_users.id)
receiver_id UUID NOT NULL, -- 接收方ID (关联 ak_users.id)
content TEXT NOT NULL,
msg_type VARCHAR(20) DEFAULT 'text', -- text, image, etc
is_read BOOLEAN DEFAULT FALSE,
is_from_user BOOLEAN DEFAULT TRUE,
extra_data TEXT, -- 额外JSON数据
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 2. 开启 RLS
ALTER TABLE public.ml_chat_messages ENABLE ROW LEVEL SECURITY;
-- 3. 清理旧策略 (避免冲突)
DROP POLICY IF EXISTS "Chat messages insert policy" ON public.ml_chat_messages;
DROP POLICY IF EXISTS "Chat messages select policy" ON public.ml_chat_messages;
DROP POLICY IF EXISTS "Users can insert their own messages" ON public.ml_chat_messages;
DROP POLICY IF EXISTS "Users can view their own messages" ON public.ml_chat_messages;
DROP POLICY IF EXISTS "chat_insert_policy" ON public.ml_chat_messages;
DROP POLICY IF EXISTS "chat_select_policy" ON public.ml_chat_messages;
-- 4. 创建新策略
-- 策略:允许用户插入消息 (只要 sender_id 是自己)
CREATE POLICY "chat_messages_insert_policy" ON public.ml_chat_messages
FOR INSERT WITH CHECK (
-- 检查当前登录用户 (auth.uid()) 对应的 ak_users.id 是否等于要插入的 sender_id
EXISTS (
SELECT 1 FROM public.ak_users
WHERE auth_id = auth.uid()
AND id = sender_id
)
);
-- 策略:允许用户查询消息 (只要自己是 sender_id 或 receiver_id)
CREATE POLICY "chat_messages_select_policy" ON public.ml_chat_messages
FOR SELECT USING (
-- 检查当前登录用户是否是发送者或接收者
EXISTS (
SELECT 1 FROM public.ak_users
WHERE auth_id = auth.uid()
AND (id = sender_id OR id = receiver_id)
)
);
-- 策略:允许用户更新消息 (仅限标记已读,且自己是接收者)
CREATE POLICY "chat_messages_update_policy" ON public.ml_chat_messages
FOR UPDATE USING (
EXISTS (
SELECT 1 FROM public.ak_users
WHERE auth_id = auth.uid()
AND id = receiver_id
)
)
WITH CHECK (
EXISTS (
SELECT 1 FROM public.ak_users
WHERE auth_id = auth.uid()
AND id = receiver_id
)
);
-- =====================================================================================
-- 补充:确保 ak_users 上有适当的索引以提高 RLS 性能
-- =====================================================================================
CREATE INDEX IF NOT EXISTS idx_ak_users_auth_id ON public.ak_users(auth_id);
CREATE INDEX IF NOT EXISTS idx_chat_messages_sender ON public.ml_chat_messages(sender_id);
CREATE INDEX IF NOT EXISTS idx_chat_messages_receiver ON public.ml_chat_messages(receiver_id);
CREATE INDEX IF NOT EXISTS idx_chat_messages_created_at ON public.ml_chat_messages(created_at DESC);

View File

@@ -0,0 +1,60 @@
-- =====================================================================================
-- 8. 修复聊天消息表 (ml_chat_messages) 的 RLS 策略
-- 解决 403 Forbidden 问题 (无法发送消息) 和无法获取聊天记录的问题
-- 说明supabaseService 发送的是 auth.uid(),所以 sender_id/receiver_id 存储的是 Auth ID
-- =====================================================================================
-- 1. 确保表存在 (如果尚未创建)
CREATE TABLE IF NOT EXISTS public.ml_chat_messages (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
sender_id UUID NOT NULL, -- 发送方 Auth ID
receiver_id UUID NOT NULL, -- 接收方 Auth ID (或店铺关联ID)
content TEXT NOT NULL,
msg_type VARCHAR(20) DEFAULT 'text', -- text, image, etc
is_read BOOLEAN DEFAULT FALSE,
is_from_user BOOLEAN DEFAULT TRUE,
extra_data TEXT, -- 额外JSON数据
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- 2. 开启 RLS
ALTER TABLE public.ml_chat_messages ENABLE ROW LEVEL SECURITY;
-- 3. 清理旧策略 (避免冲突)
DROP POLICY IF EXISTS "chat_messages_insert_policy" ON public.ml_chat_messages;
DROP POLICY IF EXISTS "chat_messages_select_policy" ON public.ml_chat_messages;
DROP POLICY IF EXISTS "chat_messages_update_policy" ON public.ml_chat_messages;
-- 4. 创建新策略
-- 策略:允许用户插入消息 (只要 sender_id 是自己)
CREATE POLICY "chat_messages_insert_policy" ON public.ml_chat_messages
FOR INSERT WITH CHECK (
auth.uid() = sender_id
);
-- 策略:允许用户查询消息 (只要自己是 sender_id 或 receiver_id)
-- 注意:如果 receiver_id 是店铺ID商家查询时可能需要额外逻辑 (此处仅保证作为 User 能看到自己的收发)
CREATE POLICY "chat_messages_select_policy" ON public.ml_chat_messages
FOR SELECT USING (
auth.uid() = sender_id
OR
auth.uid() = receiver_id
);
-- 策略:允许用户更新消息 (仅限接收者标记已读)
CREATE POLICY "chat_messages_update_policy" ON public.ml_chat_messages
FOR UPDATE USING (
auth.uid() = receiver_id
)
WITH CHECK (
auth.uid() = receiver_id
);
-- =====================================================================================
-- 5. 补充索引
-- =====================================================================================
CREATE INDEX IF NOT EXISTS idx_chat_messages_sender ON public.ml_chat_messages(sender_id);
CREATE INDEX IF NOT EXISTS idx_chat_messages_receiver ON public.ml_chat_messages(receiver_id);
CREATE INDEX IF NOT EXISTS idx_chat_messages_created_at ON public.ml_chat_messages(created_at DESC);