[Human] chore(project): 初始化导入 91dj H5 客户端项目代码
从本地工程首次入库;.npmrc(含私有 npm 源 token)与 tsbuildinfo 已加入 .gitignore,不随仓库提交。
This commit is contained in:
@@ -0,0 +1,490 @@
|
||||
<template>
|
||||
<div class="introduction-wrap overflow-y-auto">
|
||||
<div class="titleBox ellipsis2">
|
||||
{{ props.info.title }}
|
||||
</div>
|
||||
<div class="tags">
|
||||
<span
|
||||
class="tag"
|
||||
@click="goAcgTagPage(item.id, item.name, 'video')"
|
||||
v-for="item in info.tagDetails || []"
|
||||
:key="item.id"
|
||||
>
|
||||
#{{ item.name }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="videoInfoBox flex-vcenter">
|
||||
<div class="item margin-r-88">
|
||||
<span>{{ watchCount(props.info.countBrowse) }} 观看量</span>
|
||||
</div>
|
||||
<div class="item" @click="onToogleLiked">
|
||||
<span
|
||||
class="acg-action-icon acg-action-icon--like"
|
||||
:class="{ active: props.info.mediaStatus.hasLiked }"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span>{{ props.info.mediaStatus.hasLiked ? watchCount(props.info.countLike) : '点赞' }}</span>
|
||||
</div>
|
||||
<div class="item" @click="onToogleCollected">
|
||||
<span
|
||||
class="acg-action-icon acg-action-icon--collect"
|
||||
:class="{ active: props.info.mediaStatus.hasCollected }"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span>{{ props.info.mediaStatus.hasCollected ? watchCount(props.info.countCollect) : '收藏' }}</span>
|
||||
</div>
|
||||
<div class="item" @click="openShare">
|
||||
<img class="acg-share-icon" src="@/assets/images/ui/long-video-share.svg" width="24" height="24" alt="" />
|
||||
<span>分享</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="actress-box flex-center-between"
|
||||
v-if="props.info.actress && props.info.actress.id"
|
||||
@click="
|
||||
$router.push({
|
||||
name: 'AcgActress',
|
||||
query: {
|
||||
id: props.info.actress.id,
|
||||
},
|
||||
})
|
||||
"
|
||||
>
|
||||
<lazyImg class="portrait" :src="props.info.actress.portrait"></lazyImg>
|
||||
<div class="info">
|
||||
<p class="name">{{ props.info.actress.name }}</p>
|
||||
<div class="count-box flex-vcenter">
|
||||
<SvgIcon name="acg-video-icon-a-video" />
|
||||
{{ watchCount(props.info.actress.acgCount) }}部
|
||||
<SvgIcon name="acg-video-icon-a-collect" style="margin-left: 12px" />
|
||||
{{ watchCount(props.info.actress.collectCount) }}
|
||||
</div>
|
||||
</div>
|
||||
<SvgIcon class="icon" name="moreIcon" />
|
||||
</div>
|
||||
<!-- 选集区域 -->
|
||||
<div class="episodeArea">
|
||||
<div class="episodeHeader flex-center-between padding16">
|
||||
<div class="episodeTitle">选集</div>
|
||||
<div class="episodeAll flex-vcenter" @click="visibleCatalogue = true">
|
||||
全{{ props.info.totalEpisode }}话
|
||||
<SvgIcon class="icon" name="moreIcon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="episodeBox" @touchstart.stop @touchmove.stop @touchend.stop>
|
||||
<Episode
|
||||
class="item"
|
||||
@click="switchEpisodeNumberCatalogue(item)"
|
||||
v-for="item in autoList"
|
||||
:key="item.id"
|
||||
:info="item"
|
||||
:episode-number="state.episodeNumber"
|
||||
></Episode>
|
||||
</div>
|
||||
</div>
|
||||
<HomeHeader :advType="AdType.VIDEOADV" />
|
||||
<!-- <RecommendList
|
||||
:media-id="props.info.id"
|
||||
:contentType="props.info.mediaType"
|
||||
title="猜你喜欢"
|
||||
:marginHide="true"
|
||||
></RecommendList> -->
|
||||
<RecommendedList :type="info.mediaType" :tagId="info.tagDetails?.[0]?.id" />
|
||||
<!-- 分享弹窗 -->
|
||||
<AppSharePopup
|
||||
:is-open="visibleShare"
|
||||
@close="visibleShare = false"
|
||||
coverType="portrait"
|
||||
:cover="props.info.verticalCover || props.info.horizontalCover"
|
||||
/>
|
||||
|
||||
<Teleport to=".video-detail-wrap">
|
||||
<van-popup v-model:show="visibleCatalogue" position="bottom" z-index="1001" :style="{ height: '438px' }">
|
||||
<div class="play-list-box">
|
||||
<div class="line"></div>
|
||||
<div class="title flex-center-between">
|
||||
剧集列表
|
||||
<!-- <span @click="sort = !sort">
|
||||
{{ sort ? '正序' : '倒序' }}
|
||||
</span> -->
|
||||
</div>
|
||||
<div class="grading-group" v-if="gradingGroup.length > 1">
|
||||
<div
|
||||
class="grading-group-item"
|
||||
v-for="(item, index) in gradingGroup"
|
||||
:key="index"
|
||||
@click.stop="state.gradingGroupIndex = index"
|
||||
>
|
||||
{{ item[0].episodeNumber }}-{{ item[item.length - 1].episodeNumber }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-box overflow-y-auto">
|
||||
<PullRefresh :params="moreParams" @onLoad="onLoad" @onRefresh="onRefresh">
|
||||
<div class="list">
|
||||
<Episode
|
||||
class="item"
|
||||
:episodeNumber="state.episodeNumber"
|
||||
:info="item"
|
||||
v-for="item in gradingGroup[state.gradingGroupIndex]"
|
||||
:key="item.id"
|
||||
@click="state.episodeNumber = item.episodeNumber"
|
||||
></Episode>
|
||||
</div>
|
||||
</PullRefresh>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed, watchEffect, Ref } from 'vue';
|
||||
import { HistoryVideoType } from '@/enums/app';
|
||||
import { goAcgTagPage } from '../../utils/common';
|
||||
import { watchCount, videoTime } from '@/utils/index';
|
||||
// import RecommendList from '../../components/recommendList.vue';
|
||||
import { handleCollected, Collected_emit } from '../../utils/collect';
|
||||
import { AdType } from '@/enums/app';
|
||||
import mediaContentInfo from '../../utils/mediaContentInfo';
|
||||
import CommunityApi from '@/service/community';
|
||||
import { useGlobalStore } from '@/stores/global';
|
||||
import Episode from '../../components/episode.vue';
|
||||
import {
|
||||
getVideoType,
|
||||
reportCollectCommentEvent,
|
||||
reportCollectFn,
|
||||
reportLikeCommentEvent,
|
||||
} from '@/utils/eventReporter/videoComment';
|
||||
const emits = defineEmits(['updateLiked', 'updateCollected', 'updateItem', 'openRoadLine']);
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
info: Types.Media.MediaInfo;
|
||||
}>(),
|
||||
{
|
||||
info: {},
|
||||
},
|
||||
);
|
||||
|
||||
const {
|
||||
state,
|
||||
currentItem,
|
||||
autoList,
|
||||
// switchEpisodeNumberCatalogue,
|
||||
visibleCatalogue,
|
||||
sort,
|
||||
moreParams,
|
||||
onLoad,
|
||||
onRefresh,
|
||||
getList,
|
||||
buySuccess,
|
||||
replaceRouter,
|
||||
} = mediaContentInfo({
|
||||
isGetInfo: false,
|
||||
isGetHistoryInit: true,
|
||||
pageSize: 30,
|
||||
dbType: HistoryVideoType.AcgVideo,
|
||||
isScrollTop: false,
|
||||
});
|
||||
const gradingGroup = computed(() => {
|
||||
let arr = autoList.value || [];
|
||||
if (arr.length > 30) {
|
||||
const result = [];
|
||||
for (let i = 0; i < arr.length; i += 30) {
|
||||
result.push(arr.slice(i, i + 30));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return [arr];
|
||||
});
|
||||
watch(
|
||||
() => currentItem.value.id,
|
||||
() => {
|
||||
emits('updateItem', currentItem.value);
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
defineExpose({
|
||||
buySuccess,
|
||||
});
|
||||
const switchEpisodeNumberCatalogue = (item: Types.Acg.MediaContentListItem) => {
|
||||
visibleCatalogue.value = false;
|
||||
state.episodeNumber = item.episodeNumber;
|
||||
replaceRouter(item.episodeNumber);
|
||||
};
|
||||
|
||||
// 打开分享
|
||||
const visibleShare = ref(false);
|
||||
const openShare = () => {
|
||||
const { id, verticalCover, horizontalCover } = props.info;
|
||||
let obj = {
|
||||
id,
|
||||
cover: verticalCover || horizontalCover,
|
||||
};
|
||||
// globalStore.setShareInfo(obj);
|
||||
visibleShare.value = true;
|
||||
};
|
||||
const onToogleCollected = () => {
|
||||
try {
|
||||
const {
|
||||
id,
|
||||
mediaStatus: { hasCollected },
|
||||
} = props.info;
|
||||
const tempIsCollect = !hasCollected;
|
||||
tempIsCollect ? reportCollectFn(1, 1, props.info) : reportCollectFn(1, 2, props.info);
|
||||
handleCollected(id, tempIsCollect).then(() => {
|
||||
emits('updateCollected', tempIsCollect);
|
||||
Collected_emit(id, tempIsCollect);
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const onToogleLiked = () => {
|
||||
const zan = !props.info.mediaStatus.hasLiked;
|
||||
zan ? reportCollectFn(2, 1, props.info) : reportCollectFn(2, 2, props.info);
|
||||
(zan ? CommunityApi.zan : CommunityApi.cancleZan)(
|
||||
zan
|
||||
? {
|
||||
type: 'video',
|
||||
objID: props.info.id,
|
||||
}
|
||||
: {
|
||||
type: 'video',
|
||||
objIDs: [props.info.id],
|
||||
},
|
||||
).then(() => {
|
||||
emits('updateLiked', zan);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/styles/mixins.scss';
|
||||
.introduction-wrap {
|
||||
height: 100%;
|
||||
padding: 0 16px;
|
||||
color: var(--app-text-primary);
|
||||
.titleBox {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 22px;
|
||||
margin: 18px 0;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 10px;
|
||||
margin: 10px 0 14px;
|
||||
.tag {
|
||||
padding: 4px 8px;
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: var(--app-text-primary);
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px; /* 150% */
|
||||
}
|
||||
}
|
||||
|
||||
.videoInfoBox {
|
||||
color: #989898;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
margin: 10px 0 18px;
|
||||
justify-content: space-between;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.acg-action-icon {
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 4px;
|
||||
flex-shrink: 0;
|
||||
background-color: #989898;
|
||||
|
||||
&--like {
|
||||
mask: url('@/assets/images/ui/long-video-like.svg') center / contain no-repeat;
|
||||
}
|
||||
|
||||
&--collect {
|
||||
mask: url('@/assets/images/ui/long-video-collect.svg') center / contain no-repeat;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #f52c56;
|
||||
}
|
||||
}
|
||||
|
||||
.acg-share-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
> span {
|
||||
color: #989898;
|
||||
}
|
||||
}
|
||||
}
|
||||
.actress-box {
|
||||
height: 60px;
|
||||
margin: 24px 0;
|
||||
.portrait {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin-right: 12px;
|
||||
}
|
||||
.info {
|
||||
flex: 1;
|
||||
.name {
|
||||
color: var(--app-text-primary);
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.count-box {
|
||||
color: var(--app-text-secondary);
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px; /* 150% */
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.episodeArea {
|
||||
margin-bottom: 14px;
|
||||
border-top: 0.5px solid rgba(255, 255, 255, 0.1);
|
||||
border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
|
||||
padding-top: 10px;
|
||||
.episodeHeader {
|
||||
font-weight: 500;
|
||||
.episodeTitle {
|
||||
font-size: 16px;
|
||||
}
|
||||
.episodeAll {
|
||||
color: var(--app-text-secondary);
|
||||
font-size: 12px;
|
||||
svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.episodeBox {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
margin: 12px 0;
|
||||
.item {
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.play-list-box {
|
||||
$paddingBottom: 38px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 20px 20px 0px 0px;
|
||||
background: var(--app-background);
|
||||
padding: 18px 16px $paddingBottom;
|
||||
@include SafeArea('padding', 'bottom', 0);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--app-text-primary);
|
||||
font-size: 12px;
|
||||
color: var(--app-text-primary);
|
||||
> .title {
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 25px; /* 140% */
|
||||
margin: 16px 0;
|
||||
span {
|
||||
color: var(--app-text-secondary);
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px; /* 150% */
|
||||
}
|
||||
}
|
||||
.line {
|
||||
width: 36px;
|
||||
height: 5px;
|
||||
border-radius: 100px;
|
||||
background: #464646;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.list-box {
|
||||
flex: 1;
|
||||
.list {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||
grid-column-gap: 5px;
|
||||
grid-row-gap: 9px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.margin-r-88 {
|
||||
margin-right: 88px;
|
||||
}
|
||||
|
||||
.introduction-wrap,
|
||||
.play-list-box {
|
||||
:deep(.episode) {
|
||||
color: var(--app-text-secondary);
|
||||
border-color: transparent;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
font-weight: 500;
|
||||
|
||||
&.active {
|
||||
color: var(--app-primary);
|
||||
border-color: var(--app-primary);
|
||||
background: rgba(255, 126, 0, 0.2);
|
||||
}
|
||||
|
||||
.byte-wrap .item {
|
||||
background-color: var(--app-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.introduction-wrap :deep(.recommendedList .horizontalVideoBox) {
|
||||
.coverBox .vip_icon:not(.coins_icon):not(.free_trial_icon) {
|
||||
background: var(--app-primary);
|
||||
}
|
||||
|
||||
.videoTitle {
|
||||
color: var(--app-text-primary);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.acg-info span,
|
||||
.videoTitleInfo {
|
||||
color: var(--app-text-secondary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user