完善下单逻辑及其ui展示,修复支付倒计时显示错误bug

This commit is contained in:
2026-05-25 15:35:41 +08:00
parent d25f80ccdd
commit cecb51a8e2
40 changed files with 13040 additions and 3217 deletions

View File

@@ -0,0 +1,114 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.hss_service_catalog (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
category TEXT NOT NULL DEFAULT '',
price NUMERIC(10, 2) NOT NULL DEFAULT 0,
duration_text TEXT NOT NULL DEFAULT '',
summary TEXT NOT NULL DEFAULT '',
tags_json JSONB NOT NULL DEFAULT '[]'::jsonb,
suitable_for TEXT NOT NULL DEFAULT '',
sort_no INTEGER NOT NULL DEFAULT 0,
status SMALLINT NOT NULL DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_hss_service_catalog_status_sort
ON public.hss_service_catalog(status, sort_no)
WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_hss_service_catalog_category
ON public.hss_service_catalog(category)
WHERE deleted_at IS NULL;
CREATE OR REPLACE FUNCTION public.tg_hss_service_catalog_updated_at()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$;
DROP TRIGGER IF EXISTS trg_hss_service_catalog_updated_at ON public.hss_service_catalog;
CREATE TRIGGER trg_hss_service_catalog_updated_at
BEFORE UPDATE ON public.hss_service_catalog
FOR EACH ROW
EXECUTE FUNCTION public.tg_hss_service_catalog_updated_at();
ALTER TABLE public.hss_service_catalog ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS hss_service_catalog_public_select ON public.hss_service_catalog;
CREATE POLICY hss_service_catalog_public_select
ON public.hss_service_catalog
FOR SELECT
USING (deleted_at IS NULL AND status = 1);
INSERT INTO public.hss_service_catalog (
id,
name,
category,
price,
duration_text,
summary,
tags_json,
suitable_for,
sort_no,
status
) VALUES
(
'svc-001',
'基础上门护理',
'日常照护',
168,
'约 2 小时',
'覆盖生命体征监测、基础照护、风险提醒。',
'["适老化", "护理员上门", "支持家属陪同"]'::jsonb,
'行动不便、术后恢复、慢病随访老人',
10,
1
),
(
'svc-002',
'康复训练指导',
'康复支持',
260,
'约 3 小时',
'提供肢体训练、步态练习和居家康复建议。',
'["康复师", "步骤清晰", "可连续预约"]'::jsonb,
'卒中恢复、术后康复、失能半失能老人',
20,
1
),
(
'svc-003',
'慢病健康随访',
'健康管理',
128,
'约 90 分钟',
'完成血压血糖监测、用药核对与健康宣教。',
'["随访", "慢病", "可生成记录"]'::jsonb,
'高血压、糖尿病等长期管理老人',
30,
1
)
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
category = EXCLUDED.category,
price = EXCLUDED.price,
duration_text = EXCLUDED.duration_text,
summary = EXCLUDED.summary,
tags_json = EXCLUDED.tags_json,
suitable_for = EXCLUDED.suitable_for,
sort_no = EXCLUDED.sort_no,
status = EXCLUDED.status,
deleted_at = NULL,
updated_at = now();
COMMENT ON TABLE public.hss_service_catalog IS '居家上门服务目录表';
COMMIT;

View File

@@ -0,0 +1,274 @@
BEGIN;
ALTER TABLE public.ml_user_addresses
ADD COLUMN IF NOT EXISTS latitude DOUBLE PRECISION,
ADD COLUMN IF NOT EXISTS longitude DOUBLE PRECISION,
ADD COLUMN IF NOT EXISTS coordinate_type TEXT NOT NULL DEFAULT 'gcj02';
CREATE TABLE IF NOT EXISTS public.hss_service_orders (
id TEXT PRIMARY KEY,
order_no TEXT NOT NULL UNIQUE,
user_id UUID NOT NULL,
service_id TEXT NOT NULL,
service_name TEXT NOT NULL,
service_snapshot_json JSONB NOT NULL DEFAULT '{}'::jsonb,
service_address_id UUID,
address_snapshot_json JSONB NOT NULL DEFAULT '{}'::jsonb,
recipient_name TEXT NOT NULL DEFAULT '',
recipient_phone TEXT NOT NULL DEFAULT '',
contact_name TEXT NOT NULL DEFAULT '',
contact_phone TEXT NOT NULL DEFAULT '',
appointment_time TIMESTAMPTZ,
remark TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'created',
current_assignment_id TEXT NOT NULL DEFAULT '',
current_staff_id UUID,
accepted_at TIMESTAMPTZ,
departed_at TIMESTAMPTZ,
arrived_at TIMESTAMPTZ,
service_started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
pending_acceptance_at TIMESTAMPTZ,
accepted_by_user_at TIMESTAMPTZ,
reviewed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted_at TIMESTAMPTZ,
deleted_by UUID,
CONSTRAINT chk_hss_service_orders_status CHECK (
status IN (
'created', 'paid', 'assigned', 'accepted', 'rejected', 'departed', 'arrived',
'in_service', 'completed', 'pending_acceptance', 'accepted_by_user',
'reviewed', 'settled', 'cancelled', 'exception'
)
)
);
CREATE TABLE IF NOT EXISTS public.hss_service_assignments (
id TEXT PRIMARY KEY,
order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
staff_id UUID NOT NULL REFERENCES public.ml_delivery_staff(id) ON DELETE RESTRICT,
station_id UUID REFERENCES public.ml_delivery_stations(id) ON DELETE SET NULL,
status TEXT NOT NULL DEFAULT 'assigned',
assigned_at TIMESTAMPTZ NOT NULL DEFAULT now(),
accepted_at TIMESTAMPTZ,
rejected_at TIMESTAMPTZ,
reject_reason TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
CONSTRAINT chk_hss_service_assignments_status CHECK (
status IN ('assigned', 'accepted', 'rejected', 'departed', 'arrived', 'in_service', 'pending_acceptance', 'completed', 'cancelled', 'exception')
)
);
CREATE TABLE IF NOT EXISTS public.hss_service_execution_records (
id TEXT PRIMARY KEY,
order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
assignment_id TEXT NOT NULL REFERENCES public.hss_service_assignments(id) ON DELETE CASCADE,
checkin_time TIMESTAMPTZ,
checkin_latitude DOUBLE PRECISION,
checkin_longitude DOUBLE PRECISION,
checkin_address TEXT NOT NULL DEFAULT '',
service_started_at TIMESTAMPTZ,
service_finished_at TIMESTAMPTZ,
actual_duration_minutes INTEGER NOT NULL DEFAULT 0,
service_items_json JSONB NOT NULL DEFAULT '[]'::jsonb,
summary TEXT NOT NULL DEFAULT '',
remark TEXT NOT NULL DEFAULT '',
track_points_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.hss_service_evidence_files (
id TEXT PRIMARY KEY,
order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
execution_record_id TEXT REFERENCES public.hss_service_execution_records(id) ON DELETE CASCADE,
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 TABLE IF NOT EXISTS public.hss_service_order_status_logs (
id TEXT PRIMARY KEY,
order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
from_status TEXT NOT NULL DEFAULT '',
to_status TEXT NOT NULL,
operator_id UUID,
operator_role TEXT NOT NULL DEFAULT '',
remark TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS public.hss_service_reviews (
id TEXT PRIMARY KEY,
order_id TEXT NOT NULL REFERENCES public.hss_service_orders(id) ON DELETE CASCADE,
user_id UUID NOT NULL,
rating INTEGER NOT NULL DEFAULT 5,
tags_json JSONB NOT NULL DEFAULT '[]'::jsonb,
content TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_hss_service_orders_user_status
ON public.hss_service_orders(user_id, status)
WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_hss_service_orders_staff_status
ON public.hss_service_orders(current_staff_id, status)
WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS idx_hss_service_assignments_staff_status
ON public.hss_service_assignments(staff_id, status);
CREATE INDEX IF NOT EXISTS idx_hss_service_execution_records_order
ON public.hss_service_execution_records(order_id);
CREATE INDEX IF NOT EXISTS idx_hss_service_evidence_files_order
ON public.hss_service_evidence_files(order_id);
CREATE INDEX IF NOT EXISTS idx_hss_service_logs_order_created
ON public.hss_service_order_status_logs(order_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_hss_service_reviews_order
ON public.hss_service_reviews(order_id);
CREATE OR REPLACE FUNCTION public.tg_hss_set_updated_at()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$;
DROP TRIGGER IF EXISTS trg_hss_service_orders_updated_at ON public.hss_service_orders;
CREATE TRIGGER trg_hss_service_orders_updated_at
BEFORE UPDATE ON public.hss_service_orders
FOR EACH ROW
EXECUTE FUNCTION public.tg_hss_set_updated_at();
DROP TRIGGER IF EXISTS trg_hss_service_assignments_updated_at ON public.hss_service_assignments;
CREATE TRIGGER trg_hss_service_assignments_updated_at
BEFORE UPDATE ON public.hss_service_assignments
FOR EACH ROW
EXECUTE FUNCTION public.tg_hss_set_updated_at();
DROP TRIGGER IF EXISTS trg_hss_service_execution_records_updated_at ON public.hss_service_execution_records;
CREATE TRIGGER trg_hss_service_execution_records_updated_at
BEFORE UPDATE ON public.hss_service_execution_records
FOR EACH ROW
EXECUTE FUNCTION public.tg_hss_set_updated_at();
ALTER TABLE public.hss_service_orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_assignments ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_execution_records ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_evidence_files ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_order_status_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.hss_service_reviews ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS hss_service_orders_user_select ON public.hss_service_orders;
CREATE POLICY hss_service_orders_user_select
ON public.hss_service_orders
FOR SELECT
TO authenticated
USING (
deleted_at IS NULL AND (
user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
OR current_staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL)
)
);
DROP POLICY IF EXISTS hss_service_orders_user_insert ON public.hss_service_orders;
CREATE POLICY hss_service_orders_user_insert
ON public.hss_service_orders
FOR INSERT
TO authenticated
WITH CHECK (user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()));
DROP POLICY IF EXISTS hss_service_orders_user_update ON public.hss_service_orders;
CREATE POLICY hss_service_orders_user_update
ON public.hss_service_orders
FOR UPDATE
TO authenticated
USING (
deleted_at IS NULL AND (
user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
OR current_staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL)
)
)
WITH CHECK (
deleted_at IS NULL AND (
user_id IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid())
OR current_staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL)
)
);
DROP POLICY IF EXISTS hss_service_assignments_staff_select ON public.hss_service_assignments;
CREATE POLICY hss_service_assignments_staff_select
ON public.hss_service_assignments
FOR SELECT
TO authenticated
USING (staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL));
DROP POLICY IF EXISTS hss_service_assignments_staff_update ON public.hss_service_assignments;
CREATE POLICY hss_service_assignments_staff_update
ON public.hss_service_assignments
FOR UPDATE
TO authenticated
USING (staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL))
WITH CHECK (staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL));
DROP POLICY IF EXISTS hss_service_assignments_staff_insert ON public.hss_service_assignments;
CREATE POLICY hss_service_assignments_staff_insert
ON public.hss_service_assignments
FOR INSERT
TO authenticated
WITH CHECK (staff_id IN (SELECT id FROM public.ml_delivery_staff WHERE uid IN (SELECT id FROM public.ak_users WHERE auth_id = auth.uid()) AND deleted_at IS NULL));
DROP POLICY IF EXISTS hss_service_execution_records_order_access ON public.hss_service_execution_records;
CREATE POLICY hss_service_execution_records_order_access
ON public.hss_service_execution_records
FOR ALL
TO authenticated
USING (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL))
WITH CHECK (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL));
DROP POLICY IF EXISTS hss_service_evidence_files_order_access ON public.hss_service_evidence_files;
CREATE POLICY hss_service_evidence_files_order_access
ON public.hss_service_evidence_files
FOR ALL
TO authenticated
USING (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL))
WITH CHECK (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL));
DROP POLICY IF EXISTS hss_service_order_status_logs_order_access ON public.hss_service_order_status_logs;
CREATE POLICY hss_service_order_status_logs_order_access
ON public.hss_service_order_status_logs
FOR ALL
TO authenticated
USING (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL))
WITH CHECK (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL));
DROP POLICY IF EXISTS hss_service_reviews_order_access ON public.hss_service_reviews;
CREATE POLICY hss_service_reviews_order_access
ON public.hss_service_reviews
FOR ALL
TO authenticated
USING (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL))
WITH CHECK (order_id IN (SELECT id FROM public.hss_service_orders WHERE deleted_at IS NULL));
COMMENT ON TABLE public.hss_service_orders IS '居家上门服务订单主表';
COMMENT ON TABLE public.hss_service_assignments IS '居家上门服务派单表';
COMMENT ON TABLE public.hss_service_execution_records IS '居家上门服务执行记录表';
COMMENT ON TABLE public.hss_service_evidence_files IS '居家上门服务证据文件表';
COMMENT ON TABLE public.hss_service_order_status_logs IS '居家上门服务状态日志表';
COMMENT ON TABLE public.hss_service_reviews IS '居家上门服务评价表';
COMMIT;

