BEGIN; CREATE OR REPLACE FUNCTION public.tg_set_updated_at() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$; ALTER TABLE public.ml_delivery_staff ADD COLUMN IF NOT EXISTS station_id UUID REFERENCES public.ml_delivery_stations(id) ON DELETE SET NULL, ADD COLUMN IF NOT EXISTS staff_no TEXT, ADD COLUMN IF NOT EXISTS online_status TEXT NOT NULL DEFAULT 'resting', ADD COLUMN IF NOT EXISTS certificate_status TEXT NOT NULL DEFAULT 'pending', ADD COLUMN IF NOT EXISTS certificate_expire_at DATE, ADD COLUMN IF NOT EXISTS service_area TEXT NOT NULL DEFAULT '', ADD COLUMN IF NOT EXISTS skills JSONB NOT NULL DEFAULT '[]'::jsonb, ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ, ADD COLUMN IF NOT EXISTS deleted_by UUID REFERENCES public.ak_users(id) ON DELETE SET NULL; ALTER TABLE public.ml_delivery_staff DROP CONSTRAINT IF EXISTS chk_ml_delivery_staff_online_status; ALTER TABLE public.ml_delivery_staff ADD CONSTRAINT chk_ml_delivery_staff_online_status CHECK (online_status IN ('online', 'resting', 'busy')); ALTER TABLE public.ml_delivery_staff DROP CONSTRAINT IF EXISTS chk_ml_delivery_staff_certificate_status; ALTER TABLE public.ml_delivery_staff ADD CONSTRAINT chk_ml_delivery_staff_certificate_status CHECK (certificate_status IN ('valid', 'expired', 'pending')); ALTER TABLE public.ml_delivery_stations ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ, ADD COLUMN IF NOT EXISTS deleted_by UUID REFERENCES public.ak_users(id) ON DELETE SET NULL; CREATE UNIQUE INDEX IF NOT EXISTS uq_ml_delivery_staff_uid_active ON public.ml_delivery_staff(uid) WHERE uid IS NOT NULL AND deleted_at IS NULL; CREATE UNIQUE INDEX IF NOT EXISTS uq_ml_delivery_staff_staff_no_active ON public.ml_delivery_staff(staff_no) WHERE staff_no IS NOT NULL AND deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_ml_delivery_staff_station_id ON public.ml_delivery_staff(station_id) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_ml_delivery_staff_deleted_at ON public.ml_delivery_staff(deleted_at); CREATE INDEX IF NOT EXISTS idx_ml_delivery_staff_status_active ON public.ml_delivery_staff(status, is_active) WHERE deleted_at IS NULL; CREATE INDEX IF NOT EXISTS idx_ml_delivery_stations_deleted_at ON public.ml_delivery_stations(deleted_at); CREATE INDEX IF NOT EXISTS idx_ml_delivery_stations_status_active ON public.ml_delivery_stations(status) WHERE deleted_at IS NULL; DROP TRIGGER IF EXISTS trg_ml_delivery_staff_set_updated_at ON public.ml_delivery_staff; CREATE TRIGGER trg_ml_delivery_staff_set_updated_at BEFORE UPDATE ON public.ml_delivery_staff FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); DROP TRIGGER IF EXISTS trg_ml_delivery_stations_set_updated_at ON public.ml_delivery_stations; CREATE TRIGGER trg_ml_delivery_stations_set_updated_at BEFORE UPDATE ON public.ml_delivery_stations FOR EACH ROW EXECUTE FUNCTION public.tg_set_updated_at(); 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_self_update ON public.ml_delivery_staff; CREATE POLICY delivery_staff_self_select ON public.ml_delivery_staff FOR SELECT TO authenticated USING ( deleted_at IS NULL AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = ml_delivery_staff.uid AND u.auth_id = auth.uid() ) ); CREATE POLICY delivery_staff_self_update ON public.ml_delivery_staff FOR UPDATE TO authenticated USING ( deleted_at IS NULL AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = ml_delivery_staff.uid AND u.auth_id = auth.uid() ) ) WITH CHECK ( deleted_at IS NULL AND EXISTS ( SELECT 1 FROM public.ak_users u WHERE u.id = ml_delivery_staff.uid AND u.auth_id = auth.uid() ) ); DROP POLICY IF EXISTS delivery_stations_select_active ON public.ml_delivery_stations; CREATE POLICY delivery_stations_select_active ON public.ml_delivery_stations FOR SELECT TO anon, authenticated USING (status = 1 AND deleted_at IS NULL); COMMENT ON COLUMN public.ml_delivery_staff.station_id IS '所属机构/服务站点 ID'; COMMENT ON COLUMN public.ml_delivery_staff.staff_no IS '服务人员编号'; COMMENT ON COLUMN public.ml_delivery_staff.online_status IS '在线状态:online/resting/busy'; COMMENT ON COLUMN public.ml_delivery_staff.certificate_status IS '资质状态:valid/expired/pending'; COMMENT ON COLUMN public.ml_delivery_staff.certificate_expire_at IS '主要资质到期日期'; COMMENT ON COLUMN public.ml_delivery_staff.service_area IS '服务区域描述'; COMMENT ON COLUMN public.ml_delivery_staff.skills IS '技能标签 JSON 数组'; COMMENT ON COLUMN public.ml_delivery_staff.deleted_at IS '软删除时间'; 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;