chore: 初始化仓库

中华文明全图鉴——文物全图系统(PC Web 地图 + NestJS API + 管理后台)。
含三大 IP(文物南迁北归 / 国宝海外回归 / 博物馆手艺人)、AI 文物对话、
文物地图与详情、以及 demo-video-kit 演示视频生成工具。
This commit is contained in:
selfrelease
2026-06-13 20:55:44 +08:00
commit 2d847e154f
161 changed files with 22629 additions and 0 deletions
+225
View File
@@ -0,0 +1,225 @@
-- 启用 PostGIS 扩展
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS postgis;
-- 枚举类型
CREATE TYPE artifact_category AS ENUM (
'bronze','painting_calligraphy','porcelain','jade','gold_silver',
'lacquer','textile','stone_carving','wood_carving','dunhuang','ancient_book','other'
);
CREATE TYPE artifact_level AS ENUM ('level_1','level_2','level_3','general','unknown');
CREATE TYPE artifact_status AS ENUM ('at_home','away','in_transit','unknown');
CREATE TYPE location_type AS ENUM ('domestic','overseas','unknown','in_transit');
CREATE TYPE location_precision AS ENUM ('exact_room','exact_building','city','country','region');
CREATE TYPE display_status AS ENUM ('on_display','in_storage','loaned','repairing','touring','unknown');
CREATE TYPE source_type AS ENUM ('institution_feed','manual_entry','user_report','expert_verify','public_source');
CREATE TYPE publish_status AS ENUM ('draft','pending','published','archived','rejected');
CREATE TYPE tag_value_type AS ENUM ('single','multiple','boolean','text','number');
-- users
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
username VARCHAR(100) UNIQUE,
phone VARCHAR(30),
email VARCHAR(255),
password_hash VARCHAR(255),
nickname VARCHAR(100),
avatar_url TEXT,
user_type VARCHAR(30) NOT NULL DEFAULT 'public',
institution_id UUID,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- roles
CREATE TABLE roles (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- permissions
CREATE TABLE permissions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(100) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
module VARCHAR(50) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- user_roles
CREATE TABLE user_roles (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (user_id, role_id)
);
-- institutions
CREATE TABLE institutions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(255) NOT NULL,
short_name VARCHAR(100),
code VARCHAR(100) UNIQUE,
institution_type VARCHAR(50) NOT NULL DEFAULT 'museum',
country VARCHAR(100) NOT NULL DEFAULT '中国',
province VARCHAR(100),
city VARCHAR(100),
address TEXT,
location geography(Point, 4326),
official_website TEXT,
description TEXT,
is_verified BOOLEAN NOT NULL DEFAULT FALSE,
publish_status publish_status NOT NULL DEFAULT 'draft',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_institutions_location_gist ON institutions USING GIST(location);
CREATE INDEX idx_institutions_name ON institutions(name);
CREATE INDEX idx_institutions_country_city ON institutions(country, city);
-- artifacts
CREATE TABLE artifacts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
unified_map_id VARCHAR(50) UNIQUE,
name VARCHAR(255) NOT NULL,
alternative_names TEXT[] DEFAULT '{}',
category artifact_category NOT NULL DEFAULT 'other',
dynasty VARCHAR(100),
level artifact_level NOT NULL DEFAULT 'unknown',
material VARCHAR(255),
dimensions VARCHAR(255),
current_status artifact_status NOT NULL DEFAULT 'unknown',
home_institution_id UUID REFERENCES institutions(id),
summary TEXT,
story_hook VARCHAR(255),
persona_quote VARCHAR(255),
publish_status publish_status NOT NULL DEFAULT 'draft',
created_by UUID REFERENCES users(id),
updated_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_artifacts_name ON artifacts(name);
CREATE INDEX idx_artifacts_category ON artifacts(category);
CREATE INDEX idx_artifacts_dynasty ON artifacts(dynasty);
CREATE INDEX idx_artifacts_status ON artifacts(current_status);
CREATE INDEX idx_artifacts_home_institution ON artifacts(home_institution_id);
CREATE INDEX idx_artifacts_publish_status ON artifacts(publish_status);
-- artifact_locations
CREATE TABLE artifact_locations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
artifact_id UUID NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE,
location_type location_type NOT NULL DEFAULT 'unknown',
institution_id UUID REFERENCES institutions(id),
precise_location geography(Point, 4326),
public_location geography(Point, 4326),
fuzzy_area geography(Polygon, 4326),
precision location_precision NOT NULL DEFAULT 'city',
floor_plan_ref VARCHAR(255),
room_name VARCHAR(255),
cabinet_no VARCHAR(100),
display_status display_status NOT NULL DEFAULT 'unknown',
source_type source_type NOT NULL DEFAULT 'manual_entry',
source_description TEXT,
discoverer_user_id UUID REFERENCES users(id),
is_current BOOLEAN NOT NULL DEFAULT FALSE,
verified_at TIMESTAMPTZ,
valid_from TIMESTAMPTZ,
valid_until TIMESTAMPTZ,
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_artifact_locations_artifact_id ON artifact_locations(artifact_id);
CREATE INDEX idx_artifact_locations_institution_id ON artifact_locations(institution_id);
CREATE INDEX idx_artifact_locations_public_location_gist ON artifact_locations USING GIST(public_location);
CREATE INDEX idx_artifact_locations_precise_location_gist ON artifact_locations USING GIST(precise_location);
CREATE INDEX idx_artifact_locations_fuzzy_area_gist ON artifact_locations USING GIST(fuzzy_area);
CREATE INDEX idx_artifact_locations_current ON artifact_locations(artifact_id, is_current);
-- tag_categories
CREATE TABLE tag_categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(100) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
sort_order INT NOT NULL DEFAULT 0,
is_system BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- tags
CREATE TABLE tags (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
category_id UUID NOT NULL REFERENCES tag_categories(id),
code VARCHAR(100) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
value_type tag_value_type NOT NULL DEFAULT 'single',
description TEXT,
color VARCHAR(20),
icon VARCHAR(100),
is_system BOOLEAN NOT NULL DEFAULT FALSE,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- artifact_tags
CREATE TABLE artifact_tags (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
artifact_id UUID NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE,
tag_id UUID NOT NULL REFERENCES tags(id),
value_text TEXT,
value_number NUMERIC,
confidence NUMERIC(5,2),
source_type source_type NOT NULL DEFAULT 'manual_entry',
review_status VARCHAR(30) NOT NULL DEFAULT 'approved',
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_artifact_tags_unique ON artifact_tags(artifact_id, tag_id, COALESCE(value_text, ''));
CREATE INDEX idx_artifact_tags_artifact_id ON artifact_tags(artifact_id);
CREATE INDEX idx_artifact_tags_tag_id ON artifact_tags(tag_id);
-- digital_assets
CREATE TABLE digital_assets (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
artifact_id UUID REFERENCES artifacts(id) ON DELETE CASCADE,
institution_id UUID REFERENCES institutions(id),
asset_type VARCHAR(50) NOT NULL DEFAULT 'image',
title VARCHAR(255),
url TEXT NOT NULL,
thumbnail_url TEXT,
mime_type VARCHAR(100),
size_bytes BIGINT,
copyright_owner VARCHAR(255),
license_scope TEXT,
sort_order INT NOT NULL DEFAULT 0,
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_digital_assets_artifact_id ON digital_assets(artifact_id);
-- operation_logs
CREATE TABLE operation_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
operator_id UUID REFERENCES users(id),
operator_role VARCHAR(50),
action VARCHAR(100) NOT NULL,
target_type VARCHAR(100) NOT NULL,
target_id UUID,
before_data JSONB,
after_data JSONB,
ip_address VARCHAR(50),
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_operation_logs_operator_id ON operation_logs(operator_id);
CREATE INDEX idx_operation_logs_target ON operation_logs(target_type, target_id);
CREATE INDEX idx_operation_logs_created_at ON operation_logs(created_at DESC);
@@ -0,0 +1,2 @@
-- 为文物增加封面图字段(著名文物使用实拍图,其余前端用统一示意图占位)
ALTER TABLE artifacts ADD COLUMN IF NOT EXISTS image_url TEXT;
@@ -0,0 +1,28 @@
-- 三大 IP 支撑:文物回归状态 + 叙事路线(南迁之路 / 回归之路)
-- 回归状态:domestic 国内传承 / lost_overseas 流失海外 / repatriated 已回归 / in_transit 在途
ALTER TABLE artifacts ADD COLUMN IF NOT EXISTS repatriation_status VARCHAR(30) NOT NULL DEFAULT 'domestic';
-- 叙事路线(南迁、回归等)
CREATE TABLE IF NOT EXISTS narrative_routes (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(50) UNIQUE NOT NULL,
title VARCHAR(255) NOT NULL,
type VARCHAR(30) NOT NULL, -- migration(南迁)| repatriation(回归)
color VARCHAR(20),
summary TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 路线途经点(按 seq 顺序连线)
CREATE TABLE IF NOT EXISTS route_stops (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
route_id UUID NOT NULL REFERENCES narrative_routes(id) ON DELETE CASCADE,
seq INT NOT NULL,
name VARCHAR(255) NOT NULL,
lng DOUBLE PRECISION NOT NULL,
lat DOUBLE PRECISION NOT NULL,
year_label VARCHAR(50),
event TEXT
);
CREATE INDEX IF NOT EXISTS idx_route_stops_route ON route_stops(route_id, seq);
@@ -0,0 +1,2 @@
-- 回归路线与具体文物关联(每件回归国宝一条专属路线)
ALTER TABLE narrative_routes ADD COLUMN IF NOT EXISTS artifact_id UUID REFERENCES artifacts(id);