修改展示时长bug

This commit is contained in:
zerosaturation 2026-05-19 15:48:41 +08:00
parent 94b9271184
commit eaad2642a8
3 changed files with 140 additions and 12 deletions

View File

@ -591,11 +591,11 @@ func (r *socialRepositoryImpl) GetMyLikedAssets(userID, starID int64, page, page
}
// 计数查询(使用 DISTINCT 因为一个资产可能在多个展位展出)
// 显示:展品存在且未领取is_processed=false),无论是否过期
// 不显示:已领取is_processed=true)或从未展出过的
// 显示:展品未下架deleted_at IS NULL),无论是否过期
// 不显示:已领取下架的deleted_at IS NOT NULL)或从未展出过的
countQuery := r.db.Model(&models.AssetLike{}).
Joins("JOIN assets a ON a.id = asset_likes.asset_id").
Joins("JOIN exhibitions e ON e.asset_id = a.id AND e.deleted_at IS NULL AND e.is_processed = false").
Joins("JOIN exhibitions e ON e.asset_id = a.id AND e.deleted_at IS NULL").
Where("asset_likes.user_id = ? AND asset_likes.star_id = ?", userID, starID).
Where("a.deleted_at IS NULL AND a.is_active = ?", true)
@ -603,14 +603,14 @@ func (r *socialRepositoryImpl) GetMyLikedAssets(userID, starID int64, page, page
return nil, 0, err
}
// 数据查询:只过滤已下架的,不过滤过期(已过期但未领取的仍显示
// 数据查询:只过滤已下架的,不过滤过期(用户领取收益后才下架
offset := (page - 1) * pageSize
err := r.db.Model(&models.AssetLike{}).
Select(`asset_likes.asset_id, a.name, a.cover_url, a.like_count,
asset_likes.created_at as liked_at,
(a.tags @> '["craft:lenticular"]') as is_lenticular`).
Joins("JOIN assets a ON a.id = asset_likes.asset_id").
Joins("JOIN exhibitions e ON e.asset_id = a.id AND e.deleted_at IS NULL AND e.is_processed = false").
Joins("JOIN exhibitions e ON e.asset_id = a.id AND e.deleted_at IS NULL").
Where("asset_likes.user_id = ? AND asset_likes.star_id = ?", userID, starID).
Where("a.deleted_at IS NULL AND a.is_active = ?", true).
Group("asset_likes.asset_id, a.name, a.cover_url, a.like_count, asset_likes.created_at, is_lenticular").

View File

