2d847e154f
中华文明全图鉴——文物全图系统(PC Web 地图 + NestJS API + 管理后台)。 含三大 IP(文物南迁北归 / 国宝海外回归 / 博物馆手艺人)、AI 文物对话、 文物地图与详情、以及 demo-video-kit 演示视频生成工具。
226 lines
9.3 KiB
SQL
226 lines
9.3 KiB
SQL
-- 启用 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);
|