提交 0128a52a 编写于 作者: Y yxf15732625262

Sat Feb 8 17:19:00 CST 2025 inscode

上级 f3503817
......@@ -8,12 +8,16 @@
},
"dependencies": {
"guess": "^1.0.2",
"lodash-es": "^4.17.21",
"vant": "^3.6.12",
"vue": "^3.2.37",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@types/lodash-es": "^4.17.12",
"@vitejs/plugin-vue": "^3.0.1",
"less": "^4.2.2",
"less-loader": "^12.2.0",
"vite": "^5.0.1"
}
}
<script setup>
</script>
<template>
<header>
......@@ -11,7 +9,7 @@
</main>
</template>
<style scoped>
<style lang="less" scoped>
header {
line-height: 1.5;
}
......
......@@ -24,7 +24,7 @@ export const activeArray = [
}
],
bottomTitle: '请完成1单任务',
endTime: 1731467085000,
endTime: 1754952000000,
staircaseTaskScheduleVOS: [
{
taskType: 15,
......
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../components/Home.vue';
import VoucherNormal from '../components/VoucherNormal.vue';
import Home from '../views/Home.vue';
import VoucherNormal from '../views/VoucherNormal/index.vue';
const routes = [
{
......
export const SCENE = {
// OLD: 0, // 暂时没用,本阶梯任务只涉及 新客与重逢场景
// 区分新客与重逢场景(流失召回场景)
NEWUSER: 1,
REUNION: 2
}
\ No newline at end of file
......@@ -3,5 +3,4 @@
</template>
<script setup>
import { Cell } from 'vant'
</script>
<style scoped></style>
\ No newline at end of file
</script>
\ No newline at end of file
export const SCENE = {
NEWUSER: 1,
REUNION: 2
}
// 对应服务端 activityScene ,7货运 9快送 10全品类
export const CATEGORY = {
PLATFORM: 10,
FREIGHT: 7,
EXPRESS: 9
}
// 任务状态 0-起点;1-未开始;2-待完成;3-已完成
export const TASK_STATUS = {
ORIGIN: 0,
UNSTART: 1,
UNCOMPLETE: 2,
COMPLETED: 3
}
export const CARD_CATEGORY = {
COUPON: 612307,
RIGHT: 'right'
}
// 前端用于渲染的 券/权益卡片状态 枚举
export const CARD_STATUS = {
CANUSE: 'canuse',
USED: 'used',
// 未解锁或已失效或过期
UNAVAILABLE: 'unavailable'
}
// 服务端存储的 券/权益卡片状态 枚举
export const CARD_STATUS_BACKEND = {
LOCKED: 0,
VALID: 1,
USED: 2,
NOT_VALID: 3,
EXPIRED: 4
}
export const BANNER_JSON = {
topBgs: {
[SCENE.NEWUSER]: 'https://dpubstatic.udache.com/static/dpubimg/0H6iMSXcp4FIoVEMEsZfb.webp',
[SCENE.REUNION]: 'https://dpubstatic.udache.com/static/dpubimg/0H6iMSXcp4FIoVEMEsZfb.webp'
},
topTitle: {
[SCENE.NEWUSER]: {
[CATEGORY.PLATFORM]: '新人专享礼',
[CATEGORY.FREIGHT]: '送货新人专享礼',
[CATEGORY.EXPRESS]: '快送新人专享礼'
},
[SCENE.REUNION]: {
[CATEGORY.PLATFORM]: '重逢回馈礼',
[CATEGORY.FREIGHT]: '送货重逢回馈礼',
[CATEGORY.EXPRESS]: '快送重逢回馈礼'
}
},
flagBgs: {
[TASK_STATUS.UNSTART]: 'https://dpubstatic.udache.com/static/dpubimg/EuDAy81WZJLFIghJRIkn7.webp',
[TASK_STATUS.UNCOMPLETE]: 'https://dpubstatic.udache.com/static/dpubimg/EuDAy81WZJLFIghJRIkn7.webp',
[TASK_STATUS.COMPLETED]: 'https://dpubstatic.udache.com/static/dpubimg/vIq9M3c4GRnHO9VkJDW63.webp'
},
card: {
statusImgs: {
[CARD_CATEGORY.COUPON]: {
[CARD_STATUS.CANUSE]: 'https://dpubstatic.udache.com/static/dpubimg/urWtipI5yJBI9T3pizKO1.webp',
[CARD_STATUS.USED]: 'https://dpubstatic.udache.com/static/dpubimg/urWtipI5yJBI9T3pizKO1.webp',
[CARD_STATUS.UNAVAILABLE]: 'https://dpubstatic.udache.com/static/dpubimg/CrZMNglK_Upwq4ckzc8Us.webp'
},
[CARD_CATEGORY.RIGHT]: {
[CARD_STATUS.CANUSE]: 'https://dpubstatic.udache.com/static/dpubimg/i3HBM_GeLaSfQLjlIOM2T.webp',
[CARD_STATUS.USED]: 'https://dpubstatic.udache.com/static/dpubimg/i3HBM_GeLaSfQLjlIOM2T.webp',
[CARD_STATUS.UNAVAILABLE]: 'https://dpubstatic.udache.com/static/dpubimg/CrZMNglK_Upwq4ckzc8Us.webp'
}
},
statusTexts: {
[CARD_STATUS_BACKEND.LOCKED]: '待解锁',
[CARD_STATUS_BACKEND.VALID]: '待使用',
[CARD_STATUS_BACKEND.USED]: '已使用',
[CARD_STATUS_BACKEND.NOT_VALID]: '已失效',
[CARD_STATUS_BACKEND.EXPIRED]: '已过期'
}
}
}
export const getTimes = (durationStr) => {
const duration = durationStr ? parseInt(durationStr, 10) : 0
const seconds = duration % 60
const totalMinutes = Math.floor(duration / 60)
const minutes = totalMinutes % 60
const hours = Math.floor(totalMinutes / 60)
const padS2 = (num) => String(num).padStart(2, '0')
let days = 0
if (hours > 24 || (hours === 24 && (minutes > 0 || seconds > 0))) {
days = Math.floor(hours / 24)
}
return {
days: padS2(days),
hours: padS2(hours - days * 24),
minutes: padS2(minutes),
seconds: padS2(seconds)
}
}
\ No newline at end of file
<template>
<div class="stair-new-user-banner-container">
<div class="top" :style="topStyle" @click="jumpPage">
<div class="title">
<div class="left">{{ topTitle }}</div>
<div v-if="topTitle2" class="right">·</div>
<div class="right">{{ topTitle2 }}</div>
<img class="arrow" src="https://dpubstatic.udache.com/static/dpubimg/_P8zndpDAAdVooSBUGHlv.webp" />
</div>
<div class="desc">
<div v-if="showActivityRemindTime" class="remind-time">
距结束
<div v-if="activityRemindTime.days !== '00'" class="time-item">
<div class="num">{{ activityRemindTime.days }}</div>
</div>
<div v-if="activityRemindTime.hours !== '00'" class="time-item">
<div class="num">{{ activityRemindTime.hours }}</div>
小时
</div>
<div v-if="activityRemindTime.minutes !== '00' && activityRemindTime.days === '00'" class="time-item">
<div class="num">{{ activityRemindTime.minutes }}</div>
分钟
</div>
</div>
<div class="line"></div>
<div>{{ activityBizTypeDesc }}</div>
</div>
<div ref="bannerContent" class="content">
<div class="crisp">
<BannerSection
v-for="(item, index) in sectionList"
:key="index"
:section-data="item"
:static-data="staticData"
:section-list="sectionList"
:index="index"
/>
<div class="bottom-bar">
<div class="process-bar" :style="processBarStyle"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref, computed } from 'vue'
import { findLastIndex } from 'lodash-es'
import { getTimes } from '../assets/utils'
import { BANNER_JSON, SCENE, CATEGORY, TASK_STATUS } from '../assets/constant.js'
const props = withDefaults(defineProps<{ bannerData: any }>(), {
bannerData: ()=> ({})
})
const emit = defineEmits(['jumpPage']);
const bannerDataComputed = computed(()=>{
return {
...props.bannerData,
json: BANNER_JSON
}
})
const staticData = computed(()=>{
return bannerDataComputed.value.json || {}
})
const scene = computed(()=>{
return bannerDataComputed.value.taskScene || SCENE.NEWUSER
})
const category = computed(()=>{
return bannerDataComputed.value.activityScene || CATEGORY.PLATFORM
})
const activityBizTypeDesc = computed(()=>{
return bannerDataComputed.value.activityBizTypeDesc || ''
})
const topTitle2 = computed(()=>{
console.log('linda-222', bannerDataComputed.value.titleV2)
return bannerDataComputed.value.titleV2 || ''
})
const showActivityRemindTime = computed(()=>{
return bannerDataComputed.value.endTime - new Date().getTime() > 0
})
const activityRemindTime = computed(()=>{
const duration = bannerDataComputed.value.endTime - new Date().getTime()
return getTimes(duration / 1000)
})
const topStyle = computed(()=>{
const { topBgs } = staticData.value
const bgUrl = topBgs && scene.value ? topBgs[scene.value] : ''
return `
background: url(${bgUrl}) no-repeat;
background-size: 100% 100%;
`
})
const topTitle = computed(()=>{
const { topTitle } = staticData.value
return topTitle && scene.value && category.value ? topTitle[scene.value][category.value] : ''
})
const sectionList = computed(()=>{
return bannerDataComputed.value.staircaseTaskScheduleVOS || []
})
const processBarStyle = computed(()=>{
let makeOrderProgress
const idx = findLastIndex(sectionList.value, (e:any) => e.taskStatus === TASK_STATUS.COMPLETED)
const func = (arr) => arr.reduce((acc, cur) => acc + cur.benefitVOS.length, 0)
if (idx < 0) makeOrderProgress = '0'
else if (idx !== sectionList.value.length - 1) {
const completedLength = func(sectionList.value.slice(0, idx))
const cardWidth = 156
const cardMargin = 20
const cardSectionPadding = idx * (32 * 2)
const doingTaskFlag = 100
makeOrderProgress = `${
(completedLength * (cardWidth + cardMargin) + cardSectionPadding + doingTaskFlag) / 100
}rem`
} else makeOrderProgress = '100%'
console.warn('拉新场景-做单进度', makeOrderProgress)
return `width:${makeOrderProgress};`
})
// // 定义一个响应式引用,指向模板中的 bannerContent
// const bannerContent = ref(null)
// // 定义事件处理函数
// const handleTouchMove = (e) => {
// e.stopPropagation()
// }
// const handleTouchStart = (e) => {
// e.stopPropagation()
// }
onMounted(()=>{
// if (bannerContent.value) {
// bannerContent.value.addEventListener('touchmove', handleTouchMove)
// bannerContent.value.addEventListener('touchstart', handleTouchStart)
// }
})
// onBeforeUnmount(()=>{
// if (bannerContent.value) {
// bannerContent.value.removeEventListener('touchmove', handleTouchMove)
// bannerContent.value.removeEventListener('touchstart', handleTouchStart)
// }
// })
const jumpPage = () => {
if (!props.bannerData?.jumpUrl) return
emit('jumpPage', props.bannerData.jumpUrl)
}
</script>
<style lang="less" scoped>
.title {
display: flex;
flex-direction: row;
align-items: center;
.left {
font-family: MFYuanHei;
font-size: 15px;
font-weight: normal;
line-height: 16px;
letter-spacing: 0px;
color: #FF5E15;
}
.right {
font-family: PingFang SC;
font-size: 14px;
font-weight: normal;
line-height: 14px;
letter-spacing: 0px;
color: #772E1F;
}
.arrow {
height: 12px;
width: 12px;
margin-left: 4px;
}
}
.desc {
margin-top: 8px;
display: flex;
flex-direction: row;
align-items: center;
font-size: 12px;
font-weight: normal;
line-height: 12px;
text-align: right;
letter-spacing: 0px;
color: #AE795F;
.line {
width: 1px;
height: 14px;
background: #fde3e1;
transform: scaleX(0.5);
margin: 2px 6px;
}
.remind-time, .time-item {
display: flex;
flex-direction: row;
align-items: center;
}
.remind-time {
font-size: 12px;
color: #666666;
font-family: PingFangSC-Regular;
.num {
padding: 4px 2px;
text-align: center;
margin: 0 2px;
line-height: 1;
font-family: PingFangSC-medium;
font-weight: bold;
color: #ae795f;
background: #ffe2d6;
border-radius: 6px;
}
}
}
</style>
\ No newline at end of file
<script setup>
import { ref } from 'vue'
import { Swipe, SwipeItem } from 'vant';
import { activeArray } from '../mockData/activeList.js'
import { SCENE } from '../utils/constant.js'
const activeList = ref(activeArray)
defineProps({
msg: {
type: String,
required: true
}
})
</script>
<template>
<div class="greetings">
HELLO WORLD
<Swipe
class="my_swipe"
:autoplay="3000"
......@@ -27,47 +9,33 @@ defineProps({
>
<SwipeItem v-for="(item, index) in activeList" :key="item.activityId" class="swipe_item">
<div class="activity-container">
{{item.titleV2}}
<!-- <StairNewUserBanner
v-if="item.taskScene === SCENE.NEWUSER || item.taskScene === SCENE.REUNION"
<StairNewUserBanner
:banner-data="item"
@jumpPage="jumpToActivePage"
/>
<ProgressCard
v-else
:card-data="item"
:card-index="index"
@join="clickJoin(item, index)"
@jumpPage="jumpToActivePage"
/> -->
</div>
</SwipeItem>
</Swipe>
</div>
</template>
<style lang="less" scoped>
.my_swipe {
margin: 0.26rem auto 0 auto;
width: 7.1rem;
border-radius: 0.24rem;
<script setup>
import { ref } from 'vue'
import { Swipe, SwipeItem } from 'vant';
import { activeArray } from '../../mockData/activeList.js'
import StairNewUserBanner from './components/StairNewUserBanner.vue'
::v-deep .van-swipe__indicators {
bottom: 0.04rem;
}
const activeList = ref(activeArray)
const activeIndex = ref(0)
.swipe_item {
// swipper-item 生成的 width 单位为 px 换算有偏差,这里直接覆盖
width: 7.1rem !important;
.head_img {
width: 7.1rem;
height: 1.22rem;
}
}
const jumpToActivePage = ()=>{
console.log('linda-点击');
}
.activity-container {
width: 7.1rem;
height: 3.31rem;
}
const onChange = (index) => {
activeIndex.value = index
}
</script>
<style lang="less" scoped>
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册