添加ui
parent
a3474242a4
commit
c0da01e9d1
Binary file not shown.
|
After Width: | Height: | Size: 450 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 456 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 456 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 464 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -1,11 +1,11 @@
|
|||
|
||||
import axios from 'axios'
|
||||
import { localCache } from '@/io/cache'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { showToast } from 'vant';
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||||
timeout: 200000,
|
||||
withCredentials: true
|
||||
withCredentials: false
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ service.interceptors.response.use(
|
|||
return res
|
||||
} else {
|
||||
if (res.status != 0) {
|
||||
message.error(res.msg || 'Error')
|
||||
showToast(res.msg || 'Error')
|
||||
return Promise.reject(res.message || 'Error')
|
||||
} else {
|
||||
return res.data
|
||||
|
|
@ -51,11 +51,11 @@ service.interceptors.response.use(
|
|||
// localCache.remove('auth');
|
||||
// localCache.remove('userInfo');
|
||||
}
|
||||
message.error(res.errmsg || 'Error')
|
||||
showToast(res.errmsg || 'Error')
|
||||
return Promise.reject(res)
|
||||
} else {
|
||||
|
||||
message.error(res.errmsg || 'Error')
|
||||
showToast(res.errmsg || 'Error')
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,22 @@ const router = createRouter({
|
|||
},
|
||||
component: () => import("@/views/macroeconomics/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "trend",
|
||||
name: "Trend",
|
||||
meta: {
|
||||
title: "AI商情-洞见趋势详情",
|
||||
},
|
||||
component: () => import("@/views/macroeconomics/trend.vue"),
|
||||
},
|
||||
{
|
||||
path: "vip",
|
||||
name: "Vip",
|
||||
meta: {
|
||||
title: "会员专区",
|
||||
},
|
||||
component: () => import("@/views/vip/index.vue"),
|
||||
},
|
||||
{
|
||||
path: "ucenter",
|
||||
name: "ucenter",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,19 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="text-24px text-white opacity-40">2023.06.12</div>
|
||||
<div class="mt-31px text-22px text-white leading-34px">
|
||||
大自然是人类赖以生存发展的基本条件,尊重自然、顺应自然、保护自然是全面建设社会主
|
||||
<div class="text-24px text-white opacity-40">
|
||||
{{ formatDate(data.time, 'yyyy.MM.dd') }}
|
||||
</div>
|
||||
<div class="mt-31px text-22px text-white leading-34px line-clamp-2">
|
||||
{{ data.content }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<script setup>
|
||||
import { formatDate } from '@/utils/format.js'
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
<template>
|
||||
<div
|
||||
@click="handleClick"
|
||||
:style="{ backgroundImage: `url(${data.picture})` }"
|
||||
class="h-full rounded-4px cursor-pointer bg-gray-500 bg-opacity-10 bg-img"
|
||||
></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
const router = useRouter()
|
||||
|
||||
const handleClick = () => {
|
||||
const { link_config } = props.data
|
||||
if (link_config.target_url) {
|
||||
router.push(link_config.target_url)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.bg-img{
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
<template>
|
||||
<div class="px-34px">
|
||||
<div class="border border-[#A6A8AF] rounded-6px p-24px mt-62px">
|
||||
<Title title="每周大事件" sub="new"></Title>
|
||||
<van-divider class="my-20px" />
|
||||
<div>
|
||||
<NewsItem v-for="(item, i) in 3" class="my-48px" :key="i"></NewsItem>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border border-[#A6A8AF] rounded-6px p-24px mt-33px">
|
||||
<Title title="内容分类"></Title>
|
||||
<div class="grid grid-cols-2 gap-x-21px gap-y-27px py-37px">
|
||||
<CardItem :data="{ name: '111' }"></CardItem>
|
||||
<CardItem
|
||||
v-for="(item, i) in contentTypes"
|
||||
:key="i"
|
||||
:data="item"
|
||||
></CardItem>
|
||||
</div>
|
||||
<Title title="洞察趋势"></Title>
|
||||
<div class="h-300px">
|
||||
|
|
@ -31,27 +29,126 @@
|
|||
class="h-full"
|
||||
>
|
||||
<swiper-slide
|
||||
v-for="(item, i) in 3"
|
||||
v-for="(item, i) in trendsList"
|
||||
:key="i"
|
||||
:data="item"
|
||||
class="text-black relative bg-white !w-427px"
|
||||
>
|
||||
<div>{{ item }}</div>
|
||||
<TrendItem :data="item">{{ item }}</TrendItem>
|
||||
</swiper-slide>
|
||||
</swiper>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="border border-[#A6A8AF] rounded-6px py-24px mt-62px max-h-1/2 overflow-hidden flex flex-col"
|
||||
>
|
||||
<div class="px-24px">
|
||||
<Title title="每周大事件" sub="new"></Title>
|
||||
</div>
|
||||
<van-divider class="my-20px" />
|
||||
<div class=" px-24px">
|
||||
<van-list
|
||||
v-model:loading="loading"
|
||||
:finished="finished"
|
||||
finished-text="没有更多了"
|
||||
@load="weekNewOnLoad"
|
||||
>
|
||||
<NewsItem
|
||||
v-for="(item, i) in weekNewsList"
|
||||
class="my-48px"
|
||||
:key="i"
|
||||
:data="item"
|
||||
></NewsItem>
|
||||
</van-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import http from '@/io/request'
|
||||
import Title from './components/title.vue'
|
||||
import NewsItem from './components/news-item.vue'
|
||||
import CardItem from './components/card-item.vue'
|
||||
import TrendItem from './components/trends-item.vue'
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue'
|
||||
import { Mousewheel, Navigation, EffectCoverflow } from 'swiper/modules'
|
||||
import 'swiper/scss'
|
||||
import 'swiper/scss/mousewheel'
|
||||
import 'swiper/css/effect-coverflow'
|
||||
import 'swiper/css/navigation';
|
||||
import 'swiper/css/navigation'
|
||||
|
||||
const modules = [Mousewheel, Navigation, EffectCoverflow]
|
||||
|
||||
const pagetSize = 100
|
||||
const weekNewsPage = ref(1)
|
||||
const weekNewsList = ref([])
|
||||
|
||||
const contentTypes = ref([])
|
||||
|
||||
const trendsList = ref([])
|
||||
|
||||
const loading = ref(false)
|
||||
const finished = ref(false)
|
||||
|
||||
const weekNewOnLoad = () => {
|
||||
http
|
||||
.get('/api/topic', {
|
||||
params: {
|
||||
per_page: pagetSize,
|
||||
page: weekNewsPage.value,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
loading.value = false
|
||||
const { total, data } = res
|
||||
if (weekNewsPage.value === 1) weekNewsList.value = []
|
||||
weekNewsList.value = weekNewsList.value.concat(data)
|
||||
if (total <= weekNewsList.value.length) finished.value = true
|
||||
weekNewsPage.value++
|
||||
})
|
||||
}
|
||||
|
||||
function getContentTypes() {
|
||||
http
|
||||
.get('/api/keywords', {
|
||||
params: {
|
||||
type_key: 'government',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
contentTypes.value = res
|
||||
})
|
||||
}
|
||||
|
||||
function getTrendsList() {
|
||||
http
|
||||
.get('/api/banner', {
|
||||
params: {
|
||||
key: 'pc_trend_recommend',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
trendsList.value = res
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getTrendsList()
|
||||
getContentTypes()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.swiper-button-prev,.swiper-button-next{
|
||||
transform: translateY(-50%);
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 1px solid white;
|
||||
border-radius: 50%;
|
||||
&::after{
|
||||
font-size: 30px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
<template>
|
||||
<div class="px-30px">
|
||||
<div class="flex items-center justify-center mt-54px" v-if="sortList.length">
|
||||
<svg-icon
|
||||
@click="handlePrev"
|
||||
class="text-white text-53px transform -rotate-90 cursor-pointer"
|
||||
:class="{ 'opacity-40': currentSortIndex === 0 }"
|
||||
name="收起箭头小2"
|
||||
></svg-icon>
|
||||
<div class="text-27px font-bold min-w-150px text-center">
|
||||
<span class="text-white">{{ currentSort.name }}</span>
|
||||
</div>
|
||||
<svg-icon
|
||||
@click="handleNext"
|
||||
class="text-white text-53px transform rotate-90 cursor-pointer"
|
||||
name="收起箭头小2"
|
||||
:class="{ 'opacity-40': currentSortIndex === sortList.length - 1 }"
|
||||
></svg-icon>
|
||||
</div>
|
||||
|
||||
<div class="h-533px w-full border-1px border-[#A6A8AF] mt-3">
|
||||
<div class="w-full h-full" id="myEcharts"></div>
|
||||
</div>
|
||||
<div class="w-full grid grid-cols-2 gap-x-27px gap-y-18px my-50px">
|
||||
<div
|
||||
@click="changeChart(i)"
|
||||
class="border-1px border-[#A6A8AF] rounded-4px text-center h-72px text-25px flex items-center justify-center cursor-pointer"
|
||||
v-for="(item, i) in chartList"
|
||||
:class="{
|
||||
'bg-[#3662FE] text-white border-[#3662FE]': i === chartIndex,
|
||||
}"
|
||||
:key="i"
|
||||
>
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, onMounted, computed, toRaw } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import * as echarts from 'echarts'
|
||||
import http from '@/io/request'
|
||||
let myEcharts = echarts
|
||||
let chartDom = null
|
||||
const route = useRoute()
|
||||
|
||||
const id = ref(route.query.id)
|
||||
|
||||
const currentSortIndex = ref(0)
|
||||
|
||||
const chartIndex = ref(0)
|
||||
|
||||
const sortList = ref([])
|
||||
|
||||
const chartList = ref([])
|
||||
|
||||
const currentSort = computed(() => sortList.value[currentSortIndex.value])
|
||||
|
||||
const currentChart = computed(() => chartList.value[chartIndex.value])
|
||||
|
||||
const handleNext = () => {
|
||||
if (currentSortIndex.value < sortList.value.length - 1) {
|
||||
currentSortIndex.value++
|
||||
}
|
||||
changeSort()
|
||||
}
|
||||
|
||||
const handlePrev = () => {
|
||||
if (currentSortIndex.value > 0) {
|
||||
currentSortIndex.value--
|
||||
}
|
||||
changeSort()
|
||||
}
|
||||
|
||||
const changeChart = (index) => {
|
||||
if (chartIndex.value === index) return
|
||||
chartIndex.value = index
|
||||
initChart()
|
||||
}
|
||||
|
||||
const changeSort = () => {
|
||||
getTrend()
|
||||
}
|
||||
|
||||
const getTrend = () => {
|
||||
http
|
||||
.get(`/api/trend`, {
|
||||
params: {
|
||||
category_id: currentSort.value.id,
|
||||
per_page: 100,
|
||||
page: 1,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
chartIndex.value = 0
|
||||
chartList.value = res.data
|
||||
// chartList.value[1].
|
||||
initChart()
|
||||
})
|
||||
}
|
||||
|
||||
const getSorts = () => {
|
||||
http
|
||||
.get(`/api/keywords`, {
|
||||
params: {
|
||||
type_key: 'trend',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
sortList.value = res
|
||||
getTrend()
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
chartDom = myEcharts.init(document.getElementById('myEcharts'))
|
||||
getSorts()
|
||||
})
|
||||
|
||||
const setOption = (options) => {
|
||||
if (chartDom) {
|
||||
chartDom.setOption(options)
|
||||
}
|
||||
}
|
||||
|
||||
const initChart = () => {
|
||||
const data = toRaw(currentChart.value)
|
||||
if (data) {
|
||||
const { chart_options } = data
|
||||
if (chart_options.type == 'line') lineChart(data)
|
||||
if (chart_options.type == 'bar') barChart(data)
|
||||
}
|
||||
}
|
||||
|
||||
const lineChart = (data) => {
|
||||
const { chart_data, chart_options, title } = data
|
||||
|
||||
const xAxis = chart_data.xAxis.list
|
||||
|
||||
const series = chart_data.data.map((e) => {
|
||||
return {
|
||||
name: e.name,
|
||||
type: chart_options.type,
|
||||
color: '#3662FE',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(54, 98, 254, 0.3)',
|
||||
},
|
||||
{
|
||||
offset: 0.8,
|
||||
color: 'rgba(54, 98, 254, 0)',
|
||||
},
|
||||
],
|
||||
false
|
||||
),
|
||||
shadowColor: 'rgba(54, 98, 254, 0.1)',
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
data: e.list,
|
||||
}
|
||||
})
|
||||
|
||||
setOption({
|
||||
grid: {
|
||||
left: '2%',
|
||||
right: '3%',
|
||||
top: '22%',
|
||||
bottom: '2%',
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
title: {
|
||||
text: title,
|
||||
left: '2%',
|
||||
top: '3%',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: xAxis,
|
||||
axisLabel: {
|
||||
color: 'rgba(255, 255, 255, .4)',
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: 'rgba(65, 69, 72, 1)',
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '单位',
|
||||
position: 'left',
|
||||
nameTextStyle: {
|
||||
color: 'rgba(255, 255, 255, .4)',
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(255, 255, 255, .4)',
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: 'rgba(65, 69, 72, 1)',
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: 'rgba(255, 255, 255, .4)',
|
||||
},
|
||||
},
|
||||
},
|
||||
series: series,
|
||||
})
|
||||
}
|
||||
|
||||
const barChart = (data) => {
|
||||
const { chart_data, chart_options, title } = data
|
||||
|
||||
const xAxis = chart_data.xAxis.list
|
||||
|
||||
const series = chart_data.data.map((e) => {
|
||||
return {
|
||||
name: e.name,
|
||||
type: chart_options.type,
|
||||
color: '#3662FE',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(54, 98, 254, 0.3)',
|
||||
},
|
||||
{
|
||||
offset: 0.8,
|
||||
color: 'rgba(54, 98, 254, 0)',
|
||||
},
|
||||
],
|
||||
false
|
||||
),
|
||||
shadowColor: 'rgba(54, 98, 254, 0.1)',
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
data: e.list,
|
||||
}
|
||||
})
|
||||
|
||||
setOption({
|
||||
grid: {
|
||||
left: '2%',
|
||||
right: '3%',
|
||||
top: '22%',
|
||||
bottom: '2%',
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
title: {
|
||||
text: title,
|
||||
left: '2%',
|
||||
top: '3%',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: xAxis,
|
||||
axisLabel: {
|
||||
color: 'rgba(255, 255, 255, .4)',
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: 'rgba(65, 69, 72, 1)',
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '单位',
|
||||
position: 'left',
|
||||
nameTextStyle: {
|
||||
color: 'rgba(255, 255, 255, .4)',
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLabel: {
|
||||
color: 'rgba(255, 255, 255, .4)',
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: 'rgba(65, 69, 72, 1)',
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: 'rgba(255, 255, 255, .4)',
|
||||
},
|
||||
},
|
||||
},
|
||||
series: series,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
<template>
|
||||
<div
|
||||
class="bg w-full h-1229px"
|
||||
:style="{ backgroundImage: `url('${current.bg}')` }"
|
||||
>
|
||||
<div class="text-39px font-bold pt-20px ml-110px text-[#19191A]">
|
||||
{{ data.name }}
|
||||
</div>
|
||||
<div class="ml-78px mt-54px">
|
||||
<span class="text-[#E73434] text-157px font-bold">{{
|
||||
currentAttr.price
|
||||
}}</span>
|
||||
<span class="text-[#19191A] ml-28px text-39px font-bold">元</span>
|
||||
</div>
|
||||
<div class="px-50px">
|
||||
<div class="mt-28px flex items-center justify-between">
|
||||
<div
|
||||
class="bg-[#E73434] text-white text-28px font-bold rounded-4px px-18px h-43px flex items-center"
|
||||
>
|
||||
{{ currentAttr.discount }}
|
||||
</div>
|
||||
<div class="text-28px font-bold text-white line-through">
|
||||
原价 {{ currentAttr.origin_price }} 元
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-20px">
|
||||
<van-dropdown-menu v-model="value" :overlay="false">
|
||||
<van-dropdown-item title-class="w-299px" :options="options" />
|
||||
</van-dropdown-menu>
|
||||
|
||||
<!-- <a-select
|
||||
class="w-full cu-select"
|
||||
v-model:value="value"
|
||||
:options="options"
|
||||
popupClassName="cu-select-popup"
|
||||
:dropdownStyle="{
|
||||
backgroundColor: '#A5937C',
|
||||
color: 'white',
|
||||
}"
|
||||
></a-select> -->
|
||||
</div>
|
||||
<div
|
||||
class="mt-80px text-35px text-[#886E43] font-bold"
|
||||
:style="{ color: current.color }"
|
||||
>
|
||||
权益内容
|
||||
</div>
|
||||
<van-divider class="my-4 border-[#FFF4E0]" />
|
||||
<div class="flex justify-between items-center text-31px text-[#232323]">
|
||||
<div>字数上限</div>
|
||||
<div>{{ formatNumber(data.equity.words) }}</div>
|
||||
</div>
|
||||
<van-divider class="my-4 border-[#FFF4E0]" />
|
||||
<div
|
||||
class="text-[#886E43] text-35px font-bold"
|
||||
:style="{ color: current.color }"
|
||||
>
|
||||
更多权益
|
||||
</div>
|
||||
<div
|
||||
:style="{ backgroundColor: current.color + 20 }"
|
||||
v-html="data.description_html"
|
||||
class="mt-20px bg-[#C1B9AF] py-24px px-20px text-[#695F56] h-248px text-31px"
|
||||
></div>
|
||||
<div
|
||||
class="grid gap-x-5 mt-40px"
|
||||
:class="[currentAttr.is_subscribe ? 'grid-cols-2' : 'grid-cols-1']"
|
||||
>
|
||||
<van-button
|
||||
@click="handleSubscribe(0)"
|
||||
type="primary"
|
||||
:style="{ backgroundColor: current.color }"
|
||||
class="bg-[#786B56] h-79px flex items-center justify-center text-white font-bold mt-7 rounded-4px !border-none"
|
||||
>订阅</van-button
|
||||
>
|
||||
<van-button
|
||||
@click="handleSubscribe(1)"
|
||||
type="primary"
|
||||
v-if="currentAttr.is_subscribe"
|
||||
:style="{ backgroundColor: current.color }"
|
||||
class="bg-[#786B56] h-79px flex items-center justify-center text-white font-bold mt-7 rounded-4px !border-none"
|
||||
>连续订阅</van-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed, ref, toRaw } from 'vue'
|
||||
import v1 from '@/assets/images/vip_card-01.png'
|
||||
import v2 from '@/assets/images/vip_card-02.png'
|
||||
import v3 from '@/assets/images/vip_card-03.png'
|
||||
import v4 from '@/assets/images/vip_card-04.png'
|
||||
|
||||
const emit = defineEmits(['subscribe'])
|
||||
|
||||
const list = [
|
||||
{
|
||||
name: '试用版',
|
||||
bg: v1,
|
||||
color: '#786B56',
|
||||
},
|
||||
{
|
||||
name: '普惠版',
|
||||
bg: v2,
|
||||
color: '#886E43',
|
||||
},
|
||||
{
|
||||
name: '高级版',
|
||||
bg: v3,
|
||||
color: '#886E43',
|
||||
},
|
||||
{
|
||||
name: '高阶版',
|
||||
bg: v3,
|
||||
color: '#886E43',
|
||||
},
|
||||
{
|
||||
name: '专业版',
|
||||
bg: v4,
|
||||
color: '#A14739',
|
||||
},
|
||||
]
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
const value = ref('')
|
||||
|
||||
const current = computed(() => {
|
||||
return list.find((item) => item.name == props.data.name) ?? {}
|
||||
})
|
||||
|
||||
const moreEquity = computed(() => {
|
||||
let text = ''
|
||||
if (props.data.equity.pdf) {
|
||||
text += '上传pdf文件、'
|
||||
}
|
||||
if (props.data.equity.online) {
|
||||
text += `在线人数 ${props.data.equity.online}、`
|
||||
}
|
||||
if (props.data.equity.article) {
|
||||
text += `阅读文章数 ${props.data.equity.article}、`
|
||||
}
|
||||
return text.replace(/、+$/, '')
|
||||
})
|
||||
|
||||
const options = computed(() => {
|
||||
const arr = props.data.attrs.map((item, i) => {
|
||||
return {
|
||||
...item,
|
||||
text: item.name,
|
||||
value: i,
|
||||
}
|
||||
})
|
||||
if (value.value == '' && arr.length > 0) {
|
||||
value.value = arr[0].value
|
||||
}
|
||||
return arr
|
||||
})
|
||||
|
||||
const currentAttr = computed(() => {
|
||||
return options.value.find((item) => item.value == value.value) ?? {}
|
||||
})
|
||||
|
||||
const handleSubscribe = (e) => {
|
||||
emit(
|
||||
'subscribe',
|
||||
{
|
||||
data: toRaw(props.data),
|
||||
value: value.value,
|
||||
isSerial: e,
|
||||
},
|
||||
e == 1
|
||||
)
|
||||
}
|
||||
|
||||
function formatNumber(num, digits = 0) {
|
||||
if (num < 10000) {
|
||||
return num.toString()
|
||||
} else {
|
||||
return (num / 10000).toFixed(digits) + '万'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.bg {
|
||||
// background: url('@/assets/images/vip_card-01.png');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
::v-deep(.cu-select) {
|
||||
.ant-select-selector {
|
||||
background-color: #a7957e !important;
|
||||
border-color: #a7957e;
|
||||
color: white;
|
||||
}
|
||||
.ant-select-arrow {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.cu-select-popup {
|
||||
&.ant-select-dropdown
|
||||
.ant-select-item-option-active:not(.ant-select-item-option-disabled) {
|
||||
background-color: #847663;
|
||||
}
|
||||
&.ant-select-dropdown
|
||||
.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
|
||||
background-color: #847663;
|
||||
}
|
||||
&.ant-select-dropdown .ant-select-item {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="flex items-center justify-center text-4xl font-bold mt-54px">
|
||||
<img
|
||||
class="w-120px"
|
||||
src="@/assets/images/vip_title-left.png"
|
||||
alt=""
|
||||
srcset=""
|
||||
/>
|
||||
<div class="text-40px font-bold text-white px-10px">会员收费标准</div>
|
||||
<img
|
||||
class="w-120px"
|
||||
src="@/assets/images/vip_title-right.png"
|
||||
alt=""
|
||||
srcset=""
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-center mt-60px">
|
||||
<div class="flex items-center justify-center border border-white">
|
||||
<div
|
||||
class="h-62px leading-60px w-200px text-white text-28px text-center -m-2px"
|
||||
v-for="(item, i) in vipType"
|
||||
@click="active = item.id"
|
||||
:class="{ 'bg-[#3662FE]': active == item.id }"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-51px mt-60px">
|
||||
<Item
|
||||
class="mb-70px"
|
||||
v-for="item in currentVipList"
|
||||
:key="item.id"
|
||||
:data="item"
|
||||
@subscribe="handleSubscribe"
|
||||
></Item>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// import { QRCode } from 'ant-design-vue'
|
||||
import { ref, onMounted, computed, toRaw } from 'vue'
|
||||
import http from '@/io/request'
|
||||
import Item from './components/item.vue'
|
||||
// import { message } from 'ant-design-vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
|
||||
// const AQrcode = QRCode
|
||||
|
||||
const active = ref(null)
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const open = ref(false)
|
||||
|
||||
const vipType = ref([])
|
||||
|
||||
const vipList = ref([])
|
||||
|
||||
const vipValue = ref(null)
|
||||
|
||||
const orderInfo = ref(null)
|
||||
|
||||
const currentVipType = computed(() => {
|
||||
return vipType.value.find((item) => item.id == active.value) ?? {}
|
||||
})
|
||||
|
||||
const orderQrcodeUrl = computed(() => {
|
||||
return orderInfo.value?.qr_code ?? ''
|
||||
})
|
||||
|
||||
const currentVipList = computed(() => {
|
||||
return vipList.value.filter((item) => item.type_id == active.value)
|
||||
})
|
||||
const currentVipText = computed(() => {
|
||||
if (!vipValue.value) return ''
|
||||
const { value, data, isSerial } = toRaw(vipValue.value) ?? {}
|
||||
const { attrs, name } = data ?? {}
|
||||
const str = isSerial ? '连续订阅' : `${attrs[value].time}`
|
||||
return `${name}${str}`
|
||||
})
|
||||
|
||||
const getVipType = () => {
|
||||
http
|
||||
.get('/api/keywords', {
|
||||
params: {
|
||||
type_key: 'product_type',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
vipType.value = res
|
||||
if (active.value == null && vipType.value.length > 0) {
|
||||
active.value = vipType.value[0].id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getVipList = () => {
|
||||
http.get('/api/product').then((res) => {
|
||||
vipList.value = res
|
||||
})
|
||||
}
|
||||
|
||||
const handleSubscribe = (e) => {
|
||||
vipValue.value = e
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
|
||||
const { data, value } = e
|
||||
const params = {
|
||||
product_id: data.id,
|
||||
attr: value,
|
||||
pay: true,
|
||||
}
|
||||
http
|
||||
.post('/api/order', {
|
||||
...params,
|
||||
})
|
||||
.then((res) => {
|
||||
open.value = true
|
||||
loading.value = false
|
||||
orderInfo.value = res
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const handleConfirmOrder = () => {
|
||||
if (loading.value) return
|
||||
open.value = false
|
||||
router.push({
|
||||
path: '/ucenter/order',
|
||||
})
|
||||
}
|
||||
|
||||
const handleCancelOrder = () => {
|
||||
if (loading.value) return
|
||||
open.value = false
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getVipList()
|
||||
getVipType()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
Loading…
Reference in New Issue