View File

@@ -0,0 +1,17 @@
BEGIN;
ALTER TABLE public.ml_orders
ADD COLUMN IF NOT EXISTS cancelled_at TIMESTAMPTZ NULL,
ADD COLUMN IF NOT EXISTS consumer_deleted_at TIMESTAMPTZ NULL;
COMMENT ON COLUMN public.ml_orders.cancelled_at IS '订单取消时间,包含用户取消与支付超时取消';
COMMENT ON COLUMN public.ml_orders.consumer_deleted_at IS '消费者侧软删除时间,仅影响消费者订单列表展示';
CREATE INDEX IF NOT EXISTS idx_ml_orders_consumer_deleted_at
ON public.ml_orders(user_id, consumer_deleted_at, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ml_orders_consumer_visible
ON public.ml_orders(user_id, created_at DESC)
WHERE consumer_deleted_at IS NULL;
COMMIT;

View File

@@ -0,0 +1,35 @@
BEGIN;
ALTER TABLE public.hss_service_orders
ADD COLUMN IF NOT EXISTS payment_status SMALLINT NOT NULL DEFAULT 1;
ALTER TABLE public.hss_service_orders
ADD COLUMN IF NOT EXISTS pay_expire_at TIMESTAMPTZ;
ALTER TABLE public.hss_service_orders
ADD COLUMN IF NOT EXISTS cancel_reason TEXT NOT NULL DEFAULT '';
ALTER TABLE public.hss_service_orders
ADD COLUMN IF NOT EXISTS cancelled_at TIMESTAMPTZ;
ALTER TABLE public.hss_service_orders
ADD COLUMN IF NOT EXISTS consumer_deleted_at TIMESTAMPTZ;
CREATE INDEX IF NOT EXISTS idx_hss_service_orders_user_visible
ON public.hss_service_orders(user_id, created_at DESC)
WHERE consumer_deleted_at IS NULL;
UPDATE public.hss_service_orders
SET pay_expire_at = created_at + INTERVAL '10 minutes'
WHERE pay_expire_at IS NULL
AND status = 'created'
AND payment_status = 1;
ALTER TABLE public.ml_orders
ADD COLUMN IF NOT EXISTS pay_expire_at TIMESTAMPTZ,
ADD COLUMN IF NOT EXISTS payment_status SMALLINT NOT NULL DEFAULT 1,
ADD COLUMN IF NOT EXISTS cancel_reason TEXT NOT NULL DEFAULT '',
ADD COLUMN IF NOT EXISTS cancelled_at TIMESTAMPTZ,
ADD COLUMN IF NOT EXISTS consumer_deleted_at TIMESTAMPTZ;
COMMIT;

View File

@@ -0,0 +1,77 @@
BEGIN;
ALTER TABLE public.ml_orders
ADD COLUMN IF NOT EXISTS pay_expire_at TIMESTAMPTZ;
ALTER TABLE public.ml_orders
DROP CONSTRAINT IF EXISTS chk_ml_order_status;
ALTER TABLE public.ml_orders
DROP CONSTRAINT IF EXISTS chk_ml_payment_status;
ALTER TABLE public.ml_orders
ADD CONSTRAINT chk_ml_order_status CHECK (order_status IN (1,2,3,4,5,6,7,8));
ALTER TABLE public.ml_orders
ADD CONSTRAINT chk_ml_payment_status CHECK (payment_status IN (1,2,3,4,5));
COMMENT ON COLUMN public.ml_orders.pay_expire_at IS '支付截止时间,超过后订单进入已超时';
UPDATE public.ml_orders
SET pay_expire_at = created_at + INTERVAL '10 minutes'
WHERE pay_expire_at IS NULL
AND order_status = 1
AND payment_status = 1;
UPDATE public.ml_orders
SET order_status = 8,
payment_status = 5,
cancel_reason = CASE
WHEN cancel_reason IS NULL OR cancel_reason = '' THEN '支付超时自动关闭'
ELSE cancel_reason
END,
updated_at = NOW()
WHERE order_status = 1
AND payment_status = 1
AND pay_expire_at IS NOT NULL
AND pay_expire_at <= NOW();
CREATE INDEX IF NOT EXISTS idx_ml_orders_pay_expire_at
ON public.ml_orders(pay_expire_at);
DROP VIEW IF EXISTS public.ml_orders_detail_view;
CREATE VIEW public.ml_orders_detail_view AS
SELECT
o.*,
u.username as customer_name,
u.phone as customer_phone,
m.username as merchant_name,
s.shop_name,
CASE
WHEN o.order_status = 1 THEN '待付款'
WHEN o.order_status = 2 THEN '待发货'
WHEN o.order_status = 3 THEN '待收货'
WHEN o.order_status = 4 THEN '已完成'
WHEN o.order_status = 5 THEN '已取消'
WHEN o.order_status = 6 THEN '退款中'
WHEN o.order_status = 7 THEN '已退款'
WHEN o.order_status = 8 THEN '已超时'
ELSE '未知'
END as order_status_name,
CASE
WHEN o.payment_status = 1 THEN '未付款'
WHEN o.payment_status = 2 THEN '已付款'
WHEN o.payment_status = 3 THEN '部分退款'
WHEN o.payment_status = 4 THEN '全额退款'
WHEN o.payment_status = 5 THEN '已关闭'
ELSE '未知'
END as payment_status_name
FROM public.ml_orders o
LEFT JOIN public.ak_users u ON o.user_id = u.id
LEFT JOIN public.ak_users m ON o.merchant_id = m.id
LEFT JOIN public.ml_shops s ON o.merchant_id = s.merchant_id;
COMMENT ON VIEW public.ml_orders_detail_view IS '订单详情视图';
COMMIT;