feat(order-service): 重构分类资料收集与订单状态链路

This commit is contained in:
yml2213
2026-11-03 19:46:49 +08:00
parent 6e4758a3c7
commit 9f14e8de7a
59 changed files with 4866 additions and 1734 deletions
@@ -0,0 +1,74 @@
-- 128_order_service_profiles.sql
--
-- 分类级订单服务配置:资料收集字段、引导图、截图规则与自动发布策略。
-- 工单创建时固化配置快照,后续修改配置不影响已创建工单。
ALTER TABLE work_categories
ADD COLUMN IF NOT EXISTS default_work_rule_id BIGINT REFERENCES work_product_rules(id) ON DELETE SET NULL;
COMMENT ON COLUMN work_categories.default_work_rule_id IS
'分类默认接单模板;商品级映射可覆盖,未命中时整个分类使用该模板';
CREATE TABLE IF NOT EXISTS order_service_profiles (
id BIGSERIAL PRIMARY KEY,
category_id BIGINT NOT NULL REFERENCES work_categories(id) ON DELETE CASCADE,
name TEXT NOT NULL,
title TEXT NOT NULL DEFAULT '',
description TEXT NOT NULL DEFAULT '',
guide_image_json JSONB NOT NULL DEFAULT '{}'::jsonb,
fields_json JSONB NOT NULL DEFAULT '[]'::jsonb,
screenshots_json JSONB NOT NULL DEFAULT '{}'::jsonb,
auto_publish_json JSONB NOT NULL DEFAULT '{"enabled":false}'::jsonb,
submit_text TEXT NOT NULL DEFAULT '提交资料',
success_text TEXT NOT NULL DEFAULT '资料已提交,请等待处理',
status TEXT NOT NULL DEFAULT 'draft',
current_version_id BIGINT,
created_by_admin_user_id BIGINT REFERENCES admin_users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT order_service_profiles_status_check
CHECK (status IN ('draft', 'published', 'archived'))
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_order_service_profiles_category
ON order_service_profiles (category_id);
CREATE INDEX IF NOT EXISTS idx_order_service_profiles_status
ON order_service_profiles (status);
CREATE TABLE IF NOT EXISTS order_service_profile_versions (
id BIGSERIAL PRIMARY KEY,
profile_id BIGINT NOT NULL REFERENCES order_service_profiles(id) ON DELETE CASCADE,
version_no INTEGER NOT NULL,
config_json JSONB NOT NULL DEFAULT '{}'::jsonb,
published_by_admin_user_id BIGINT REFERENCES admin_users(id) ON DELETE SET NULL,
published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_order_service_profile_versions_no
UNIQUE (profile_id, version_no)
);
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'fk_order_service_profiles_current_version'
) THEN
ALTER TABLE order_service_profiles
ADD CONSTRAINT fk_order_service_profiles_current_version
FOREIGN KEY (current_version_id)
REFERENCES order_service_profile_versions(id) ON DELETE SET NULL;
END IF;
END $$;
ALTER TABLE work_orders
ADD COLUMN IF NOT EXISTS service_profile_id BIGINT REFERENCES order_service_profiles(id) ON DELETE SET NULL,
ADD COLUMN IF NOT EXISTS service_profile_version_id BIGINT REFERENCES order_service_profile_versions(id) ON DELETE SET NULL,
ADD COLUMN IF NOT EXISTS service_profile_snapshot_json JSONB;
CREATE INDEX IF NOT EXISTS idx_work_orders_service_profile
ON work_orders (service_profile_id, service_profile_version_id)
WHERE service_profile_id IS NOT NULL;
COMMENT ON TABLE order_service_profiles IS
'分类级订单服务配置:资料字段、引导图、截图规则与自动发布策略';
COMMENT ON COLUMN work_orders.service_profile_snapshot_json IS
'工单创建时固化的订单服务配置快照;配置后续变更不影响该工单';
@@ -0,0 +1,29 @@
-- 129_order_service_auto_publish_jobs.sql
--
-- 资料提交后自动发布工单。任务先落库,外部电子凭证核销失败时可以重试。
CREATE TABLE IF NOT EXISTS order_service_auto_publish_jobs (
id BIGSERIAL PRIMARY KEY,
work_order_id BIGINT NOT NULL REFERENCES work_orders(id) ON DELETE CASCADE,
status TEXT NOT NULL DEFAULT 'pending',
attempt_count INTEGER NOT NULL DEFAULT 0,
max_attempts INTEGER NOT NULL DEFAULT 3,
next_run_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_error TEXT NOT NULL DEFAULT '',
result_json JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT order_service_auto_publish_jobs_status_check
CHECK (status IN ('pending', 'succeeded', 'failed', 'skipped'))
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_order_service_auto_publish_pending
ON order_service_auto_publish_jobs (work_order_id)
WHERE status = 'pending';
CREATE INDEX IF NOT EXISTS idx_order_service_auto_publish_due
ON order_service_auto_publish_jobs (next_run_at)
WHERE status = 'pending';
COMMENT ON TABLE order_service_auto_publish_jobs IS
'客户资料提交后的自动发布任务;核销失败可按配置重试';
@@ -0,0 +1,35 @@
-- 130_customer_notifications.sql
--
-- 客户订单通知事件模型。首版只落事件,不发送短信;
-- 后续接入 SMS Provider 时消费 pending 任务即可。
CREATE TABLE IF NOT EXISTS customer_order_notifications (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT REFERENCES orders(id) ON DELETE CASCADE,
order_item_id BIGINT REFERENCES order_items(id) ON DELETE SET NULL,
work_order_id BIGINT REFERENCES work_orders(id) ON DELETE CASCADE,
event_type TEXT NOT NULL,
channel TEXT NOT NULL DEFAULT 'sms',
status TEXT NOT NULL DEFAULT 'skipped',
phone TEXT NOT NULL DEFAULT '',
template_key TEXT NOT NULL DEFAULT '',
payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
dedupe_key TEXT NOT NULL,
attempt_count INTEGER NOT NULL DEFAULT 0,
last_error TEXT NOT NULL DEFAULT '',
sent_at TIMESTAMPTZ,
next_run_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT customer_order_notifications_channel_check
CHECK (channel IN ('web', 'sms')),
CONSTRAINT customer_order_notifications_status_check
CHECK (status IN ('pending', 'sent', 'failed', 'skipped'))
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_customer_order_notifications_dedupe
ON customer_order_notifications (dedupe_key);
CREATE INDEX IF NOT EXISTS idx_customer_order_notifications_pending
ON customer_order_notifications (next_run_at)
WHERE status = 'pending';
@@ -0,0 +1,34 @@
-- 131_order_service_hardening.sql
--
-- 订单服务配置以“分类 -> 当前发布版本”为线上唯一读取源。
-- 分类与接单模板的绑定沿用 work_product_rules.category_id,不再维护反向默认模板。
ALTER TABLE work_categories
DROP COLUMN IF EXISTS default_work_rule_id;
ALTER TABLE order_service_auto_publish_jobs
ADD COLUMN IF NOT EXISTS locked_until TIMESTAMPTZ,
ADD COLUMN IF NOT EXISTS locked_by TEXT NOT NULL DEFAULT '',
ADD COLUMN IF NOT EXISTS finished_at TIMESTAMPTZ;
ALTER TABLE order_service_auto_publish_jobs
DROP CONSTRAINT IF EXISTS order_service_auto_publish_jobs_status_check;
ALTER TABLE order_service_auto_publish_jobs
ADD CONSTRAINT order_service_auto_publish_jobs_status_check
CHECK (status IN ('pending', 'processing', 'succeeded', 'failed', 'skipped'));
DROP INDEX IF EXISTS uq_order_service_auto_publish_pending;
CREATE UNIQUE INDEX IF NOT EXISTS uq_order_service_auto_publish_active
ON order_service_auto_publish_jobs (work_order_id)
WHERE status IN ('pending', 'processing');
CREATE INDEX IF NOT EXISTS idx_order_service_auto_publish_lease
ON order_service_auto_publish_jobs (locked_until)
WHERE status = 'processing';
COMMENT ON COLUMN order_service_auto_publish_jobs.locked_until IS
'任务处理租约到期时间;进程中断后可被其它 worker 重新领取';
COMMENT ON COLUMN order_service_auto_publish_jobs.locked_by IS
'领取任务的进程或实例标识';