@ -163,9 +163,6 @@ func (s *revenueService) ClaimExhibitionRevenue(ctx context.Context, userID, sta
// 增加用户累计上架时长(触发升级检查)
// 计算上架时长(毫秒转小时)
exhibitionHours := (record.CycleEndTime - record.CycleStartTime) / 3600000
if exhibitionHours < 1 {
exhibitionHours = 1 // 最少1小时
}
if s.userRPCClient != nil {
newLevel, levelDelta, crystalReward, err := s.userRPCClient.AddExhibitionHours(ctx, userID, starID, exhibitionHours,
fmt.Sprintf("%d", record.ID))
@ -341,9 +338,6 @@ func (s *revenueService) OnExhibitionCompleted(ctx context.Context, req *pb.OnEx
startTime := req.StartTime
expireAt := req.ExpireAt
actualHours := (expireAt - startTime) / 3600000
if actualHours < 1 {
actualHours = 1
}
// sourceID 用于去重,避免重复累计
sourceID := fmt.Sprintf("exhibition_%d", req.ExhibitionId)

View File

@ -133,7 +133,17 @@
<view class="liked-item" :class="index === 0 ? 'liked-item-first' : ''">
<!-- 作品封面 -->
<view class="liked-cover-wrap" :class="index === 0 ? 'liked-cover-wrap-first' : ''">
<image class="liked-cover" :src="item.cover_url || '/static/nft/placeholder.png'"
<LenticularCard
v-if="item.is_lenticular"
class="liked-lenticular"
:layers="getLikedLenticularLayers(item.id)"
:transforms="getLikedLenticularTransforms(item.id)"
:gyro-source="gyroSourceLabel"
:skip-built-in-touch="false"
:shimmer-mid-opacity="0.16"
@simulate="(x, y) => onLikedLenticularSimulate(item.id, x, y)"
/>
<image v-else class="liked-cover" :src="item.cover_url || '/static/nft/placeholder.png'"
mode="aspectFill"></image>
<image class="liked-cover-frame" src="/static/square/cangpinkuang1.png"
mode="aspectFill"></image>
@ -518,6 +528,10 @@ const lenticularLayersByAsset = ref({});
const activeLenticularId = ref(null);
const gyroSourceLabel = ref('device');
//
const likedLenticularLayersByAsset = ref({});
const likedLenticularTransformsMap = ref({});
// 使
const lenticularPhysics = ref(null);
const lenticularEngine = ref(null);
@ -534,6 +548,86 @@ function getLenticularTransforms(assetId) {
return lenticularTransformsMap.value[assetId] || {};
}
//
function getLikedLenticularLayers(assetId) {
return likedLenticularLayersByAsset.value[assetId] || [];
}
function getLikedLenticularTransforms(assetId) {
return likedLenticularTransformsMap.value[assetId] || {};
}
function onLikedLenticularSimulate(assetId, x, y) {
simulateLikedLenticularTilt(assetId, x, y);
}
function simulateLikedLenticularTilt(assetId, x, y) {
if (!lenticularEngine.value) return;
const layers = likedLenticularLayersByAsset.value[assetId];
if (!layers || layers.length === 0) return;
lenticularEngine.value.setLayers(layers);
const renderState = lenticularEngine.value.feedSimulatedTilt(x, y ? y : 0);
const transforms = {};
for (const l of layers) {
const rs = renderState.layerOffsets.get(l.id);
const op = renderState.layerOpacities.get(l.id);
transforms[l.id] = {
x: rs ? rs.x : 0,
y: rs ? rs.y : 0,
opacity: op != null ? op : l.opacity,
};
}
likedLenticularTransformsMap.value = { ...likedLenticularTransformsMap.value, [assetId]: transforms };
}
async function loadLikedLenticularLayersForAsset(assetId) {
const item = likedWorks.value.find(w => w.id === assetId);
if (!item) return;
try {
const materialsRes = await getAssetMaterialsApi(assetId);
if (materialsRes.code === 200 && materialsRes.data) {
const materialsList = Array.isArray(materialsRes.data) ? materialsRes.data : materialsRes.data.materials || [];
let subjectUrl = item.cover_url;
let bgUrl = '';
for (const mat of materialsList) {
if (mat.material_type === 'main' && mat.material_url_signed) {
subjectUrl = mat.material_url_signed;
}
if (mat.material_type === 'bg' && mat.material_url_signed) {
bgUrl = mat.material_url_signed;
}
}
if (bgUrl) {
const { buildLenticularLayersTwo } = await import('@/utils/castloveMintForm.js');
likedLenticularLayersByAsset.value[assetId] = buildLenticularLayersTwo(bgUrl, subjectUrl);
} else {
likedLenticularLayersByAsset.value[assetId] = buildLenticularLayers(subjectUrl);
}
initLikedTransformsForAsset(assetId);
} else {
likedLenticularLayersByAsset.value[assetId] = buildLenticularLayers(item.cover_url);
initLikedTransformsForAsset(assetId);
}
} catch (e) {
console.error('[myWorks] 获取点赞作品素材列表失败:', e);
likedLenticularLayersByAsset.value[assetId] = buildLenticularLayers(item.cover_url);
initLikedTransformsForAsset(assetId);
}
}
function initLikedTransformsForAsset(assetId) {
const layers = likedLenticularLayersByAsset.value[assetId];
if (!layers || layers.length === 0) return;
const transforms = {};
for (const l of layers) {
transforms[l.id] = { x: 0, y: 0, opacity: l.opacity || 1 };
}
likedLenticularTransformsMap.value = { ...likedLenticularTransformsMap.value, [assetId]: transforms };
}
async function loadLenticularLayersForAsset(assetId) {
// bg + subject layers
// 使 buildLenticularLayers(coverUrl)
@ -650,6 +744,24 @@ function startLenticularRenderLoop() {
}
lenticularTransformsMap.value = { ...lenticularTransformsMap.value, [assetId]: transforms };
}
//
for (const assetId of Object.keys(likedLenticularLayersByAsset.value)) {
const layers = likedLenticularLayersByAsset.value[assetId];
if (!layers || layers.length === 0) continue;
lenticularEngine.value.setLayers(layers);
const renderState = lenticularEngine.value.feedSimulatedTilt(0, 0);
const transforms = {};
for (const l of layers) {
const rs = renderState.layerOffsets.get(l.id);
const op = renderState.layerOpacities.get(l.id);
transforms[l.id] = {
x: rs ? rs.x : 0,
y: rs ? rs.y : 0,
opacity: op != null ? op : l.opacity,
};
}
likedLenticularTransformsMap.value = { ...likedLenticularTransformsMap.value, [assetId]: transforms };
}
lenticularRafId = requestAnimationFrame(tick);
};
lenticularRafId = requestAnimationFrame(tick);
@ -667,6 +779,9 @@ const switchLikedTab = async (tab) => {
if (likedTab.value === tab) return;
likedTab.value = tab;
likedWorks.value = [];
//
likedLenticularLayersByAsset.value = {};
likedLenticularTransformsMap.value = {};
await loadLikedAssets();
};
@ -726,11 +841,19 @@ const loadLikedAssets = async () => {
earnings: item.earnings,
liked_at: item.liked_at,
name: item.name,
is_lenticular: item.is_lenticular ?? false,
//
status_text: index < 3 ? '排名进榜' : '潜力待挖',
score: item.like_count,
reward: Math.floor(item.earnings || 0),
}));
//
for (const item of likedWorks.value) {
if (item.is_lenticular) {
loadLikedLenticularLayersForAsset(item.id);
}
}
}
} catch (err) {
console.error('加载点赞作品失败:', err);
@ -1318,6 +1441,17 @@ onShow(() => {
padding: 0.25rem;
}
.liked-lenticular {
width: 90%;
height: 90%;
border-radius: 24rpx;
transform: rotate(-22deg);
transform-origin: center center;
position: relative;
z-index: 3;
overflow: hidden;
}
.liked-cover-frame {
position: absolute;
top: 0;