跑通consumer下单之后派单给delivery2
This commit is contained in:
@@ -173,4 +173,53 @@ $$;
|
||||
REVOKE ALL ON FUNCTION public.rpc_admin_get_delivery_staff_list(TEXT, SMALLINT, INTEGER, INTEGER) FROM PUBLIC;
|
||||
GRANT EXECUTE ON FUNCTION public.rpc_admin_get_delivery_staff_list(TEXT, SMALLINT, INTEGER, INTEGER) TO authenticated;
|
||||
|
||||
DROP FUNCTION IF EXISTS public.rpc_homecare_dispatch_candidate(TEXT, UUID);
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.rpc_homecare_dispatch_candidate(
|
||||
p_service_code TEXT DEFAULT NULL,
|
||||
p_station_id UUID DEFAULT NULL
|
||||
)
|
||||
RETURNS JSONB
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
AS $$
|
||||
DECLARE
|
||||
v_candidate JSONB;
|
||||
BEGIN
|
||||
IF auth.uid() IS NULL OR NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.ak_users u
|
||||
WHERE u.auth_id = auth.uid()
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Permission denied';
|
||||
END IF;
|
||||
|
||||
SELECT jsonb_build_object(
|
||||
'id', s.id,
|
||||
'uid', s.uid,
|
||||
'station_id', s.station_id,
|
||||
'status', s.status,
|
||||
'online_status', s.online_status,
|
||||
'updated_at', s.updated_at,
|
||||
'created_at', s.created_at
|
||||
)
|
||||
INTO v_candidate
|
||||
FROM public.ml_delivery_staff s
|
||||
WHERE s.deleted_at IS NULL
|
||||
AND s.status = 1
|
||||
AND COALESCE(s.is_active, TRUE) = TRUE
|
||||
AND s.online_status = 'online'
|
||||
AND s.uid IS NOT NULL
|
||||
AND (p_station_id IS NULL OR s.station_id = p_station_id)
|
||||
ORDER BY COALESCE(s.updated_at, s.created_at) DESC, s.created_at DESC
|
||||
LIMIT 1;
|
||||
|
||||
RETURN v_candidate;
|
||||
END;
|
||||
$$;
|
||||
|
||||
REVOKE ALL ON FUNCTION public.rpc_homecare_dispatch_candidate(TEXT, UUID) FROM PUBLIC;
|
||||
GRANT EXECUTE ON FUNCTION public.rpc_homecare_dispatch_candidate(TEXT, UUID) TO authenticated;
|
||||
|
||||
COMMIT;
|
||||
@@ -79,7 +79,6 @@ ALTER TABLE public.ml_delivery_staff ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.ml_delivery_stations ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS delivery_staff_self_select ON public.ml_delivery_staff;
|
||||
DROP POLICY IF EXISTS delivery_staff_assignable_select ON public.ml_delivery_staff;
|
||||
DROP POLICY IF EXISTS delivery_staff_self_update ON public.ml_delivery_staff;
|
||||
CREATE POLICY delivery_staff_self_select
|
||||
ON public.ml_delivery_staff
|
||||
@@ -95,18 +94,6 @@ CREATE POLICY delivery_staff_self_select
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY delivery_staff_assignable_select
|
||||
ON public.ml_delivery_staff
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
deleted_at IS NULL
|
||||
AND status = 1
|
||||
AND COALESCE(is_active, true) = true
|
||||
AND online_status = 'online'
|
||||
AND uid IS NOT NULL
|
||||
);
|
||||
|
||||
CREATE POLICY delivery_staff_self_update
|
||||
ON public.ml_delivery_staff
|
||||
FOR UPDATE
|
||||
@@ -149,4 +136,6 @@ COMMENT ON COLUMN public.ml_delivery_staff.deleted_by IS '软删除操作人';
|
||||
COMMENT ON COLUMN public.ml_delivery_stations.deleted_at IS '软删除时间';
|
||||
COMMENT ON COLUMN public.ml_delivery_stations.deleted_by IS '软删除操作人';
|
||||
|
||||
-- 派单候选人读取统一走 SECURITY DEFINER RPC,避免公开在线人员列表。
|
||||
|
||||
COMMIT;
|
||||
|
||||
1536
mall_sql/migrations/20260526_delivery_homecare_rpc_v1.sql
Normal file
1536
mall_sql/migrations/20260526_delivery_homecare_rpc_v1.sql
Normal file
File diff suppressed because it is too large
Load Diff
336
mall_sql/migrations/20260526_homecare_foundation_v1.sql
Normal file
336
mall_sql/migrations/20260526_homecare_foundation_v1.sql
Normal file
@@ -0,0 +1,336 @@
|
||||
BEGIN;
|
||||
|
||||
-- 与 delivery 侧保持同版,供 consumer/delivery 双端使用同一套 homecare foundation schema。
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.ec_service_requests (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id UUID NOT NULL,
|
||||
service_catalog_id TEXT NOT NULL DEFAULT '',
|
||||
service_name TEXT NOT NULL DEFAULT '',
|
||||
service_category TEXT NOT NULL DEFAULT '',
|
||||
elder_name TEXT NOT NULL DEFAULT '',
|
||||
elder_phone TEXT NOT NULL DEFAULT '',
|
||||
contact_name TEXT NOT NULL DEFAULT '',
|
||||
contact_phone TEXT NOT NULL DEFAULT '',
|
||||
address_snapshot JSONB,
|
||||
address_snapshot_json JSONB,
|
||||
scheduled_at TIMESTAMPTZ,
|
||||
remark TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT 'ORDER_CREATED',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.ec_care_tasks (
|
||||
id UUID PRIMARY KEY,
|
||||
task_no TEXT NOT NULL UNIQUE,
|
||||
request_id UUID REFERENCES public.ec_service_requests(id) ON DELETE SET NULL,
|
||||
user_id UUID NOT NULL,
|
||||
assigned_to UUID,
|
||||
service_catalog_id TEXT NOT NULL DEFAULT '',
|
||||
service_name TEXT NOT NULL DEFAULT '',
|
||||
service_category TEXT NOT NULL DEFAULT '',
|
||||
service_snapshot_json JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
elder_name TEXT NOT NULL DEFAULT '',
|
||||
elder_phone TEXT NOT NULL DEFAULT '',
|
||||
contact_name TEXT NOT NULL DEFAULT '',
|
||||
contact_phone TEXT NOT NULL DEFAULT '',
|
||||
address_snapshot JSONB,
|
||||
address_snapshot_json JSONB,
|
||||
scheduled_at TIMESTAMPTZ,
|
||||
appointment_time TIMESTAMPTZ,
|
||||
remark TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT 'ORDER_CREATED',
|
||||
reject_reason TEXT NOT NULL DEFAULT '',
|
||||
accepted_at TIMESTAMPTZ,
|
||||
departed_at TIMESTAMPTZ,
|
||||
checked_in_at TIMESTAMPTZ,
|
||||
service_started_at TIMESTAMPTZ,
|
||||
service_completed_at TIMESTAMPTZ,
|
||||
acceptance_pending_at TIMESTAMPTZ,
|
||||
accepted_by_family_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.ec_care_records (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id UUID NOT NULL REFERENCES public.ec_care_tasks(id) ON DELETE CASCADE,
|
||||
record_type TEXT NOT NULL DEFAULT 'service_record',
|
||||
care_record_type TEXT,
|
||||
created_by UUID,
|
||||
started_at TIMESTAMPTZ,
|
||||
finished_at TIMESTAMPTZ,
|
||||
checked_in_at TIMESTAMPTZ,
|
||||
checkin_time TIMESTAMPTZ,
|
||||
latitude DOUBLE PRECISION,
|
||||
longitude DOUBLE PRECISION,
|
||||
location_text TEXT NOT NULL DEFAULT '',
|
||||
duration_minutes INTEGER NOT NULL DEFAULT 0,
|
||||
actual_duration_minutes INTEGER NOT NULL DEFAULT 0,
|
||||
service_items_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
service_content_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
service_summary TEXT NOT NULL DEFAULT '',
|
||||
process_note TEXT NOT NULL DEFAULT '',
|
||||
summary TEXT NOT NULL DEFAULT '',
|
||||
content TEXT NOT NULL DEFAULT '',
|
||||
remark TEXT NOT NULL DEFAULT '',
|
||||
elder_status TEXT NOT NULL DEFAULT '',
|
||||
health_metrics_json JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
materials_used TEXT NOT NULL DEFAULT '',
|
||||
abnormal_note TEXT NOT NULL DEFAULT '',
|
||||
photos_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
staff_remark TEXT NOT NULL DEFAULT '',
|
||||
family_confirmation_json JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
rating INTEGER,
|
||||
tags_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.hc_work_order_events (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id UUID NOT NULL REFERENCES public.ec_care_tasks(id) ON DELETE CASCADE,
|
||||
from_status TEXT,
|
||||
to_status TEXT NOT NULL DEFAULT '',
|
||||
actor_id UUID,
|
||||
actor_role TEXT NOT NULL DEFAULT '',
|
||||
action TEXT NOT NULL DEFAULT '',
|
||||
remark TEXT NOT NULL DEFAULT '',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.hc_work_order_exceptions (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id UUID NOT NULL REFERENCES public.ec_care_tasks(id) ON DELETE CASCADE,
|
||||
exception_type TEXT NOT NULL DEFAULT 'other',
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
occurred_at TIMESTAMPTZ,
|
||||
location_text TEXT NOT NULL DEFAULT '',
|
||||
images_json JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
need_platform_intervention BOOLEAN NOT NULL DEFAULT false,
|
||||
request_cancel_order BOOLEAN NOT NULL DEFAULT false,
|
||||
request_reschedule BOOLEAN NOT NULL DEFAULT false,
|
||||
created_by UUID,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.hc_evidence_files (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_id UUID NOT NULL REFERENCES public.ec_care_tasks(id) ON DELETE CASCADE,
|
||||
care_record_id TEXT,
|
||||
phase TEXT NOT NULL DEFAULT 'service',
|
||||
file_type TEXT NOT NULL DEFAULT 'image',
|
||||
storage_path TEXT NOT NULL DEFAULT '',
|
||||
file_url TEXT NOT NULL DEFAULT '',
|
||||
latitude DOUBLE PRECISION,
|
||||
longitude DOUBLE PRECISION,
|
||||
captured_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ec_service_requests_user_created
|
||||
ON public.ec_service_requests(user_id, created_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ec_care_tasks_user_created
|
||||
ON public.ec_care_tasks(user_id, created_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ec_care_tasks_assigned_status
|
||||
ON public.ec_care_tasks(assigned_to, status, created_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ec_care_records_task_created
|
||||
ON public.ec_care_records(task_id, created_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_hc_work_order_events_task_created
|
||||
ON public.hc_work_order_events(task_id, created_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_hc_work_order_exceptions_task_created
|
||||
ON public.hc_work_order_exceptions(task_id, created_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_hc_evidence_files_task_created
|
||||
ON public.hc_evidence_files(task_id, created_at DESC);
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.tg_ec_set_updated_at()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_ec_service_requests_updated_at ON public.ec_service_requests;
|
||||
CREATE TRIGGER trg_ec_service_requests_updated_at
|
||||
BEFORE UPDATE ON public.ec_service_requests
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.tg_ec_set_updated_at();
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_ec_care_tasks_updated_at ON public.ec_care_tasks;
|
||||
CREATE TRIGGER trg_ec_care_tasks_updated_at
|
||||
BEFORE UPDATE ON public.ec_care_tasks
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.tg_ec_set_updated_at();
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_ec_care_records_updated_at ON public.ec_care_records;
|
||||
CREATE TRIGGER trg_ec_care_records_updated_at
|
||||
BEFORE UPDATE ON public.ec_care_records
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.tg_ec_set_updated_at();
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_hc_work_order_exceptions_updated_at ON public.hc_work_order_exceptions;
|
||||
CREATE TRIGGER trg_hc_work_order_exceptions_updated_at
|
||||
BEFORE UPDATE ON public.hc_work_order_exceptions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.tg_ec_set_updated_at();
|
||||
|
||||
ALTER TABLE public.ec_service_requests ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.ec_care_tasks ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.ec_care_records ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.hc_work_order_events ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.hc_work_order_exceptions ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.hc_evidence_files ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS ec_service_requests_owner_select ON public.ec_service_requests;
|
||||
CREATE POLICY ec_service_requests_owner_select
|
||||
ON public.ec_service_requests
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()));
|
||||
|
||||
DROP POLICY IF EXISTS ec_service_requests_owner_insert ON public.ec_service_requests;
|
||||
CREATE POLICY ec_service_requests_owner_insert
|
||||
ON public.ec_service_requests
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()));
|
||||
|
||||
DROP POLICY IF EXISTS ec_service_requests_owner_update ON public.ec_service_requests;
|
||||
CREATE POLICY ec_service_requests_owner_update
|
||||
ON public.ec_service_requests
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()))
|
||||
WITH CHECK (user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()));
|
||||
|
||||
DROP POLICY IF EXISTS ec_care_tasks_owner_or_staff_select ON public.ec_care_tasks;
|
||||
CREATE POLICY ec_care_tasks_owner_or_staff_select
|
||||
ON public.ec_care_tasks
|
||||
FOR SELECT
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
);
|
||||
|
||||
DROP POLICY IF EXISTS ec_care_tasks_owner_insert ON public.ec_care_tasks;
|
||||
CREATE POLICY ec_care_tasks_owner_insert
|
||||
ON public.ec_care_tasks
|
||||
FOR INSERT
|
||||
TO authenticated
|
||||
WITH CHECK (user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()));
|
||||
|
||||
DROP POLICY IF EXISTS ec_care_tasks_owner_or_staff_update ON public.ec_care_tasks;
|
||||
CREATE POLICY ec_care_tasks_owner_or_staff_update
|
||||
ON public.ec_care_tasks
|
||||
FOR UPDATE
|
||||
TO authenticated
|
||||
USING (
|
||||
user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
WITH CHECK (
|
||||
user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
);
|
||||
|
||||
DROP POLICY IF EXISTS ec_care_records_task_access ON public.ec_care_records;
|
||||
CREATE POLICY ec_care_records_task_access
|
||||
ON public.ec_care_records
|
||||
FOR ALL
|
||||
TO authenticated
|
||||
USING (
|
||||
task_id IN (
|
||||
SELECT t.id
|
||||
FROM public.ec_care_tasks t
|
||||
WHERE t.user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR t.assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
)
|
||||
WITH CHECK (
|
||||
task_id IN (
|
||||
SELECT t.id
|
||||
FROM public.ec_care_tasks t
|
||||
WHERE t.user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR t.assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
);
|
||||
|
||||
DROP POLICY IF EXISTS hc_work_order_events_task_access ON public.hc_work_order_events;
|
||||
CREATE POLICY hc_work_order_events_task_access
|
||||
ON public.hc_work_order_events
|
||||
FOR ALL
|
||||
TO authenticated
|
||||
USING (
|
||||
task_id IN (
|
||||
SELECT t.id
|
||||
FROM public.ec_care_tasks t
|
||||
WHERE t.user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR t.assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
)
|
||||
WITH CHECK (
|
||||
task_id IN (
|
||||
SELECT t.id
|
||||
FROM public.ec_care_tasks t
|
||||
WHERE t.user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR t.assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
);
|
||||
|
||||
DROP POLICY IF EXISTS hc_work_order_exceptions_task_access ON public.hc_work_order_exceptions;
|
||||
CREATE POLICY hc_work_order_exceptions_task_access
|
||||
ON public.hc_work_order_exceptions
|
||||
FOR ALL
|
||||
TO authenticated
|
||||
USING (
|
||||
task_id IN (
|
||||
SELECT t.id
|
||||
FROM public.ec_care_tasks t
|
||||
WHERE t.user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR t.assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
)
|
||||
WITH CHECK (
|
||||
task_id IN (
|
||||
SELECT t.id
|
||||
FROM public.ec_care_tasks t
|
||||
WHERE t.user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR t.assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
);
|
||||
|
||||
DROP POLICY IF EXISTS hc_evidence_files_task_access ON public.hc_evidence_files;
|
||||
CREATE POLICY hc_evidence_files_task_access
|
||||
ON public.hc_evidence_files
|
||||
FOR ALL
|
||||
TO authenticated
|
||||
USING (
|
||||
task_id IN (
|
||||
SELECT t.id
|
||||
FROM public.ec_care_tasks t
|
||||
WHERE t.user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR t.assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
)
|
||||
WITH CHECK (
|
||||
task_id IN (
|
||||
SELECT t.id
|
||||
FROM public.ec_care_tasks t
|
||||
WHERE t.user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
OR t.assigned_to IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
|
||||
)
|
||||
);
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user