-- ============================================================================= -- zqyy_app / public(小程序业务表) -- 生成日期:2026-03-15 -- 来源:测试库(通过脚本自动导出) -- ============================================================================= CREATE SCHEMA IF NOT EXISTS public; -- 序列 CREATE SEQUENCE IF NOT EXISTS public.admin_users_id_seq AS integer; CREATE SEQUENCE IF NOT EXISTS public.approvals_id_seq AS bigint; CREATE SEQUENCE IF NOT EXISTS public.member_retention_clue_id_seq AS bigint; CREATE SEQUENCE IF NOT EXISTS public.permissions_id_seq AS integer; CREATE SEQUENCE IF NOT EXISTS public.roles_id_seq AS integer; CREATE SEQUENCE IF NOT EXISTS public.tasks_id_seq AS bigint; CREATE SEQUENCE IF NOT EXISTS public.users_id_seq AS bigint; -- 表 CREATE TABLE public.admin_users ( id integer DEFAULT nextval('admin_users_id_seq'::regclass) NOT NULL, username character varying(64) NOT NULL, password_hash character varying(256) NOT NULL, display_name character varying(128), site_id bigint NOT NULL, is_active boolean DEFAULT true, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); CREATE TABLE public.approvals ( id bigint DEFAULT nextval('approvals_id_seq'::regclass) NOT NULL, task_id bigint, approver_id bigint, status text DEFAULT 'pending'::text, comment text, site_id bigint NOT NULL, created_at timestamp with time zone DEFAULT now() ); CREATE TABLE public.member_retention_clue ( id bigint DEFAULT nextval('member_retention_clue_id_seq'::regclass) NOT NULL, member_id bigint NOT NULL, category character varying(20) NOT NULL, summary character varying(200) NOT NULL, detail text, recorded_by_assistant_id bigint, recorded_by_name character varying(50), recorded_at timestamp with time zone DEFAULT now() NOT NULL, site_id bigint NOT NULL, source character varying(20) DEFAULT 'manual'::character varying NOT NULL ); CREATE TABLE public.permissions ( id integer DEFAULT nextval('permissions_id_seq'::regclass) NOT NULL, resource text NOT NULL, action text NOT NULL, description text ); CREATE TABLE public.role_permissions ( role_id integer NOT NULL, permission_id integer NOT NULL ); CREATE TABLE public.roles ( id integer DEFAULT nextval('roles_id_seq'::regclass) NOT NULL, name text NOT NULL, description text, site_id bigint NOT NULL, created_at timestamp with time zone DEFAULT now() ); CREATE TABLE public.scheduled_tasks ( id uuid DEFAULT gen_random_uuid() NOT NULL, site_id bigint NOT NULL, name character varying(256) NOT NULL, task_codes _text NOT NULL, task_config jsonb NOT NULL, schedule_config jsonb NOT NULL, enabled boolean DEFAULT true, last_run_at timestamp with time zone, next_run_at timestamp with time zone, run_count integer DEFAULT 0, last_status character varying(20), created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); CREATE TABLE public.task_execution_log ( id uuid DEFAULT gen_random_uuid() NOT NULL, queue_id uuid, site_id bigint NOT NULL, task_codes _text NOT NULL, status character varying(20) NOT NULL, started_at timestamp with time zone NOT NULL, finished_at timestamp with time zone, exit_code integer, duration_ms bigint, command text, output_log text, error_log text, summary jsonb, created_at timestamp with time zone DEFAULT now(), schedule_id uuid ); CREATE TABLE public.task_queue ( id uuid DEFAULT gen_random_uuid() NOT NULL, site_id bigint NOT NULL, config jsonb NOT NULL, status character varying(20) DEFAULT 'pending'::character varying NOT NULL, "position" integer DEFAULT 0 NOT NULL, created_at timestamp with time zone DEFAULT now(), started_at timestamp with time zone, finished_at timestamp with time zone, exit_code integer, error_message text, schedule_id uuid, enqueued_by character varying(255) DEFAULT NULL::character varying ); CREATE TABLE public.tasks ( id bigint DEFAULT nextval('tasks_id_seq'::regclass) NOT NULL, title text NOT NULL, description text, status text DEFAULT 'pending'::text, assignee_id bigint, creator_id bigint, site_id bigint NOT NULL, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); CREATE TABLE public.user_roles ( user_id bigint NOT NULL, role_id integer NOT NULL, site_id bigint NOT NULL ); CREATE TABLE public.users ( id bigint DEFAULT nextval('users_id_seq'::regclass) NOT NULL, wx_openid text, mobile text, nickname text, status integer DEFAULT 1, site_id bigint NOT NULL, created_at timestamp with time zone DEFAULT now(), updated_at timestamp with time zone DEFAULT now() ); -- 约束(主键 / 唯一 / 外键) ALTER TABLE admin_users ADD CONSTRAINT admin_users_pkey PRIMARY KEY (id); ALTER TABLE admin_users ADD CONSTRAINT admin_users_username_key UNIQUE (username); ALTER TABLE approvals ADD CONSTRAINT approvals_approver_id_fkey FOREIGN KEY (approver_id) REFERENCES users(id); ALTER TABLE approvals ADD CONSTRAINT approvals_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE; ALTER TABLE approvals ADD CONSTRAINT approvals_pkey PRIMARY KEY (id); ALTER TABLE member_retention_clue ADD CONSTRAINT member_retention_clue_pkey PRIMARY KEY (id); ALTER TABLE permissions ADD CONSTRAINT permissions_pkey PRIMARY KEY (id); ALTER TABLE permissions ADD CONSTRAINT permissions_resource_action_key UNIQUE (resource, action); ALTER TABLE role_permissions ADD CONSTRAINT role_permissions_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE; ALTER TABLE role_permissions ADD CONSTRAINT role_permissions_role_id_fkey FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE; ALTER TABLE role_permissions ADD CONSTRAINT role_permissions_pkey PRIMARY KEY (role_id, permission_id); ALTER TABLE roles ADD CONSTRAINT roles_pkey PRIMARY KEY (id); ALTER TABLE roles ADD CONSTRAINT roles_name_key UNIQUE (name); ALTER TABLE scheduled_tasks ADD CONSTRAINT scheduled_tasks_pkey PRIMARY KEY (id); ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_queue_id_fkey FOREIGN KEY (queue_id) REFERENCES task_queue(id); ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_schedule_id_fkey FOREIGN KEY (schedule_id) REFERENCES scheduled_tasks(id) ON DELETE SET NULL; ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_pkey PRIMARY KEY (id); ALTER TABLE task_queue ADD CONSTRAINT task_queue_schedule_id_fkey FOREIGN KEY (schedule_id) REFERENCES scheduled_tasks(id) ON DELETE SET NULL; ALTER TABLE task_queue ADD CONSTRAINT task_queue_pkey PRIMARY KEY (id); ALTER TABLE tasks ADD CONSTRAINT tasks_assignee_id_fkey FOREIGN KEY (assignee_id) REFERENCES users(id); ALTER TABLE tasks ADD CONSTRAINT tasks_creator_id_fkey FOREIGN KEY (creator_id) REFERENCES users(id); ALTER TABLE tasks ADD CONSTRAINT tasks_pkey PRIMARY KEY (id); ALTER TABLE user_roles ADD CONSTRAINT user_roles_role_id_fkey FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE; ALTER TABLE user_roles ADD CONSTRAINT user_roles_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ALTER TABLE user_roles ADD CONSTRAINT user_roles_pkey PRIMARY KEY (user_id, role_id); ALTER TABLE users ADD CONSTRAINT users_pkey PRIMARY KEY (id); ALTER TABLE users ADD CONSTRAINT users_wx_openid_key UNIQUE (wx_openid); -- 索引 CREATE INDEX idx_admin_users_site ON public.admin_users USING btree (site_id); CREATE INDEX idx_approvals_site_id ON public.approvals USING btree (site_id); CREATE INDEX idx_approvals_task_id ON public.approvals USING btree (task_id); CREATE INDEX idx_retention_clue_category ON public.member_retention_clue USING btree (member_id, category); CREATE INDEX idx_retention_clue_member ON public.member_retention_clue USING btree (member_id); CREATE INDEX idx_retention_clue_site ON public.member_retention_clue USING btree (site_id); CREATE INDEX idx_roles_site_id ON public.roles USING btree (site_id); CREATE INDEX idx_scheduled_tasks_next_run ON public.scheduled_tasks USING btree (next_run_at) WHERE (enabled = true); CREATE INDEX idx_scheduled_tasks_site ON public.scheduled_tasks USING btree (site_id); CREATE INDEX idx_execution_log_schedule_id ON public.task_execution_log USING btree (schedule_id) WHERE (schedule_id IS NOT NULL); CREATE INDEX idx_execution_log_site_started ON public.task_execution_log USING btree (site_id, started_at DESC); CREATE INDEX idx_task_queue_site_position ON public.task_queue USING btree (site_id, "position") WHERE ((status)::text = 'pending'::text); CREATE INDEX idx_task_queue_status ON public.task_queue USING btree (status); CREATE INDEX idx_tasks_assignee_id ON public.tasks USING btree (assignee_id); CREATE INDEX idx_tasks_site_id ON public.tasks USING btree (site_id); CREATE INDEX idx_tasks_status ON public.tasks USING btree (status); CREATE INDEX idx_user_roles_site_id ON public.user_roles USING btree (site_id); CREATE INDEX idx_users_mobile ON public.users USING btree (mobile); CREATE INDEX idx_users_site_id ON public.users USING btree (site_id); -- ============================================================================= -- 种子数据:Web 管理后台默认管理员账号 -- 默认密码:admin123(bcrypt hash,cost=12) -- 生产环境部署后务必立即修改密码 -- ============================================================================= INSERT INTO admin_users (username, password_hash, display_name, site_id, is_active) VALUES ( 'admin', '$2b$12$2MTWlJKL0HTgHIkv5Rmpie2pQ9PkeJu0iciLbzPEpPcA94ZakIQzq', '默认管理员', 1, TRUE ) ON CONFLICT (username) DO NOTHING;