[Human] chore(project): 初始化导入 91dj H5 客户端项目代码

从本地工程首次入库;.npmrc(含私有 npm 源 token)与 tsbuildinfo 已加入 .gitignore,不随仓库提交。
This commit is contained in:
谢宇宁
2026-10-08 14:22:35 +07:00
commit eada71e211
1421 changed files with 144498 additions and 0 deletions
+339
View File
@@ -0,0 +1,339 @@
<template>
<Teleport to="body">
<van-popup :show="isShow" z-index="2001" position="bottom" @click-overlay="emit('close')">
<div class="wrapper flex-center-center">
<div class="content" :class="[props.theme]" @click.stop="void 0">
<div class="line_top" />
<div class="title">{{ props.title }}</div>
<div class="priceList">
<div class="leader">作品解锁</div>
<div class="price gold flex-vcenter">
<!-- <SvgIcon name="gold" /> -->
{{ gold }} 金币
</div>
</div>
<template v-if="props.isSale">
<div class="priceList">
<div class="leader">作品原价</div>
<div class="price through flex-vcenter">{{ props.videoInfo.originCoins }}金币</div>
</div>
<div v-if="userInfo.isVip" class="priceList vip">
<div class="leader">您当前享受{{ sale }}折扣优惠</div>
<div class="price underline flex-vcenter" @click.stop="$router.push('member'), emit('close')">
升级会员
</div>
</div>
<div v-else class="priceList vip">
<div class="leader">您当前不享受免费观看</div>
<div class="price underline flex-vcenter" @click.stop="$router.push('member'), emit('close')">
购买VIP享免费观看
</div>
</div>
</template>
<div class="priceList split">
<div class="leader">我的金币</div>
<div class="price flex-vcenter">
{{ recharge }}
<!-- 100 -->
<span class="go" @click.stop="$router.push('wallet'), emit('close')">充值</span>
</div>
</div>
<!-- <div class="couponBox" v-if="userGoldVideoCoupon.length">
<div
class="couponItem flex-center-between"
:class="index === changeGoldVideoCouponIndex ? 'active' : ''"
v-for="(item, index) in userGoldVideoCoupon"
:key="index"
@click.stop="selectCoupon(item, index)"
>
<div>观影券({{ item.num }}金币)</div>
<div class="count">剩余{{ item.newcount }}张</div>
<div class="checkbox"></div>
</div>
</div> -->
<div class="btnBox flex-center-between">
<div class="btn flex-center-center" :class="!showVipBtn ? 'themeColor' : ''" @click="unlockNow">
{{ !showVipBtn ? `${gold}金币/立即支付` : `${gold}金币支付` }}
</div>
<div v-if="showVipBtn" class="btn vip-btn flex-center-center" @click.stop="clickVipHandle">
开通会员免费看
</div>
</div>
</div>
</div>
</van-popup>
</Teleport>
</template>
<script lang="ts" setup>
import { computed, nextTick } from 'vue';
import useLoading from '@/hooks/loading';
import VideoApi from '@/service/video';
import { ProductType } from '@/enums/app';
import { showToast } from 'vant';
import { useUserStore } from '@/stores/user';
import { useRouter } from 'vue-router';
const props = withDefaults(
defineProps<{
videoInfo: Types.Video.VInfosItem;
isOpen: boolean;
productType?: ProductType;
theme?: string; //black 为黑色主题,默认为白色主题
title?: string; //弹窗标题
isSale?: boolean; //是否显示折扣区
showVipBtn?: boolean; // 是否显示购买vip按钮
membershipActivation?: boolean;
}>(),
{
title: '购买作品',
theme: 'black',
productType: ProductType.VIDEO,
isSale: true,
showVipBtn: false,
membershipActivation: false,
},
);
const userStore = useUserStore();
const userInfo = userStore.userInfo;
const router = useRouter();
const { openLoading, closeLoading } = useLoading();
const emit = defineEmits(['close', 'buySuccess', 'membershipActivationShow']);
const isShow = computed(() => {
return props.isOpen;
});
// const changeGoldVideoCouponIndex = ref(-1);
// const userGoldVideoCoupon = computed(() => {
// const mergedData: any = [];
// (userInfo.userGoldVideoCoupon || [])
// .filter((item: any) => !item.used)
// .forEach((item: any) => {
// const existingItem = mergedData.find((element: any) => element.num === item.num);
// if (existingItem) {
// existingItem.newcount += 1;
// } else {
// item.newcount = 1;
// mergedData.push(item);
// }
// });
// return mergedData;
// });
const gold = computed(() => {
// return userInfo.isVip ? props.videoInfo.coins : props.videoInfo.originCoins;
return props.isSale ? props.videoInfo.coins : props.videoInfo.originCoins;
});
const sale = computed(() => {
return userStore.userInfo.payVidDiscount;
});
const recharge = computed(() => {
const balance = ((userStore.walletInfo.amount || 0) * 100 + (userStore.walletInfo.income || 0) * 100) / 100;
return balance === 0 ? '0' : balance.toFixed(1);
});
// const selectCoupon = (item: any, index: number) => {
// if (changeGoldVideoCouponIndex.value === index) {
// changeGoldVideoCouponIndex.value = -1;
// return;
// }
// let money = gold.value;
// if (item.num < money) return showToast('观影券面值过小,请选择其他支付方式');
// changeGoldVideoCouponIndex.value = index;
// let productID = props.videoInfo.id;
// if (!productID) {
// showToast('购买出错~');
// return;
// }
// };
const clickVipHandle = () => {
emit('close');
if (props.membershipActivation) {
emit('membershipActivationShow');
return;
}
router.push('/member');
};
const unlockNow = () => {
try {
openLoading();
// const money =
// changeGoldVideoCouponIndex.value > -1 ? userGoldVideoCoupon.value[changeGoldVideoCouponIndex.value].num : 0;
let productID = props.videoInfo.id;
if (!productID) {
showToast('购买出错~');
return;
}
VideoApi.videoBuying({
productType: props.productType, //props.productType ||
productID: productID,
goldVideoCouponNum: 0, //money || 0,
})
.then(async () => {
showToast('购买成功');
userStore.updateWallet();
emit('buySuccess');
})
.catch((e) => {
if (e.toString().indexOf('8000') != -1) {
emit('close');
nextTick(() => {
router.push({
path: '/wallet',
query: {
activeTab: 1,
id: props.videoInfo.id,
title: props.videoInfo.title || '无标题',
},
});
});
}
});
} finally {
closeLoading();
}
};
</script>
<style lang="scss" scoped>
.wrapper {
width: 100%;
height: 100%;
.content {
color: #000;
width: 100%;
padding: 18px 10px 0;
background-color: #fff;
position: relative;
border-radius: 10px 10px 0 0;
padding-bottom: 24px;
.line_top {
width: 36px;
height: 5px;
background: #f5f5f5;
margin: 0 auto;
border-radius: 99px;
}
.title {
padding: 18px 0;
font-size: 20px;
font-weight: 500;
text-align: center;
}
.priceList {
display: flex;
align-items: center;
justify-content: space-between;
margin: 18px 0;
&.vip {
.leader,
.price {
color: #ac7e6e;
}
}
&.split {
border-top: $borderSplit;
margin-top: 18px;
padding-top: 18px;
}
.leader {
color: #757575;
font-size: 14px;
}
.price {
font-size: 14px;
font-weight: 500;
> svg {
height: 18px;
width: 18px;
margin-right: 10px;
}
.go {
text-decoration-line: underline;
color: #ac7e6e;
margin-left: 12px;
}
}
.gold {
color: #ff9000;
}
.through {
text-decoration: line-through;
color: rgba(255, 255, 255, 0.55);
}
.underline {
text-decoration: underline;
color: rgba(0, 0, 0, 0.5);
}
}
&.black {
background-color: #0f0f0f;
color: rgba(255, 255, 255, 0.9);
.line_top {
background: rgba(255, 255, 255, 0.2);
}
.leader {
color: rgba(255, 255, 255, 0.9);
font-size: 14px;
}
}
.text {
font-size: 20px;
text-align: center;
margin: 30px 0 18px;
span {
font-size: 28px;
color: $themeColor;
}
&.line {
display: flex;
justify-content: center;
.text-center {
position: relative;
&::after {
content: '';
position: absolute;
left: 0;
bottom: 30%;
height: 1px;
width: 100%;
background: rgba(255, 255, 255, 0.1);
}
}
}
}
p {
font-size: 14px;
text-align: center;
opacity: 0.9;
}
.btnBox {
margin-top: 26px;
.btn {
height: 44px;
width: 100%;
background: linear-gradient(165deg, #f8f3ae 0%, #ddac44 100%);
text-align: center;
line-height: 44px;
font-size: 16px;
font-weight: 500;
color: #7b0000;
border-radius: 3px;
}
.vip-btn {
background: var(--app-primary);
color: var(--app-primary-text);
margin-left: 18px;
}
.themeColor {
background: var(--app-primary);
color: var(--app-primary-text);
}
}
}
}
</style>
+112
View File
@@ -0,0 +1,112 @@
<template>
<van-overlay :show="isShow" z-index="2001" @click="emit('close')">
<div class="wrapper flex-center-center">
<div class="content">
<p>金币购买本视频解锁精彩完整版!</p>
<p style="color: #3f57b9">{{ videoInfo.originCoins }}金币</p>
<p>可用金币{{ (userWallet.amount * 100 + userWallet.income * 100) / 100 || 0 }}金币</p>
<div class="btnBox flex-center-between">
<div class="btn" @click="unlockNow(0)">立即购买</div>
<div class="btn" @click="$router.push('freeBenefits')">做任务得VIP</div>
</div>
</div>
</div>
</van-overlay>
</template>
<script lang="ts" setup>
import useLoading from '@/hooks/loading';
import VideoApi from '@/service/video';
import { computed } from 'vue';
import { ProductType } from '@/enums/app';
import { showToast } from 'vant';
import { useUserStore } from '@/stores/user';
const props = defineProps<{
videoInfo: Types.Video.VInfosItem;
isOpen: boolean;
}>();
const emit = defineEmits(['close', 'buySuccess']);
const userInfo = useUserStore().userInfo;
const userWallet = useUserStore().walletInfo;
const { openLoading, closeLoading } = useLoading();
const isShow = computed(() => {
return props.isOpen;
});
/**
* @description 视频购买
*/
const unlockNow = (money: any) => {
try {
openLoading();
let productID = props.videoInfo.id;
if (!productID) {
showToast('购买出错~');
return;
}
VideoApi.videoBuying({ productType: ProductType.VIDEO, productID: productID, goldVideoCouponNum: money || 0 })
.then(async () => {
showToast('购买成功');
if (money) {
for (let i = 0; i < userInfo.goldVideoCoupon.length; i++) {
if (money == userInfo.goldVideoCoupon[i].gold) {
if (userInfo.goldVideoCoupon[i].count > 1) {
userInfo.goldVideoCoupon[i].count--;
} else {
userInfo.goldVideoCoupon.splice(i, 1);
}
}
}
}
useUserStore().updateWallet();
emit('buySuccess');
})
.catch((e) => {
if (e.toString().indexOf('8000') != -1) {
router.push({
path: '/wallet',
query: {
id: props.videoInfo.id,
title: props.videoInfo.title || '无标题',
},
});
}
});
} finally {
closeLoading();
}
};
</script>
<style lang="scss" scoped>
.wrapper {
width: 100%;
height: 100%;
flex-direction: column;
.content {
width: 313px;
height: 293px;
background: url('@/assets/images/png/popVip.png') no-repeat;
background-size: 100% 100%;
padding: 135px 34px 0;
position: relative;
p {
font-size: 12px;
line-height: 26px;
text-align: center;
}
}
.btnBox {
width: 235px;
margin-top: 21px;
.btn {
height: 31px;
width: 92px;
background: #3476ff;
text-align: center;
line-height: 31px;
font-size: 11px;
border-radius: 4px;
}
}
}
</style>