feat:新增docker密钥登录部署
This commit is contained in:
parent
e761bde30b
commit
f6e1caad8b
@ -98,10 +98,11 @@ func (r *rankingRepository) getHotRankingByDimension(starID int64, dimension str
|
|||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
startOfMonth := time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 0, 0, 0, time.Local).UnixMilli()
|
startOfMonth := time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 0, 0, 0, time.Local).UnixMilli()
|
||||||
|
|
||||||
// 构建基础查询,JOIN 用户表和粉丝档案表获取昵称和头像(一次查询,避免 N+1 问题)
|
// 构建基础查询,JOIN 用户表和粉丝档案表获取昵称和头像
|
||||||
|
// 使用 GROUP BY 去重,并用聚合函数获取 owner 信息
|
||||||
|
// is_original 是布尔值,需要转为 int 再取 MAX
|
||||||
db := r.db.Model(&models.Asset{}).
|
db := r.db.Model(&models.Asset{}).
|
||||||
Select("assets.id as asset_id, assets.name as asset_name, assets.cover_url, assets.owner_uid, assets.like_count, assets.is_original, fp.nickname as owner_nickname, fp.avatar_url as owner_avatar").
|
Select("assets.id as asset_id, assets.name as asset_name, assets.cover_url, assets.owner_uid, MAX(assets.like_count) as like_count, MAX(assets.is_original::int) as is_original, MAX(fp.nickname) as owner_nickname, MAX(fp.avatar_url) as owner_avatar").
|
||||||
|
|
||||||
Joins("LEFT JOIN fan_profiles fp ON fp.user_id = assets.owner_uid AND fp.star_id = ?", starID).
|
Joins("LEFT JOIN fan_profiles fp ON fp.user_id = assets.owner_uid AND fp.star_id = ?", starID).
|
||||||
Where("assets.star_id = ? AND assets.is_active = ? AND assets.status = ?", starID, true, models.AssetStatusActive)
|
Where("assets.star_id = ? AND assets.is_active = ? AND assets.status = ?", starID, true, models.AssetStatusActive)
|
||||||
|
|
||||||
@ -112,20 +113,21 @@ func (r *rankingRepository) getHotRankingByDimension(starID int64, dimension str
|
|||||||
// 根据维度添加条件
|
// 根据维度添加条件
|
||||||
switch dimension {
|
switch dimension {
|
||||||
case "displaying":
|
case "displaying":
|
||||||
// 展示中:关联 Exhibition 表,筛选未过期的,且是当前star的展馆
|
// 展示中:关联 Exhibition 表,筛选未过期的、未删除的,且是当前star的展品
|
||||||
db = db.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
// occupier_star_id 表示展品所属的明星
|
||||||
Joins("INNER JOIN fan_profiles ON fan_profiles.id = exhibitions.host_profile_id").
|
db = db.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id AND exhibitions.deleted_at IS NULL").
|
||||||
Where("exhibitions.expire_at > ?", now).
|
Where("exhibitions.expire_at > ?", now).
|
||||||
Where("fan_profiles.star_id = ?", starID)
|
Where("exhibitions.occupier_star_id = ?", starID)
|
||||||
case "month":
|
case "month":
|
||||||
// 本月:本月内展览过的(未下架或本月内下架的)
|
// 本月:本月内展览过的藏品(包括已下架的,只要 expire_at 在本月内即可)
|
||||||
db = db.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
db = db.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
||||||
Where("exhibitions.expire_at >= ?", startOfMonth)
|
Where("exhibitions.expire_at >= ?", startOfMonth).
|
||||||
|
Where("exhibitions.occupier_star_id = ?", starID)
|
||||||
case "total":
|
case "total":
|
||||||
// 全部:直接使用 assets 表的 like_count,无需额外条件
|
// 全部:直接使用 assets 表的 like_count,无需额外条件
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统计总数
|
// 统计总数(先查询 ID 列表再 Count,避免 DISTINCT 干扰)
|
||||||
var total int64
|
var total int64
|
||||||
countDB := r.db.Model(&models.Asset{}).
|
countDB := r.db.Model(&models.Asset{}).
|
||||||
Select("assets.id").
|
Select("assets.id").
|
||||||
@ -136,22 +138,23 @@ func (r *rankingRepository) getHotRankingByDimension(starID int64, dimension str
|
|||||||
}
|
}
|
||||||
switch dimension {
|
switch dimension {
|
||||||
case "displaying":
|
case "displaying":
|
||||||
countDB = countDB.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
countDB = countDB.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id AND exhibitions.deleted_at IS NULL").
|
||||||
Joins("INNER JOIN fan_profiles AS host_fp ON host_fp.id = exhibitions.host_profile_id").
|
|
||||||
Where("exhibitions.expire_at > ?", now).
|
Where("exhibitions.expire_at > ?", now).
|
||||||
Where("host_fp.star_id = ?", starID)
|
Where("exhibitions.occupier_star_id = ?", starID)
|
||||||
case "month":
|
case "month":
|
||||||
// 本月:本月内展览过的(未下架或本月内下架的)
|
// 本月:本月内展览过的藏品(包括已下架的)
|
||||||
countDB = countDB.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
countDB = countDB.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
||||||
Where("exhibitions.expire_at >= ?", startOfMonth)
|
Where("exhibitions.expire_at >= ?", startOfMonth).
|
||||||
|
Where("exhibitions.occupier_star_id = ?", starID)
|
||||||
}
|
}
|
||||||
if err := countDB.Count(&total).Error; err != nil {
|
if err := countDB.Count(&total).Error; err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询列表
|
// 查询列表(使用 GROUP BY 去重,按点赞数排序)
|
||||||
var results []*RankingItem
|
var results []*RankingItem
|
||||||
err := db.Order("assets.like_count DESC, assets.id ASC").
|
err := db.Group("assets.id").
|
||||||
|
Order("MAX(assets.like_count) DESC, assets.id ASC").
|
||||||
Limit(limit).
|
Limit(limit).
|
||||||
Offset(offset).
|
Offset(offset).
|
||||||
Scan(&results).Error
|
Scan(&results).Error
|
||||||
@ -187,15 +190,15 @@ func (r *rankingRepository) GetMyBestRanking(userID, starID int64, dimension str
|
|||||||
// 根据维度添加条件,与 getHotRankingByDimension 保持一致
|
// 根据维度添加条件,与 getHotRankingByDimension 保持一致
|
||||||
switch dimension {
|
switch dimension {
|
||||||
case "displaying":
|
case "displaying":
|
||||||
// 展示中:关联 Exhibition 表,筛选未过期的,且是当前star的展馆
|
// 展示中:关联 Exhibition 表,筛选未过期的、未删除的,且是当前star的展品
|
||||||
db = db.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
db = db.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id AND exhibitions.deleted_at IS NULL").
|
||||||
Joins("INNER JOIN fan_profiles AS host_fp ON host_fp.id = exhibitions.host_profile_id").
|
|
||||||
Where("exhibitions.expire_at > ?", now).
|
Where("exhibitions.expire_at > ?", now).
|
||||||
Where("host_fp.star_id = ?", starID)
|
Where("exhibitions.occupier_star_id = ?", starID)
|
||||||
case "month":
|
case "month":
|
||||||
// 本月:本月内展览过的(未下架或本月内下架的)
|
// 本月:本月内展览过的藏品(包括已下架的)
|
||||||
db = db.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
db = db.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
||||||
Where("exhibitions.expire_at >= ?", startOfMonth)
|
Where("exhibitions.expire_at >= ?", startOfMonth).
|
||||||
|
Where("exhibitions.occupier_star_id = ?", starID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户在该star下点赞数最高的藏品
|
// 获取用户在该star下点赞数最高的藏品
|
||||||
@ -231,14 +234,14 @@ func (r *rankingRepository) GetMyBestRanking(userID, starID int64, dimension str
|
|||||||
|
|
||||||
switch dimension {
|
switch dimension {
|
||||||
case "displaying":
|
case "displaying":
|
||||||
rankingDB = rankingDB.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
rankingDB = rankingDB.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id AND exhibitions.deleted_at IS NULL").
|
||||||
Joins("INNER JOIN fan_profiles AS host_fp ON host_fp.id = exhibitions.host_profile_id").
|
|
||||||
Where("exhibitions.expire_at > ?", now).
|
Where("exhibitions.expire_at > ?", now).
|
||||||
Where("host_fp.star_id = ?", starID)
|
Where("exhibitions.occupier_star_id = ?", starID)
|
||||||
case "month":
|
case "month":
|
||||||
// 本月:本月内展览过的(未下架或本月内下架的)
|
// 本月:本月内展览过的藏品(包括已下架的)
|
||||||
rankingDB = rankingDB.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
rankingDB = rankingDB.Joins("INNER JOIN exhibitions ON exhibitions.asset_id = assets.id").
|
||||||
Where("exhibitions.expire_at >= ?", startOfMonth)
|
Where("exhibitions.expire_at >= ?", startOfMonth).
|
||||||
|
Where("exhibitions.occupier_star_id = ?", starID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rankingDB.Count(&rank).Error; err != nil {
|
if err := rankingDB.Count(&rank).Error; err != nil {
|
||||||
|
|||||||
@ -42,7 +42,13 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" \
|
|||||||
echo "Built galleryservice" && \
|
echo "Built galleryservice" && \
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" \
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" \
|
||||||
-o /tmp/activityservice services/activityService/main.go && \
|
-o /tmp/activityservice services/activityService/main.go && \
|
||||||
echo "Built activityservice"
|
echo "Built activityservice" && \
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" \
|
||||||
|
-o /tmp/taskservice services/taskService/main.go && \
|
||||||
|
echo "Built taskservice" && \
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="-s -w" \
|
||||||
|
-o /tmp/starbookservice services/starbookService/main.go && \
|
||||||
|
echo "Built starbookservice"
|
||||||
|
|
||||||
# ---- Runtime Stage: Gateway ----
|
# ---- Runtime Stage: Gateway ----
|
||||||
FROM --platform=linux/amd64 alpine:3.19 AS gateway
|
FROM --platform=linux/amd64 alpine:3.19 AS gateway
|
||||||
@ -135,3 +141,33 @@ HEALTHCHECK --interval=10s --timeout=5s --start-period=10s --retries=3 \
|
|||||||
CMD wget --no-verbose --tries=1 --spider http://localhost:20005 || exit 1
|
CMD wget --no-verbose --tries=1 --spider http://localhost:20005 || exit 1
|
||||||
|
|
||||||
ENTRYPOINT ["/app/activityservice"]
|
ENTRYPOINT ["/app/activityservice"]
|
||||||
|
|
||||||
|
# ---- Runtime Stage: TaskService ----
|
||||||
|
FROM --platform=linux/amd64 alpine:3.19 AS taskservice
|
||||||
|
|
||||||
|
RUN apk add --no-cache ca-certificates tzdata
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /tmp/taskservice /app/taskservice
|
||||||
|
|
||||||
|
EXPOSE 20006
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=10s --timeout=5s --start-period=10s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:21006 || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/taskservice"]
|
||||||
|
|
||||||
|
# ---- Runtime Stage: StarbookService ----
|
||||||
|
FROM --platform=linux/amd64 alpine:3.19 AS starbookservice
|
||||||
|
|
||||||
|
RUN apk add --no-cache ca-certificates tzdata
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /tmp/starbookservice /app/starbookservice
|
||||||
|
|
||||||
|
EXPOSE 20007
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=10s --timeout=5s --start-period=10s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:21007 || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/starbookservice"]
|
||||||
|
|||||||
@ -77,7 +77,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
echo ""
|
echo ""
|
||||||
echo "服务名 (可选):"
|
echo "服务名 (可选):"
|
||||||
echo " gateway, userService, socialService, assetService,"
|
echo " gateway, userService, socialService, assetService,"
|
||||||
echo " galleryService, activityService"
|
echo " galleryService, activityService, taskService, starbookService"
|
||||||
echo ""
|
echo ""
|
||||||
echo "示例:"
|
echo "示例:"
|
||||||
echo " $0 # 构建所有服务"
|
echo " $0 # 构建所有服务"
|
||||||
@ -96,6 +96,8 @@ while [[ $# -gt 0 ]]; do
|
|||||||
asset|assetService) SERVICES+=("assetService") ;;
|
asset|assetService) SERVICES+=("assetService") ;;
|
||||||
gallery|galleryService) SERVICES+=("galleryService") ;;
|
gallery|galleryService) SERVICES+=("galleryService") ;;
|
||||||
activity|activityService) SERVICES+=("activityService") ;;
|
activity|activityService) SERVICES+=("activityService") ;;
|
||||||
|
task|taskService) SERVICES+=("taskService") ;;
|
||||||
|
starbook|starbookService) SERVICES+=("starbookService") ;;
|
||||||
all)
|
all)
|
||||||
# all 关键字,构建所有服务
|
# all 关键字,构建所有服务
|
||||||
SERVICES=()
|
SERVICES=()
|
||||||
@ -114,7 +116,7 @@ done
|
|||||||
|
|
||||||
# ==================== 服务列表 ====================
|
# ==================== 服务列表 ====================
|
||||||
# 所有可用服务及其配置(使用小写 target 名)
|
# 所有可用服务及其配置(使用小写 target 名)
|
||||||
ALL_SERVICES_NAME=("gateway" "userservice" "socialservice" "assetservice" "galleryservice" "activityservice")
|
ALL_SERVICES_NAME=("gateway" "userservice" "socialservice" "assetservice" "galleryservice" "activityservice" "taskservice" "starbookservice")
|
||||||
|
|
||||||
# 确定要构建的服务
|
# 确定要构建的服务
|
||||||
if [ ${#SERVICES[@]} -eq 0 ]; then
|
if [ ${#SERVICES[@]} -eq 0 ]; then
|
||||||
@ -201,12 +203,16 @@ main() {
|
|||||||
assetservice) docker_target="assetservice" ;;
|
assetservice) docker_target="assetservice" ;;
|
||||||
galleryservice) docker_target="galleryservice" ;;
|
galleryservice) docker_target="galleryservice" ;;
|
||||||
activityservice) docker_target="activityservice" ;;
|
activityservice) docker_target="activityservice" ;;
|
||||||
|
taskservice) docker_target="taskservice" ;;
|
||||||
|
starbookservice) docker_target="starbookservice" ;;
|
||||||
# 兼容旧的大写服务名
|
# 兼容旧的大写服务名
|
||||||
userService) docker_target="userservice" ;;
|
userService) docker_target="userservice" ;;
|
||||||
socialService) docker_target="socialservice" ;;
|
socialService) docker_target="socialservice" ;;
|
||||||
assetService) docker_target="assetservice" ;;
|
assetService) docker_target="assetservice" ;;
|
||||||
galleryService) docker_target="galleryservice" ;;
|
galleryService) docker_target="galleryservice" ;;
|
||||||
activityService) docker_target="activityservice" ;;
|
activityService) docker_target="activityservice" ;;
|
||||||
|
taskService) docker_target="taskservice" ;;
|
||||||
|
starbookService) docker_target="starbookservice" ;;
|
||||||
*) docker_target="$service" ;;
|
*) docker_target="$service" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|||||||
@ -76,6 +76,8 @@ SERVICES=(
|
|||||||
"assetservice"
|
"assetservice"
|
||||||
"galleryservice"
|
"galleryservice"
|
||||||
"activityservice"
|
"activityservice"
|
||||||
|
"taskservice"
|
||||||
|
"starbookservice"
|
||||||
)
|
)
|
||||||
|
|
||||||
# ==================== 服务器配置 ====================
|
# ==================== 服务器配置 ====================
|
||||||
@ -83,19 +85,32 @@ SERVICES=(
|
|||||||
SERVER_HOST="101.132.250.62" # 服务器 IP 或域名
|
SERVER_HOST="101.132.250.62" # 服务器 IP 或域名
|
||||||
SERVER_PORT="22" # SSH 端口
|
SERVER_PORT="22" # SSH 端口
|
||||||
SERVER_USER="root" # SSH 用户名
|
SERVER_USER="root" # SSH 用户名
|
||||||
SERVER_PASSWORD=">n73qBnCja-,#VF+Wq" # 服务器密码
|
SERVER_PASSWORD="" # 服务器密码(仅在未配置 SSH 密钥时使用)
|
||||||
SERVER_PATH="/opt/topfans/docker" # 服务器上 docker 目录路径
|
SERVER_PATH="/opt/topfans/docker" # 服务器上 docker 目录路径
|
||||||
|
SSH_KEY_PATH="$HOME/.ssh/id_rsa" # SSH 密钥路径,默认使用 ~/.ssh/id_rsa
|
||||||
|
|
||||||
# ==================== SSH 别名 ====================
|
# ==================== SSH 别名 ====================
|
||||||
# 使用 sshpass 执行 SSH 命令
|
# 优先使用 SSH 密钥,如果失败则使用密码
|
||||||
ssh_cmd() {
|
ssh_cmd() {
|
||||||
|
if [ -n "$SERVER_PASSWORD" ]; then
|
||||||
sshpass -p "$SERVER_PASSWORD" ssh -o StrictHostKeyChecking=no -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" "$@"
|
sshpass -p "$SERVER_PASSWORD" ssh -o StrictHostKeyChecking=no -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" "$@"
|
||||||
|
else
|
||||||
|
ssh -o StrictHostKeyChecking=no -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" "$@"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
ssh_cmd_batch() {
|
ssh_cmd_batch() {
|
||||||
|
if [ -n "$SERVER_PASSWORD" ]; then
|
||||||
sshpass -p "$SERVER_PASSWORD" ssh -o StrictHostKeyChecking=no -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" "$@"
|
sshpass -p "$SERVER_PASSWORD" ssh -o StrictHostKeyChecking=no -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" "$@"
|
||||||
|
else
|
||||||
|
ssh -o StrictHostKeyChecking=no -p "$SERVER_PORT" "$SERVER_USER@$SERVER_HOST" "$@"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
scp_cmd() {
|
scp_cmd() {
|
||||||
sshpass -p "$SERVER_PASSWORD" scp -P "$SERVER_PORT" "$@"
|
if [ -n "$SERVER_PASSWORD" ]; then
|
||||||
|
sshpass -p "$SERVER_PASSWORD" scp -o StrictHostKeyChecking=no -P "$SERVER_PORT" "$@"
|
||||||
|
else
|
||||||
|
scp -o StrictHostKeyChecking=no -P "$SERVER_PORT" "$@"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ==================== 打印函数 ====================
|
# ==================== 打印函数 ====================
|
||||||
@ -148,7 +163,11 @@ ${YELLOW}示例:${NC}
|
|||||||
|
|
||||||
${YELLOW}前提准备:${NC}
|
${YELLOW}前提准备:${NC}
|
||||||
1. 修改 SERVER_HOST 为你的服务器 IP
|
1. 修改 SERVER_HOST 为你的服务器 IP
|
||||||
2. 配置服务器 SSH 免密登录(建议)
|
2. 配置 SSH 密钥登录(推荐):
|
||||||
|
- 生成密钥:ssh-keygen -t rsa
|
||||||
|
- 上传公钥:ssh-copy-id -i ~/.ssh/id_rsa.pub root@你的服务器IP
|
||||||
|
- 设置 SSH_KEY_PATH="~/.ssh/id_rsa"
|
||||||
|
3. 或使用密码登录:设置 SERVER_PASSWORD
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@ -341,10 +360,11 @@ ENDSSH
|
|||||||
|
|
||||||
# 上传配置文件
|
# 上传配置文件
|
||||||
print_step "📤 上传配置文件"
|
print_step "📤 上传配置文件"
|
||||||
print_msg "$YELLOW" "上传 docker-compose.prod.yml 和 .env.prod..."
|
print_msg "$YELLOW" "上传 docker-compose.prod.yml, .env.prod, init-db.sql..."
|
||||||
scp_cmd "${SCRIPT_DIR}/docker-compose.prod.yml" "${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/"
|
scp_cmd "${SCRIPT_DIR}/docker-compose.prod.yml" "${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/"
|
||||||
scp_cmd "${SCRIPT_DIR}/.env.prod" "${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/"
|
scp_cmd "${SCRIPT_DIR}/.env.prod" "${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/"
|
||||||
scp_cmd "${SCRIPT_DIR}/init-db.sql" "${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/"
|
scp_cmd "${SCRIPT_DIR}/init-db.sql" "${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/"
|
||||||
|
scp_cmd -r "${SCRIPT_DIR}/sql" "${SERVER_USER}@${SERVER_HOST}:${SERVER_PATH}/"
|
||||||
print_msg "$GREEN" "✅ 配置文件上传完成"
|
print_msg "$GREEN" "✅ 配置文件上传完成"
|
||||||
|
|
||||||
# 从 tar 文件加载镜像
|
# 从 tar 文件加载镜像
|
||||||
|
|||||||
@ -192,6 +192,70 @@ services:
|
|||||||
reservations:
|
reservations:
|
||||||
memory: 256M
|
memory: 256M
|
||||||
|
|
||||||
|
taskservice:
|
||||||
|
image: topfans/taskservice:latest
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: docker/Dockerfile.services
|
||||||
|
target: taskservice
|
||||||
|
container_name: topfans-taskservice
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
<<: *common-env
|
||||||
|
PORT: 20006
|
||||||
|
USER_SERVICE_URL: tri://userservice:20000
|
||||||
|
depends_on:
|
||||||
|
userservice:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- topfans-net
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
expose:
|
||||||
|
- "20006"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "nc -z localhost 20006 || exit 1"]
|
||||||
|
<<: *healthcheck
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
memory: 256M
|
||||||
|
|
||||||
|
starbookservice:
|
||||||
|
image: topfans/starbookservice:latest
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: docker/Dockerfile.services
|
||||||
|
target: starbookservice
|
||||||
|
container_name: topfans-starbookservice
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
<<: *common-env
|
||||||
|
PORT: 20007
|
||||||
|
ASSET_SERVICE_URL: tri://assetservice:20003
|
||||||
|
depends_on:
|
||||||
|
userservice:
|
||||||
|
condition: service_healthy
|
||||||
|
assetservice:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- topfans-net
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
expose:
|
||||||
|
- "20007"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "nc -z localhost 20007 || exit 1"]
|
||||||
|
<<: *healthcheck
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
memory: 256M
|
||||||
|
|
||||||
# ==================== API Gateway ====================
|
# ==================== API Gateway ====================
|
||||||
gateway:
|
gateway:
|
||||||
image: topfans/gateway:latest
|
image: topfans/gateway:latest
|
||||||
@ -210,6 +274,8 @@ services:
|
|||||||
DUBBO_ASSET_SERVICE_URL: tri://assetservice:20003
|
DUBBO_ASSET_SERVICE_URL: tri://assetservice:20003
|
||||||
DUBBO_GALLERY_SERVICE_URL: tri://galleryservice:20004
|
DUBBO_GALLERY_SERVICE_URL: tri://galleryservice:20004
|
||||||
DUBBO_ACTIVITY_SERVICE_URL: tri://activityservice:20005
|
DUBBO_ACTIVITY_SERVICE_URL: tri://activityservice:20005
|
||||||
|
DUBBO_TASK_SERVICE_URL: tri://taskservice:20006
|
||||||
|
DUBBO_STARBOOK_SERVICE_URL: tri://starbookservice:20007
|
||||||
depends_on:
|
depends_on:
|
||||||
userservice:
|
userservice:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@ -221,6 +287,10 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
activityservice:
|
activityservice:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
taskservice:
|
||||||
|
condition: service_healthy
|
||||||
|
starbookservice:
|
||||||
|
condition: service_healthy
|
||||||
networks:
|
networks:
|
||||||
- topfans-net
|
- topfans-net
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@ -44,7 +44,6 @@ services:
|
|||||||
<<: *postgres-env
|
<<: *postgres-env
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql
|
- postgres_data:/var/lib/postgresql
|
||||||
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
|
|
||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
networks:
|
networks:
|
||||||
@ -59,6 +58,27 @@ services:
|
|||||||
reservations:
|
reservations:
|
||||||
memory: 128M
|
memory: 128M
|
||||||
|
|
||||||
|
# ==================== Flyway Migration ====================
|
||||||
|
flyway:
|
||||||
|
image: flyway/flyway:10
|
||||||
|
container_name: topfans-flyway
|
||||||
|
restart: "no"
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
- FLYWAY_URL=jdbc:postgresql://postgres:5432/topfans
|
||||||
|
- FLYWAY_USER=postgres
|
||||||
|
- FLYWAY_PASSWORD=${DB_PASSWORD:-postgres123}
|
||||||
|
- FLYWAY_SCHEMAS=public
|
||||||
|
- FLYWAY_PLACEHOLDER_REPLACEMENT=true
|
||||||
|
volumes:
|
||||||
|
- ./sql/migrations:/flyway/sql
|
||||||
|
- flyway_data:/flyway/data
|
||||||
|
command: migrate -baselineOnMigrate=true
|
||||||
|
networks:
|
||||||
|
- topfans-net
|
||||||
|
|
||||||
# ==================== Dubbo Services ====================
|
# ==================== Dubbo Services ====================
|
||||||
userservice:
|
userservice:
|
||||||
image: topfans/userservice:latest
|
image: topfans/userservice:latest
|
||||||
@ -77,8 +97,8 @@ services:
|
|||||||
DB_PASSWORD: ${DB_PASSWORD:-postgres123}
|
DB_PASSWORD: ${DB_PASSWORD:-postgres123}
|
||||||
DB_NAME: topfans
|
DB_NAME: topfans
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
flyway:
|
||||||
condition: service_started
|
condition: service_completed_successfully
|
||||||
networks:
|
networks:
|
||||||
- topfans-net
|
- topfans-net
|
||||||
expose:
|
expose:
|
||||||
@ -253,6 +273,80 @@ services:
|
|||||||
memory: 32M
|
memory: 32M
|
||||||
cpus: '0.25'
|
cpus: '0.25'
|
||||||
|
|
||||||
|
taskservice:
|
||||||
|
image: topfans/taskservice:latest
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: docker/Dockerfile.services
|
||||||
|
target: taskservice
|
||||||
|
container_name: topfans-taskservice
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
<<: *common-env
|
||||||
|
PORT: 20006
|
||||||
|
DB_HOST: postgres
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_USER: postgres
|
||||||
|
DB_PASSWORD: ${DB_PASSWORD:-postgres123}
|
||||||
|
DB_NAME: topfans
|
||||||
|
USER_SERVICE_URL: tri://userservice:20000
|
||||||
|
depends_on:
|
||||||
|
userservice:
|
||||||
|
condition: service_started
|
||||||
|
networks:
|
||||||
|
- topfans-net
|
||||||
|
expose:
|
||||||
|
- "20006"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:21006 || exit 1"]
|
||||||
|
<<: *healthcheck
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 150M
|
||||||
|
cpus: '0.5'
|
||||||
|
reservations:
|
||||||
|
memory: 64M
|
||||||
|
cpus: '0.25'
|
||||||
|
|
||||||
|
starbookservice:
|
||||||
|
image: topfans/starbookservice:latest
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: docker/Dockerfile.services
|
||||||
|
target: starbookservice
|
||||||
|
container_name: topfans-starbookservice
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
<<: *common-env
|
||||||
|
PORT: 20007
|
||||||
|
DB_HOST: postgres
|
||||||
|
DB_PORT: 5432
|
||||||
|
DB_USER: postgres
|
||||||
|
DB_PASSWORD: ${DB_PASSWORD:-postgres123}
|
||||||
|
DB_NAME: topfans
|
||||||
|
ASSET_SERVICE_URL: tri://assetservice:20003
|
||||||
|
depends_on:
|
||||||
|
userservice:
|
||||||
|
condition: service_started
|
||||||
|
assetservice:
|
||||||
|
condition: service_started
|
||||||
|
networks:
|
||||||
|
- topfans-net
|
||||||
|
expose:
|
||||||
|
- "20007"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:21007 || exit 1"]
|
||||||
|
<<: *healthcheck
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 150M
|
||||||
|
cpus: '0.5'
|
||||||
|
reservations:
|
||||||
|
memory: 64M
|
||||||
|
cpus: '0.25'
|
||||||
|
|
||||||
# ==================== API Gateway ====================
|
# ==================== API Gateway ====================
|
||||||
gateway:
|
gateway:
|
||||||
image: topfans/gateway:latest
|
image: topfans/gateway:latest
|
||||||
@ -273,6 +367,8 @@ services:
|
|||||||
DUBBO_ASSET_SERVICE_URL: tri://assetservice:20003
|
DUBBO_ASSET_SERVICE_URL: tri://assetservice:20003
|
||||||
DUBBO_GALLERY_SERVICE_URL: tri://galleryservice:20001
|
DUBBO_GALLERY_SERVICE_URL: tri://galleryservice:20001
|
||||||
DUBBO_ACTIVITY_SERVICE_URL: tri://activityservice:20004
|
DUBBO_ACTIVITY_SERVICE_URL: tri://activityservice:20004
|
||||||
|
DUBBO_TASK_SERVICE_URL: tri://taskservice:20006
|
||||||
|
DUBBO_STARBOOK_SERVICE_URL: tri://starbookservice:20007
|
||||||
depends_on:
|
depends_on:
|
||||||
userservice:
|
userservice:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
@ -284,6 +380,10 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
activityservice:
|
activityservice:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
|
taskservice:
|
||||||
|
condition: service_started
|
||||||
|
starbookservice:
|
||||||
|
condition: service_started
|
||||||
networks:
|
networks:
|
||||||
- topfans-net
|
- topfans-net
|
||||||
ports:
|
ports:
|
||||||
@ -300,10 +400,11 @@ services:
|
|||||||
memory: 64M
|
memory: 64M
|
||||||
cpus: '0.25'
|
cpus: '0.25'
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
flyway_data:
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
topfans-net:
|
topfans-net:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
external: true
|
external: true
|
||||||
|
|
||||||
volumes:
|
|
||||||
postgres_data:
|
|
||||||
|
|||||||
@ -253,6 +253,54 @@ CREATE SEQUENCE public.asset_likes_id_seq
|
|||||||
ALTER SEQUENCE public.asset_likes_id_seq OWNED BY public.asset_likes.id;
|
ALTER SEQUENCE public.asset_likes_id_seq OWNED BY public.asset_likes.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.asset_registry (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
asset_id bigint NOT NULL,
|
||||||
|
asset_type character varying(20) NOT NULL,
|
||||||
|
owner_uid bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
grade integer,
|
||||||
|
collection_category character varying(50),
|
||||||
|
activity_id bigint,
|
||||||
|
activity_type character varying(50),
|
||||||
|
status integer DEFAULT 0 NOT NULL,
|
||||||
|
like_count integer DEFAULT 0 NOT NULL,
|
||||||
|
display_status integer DEFAULT 0 NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: TABLE asset_registry; Type: COMMENT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
COMMENT ON TABLE public.asset_registry IS '资产注册表(星册体系)';
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.asset_registry_id_seq
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.asset_registry_id_seq OWNED BY public.asset_registry.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: assets; Type: TABLE; Schema: public; Owner: -
|
-- Name: assets; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -408,7 +456,8 @@ CREATE TABLE public.exhibitions (
|
|||||||
start_time bigint NOT NULL,
|
start_time bigint NOT NULL,
|
||||||
expire_at bigint NOT NULL,
|
expire_at bigint NOT NULL,
|
||||||
created_at bigint NOT NULL,
|
created_at bigint NOT NULL,
|
||||||
updated_at bigint NOT NULL
|
updated_at bigint NOT NULL,
|
||||||
|
deleted_at bigint
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -845,6 +894,13 @@ ALTER TABLE ONLY public.activity_user_stats ALTER COLUMN id SET DEFAULT nextval(
|
|||||||
ALTER TABLE ONLY public.asset_likes ALTER COLUMN id SET DEFAULT nextval('public.asset_likes_id_seq'::regclass);
|
ALTER TABLE ONLY public.asset_likes ALTER COLUMN id SET DEFAULT nextval('public.asset_likes_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.asset_registry ALTER COLUMN id SET DEFAULT nextval('public.asset_registry_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: assets id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: assets id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -852,6 +908,13 @@ ALTER TABLE ONLY public.asset_likes ALTER COLUMN id SET DEFAULT nextval('public.
|
|||||||
ALTER TABLE ONLY public.assets ALTER COLUMN id SET DEFAULT nextval('public.assets_id_seq'::regclass);
|
ALTER TABLE ONLY public.assets ALTER COLUMN id SET DEFAULT nextval('public.assets_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.asset_registry ALTER COLUMN id SET DEFAULT nextval('public.asset_registry_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: booth_slots slot_id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: booth_slots slot_id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -969,6 +1032,14 @@ ALTER TABLE ONLY public.asset_likes
|
|||||||
ADD CONSTRAINT asset_likes_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT asset_likes_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry asset_registry_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.asset_registry
|
||||||
|
ADD CONSTRAINT asset_registry_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: assets assets_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: assets assets_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -1180,6 +1251,13 @@ CREATE INDEX idx_asset_likes_asset ON public.asset_likes USING btree (asset_id);
|
|||||||
CREATE INDEX idx_asset_likes_user_star ON public.asset_likes USING btree (user_id, star_id);
|
CREATE INDEX idx_asset_likes_user_star ON public.asset_likes USING btree (user_id, star_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: idx_registry_owner_star; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX idx_registry_owner_star ON public.asset_registry USING btree (owner_uid, star_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: idx_assets_created_at; Type: INDEX; Schema: public; Owner: -
|
-- Name: idx_assets_created_at; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -1549,6 +1627,30 @@ ALTER TABLE ONLY public.asset_likes
|
|||||||
ADD CONSTRAINT fk_asset_likes_user FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_asset_likes_user FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry fk_registry_asset; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.asset_registry
|
||||||
|
ADD CONSTRAINT fk_registry_asset FOREIGN KEY (asset_id) REFERENCES public.assets(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry fk_registry_owner; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.asset_registry
|
||||||
|
ADD CONSTRAINT fk_registry_owner FOREIGN KEY (owner_uid) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: asset_registry fk_registry_star; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.asset_registry
|
||||||
|
ADD CONSTRAINT fk_registry_star FOREIGN KEY (star_id) REFERENCES public.stars(star_id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: assets fk_assets_owner; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: assets fk_assets_owner; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|||||||
491
docker/sql/migrations/V1__init_schema.sql
Normal file
491
docker/sql/migrations/V1__init_schema.sql
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
-- V1__init_schema.sql
|
||||||
|
-- 初始表结构
|
||||||
|
|
||||||
|
-- postgres 扩展
|
||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 用户相关表
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 用户表
|
||||||
|
CREATE TABLE public.users (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
mobile character varying(11) NOT NULL,
|
||||||
|
password_hash character varying(255) NOT NULL,
|
||||||
|
access_token text,
|
||||||
|
token_expires_at bigint,
|
||||||
|
avatar_url character varying(500),
|
||||||
|
global_wallet_address character varying(100),
|
||||||
|
is_active boolean DEFAULT true NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL,
|
||||||
|
deleted_at bigint
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.users_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.users ADD CONSTRAINT users_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX uk_users_mobile ON public.users USING btree (mobile);
|
||||||
|
CREATE INDEX idx_users_deleted_at ON public.users USING btree (deleted_at);
|
||||||
|
ALTER TABLE ONLY public.users ADD CONSTRAINT fk_users FOREIGN KEY (owner_uid) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 明星信息表
|
||||||
|
CREATE TABLE public.stars (
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
name character varying(100) NOT NULL,
|
||||||
|
tag character varying(100),
|
||||||
|
name_en character varying(100),
|
||||||
|
pic_url character varying(500),
|
||||||
|
description text,
|
||||||
|
identity_id character varying(50) NOT NULL,
|
||||||
|
is_active boolean DEFAULT true NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.stars_star_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.stars ALTER COLUMN star_id SET DEFAULT nextval('public.stars_star_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.stars ADD CONSTRAINT stars_pkey PRIMARY KEY (star_id);
|
||||||
|
CREATE UNIQUE INDEX uk_stars_identity_id ON public.stars USING btree (identity_id);
|
||||||
|
|
||||||
|
-- 粉丝档案表
|
||||||
|
CREATE TABLE public.fan_profiles (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
nickname character varying(50) NOT NULL,
|
||||||
|
level integer DEFAULT 1 NOT NULL,
|
||||||
|
times integer DEFAULT 1 NOT NULL,
|
||||||
|
social integer DEFAULT 0 NOT NULL,
|
||||||
|
experience bigint DEFAULT 0 NOT NULL,
|
||||||
|
coin_balance bigint DEFAULT 0 NOT NULL,
|
||||||
|
crystal_balance bigint DEFAULT 0 NOT NULL,
|
||||||
|
tags jsonb,
|
||||||
|
starbook_limit integer DEFAULT 3 NOT NULL,
|
||||||
|
slot_limit integer DEFAULT 3 NOT NULL,
|
||||||
|
assets_count integer DEFAULT 0 NOT NULL,
|
||||||
|
chain_address character varying(100),
|
||||||
|
is_active boolean DEFAULT true NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL,
|
||||||
|
avatar_url character varying(500)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.fan_profiles_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.fan_profiles ALTER COLUMN id SET DEFAULT nextval('public.fan_profiles_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.fan_profiles ADD CONSTRAINT fan_profiles_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX uk_fan_profiles_user_star ON public.fan_profiles USING btree (user_id, star_id);
|
||||||
|
CREATE UNIQUE INDEX uk_fan_profiles_star_nickname ON public.fan_profiles USING btree (star_id, nickname);
|
||||||
|
CREATE INDEX idx_fan_profiles_user_id ON public.fan_profiles USING btree (user_id);
|
||||||
|
CREATE INDEX idx_fan_profiles_star_id ON public.fan_profiles USING btree (star_id);
|
||||||
|
ALTER TABLE ONLY public.fan_profiles ADD CONSTRAINT fk_fan_profiles_user FOREIGN KEY (user_id) REFERENCES public.users(id);
|
||||||
|
ALTER TABLE ONLY public.fan_profiles ADD CONSTRAINT fk_fan_profiles_star FOREIGN KEY (star_id) REFERENCES public.stars(star_id);
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 藏品相关表
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 资产表(藏品)
|
||||||
|
CREATE TABLE public.assets (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
owner_uid bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
name character varying(100) NOT NULL,
|
||||||
|
cover_url character varying(500) NOT NULL,
|
||||||
|
material_url character varying(500),
|
||||||
|
description text,
|
||||||
|
rarity integer,
|
||||||
|
tags jsonb,
|
||||||
|
visibility character varying(20) DEFAULT 'private'::character varying,
|
||||||
|
status integer DEFAULT 0 NOT NULL,
|
||||||
|
tx_hash character varying(100),
|
||||||
|
block_number bigint,
|
||||||
|
like_count integer DEFAULT 0 NOT NULL,
|
||||||
|
is_original boolean DEFAULT false NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL,
|
||||||
|
minted_at bigint,
|
||||||
|
deleted_at bigint,
|
||||||
|
is_active boolean DEFAULT true NOT NULL,
|
||||||
|
info text
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.assets_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.assets ALTER COLUMN id SET DEFAULT nextval('public.assets_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.assets ADD CONSTRAINT assets_pkey PRIMARY KEY (id);
|
||||||
|
CREATE INDEX idx_assets_created_at ON public.assets USING btree (created_at DESC);
|
||||||
|
CREATE INDEX idx_assets_deleted_at ON public.assets USING btree (deleted_at);
|
||||||
|
CREATE INDEX idx_assets_owner_star ON public.assets USING btree (owner_uid, star_id);
|
||||||
|
CREATE INDEX idx_assets_star_active ON public.assets USING btree (star_id, is_active);
|
||||||
|
CREATE INDEX idx_assets_status ON public.assets USING btree (status);
|
||||||
|
CREATE INDEX idx_assets_tx_hash ON public.assets USING btree (tx_hash);
|
||||||
|
ALTER TABLE ONLY public.assets ADD CONSTRAINT fk_assets_owner FOREIGN KEY (owner_uid) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.assets ADD CONSTRAINT fk_assets_star FOREIGN KEY (star_id) REFERENCES public.stars(star_id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 资产注册表(星册体系)
|
||||||
|
CREATE TABLE public.asset_registry (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
asset_id bigint NOT NULL,
|
||||||
|
asset_type character varying(20) NOT NULL,
|
||||||
|
owner_uid bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
grade integer,
|
||||||
|
collection_category character varying(50),
|
||||||
|
activity_id bigint,
|
||||||
|
activity_type character varying(50),
|
||||||
|
status integer DEFAULT 0 NOT NULL,
|
||||||
|
like_count integer DEFAULT 0 NOT NULL,
|
||||||
|
display_status integer DEFAULT 0 NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.asset_registry_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.asset_registry ALTER COLUMN id SET DEFAULT nextval('public.asset_registry_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.asset_registry ADD CONSTRAINT asset_registry_pkey PRIMARY KEY (id);
|
||||||
|
CREATE INDEX idx_registry_owner_star ON public.asset_registry USING btree (owner_uid, star_id);
|
||||||
|
ALTER TABLE ONLY public.asset_registry ADD CONSTRAINT fk_registry_asset FOREIGN KEY (asset_id) REFERENCES public.assets(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.asset_registry ADD CONSTRAINT fk_registry_owner FOREIGN KEY (owner_uid) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.asset_registry ADD CONSTRAINT fk_registry_star FOREIGN KEY (star_id) REFERENCES public.stars(star_id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 点赞记录表
|
||||||
|
CREATE TABLE public.asset_likes (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
asset_id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
created_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.asset_likes_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.asset_likes ALTER COLUMN id SET DEFAULT nextval('public.asset_likes_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.asset_likes ADD CONSTRAINT asset_likes_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX uk_asset_likes_user_asset ON public.asset_likes USING btree (user_id, asset_id);
|
||||||
|
CREATE INDEX idx_asset_likes_asset ON public.asset_likes USING btree (asset_id);
|
||||||
|
CREATE INDEX idx_asset_likes_user_star ON public.asset_likes USING btree (user_id, star_id);
|
||||||
|
ALTER TABLE ONLY public.asset_likes ADD CONSTRAINT fk_asset_likes_asset FOREIGN KEY (asset_id) REFERENCES public.assets(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.asset_likes ADD CONSTRAINT fk_asset_likes_star FOREIGN KEY (star_id) REFERENCES public.stars(star_id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.asset_likes ADD CONSTRAINT fk_asset_likes_user FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 铸造订单表
|
||||||
|
CREATE TABLE public.mint_orders (
|
||||||
|
order_id character varying(100) NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
asset_id bigint,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
status character varying(20) DEFAULT 'PENDING'::character varying NOT NULL,
|
||||||
|
cost_crystal bigint DEFAULT 0,
|
||||||
|
error_message text,
|
||||||
|
retry_count integer DEFAULT 0,
|
||||||
|
material_url character varying(500),
|
||||||
|
name character varying(100),
|
||||||
|
description text,
|
||||||
|
material_type character varying(50),
|
||||||
|
event character varying(100),
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL,
|
||||||
|
minted_at bigint,
|
||||||
|
info text
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.mint_orders ADD CONSTRAINT mint_orders_pkey PRIMARY KEY (order_id);
|
||||||
|
CREATE INDEX idx_mint_orders_asset ON public.mint_orders USING btree (asset_id);
|
||||||
|
CREATE INDEX idx_mint_orders_created_at ON public.mint_orders USING btree (created_at DESC);
|
||||||
|
CREATE INDEX idx_mint_orders_status ON public.mint_orders USING btree (status);
|
||||||
|
CREATE INDEX idx_mint_orders_user_star ON public.mint_orders USING btree (user_id, star_id);
|
||||||
|
ALTER TABLE ONLY public.mint_orders ADD CONSTRAINT fk_mint_orders_asset FOREIGN KEY (asset_id) REFERENCES public.assets(id) ON DELETE SET NULL;
|
||||||
|
ALTER TABLE ONLY public.mint_orders ADD CONSTRAINT fk_mint_orders_star FOREIGN KEY (star_id) REFERENCES public.stars(star_id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.mint_orders ADD CONSTRAINT fk_mint_orders_user FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 展馆相关表
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 展位表
|
||||||
|
CREATE TABLE public.booth_slots (
|
||||||
|
slot_id bigint NOT NULL,
|
||||||
|
host_profile_id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
slot_index bigint NOT NULL,
|
||||||
|
visibility character varying(20) DEFAULT 'public'::character varying,
|
||||||
|
is_enabled boolean DEFAULT false,
|
||||||
|
unlock_type character varying(20),
|
||||||
|
unlock_value bigint,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.booth_slots_slot_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.booth_slots ALTER COLUMN slot_id SET DEFAULT nextval('public.booth_slots_slot_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.booth_slots ADD CONSTRAINT booth_slots_pkey PRIMARY KEY (slot_id);
|
||||||
|
CREATE UNIQUE INDEX idx_host_slot ON public.booth_slots USING btree (host_profile_id, slot_index);
|
||||||
|
CREATE INDEX idx_star_enabled ON public.booth_slots USING btree (star_id);
|
||||||
|
CREATE INDEX idx_user_star ON public.booth_slots USING btree (user_id, star_id);
|
||||||
|
ALTER TABLE ONLY public.booth_slots ADD CONSTRAINT fk_booth_slots_profile FOREIGN KEY (host_profile_id) REFERENCES public.fan_profiles(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 展品展示表
|
||||||
|
CREATE TABLE public.exhibitions (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
asset_id bigint NOT NULL,
|
||||||
|
slot_id bigint NOT NULL,
|
||||||
|
host_profile_id bigint NOT NULL,
|
||||||
|
occupier_uid bigint NOT NULL,
|
||||||
|
occupier_star_id bigint NOT NULL,
|
||||||
|
start_time bigint NOT NULL,
|
||||||
|
expire_at bigint NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL,
|
||||||
|
deleted_at bigint
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.exhibitions_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.exhibitions ALTER COLUMN id SET DEFAULT nextval('public.exhibitions_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.exhibitions ADD CONSTRAINT exhibitions_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX uk_asset ON public.exhibitions USING btree (asset_id);
|
||||||
|
CREATE INDEX idx_expire ON public.exhibitions USING btree (expire_at);
|
||||||
|
CREATE INDEX idx_host ON public.exhibitions USING btree (host_profile_id);
|
||||||
|
CREATE INDEX idx_occupier ON public.exhibitions USING btree (occupier_uid, occupier_star_id);
|
||||||
|
CREATE INDEX idx_slot ON public.exhibitions USING btree (slot_id);
|
||||||
|
ALTER TABLE ONLY public.exhibitions ADD CONSTRAINT fk_exhibitions_asset FOREIGN KEY (asset_id) REFERENCES public.assets(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.exhibitions ADD CONSTRAINT fk_exhibitions_slot FOREIGN KEY (slot_id) REFERENCES public.booth_slots(slot_id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 展览收入记录表
|
||||||
|
CREATE TABLE public.exhibition_revenue_records (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
exhibition_id bigint NOT NULL,
|
||||||
|
asset_id bigint NOT NULL,
|
||||||
|
slot_id bigint NOT NULL,
|
||||||
|
slot_owner_uid bigint NOT NULL,
|
||||||
|
slot_type character varying(20) NOT NULL,
|
||||||
|
crystal_amount bigint NOT NULL,
|
||||||
|
cycle_start_time bigint NOT NULL,
|
||||||
|
cycle_end_time bigint NOT NULL,
|
||||||
|
status character varying(20) DEFAULT 'claimable'::character varying NOT NULL,
|
||||||
|
claimed_at bigint,
|
||||||
|
created_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.exhibition_revenue_records_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.exhibition_revenue_records ALTER COLUMN id SET DEFAULT nextval('public.exhibition_revenue_records_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.exhibition_revenue_records ADD CONSTRAINT exhibition_revenue_records_pkey PRIMARY KEY (id);
|
||||||
|
CREATE INDEX idx_user_revenue ON public.exhibition_revenue_records USING btree (user_id, star_id);
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 社交相关表
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 好友请求表
|
||||||
|
CREATE TABLE public.friend_requests (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
from_user_id bigint NOT NULL,
|
||||||
|
to_user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
message character varying(200),
|
||||||
|
status character varying(20) DEFAULT 'pending'::character varying NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL,
|
||||||
|
expires_at bigint,
|
||||||
|
processed_at bigint
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.friend_requests_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.friend_requests ALTER COLUMN id SET DEFAULT nextval('public.friend_requests_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.friend_requests ADD CONSTRAINT friend_requests_pkey PRIMARY KEY (id);
|
||||||
|
CREATE INDEX idx_friend_requests_expires ON public.friend_requests USING btree (expires_at);
|
||||||
|
CREATE INDEX idx_friend_requests_from_status ON public.friend_requests USING btree (from_user_id, status, created_at DESC);
|
||||||
|
CREATE INDEX idx_friend_requests_star ON public.friend_requests USING btree (star_id);
|
||||||
|
CREATE INDEX idx_friend_requests_to_status ON public.friend_requests USING btree (to_user_id, status, created_at DESC);
|
||||||
|
CREATE INDEX idx_friend_requests_users_star ON public.friend_requests USING btree (from_user_id, to_user_id, star_id, created_at DESC);
|
||||||
|
ALTER TABLE ONLY public.friend_requests ADD CONSTRAINT fk_friend_requests_from_user FOREIGN KEY (from_user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.friend_requests ADD CONSTRAINT fk_friend_requests_to_user FOREIGN KEY (to_user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 好友关系表
|
||||||
|
CREATE TABLE public.friendships (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
friend_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
status character varying(20) DEFAULT 'accepted'::character varying NOT NULL,
|
||||||
|
remark character varying(50),
|
||||||
|
intimacy integer DEFAULT 0 NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.friendships_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.friendships ALTER COLUMN id SET DEFAULT nextval('public.friendships_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.friendships ADD CONSTRAINT friendships_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX uk_friendships_user_friend_star ON public.friendships USING btree (user_id, friend_id, star_id);
|
||||||
|
CREATE INDEX idx_friendships_friend_star ON public.friendships USING btree (friend_id);
|
||||||
|
CREATE INDEX idx_friendships_list_query ON public.friendships USING btree (user_id, friend_id, star_id, status, remark, created_at);
|
||||||
|
CREATE INDEX idx_friendships_user_star_created ON public.friendships USING btree (user_id, star_id, created_at DESC);
|
||||||
|
CREATE INDEX idx_friendships_user_star_status ON public.friendships USING btree (user_id, star_id, status);
|
||||||
|
ALTER TABLE ONLY public.friendships ADD CONSTRAINT fk_friendships_friend FOREIGN KEY (friend_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.friendships ADD CONSTRAINT fk_friendships_user FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 任务相关表
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 任务定义表
|
||||||
|
CREATE TABLE public.task_definitions (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
task_key character varying(50) NOT NULL,
|
||||||
|
task_type character varying(20) NOT NULL,
|
||||||
|
name character varying(100) NOT NULL,
|
||||||
|
description text,
|
||||||
|
crystal_reward bigint DEFAULT 0 NOT NULL,
|
||||||
|
exp_reward bigint DEFAULT 0 NOT NULL,
|
||||||
|
sort_order integer DEFAULT 0 NOT NULL,
|
||||||
|
is_active boolean DEFAULT true NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.task_definitions_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.task_definitions ALTER COLUMN id SET DEFAULT nextval('public.task_definitions_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.task_definitions ADD CONSTRAINT task_definitions_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX idx_task_definitions_task_key ON public.task_definitions USING btree (task_key);
|
||||||
|
|
||||||
|
-- 用户任务进度表
|
||||||
|
CREATE TABLE public.user_task_progress (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
task_key character varying(50) NOT NULL,
|
||||||
|
status character varying(20) DEFAULT 'pending'::character varying NOT NULL,
|
||||||
|
completed_at bigint,
|
||||||
|
claimed_at bigint,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.user_task_progress_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.user_task_progress ALTER COLUMN id SET DEFAULT nextval('public.user_task_progress_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.user_task_progress ADD CONSTRAINT user_task_progress_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX uk_user_task ON public.user_task_progress USING btree (user_id, star_id, task_key);
|
||||||
|
|
||||||
|
-- 用户引导状态表
|
||||||
|
CREATE TABLE public.user_onboarding_status (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
is_onboarding_completed boolean DEFAULT false NOT NULL,
|
||||||
|
is_onboarding_claimed boolean DEFAULT false NOT NULL,
|
||||||
|
has_friend_display_bonus boolean DEFAULT false NOT NULL,
|
||||||
|
onboarding_completed_at bigint,
|
||||||
|
onboarding_claimed_at bigint,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.user_onboarding_status_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.user_onboarding_status ALTER COLUMN id SET DEFAULT nextval('public.user_onboarding_status_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.user_onboarding_status ADD CONSTRAINT user_onboarding_status_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX uk_user_star_onboarding ON public.user_onboarding_status USING btree (user_id, star_id);
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 活动相关表
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 活动表
|
||||||
|
CREATE TABLE public.activities (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
activity_type character varying(50) NOT NULL,
|
||||||
|
title character varying(100) NOT NULL,
|
||||||
|
description text,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
start_time bigint NOT NULL,
|
||||||
|
end_time bigint NOT NULL,
|
||||||
|
target_progress bigint DEFAULT 1000 NOT NULL,
|
||||||
|
current_progress bigint DEFAULT 0 NOT NULL,
|
||||||
|
status character varying(20) DEFAULT 'pending'::character varying,
|
||||||
|
stage_configs jsonb,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL,
|
||||||
|
theme character varying(100),
|
||||||
|
overall_end_time bigint DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.activities_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.activities ALTER COLUMN id SET DEFAULT nextval('public.activities_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.activities ADD CONSTRAINT activities_pkey PRIMARY KEY (id);
|
||||||
|
CREATE INDEX idx_activities_star_id ON public.activities USING btree (star_id);
|
||||||
|
CREATE INDEX idx_activities_start_end ON public.activities USING btree (start_time, end_time);
|
||||||
|
CREATE INDEX idx_activities_status ON public.activities USING btree (status);
|
||||||
|
|
||||||
|
-- 活动道具表
|
||||||
|
CREATE TABLE public.activity_items (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
activity_id bigint NOT NULL,
|
||||||
|
item_type character varying(50) NOT NULL,
|
||||||
|
item_name character varying(50) NOT NULL,
|
||||||
|
icon_url character varying(500),
|
||||||
|
crystal_cost bigint NOT NULL,
|
||||||
|
contribution_points bigint NOT NULL,
|
||||||
|
sort_order integer DEFAULT 0 NOT NULL,
|
||||||
|
is_active boolean DEFAULT true NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.activity_items_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.activity_items ALTER COLUMN id SET DEFAULT nextval('public.activity_items_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.activity_items ADD CONSTRAINT activity_items_pkey PRIMARY KEY (id);
|
||||||
|
CREATE INDEX idx_activity_items_activity ON public.activity_items USING btree (activity_id);
|
||||||
|
CREATE INDEX idx_activity_items_type ON public.activity_items USING btree (item_type);
|
||||||
|
ALTER TABLE ONLY public.activity_items ADD CONSTRAINT fk_activity_items_activity FOREIGN KEY (activity_id) REFERENCES public.activities(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 活动贡献记录表
|
||||||
|
CREATE TABLE public.activity_contributions (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
activity_id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
item_id bigint NOT NULL,
|
||||||
|
item_type character varying(50) NOT NULL,
|
||||||
|
quantity integer DEFAULT 1 NOT NULL,
|
||||||
|
crystal_spent bigint NOT NULL,
|
||||||
|
contribution_points bigint NOT NULL,
|
||||||
|
created_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.activity_contributions_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.activity_contributions ALTER COLUMN id SET DEFAULT nextval('public.activity_contributions_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.activity_contributions ADD CONSTRAINT activity_contributions_pkey PRIMARY KEY (id);
|
||||||
|
CREATE INDEX idx_activity_contributions_activity ON public.activity_contributions USING btree (activity_id);
|
||||||
|
CREATE INDEX idx_activity_contributions_created ON public.activity_contributions USING btree (created_at DESC);
|
||||||
|
CREATE INDEX idx_activity_contributions_user_star ON public.activity_contributions USING btree (user_id, star_id);
|
||||||
|
ALTER TABLE ONLY public.activity_contributions ADD CONSTRAINT fk_activity_contributions_activity FOREIGN KEY (activity_id) REFERENCES public.activities(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.activity_contributions ADD CONSTRAINT fk_activity_contributions_item FOREIGN KEY (item_id) REFERENCES public.activity_items(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.activity_contributions ADD CONSTRAINT fk_activity_contributions_star FOREIGN KEY (star_id) REFERENCES public.stars(star_id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.activity_contributions ADD CONSTRAINT fk_activity_contributions_user FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 用户活动统计表
|
||||||
|
CREATE TABLE public.activity_user_stats (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
activity_id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
star_id bigint NOT NULL,
|
||||||
|
total_contribution bigint DEFAULT 0 NOT NULL,
|
||||||
|
total_crystal_spent bigint DEFAULT 0 NOT NULL,
|
||||||
|
total_items integer DEFAULT 0 NOT NULL,
|
||||||
|
last_contribute_at bigint NOT NULL,
|
||||||
|
created_at bigint NOT NULL,
|
||||||
|
updated_at bigint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.activity_user_stats_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
|
||||||
|
ALTER TABLE ONLY public.activity_user_stats ALTER COLUMN id SET DEFAULT nextval('public.activity_user_stats_id_seq'::regclass);
|
||||||
|
ALTER TABLE ONLY public.activity_user_stats ADD CONSTRAINT activity_user_stats_pkey PRIMARY KEY (id);
|
||||||
|
CREATE UNIQUE INDEX uk_activity_user_star ON public.activity_user_stats UNIQUE (activity_id, user_id, star_id);
|
||||||
|
CREATE INDEX idx_activity_user_stats_activity ON public.activity_user_stats USING btree (activity_id);
|
||||||
|
CREATE INDEX idx_activity_user_stats_contribution ON public.activity_user_stats USING btree (activity_id, total_contribution DESC);
|
||||||
|
CREATE INDEX idx_activity_user_stats_user_star ON public.activity_user_stats USING btree (user_id, star_id);
|
||||||
|
ALTER TABLE ONLY public.activity_user_stats ADD CONSTRAINT fk_activity_user_stats_activity FOREIGN KEY (activity_id) REFERENCES public.activities(id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.activity_user_stats ADD CONSTRAINT fk_activity_user_stats_star FOREIGN KEY (star_id) REFERENCES public.stars(star_id) ON DELETE CASCADE;
|
||||||
|
ALTER TABLE ONLY public.activity_user_stats ADD CONSTRAINT fk_activity_user_stats_user FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
-- V2__add_deleted_at_to_exhibitions.sql
|
||||||
|
-- 为 exhibitions 表添加 deleted_at 字段(软删除)
|
||||||
|
|
||||||
|
ALTER TABLE public.exhibitions ADD COLUMN IF NOT EXISTS deleted_at bigint;
|
||||||
17
docker/sql/migrations/V3__seed_data.sql
Normal file
17
docker/sql/migrations/V3__seed_data.sql
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
-- V3__seed_data.sql
|
||||||
|
-- 种子数据(测试用)
|
||||||
|
|
||||||
|
-- 插入测试明星
|
||||||
|
INSERT INTO public.stars (star_id, name, tag, identity_id, is_active, created_at, updated_at) VALUES
|
||||||
|
(87, '测试明星', '测试', 'test_star_001', true, 1704067200000, 1704067200000)
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
-- 插入测试用户
|
||||||
|
INSERT INTO public.users (id, mobile, password_hash, is_active, created_at, updated_at) VALUES
|
||||||
|
(1, '13800138000', '$2a$10$N9qo8uLOickgx2ZMRZoMye6e7q5R5pR6Vx9qPCr5dLq5R5pR6Vx9q', true, 1704067200000, 1704067200000)
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
-- 插入测试粉丝档案
|
||||||
|
INSERT INTO public.fan_profiles (id, user_id, star_id, nickname, level, times, social, experience, coin_balance, crystal_balance, starbook_limit, slot_limit, assets_count, is_active, created_at, updated_at, avatar_url) VALUES
|
||||||
|
(1, 1, 87, '测试用户', 5, 3, 10, 1000, 500, 100, 3, 3, 5, true, 1704067200000, 1704067200000, 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/avatar/1/87/avatar.png')
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
53
docker/sql/migrations/V4__seed_data.sql
Normal file
53
docker/sql/migrations/V4__seed_data.sql
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
-- V4__seed_data.sql
|
||||||
|
-- 种子数据
|
||||||
|
|
||||||
|
-- 插入明星数据
|
||||||
|
INSERT INTO public.stars (star_id, name, tag, name_en, pic_url, description, identity_id, is_active, created_at, updated_at) VALUES
|
||||||
|
(87, '肖战', '小飞侠', 'Xiao Zhan', NULL, NULL, 'xz', true, 1773322573872, 1773322573872),
|
||||||
|
(88, '王一博', '小摩托', 'Wang Yibo', NULL, NULL, 'wyb', true, 1773322573872, 1773322573872),
|
||||||
|
(89, '杨洋', NULL, 'Yang Yang', NULL, NULL, 'yy', true, 1773322573872, 1773322573872),
|
||||||
|
(93, 'Lisa', 'BLACKPINK', 'Lalisa Manoban', 'https://example.com/lisa.jpg', 'BLACKPINK成员', 'lisa_test_001', true, 1773407317000, 1773407317000),
|
||||||
|
(94, 'Jennie', 'BLACKPINK', 'Jennie Kim', 'https://example.com/jennie.jpg', 'BLACKPINK成员', 'jennie_test_001', true, 1773407317000, 1773407317000),
|
||||||
|
(95, 'Rosé', 'BLACKPINK', 'Park Chae-young', 'https://example.com/rose.jpg', 'BLACKPINK成员', 'rose_test_001', true, 1773407317000, 1773407317000)
|
||||||
|
ON CONFLICT (star_id) DO UPDATE SET name = EXCLUDED.name, tag = EXCLUDED.tag;
|
||||||
|
|
||||||
|
-- 插入用户数据
|
||||||
|
INSERT INTO public.users (id, mobile, password_hash, access_token, token_expires_at, avatar_url, global_wallet_address, is_active, created_at, updated_at, deleted_at) VALUES
|
||||||
|
(1, '13900000001', '$2a$10$bNqpiVCSSrhxAsUelgkEp.j1untPPWMDT5208fmcUPKpsFHZlhjrW', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJzdGFyX2lkIjo4NywidXBkYXRlZF9hdCI6MTc3MzU4MTI5MiwiZXhwIjoxNzc3NTI5OTg5LCJpYXQiOjE3NzY5MjUxODl9.LooVCY-ST2y02qKud8A6GRVL1RxOy4pXVD6KC7NLs6w', 1777529989817, 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/avatar/1/87/avatar.png', NULL, true, 1773322609887, 1773581292, NULL),
|
||||||
|
(2, '17319409126', '$2a$10$bNqpiVCSSrhxAsUelgkEp.j1untPPWMDT5208fmcUPKpsFHZlhjrW', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyLCJzdGFyX2lkIjo4NywidXBkYXRlZF9hdCI6MTc3MzMyNDEwMTU5OCwiZXhwIjoxNzc0NDIxOTIxLCJpYXQiOjE3NzM4MTcxMjF9.GnAL9exh-VcXDHqwTn1bNKVAEAg6xfMMpd6JTqkwugk', 1774421921871, NULL, NULL, true, 1773324101598, 1773324101598, NULL),
|
||||||
|
(8, '13800000001', '$2a$10$LC8XORj6Nx9nT6j5QHfN5u2nB4z8e0v2dWm7X2uF5m6W6br8NnDPS', NULL, NULL, NULL, NULL, true, 1773407317000, 1776649807972, NULL),
|
||||||
|
(9, '13800000002', '$2a$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', NULL, NULL, NULL, NULL, true, 1773407317000, 1773407317000, NULL),
|
||||||
|
(10, '13800000003', '$2a$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', NULL, NULL, NULL, NULL, true, 1773407317000, 1773407317000, NULL),
|
||||||
|
(11, '13800000004', '$2a$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', NULL, NULL, NULL, NULL, true, 1773407317000, 1773407317000, NULL),
|
||||||
|
(12, '13800000005', '$2a$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', NULL, NULL, NULL, NULL, true, 1773407317000, 1773407317000, NULL)
|
||||||
|
ON CONFLICT (id) DO UPDATE SET access_token = EXCLUDED.access_token, updated_at = EXCLUDED.updated_at;
|
||||||
|
|
||||||
|
-- 插入粉丝档案数据
|
||||||
|
INSERT INTO public.fan_profiles (id, user_id, star_id, nickname, level, times, social, experience, coin_balance, crystal_balance, tags, starbook_limit, slot_limit, assets_count, chain_address, is_active, created_at, updated_at, avatar_url) VALUES
|
||||||
|
(1, 1, 87, '测试用户', 6, 1, 0, 1750, 0, 10919, '[]', 3, 3, 42, NULL, true, 1773322609890, 1776926969, 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/avatar/1/87/avatar.png'),
|
||||||
|
(2, 2, 87, 'topfans1', 1, 1, 0, 0, 0, 0, '[]', 3, 3, 0, NULL, true, 1773324101600, 1773324101600, NULL)
|
||||||
|
ON CONFLICT (id) DO UPDATE SET level = EXCLUDED.level, experience = EXCLUDED.experience, updated_at = EXCLUDED.updated_at;
|
||||||
|
|
||||||
|
-- 插入 Booth Slots 数据
|
||||||
|
INSERT INTO public.booth_slots (slot_id, host_profile_id, user_id, star_id, slot_index, visibility, is_enabled, unlock_type, unlock_value, created_at, updated_at) VALUES
|
||||||
|
(37, 1, 1, 87, 1, 'public', true, 'free', 0, 1773748940460, 1773748940460),
|
||||||
|
(38, 1, 1, 87, 2, 'public', true, 'free', 0, 1773748940460, 1773748940460),
|
||||||
|
(39, 1, 1, 87, 3, 'public', true, 'free', 0, 1773748940460, 1773748940460),
|
||||||
|
(40, 1, 1, 87, 4, 'private', true, 'free', 0, 1773748940460, 1773748940460),
|
||||||
|
(41, 1, 1, 87, 5, 'private', true, 'free', 0, 1773748940460, 1773748940460),
|
||||||
|
(42, 1, 1, 87, 6, 'private', true, 'free', 0, 1773748940460, 1773748940460)
|
||||||
|
ON CONFLICT (slot_id) DO NOTHING;
|
||||||
|
|
||||||
|
-- 插入 Assets 数据
|
||||||
|
INSERT INTO public.assets (id, owner_uid, star_id, name, cover_url, material_url, description, grade, tags, visibility, status, tx_hash, block_number, like_count, is_original, created_at, updated_at, minted_at, deleted_at, is_active, info) VALUES
|
||||||
|
(17, 1, 87, '1', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/covers/17_1775472017.png', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/ai_generated_1775472013603_g87iwk.png', NULL, NULL, NULL, 'private', 1, '0x1922ffb92fcd1a7e4a8c6b3347e8e0791f6107fa44cbde1734ecb1bcd861d63c', 1493537, 4, false, 1775472014756, 1775472018619, 1775472018619, NULL, true, NULL),
|
||||||
|
(18, 1, 87, '1', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/covers/18_1775539093.png', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/ai_generated_1775539090338_fwzxhs.png', NULL, NULL, NULL, 'private', 1, '0x40ca6efcf29f47731453f01b5c364cde52acbce597c1fbf8261301cc44ec4b7a', 1406147, 2, false, 1775539090589, 1775539093945, 1775539093945, NULL, true, NULL),
|
||||||
|
(19, 1, 87, '未命名藏品', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/covers/19_1775812743.png', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/ai_generated_1775812740051_gf8ew2.png', NULL, NULL, NULL, 'private', 1, '0x0e3e47c58814e52465ac1e928f3392ff1c692ea448103fcb03c4a10077141308', 1219083, 3, false, 1775812740261, 1775812743690, 1775812743690, NULL, true, '111'),
|
||||||
|
(20, 1, 87, '星卡', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/covers/20_1775812994.png', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/1775812991404.jpg', NULL, NULL, NULL, 'private', 1, '0x49d04d7463cf03374f6e622d739f69e83cd4ba84b145627f039a22340daead93', 1938046, 2, false, 1775812991507, 1775812994841, 1775812994841, NULL, true, '11'),
|
||||||
|
(21, 1, 87, '星卡', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/covers/21_1775813155.png', 'https://top-fans-test.oss-cn-shanghai.aliyuncs.com/asset/1/87/1775813152104.jpg', NULL, NULL, NULL, 'private', 1, '0x6d7c0c276d7485d17e6dea4c9d1e394315613d69114699d341c221a22e8156f8', 1118388, 2, false, 1775813152198, 1775813155515, 1775813155515, NULL, true, '2')
|
||||||
|
ON CONFLICT (id) DO UPDATE SET like_count = EXCLUDED.like_count;
|
||||||
|
|
||||||
|
-- 插入 Exhibitions 数据
|
||||||
|
INSERT INTO public.exhibitions (id, asset_id, slot_id, host_profile_id, occupier_uid, occupier_star_id, start_time, expire_at, created_at, updated_at, deleted_at) VALUES
|
||||||
|
(1, 17, 37, 1, 1, 87, 1776926400000, 1777555200000, 1776926400000, 1776926400000, NULL)
|
||||||
|
ON CONFLICT (id) DO NOTHING;
|
||||||
@ -161,18 +161,18 @@
|
|||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
"path": "pages/tasks/daily-tasks",
|
// "path": "pages/tasks/daily-tasks",
|
||||||
"style": {
|
// "style": {
|
||||||
"navigationStyle": "custom"
|
// "navigationStyle": "custom"
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
"path": "pages/tasks/guide",
|
// "path": "pages/tasks/guide",
|
||||||
"style": {
|
// "style": {
|
||||||
"navigationStyle": "custom"
|
// "navigationStyle": "custom"
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
"path": "pages/tasks/revenue",
|
"path": "pages/tasks/revenue",
|
||||||
"style": {
|
"style": {
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
<view class="user-info-with-artwork">
|
<view class="user-info-with-artwork">
|
||||||
<image
|
<image
|
||||||
class="user-avatar-small"
|
class="user-avatar-small"
|
||||||
:src="item.avatar_url || '/static/avatar/1.jpeg'"
|
:src="item.owner_avatar || '/static/avatar/1.jpeg'"
|
||||||
mode="aspectFit"
|
mode="aspectFit"
|
||||||
/>
|
/>
|
||||||
<text class="user-nickname">用户 :
|
<text class="user-nickname">用户 :
|
||||||
|
|||||||
@ -66,11 +66,12 @@
|
|||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
class="nft-image"
|
class="nft-image"
|
||||||
|
:class="{ 'nft-image-displayed': item.display_status === 1 }"
|
||||||
:src="item.coverUrl"
|
:src="item.coverUrl"
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
/>
|
/>
|
||||||
<view class="status-badge" :class="item.display_status === 1 ? 'status-badge-active' : 'status-badge-pending'">
|
<view v-if="item.display_status === 1" class="status-overlay">
|
||||||
<text class="status-text">{{ item.display_status === 1 ? '已展示' : '待展示' }}</text>
|
<text class="status-text-center">已展示</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="nft-info">
|
<view class="nft-info">
|
||||||
<text class="nft-name">{{ item.name }}</text>
|
<text class="nft-name">{{ item.name }}</text>
|
||||||
@ -89,7 +90,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 典藏藏品:按 category 分组 -->
|
<!-- 典藏藏品:按 category 分组 -->
|
||||||
<view v-if="currentType === 'collection'">
|
<view v-if="currentType === 'collection'">
|
||||||
<view v-for="group in collectionGroups" :key="group.category" class="nft-group">
|
<view v-for="group in collectionGroups" :key="group.category" class="nft-group">
|
||||||
<!-- 分组标题 -->
|
<!-- 分组标题 -->
|
||||||
@ -108,11 +109,12 @@
|
|||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
class="nft-image"
|
class="nft-image"
|
||||||
|
:class="{ 'nft-image-displayed': item.display_status === 1 }"
|
||||||
:src="item.coverUrl"
|
:src="item.coverUrl"
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
/>
|
/>
|
||||||
<view class="status-badge" :class="item.display_status === 1 ? 'status-badge-active' : 'status-badge-pending'">
|
<view v-if="item.display_status === 1" class="status-overlay">
|
||||||
<text class="status-text">{{ item.display_status === 1 ? '已展示' : '待展示' }}</text>
|
<text class="status-text-center">已展示</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="nft-info">
|
<view class="nft-info">
|
||||||
<text class="nft-name">{{ item.name }}</text>
|
<text class="nft-name">{{ item.name }}</text>
|
||||||
@ -131,7 +133,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 活动藏品:按 activity_type 分组 -->
|
<!-- 活动藏品:按 activity_type 分组 -->
|
||||||
<view v-if="currentType === 'activity'">
|
<view v-if="currentType === 'activity'">
|
||||||
<view v-for="group in activityGroups" :key="group.category" class="nft-group">
|
<view v-for="group in activityGroups" :key="group.category" class="nft-group">
|
||||||
<!-- 分组标题 -->
|
<!-- 分组标题 -->
|
||||||
@ -150,11 +152,12 @@
|
|||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
class="nft-image"
|
class="nft-image"
|
||||||
|
:class="{ 'nft-image-displayed': item.display_status === 1 }"
|
||||||
:src="item.coverUrl"
|
:src="item.coverUrl"
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
/>
|
/>
|
||||||
<view class="status-badge" :class="item.display_status === 1 ? 'status-badge-active' : 'status-badge-pending'">
|
<view v-if="item.display_status === 1" class="status-overlay">
|
||||||
<text class="status-text">{{ item.display_status === 1 ? '已展示' : '待展示' }}</text>
|
<text class="status-text-center">已展示</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="nft-info">
|
<view class="nft-info">
|
||||||
<text class="nft-name">{{ item.name }}</text>
|
<text class="nft-name">{{ item.name }}</text>
|
||||||
@ -540,10 +543,15 @@ watch(() => props.isActive, (newVal) => {
|
|||||||
width: 192rpx;
|
width: 192rpx;
|
||||||
height: 224rpx;
|
height: 224rpx;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
background: rgba(255, 255, 255, 0.05);
|
/* background: rgba(255, 255, 255, 0.05); */
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 已展示的图片 - 灰色滤镜 */
|
||||||
|
.nft-image-displayed {
|
||||||
|
filter: grayscale(23%);
|
||||||
|
}
|
||||||
|
|
||||||
/* 更多占位符 */
|
/* 更多占位符 */
|
||||||
.more-placeholder {
|
.more-placeholder {
|
||||||
background: rgba(255, 255, 255, 0.1);
|
background: rgba(255, 255, 255, 0.1);
|
||||||
@ -559,26 +567,45 @@ watch(() => props.isActive, (newVal) => {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 展示状态标签 */
|
/* 展示状态覆盖层 - 居中显示 */
|
||||||
.status-badge {
|
.status-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 8rpx;
|
top: 0;
|
||||||
right: 8rpx;
|
left: 0;
|
||||||
border-radius: 8rpx;
|
width: 192rpx;
|
||||||
padding: 4rpx 8rpx;
|
height: 224rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 16rpx;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
.status-badge-active {
|
|
||||||
background: linear-gradient(135deg, #FFD700, #FFA500);
|
.status-text-center {
|
||||||
box-shadow: 0 0 12rpx rgba(255, 215, 0, 0.6);
|
font-size: 24rpx;
|
||||||
}
|
|
||||||
.status-badge-pending {
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
}
|
|
||||||
.status-text {
|
|
||||||
font-size: 18rpx;
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.8);
|
||||||
|
/* 渐变:左浅橙粉 → 右柔粉红 */
|
||||||
|
background: linear-gradient(to bottom right,
|
||||||
|
#F0E4B1 0%, /* 左:浅橙粉 */
|
||||||
|
#F08399 50%,
|
||||||
|
#B94E73 100% /* 右:柔粉红 */
|
||||||
|
);
|
||||||
|
|
||||||
|
border-radius: 24rpx; /* 胶囊形 */
|
||||||
|
|
||||||
|
/* 立体感核心:多层阴影 + 内阴影模拟凸起 */
|
||||||
|
box-shadow:
|
||||||
|
/* 外层投影 - 让按钮浮起 */
|
||||||
|
0 4rpx 12rpx rgba(255, 143, 158, 0.2),
|
||||||
|
0 2rpx 6rpx rgba(255, 143, 158, 0.15),
|
||||||
|
|
||||||
|
/* 内阴影 - 模拟顶部受光 + 底部凹陷 */
|
||||||
|
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4), /* 顶部高光 */
|
||||||
|
inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.05); /* 底部暗部 */
|
||||||
|
padding: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nft-name {
|
.nft-name {
|
||||||
|
|||||||
@ -5,15 +5,7 @@
|
|||||||
|
|
||||||
<!-- 礼盒区域 -->
|
<!-- 礼盒区域 -->
|
||||||
<view class="gift-box">
|
<view class="gift-box">
|
||||||
<view class="gift-container">
|
<image class="gift-image" src="/static/nft/lihe.png" mode="aspectFit" />
|
||||||
<view class="gift-bow"></view>
|
|
||||||
<view class="gift-body">
|
|
||||||
<text class="gift-text">TOPFANS</text>
|
|
||||||
<view class="gift-window">
|
|
||||||
<text class="question-mark">?</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 进度条区域 -->
|
<!-- 进度条区域 -->
|
||||||
@ -206,11 +198,11 @@ onMounted(() => {
|
|||||||
|
|
||||||
.gift-box {
|
.gift-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20%;
|
top: 25%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 450rpx;
|
width: 480rpx;
|
||||||
height: 450rpx;
|
height: 480rpx;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
animation: float 3s ease-in-out infinite;
|
animation: float 3s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
@ -224,125 +216,9 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.gift-container {
|
.gift-image {
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-bow {
|
|
||||||
position: absolute;
|
|
||||||
top: -30rpx;
|
|
||||||
width: 200rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
background: linear-gradient(135deg, #FFB6D9 0%, #FFA8C5 50%, #FFB6D9 100%);
|
|
||||||
border-radius: 50rpx 50rpx 20rpx 20rpx;
|
|
||||||
box-shadow: 0 8rpx 24rpx rgba(255, 107, 157, 0.4);
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-bow::before,
|
|
||||||
.gift-bow::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 10rpx;
|
|
||||||
width: 80rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
background: linear-gradient(135deg, #FFB6D9 0%, #FFA8C5 100%);
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-bow::before {
|
|
||||||
left: -40rpx;
|
|
||||||
transform: rotate(-20deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-bow::after {
|
|
||||||
right: -40rpx;
|
|
||||||
transform: rotate(20deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-body {
|
|
||||||
position: relative;
|
|
||||||
width: 350rpx;
|
|
||||||
height: 350rpx;
|
|
||||||
background: linear-gradient(135deg, #FFE5F0 0%, #FFD4E8 50%, #FFC9E3 100%);
|
|
||||||
border-radius: 30rpx;
|
|
||||||
box-shadow: 0 16rpx 48rpx rgba(255, 107, 157, 0.3);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-body::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: 60rpx;
|
|
||||||
height: 100%;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 182, 217, 0.6) 0%, rgba(255, 168, 197, 0.6) 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-body::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 0;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
width: 100%;
|
|
||||||
height: 60rpx;
|
|
||||||
background: linear-gradient(90deg, rgba(255, 182, 217, 0.6) 0%, rgba(255, 168, 197, 0.6) 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-text {
|
|
||||||
position: absolute;
|
|
||||||
top: 40rpx;
|
|
||||||
font-size: 36rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #FF6B9D;
|
|
||||||
letter-spacing: 4rpx;
|
|
||||||
text-shadow: 0 2rpx 8rpx rgba(255, 107, 157, 0.3);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-window {
|
|
||||||
position: relative;
|
|
||||||
width: 180rpx;
|
|
||||||
height: 180rpx;
|
|
||||||
background: linear-gradient(135deg, #FFF5FA 0%, #FFEBF3 100%);
|
|
||||||
border-radius: 20rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
box-shadow: inset 0 4rpx 12rpx rgba(255, 107, 157, 0.2);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-mark {
|
|
||||||
font-size: 120rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #FFB6D9;
|
|
||||||
text-shadow: 0 4rpx 12rpx rgba(255, 107, 157, 0.3);
|
|
||||||
animation: questionPulse 2s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes questionPulse {
|
|
||||||
0%, 100% {
|
|
||||||
opacity: 0.8;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1.05);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-container {
|
.progress-container {
|
||||||
|
|||||||
@ -49,19 +49,18 @@
|
|||||||
|
|
||||||
<!-- 礼盒 -->
|
<!-- 礼盒 -->
|
||||||
<view class="gift-box" :class="{ 'gift-opened': isGiftOpened }">
|
<view class="gift-box" :class="{ 'gift-opened': isGiftOpened }">
|
||||||
<view class="gift-container">
|
<image
|
||||||
<view class="gift-lid">
|
v-if="!isGiftOpened"
|
||||||
<view class="gift-bow"></view>
|
class="gift-image"
|
||||||
<view class="gift-lid-top">
|
src="/static/nft/lihe.png"
|
||||||
<text class="gift-text">TOPFANS</text>
|
mode="aspectFit"
|
||||||
</view>
|
/>
|
||||||
</view>
|
<image
|
||||||
<view class="gift-body">
|
v-else
|
||||||
<view class="gift-window">
|
class="gift-image gift-image-opened"
|
||||||
<text class="question-mark">?</text>
|
src="/static/nft/lihe_kaiqi.png"
|
||||||
</view>
|
mode="aspectFit"
|
||||||
</view>
|
/>
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 底部按钮 -->
|
<!-- 底部按钮 -->
|
||||||
@ -1086,16 +1085,16 @@ onMounted(() => {
|
|||||||
bottom: 20%;
|
bottom: 20%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
width: 420rpx;
|
width: 480rpx;
|
||||||
height: 450rpx;
|
height: 480rpx;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
animation: giftFloat 3s ease-in-out infinite;
|
animation: giftFloat 3s ease-in-out infinite;
|
||||||
transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
|
transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
perspective: 1000rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.gift-box.gift-opened {
|
.gift-box.gift-opened {
|
||||||
bottom: 5%;
|
width: 17rem;
|
||||||
|
bottom: 15%;
|
||||||
animation: none;
|
animation: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1108,192 +1107,29 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.gift-container {
|
.gift-image {
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
transition: opacity 0.5s ease-in-out;
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.gift-lid {
|
.gift-image-opened {
|
||||||
position: absolute;
|
width: 17rem;
|
||||||
top: 0;
|
animation: giftOpenPop 0.5s ease-out;
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: 340rpx;
|
|
||||||
height: 140rpx;
|
|
||||||
z-index: 3;
|
|
||||||
transition: all 1s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transform-style: preserve-3d;
|
|
||||||
transform-origin: bottom left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.gift-opened .gift-lid {
|
@keyframes giftOpenPop {
|
||||||
transform: translateX(-70%) translateY(140rpx) rotateZ(-45deg);
|
0% {
|
||||||
opacity: 0.9;
|
transform: scale(0.8);
|
||||||
}
|
opacity: 0;
|
||||||
|
}
|
||||||
.gift-bow {
|
50% {
|
||||||
position: absolute;
|
transform: scale(1.1);
|
||||||
top: -30rpx;
|
}
|
||||||
left: 50%;
|
100% {
|
||||||
transform: translateX(-50%);
|
transform: scale(1);
|
||||||
width: 200rpx;
|
opacity: 1;
|
||||||
height: 80rpx;
|
}
|
||||||
z-index: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-bow::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 20rpx;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: 40rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
background: linear-gradient(135deg, #FFB6D9 0%, #FF9DC5 100%);
|
|
||||||
border-radius: 8rpx;
|
|
||||||
box-shadow: 0 4rpx 15rpx rgba(255, 107, 157, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-bow::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: 180rpx;
|
|
||||||
height: 50rpx;
|
|
||||||
background: linear-gradient(135deg, #FFB6D9 0%, #FF9DC5 50%, #FFB6D9 100%);
|
|
||||||
border-radius: 30rpx;
|
|
||||||
box-shadow: 0 6rpx 20rpx rgba(255, 107, 157, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-lid-top {
|
|
||||||
position: relative;
|
|
||||||
width: 340rpx;
|
|
||||||
height: 100rpx;
|
|
||||||
background: linear-gradient(180deg,
|
|
||||||
#FFF0F5 0%,
|
|
||||||
#FFE5F0 30%,
|
|
||||||
#FFD4E8 100%);
|
|
||||||
border-radius: 20rpx 20rpx 8rpx 8rpx;
|
|
||||||
box-shadow:
|
|
||||||
0 10rpx 40rpx rgba(255, 107, 157, 0.4),
|
|
||||||
inset 0 -5rpx 15rpx rgba(255, 182, 217, 0.3),
|
|
||||||
inset 0 5rpx 15rpx rgba(255, 255, 255, 0.5);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: visible;
|
|
||||||
border: 3rpx solid rgba(255, 255, 255, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-lid-top::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 280rpx;
|
|
||||||
height: 60rpx;
|
|
||||||
background: linear-gradient(90deg,
|
|
||||||
transparent 0%,
|
|
||||||
rgba(255, 182, 217, 0.4) 50%,
|
|
||||||
transparent 100%);
|
|
||||||
border-radius: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-text {
|
|
||||||
position: relative;
|
|
||||||
font-size: 36rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #FF6B9D;
|
|
||||||
letter-spacing: 4rpx;
|
|
||||||
text-shadow:
|
|
||||||
0 2rpx 8rpx rgba(255, 107, 157, 0.5),
|
|
||||||
0 0 20rpx rgba(255, 182, 217, 0.3);
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-body {
|
|
||||||
position: relative;
|
|
||||||
width: 340rpx;
|
|
||||||
height: 280rpx;
|
|
||||||
background: linear-gradient(180deg,
|
|
||||||
#FFE5F0 0%,
|
|
||||||
#FFD4E8 50%,
|
|
||||||
#FFC9E3 100%);
|
|
||||||
border-radius: 8rpx 8rpx 20rpx 20rpx;
|
|
||||||
box-shadow:
|
|
||||||
0 15rpx 50rpx rgba(255, 107, 157, 0.4),
|
|
||||||
inset 0 5rpx 20rpx rgba(255, 255, 255, 0.3),
|
|
||||||
inset 0 -5rpx 20rpx rgba(255, 182, 217, 0.3);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 3rpx solid rgba(255, 255, 255, 0.5);
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-body::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 8rpx;
|
|
||||||
background: linear-gradient(90deg,
|
|
||||||
rgba(255, 107, 157, 0.3) 0%,
|
|
||||||
rgba(255, 182, 217, 0.5) 50%,
|
|
||||||
rgba(255, 107, 157, 0.3) 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-body::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 90%;
|
|
||||||
height: 90%;
|
|
||||||
background: radial-gradient(circle at center,
|
|
||||||
rgba(255, 255, 255, 0.2) 0%,
|
|
||||||
transparent 70%);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gift-window {
|
|
||||||
position: relative;
|
|
||||||
width: 180rpx;
|
|
||||||
height: 180rpx;
|
|
||||||
background: linear-gradient(135deg,
|
|
||||||
#FFF5FA 0%,
|
|
||||||
#FFEBF3 50%,
|
|
||||||
#FFE0ED 100%);
|
|
||||||
border-radius: 20rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
box-shadow:
|
|
||||||
inset 0 4rpx 15rpx rgba(255, 107, 157, 0.2),
|
|
||||||
0 4rpx 20rpx rgba(255, 182, 217, 0.3);
|
|
||||||
z-index: 2;
|
|
||||||
border: 2rpx solid rgba(255, 182, 217, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.question-mark {
|
|
||||||
font-size: 120rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #FFB6D9;
|
|
||||||
text-shadow:
|
|
||||||
0 4rpx 15rpx rgba(255, 107, 157, 0.4),
|
|
||||||
0 0 30rpx rgba(255, 182, 217, 0.3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom-action {
|
.bottom-action {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// API 基础配置
|
// API 基础配置
|
||||||
// const baseURL = 'http://101.132.250.62:8080'
|
const baseURL = 'http://101.132.250.62:8080'
|
||||||
// const baseURL = 'http://192.168.110.60:8080'
|
// const baseURL = 'http://192.168.110.60:8080'
|
||||||
const baseURL = 'http://localhost:8080'
|
// const baseURL = 'http://localhost:8080'
|
||||||
|
|
||||||
// 是否使用模拟数据(开发调试时设为 true,后端API准备好后改为 false)
|
// 是否使用模拟数据(开发调试时设为 true,后端API准备好后改为 false)
|
||||||
const USE_MOCK_API = false
|
const USE_MOCK_API = false
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user