Files
qiming/qiming-mobile/subpackages/pages/my-subscriptions/components/subscribed-content/subscribed-agents/subscribed-agents.uvue

315 lines
7.8 KiB
Plaintext

<template>
<view class="subscribed-agents">
<view v-if="loading" class="loading-state">
<text class="loading-text">...</text>
</view>
<view v-else-if="list.length === 0" class="empty-wrapper">
<empty-state text="Mobile.MySubscriptions.empty" />
</view>
<view v-else class="agent-list">
<view v-for="item in list" :key="item.id" class="agent-card">
<!-- 头部 -->
<view class="agent-header">
<view
class="agent-icon"
:style="{ backgroundColor: item.icon ? 'transparent' : '#1e6deb' }"
>
<image
v-if="item.icon"
:src="item.icon"
class="agent-icon-img"
mode="aspectFill"
/>
<text v-else class="iconfont icon-Grid"></text>
</view>
<view class="agent-title-box">
<text class="agent-name">{{ item.bizName }}</text>
<text class="agent-desc" v-if="item.planName">{{
item.planName
}}</text>
</view>
</view>
<!-- 信息网格 -->
<view class="agent-grid">
<view class="grid-item">
<text class="grid-label">{{
t("Mobile.MySubscriptions.subAmount")
}}</text>
<view class="grid-value-row">
<text class="amount-val"
>¥{{ formatNumber(item.plan?.price ?? 0, 2) }}</text
>
<text class="amount-unit">{{ getPeriodUnit(item.period) }}</text>
</view>
</view>
<view class="grid-item" v-if="item.endTime">
<text class="grid-label">{{
t("Mobile.MySubscriptions.expireTime")
}}</text>
<text class="grid-value">{{
formatDate(item.endTime || "", "YYYY-MM-DD")
}}</text>
</view>
</view>
<!-- 底部 -->
<view class="agent-footer">
<view
class="status-text"
:class="isActive(item.status) ? 'status-active' : 'status-expired'"
>
<text class="icon-char">{{
isActive(item.status) ? "✓" : "✗"
}}</text>
<text class="text">{{ getStatusText(item.status) }}</text>
</view>
<view class="renew-btn" @tap="handleRenew(item)">
<text class="btn-text">{{
t("Mobile.MySubscriptions.renewNow")
}}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import type { MySubscriptionItem } from "@/subpackages/types/interfaces/subscription";
import { SUCCESS_CODE } from "@/constants/codes.constants.uts";
import { apiGetMySubscription } from "@/subpackages/servers/subscription";
import { useI18n } from "@/utils/i18n";
import { useSubscriptionPurchase } from "../../../hooks/useSubscriptionPurchase.uts";
import { getPeriodUnit, getStatusText, isActive } from "../../../utils.uts";
import EmptyState from "@/components/empty-state/empty-state.uvue";
import { formatDate, formatNumber } from "@/utils/system";
const { t } = useI18n();
const list = ref<MySubscriptionItem[]>([]);
const loading = ref(true);
const fetchData = async () => {
loading.value = true;
try {
const res = await apiGetMySubscription({ bizType: "AGENT" });
if (res.code === SUCCESS_CODE && res.data) {
list.value = res.data.subscriptions || [];
}
} catch (e) {
// ignore
} finally {
loading.value = false;
}
};
const { handlePaySubscription, processingId } = useSubscriptionPurchase();
const handleRenew = async (item: MySubscriptionItem) => {
await handlePaySubscription(item.planId);
};
onMounted(() => {
fetchData();
});
</script>
<style lang="scss" scoped>
.subscribed-agents {
min-height: 200rpx;
.loading-state {
display: flex;
align-items: center;
justify-content: center;
padding: 80rpx 0;
.loading-text {
font-size: 28rpx;
color: #999;
}
}
.empty-wrapper {
padding: 40rpx 0;
}
.agent-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.agent-card {
display: flex;
flex-direction: column;
background: #fff;
border-radius: 16rpx;
padding: 28rpx 28rpx 0 28rpx;
border: 2rpx solid #e5e6eb;
overflow: hidden;
.agent-header {
display: flex;
flex-direction: row;
align-items: center;
gap: 24rpx;
margin-bottom: 40rpx;
.agent-icon {
width: 96rpx;
height: 96rpx;
border-radius: 20rpx;
background: #1e6deb;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 16rpx rgba(30, 109, 235, 0.15);
overflow: hidden;
.agent-icon-img {
width: 100%;
height: 100%;
border-radius: 20rpx;
}
.iconfont {
font-size: 48rpx;
color: #fff;
}
}
.agent-title-box {
display: flex;
flex-direction: column;
gap: 12rpx;
flex: 1;
overflow: hidden;
.agent-name {
font-size: 32rpx;
font-weight: 600;
color: #1d2129;
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.agent-desc {
font-size: 24rpx;
color: #8c96a0;
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}
}
.agent-grid {
display: flex;
flex-direction: row;
margin-bottom: 28rpx;
.grid-item {
flex: 1;
display: flex;
flex-direction: column;
gap: 12rpx;
.grid-label {
font-size: 24rpx;
color: #8c96a0;
}
.grid-value {
font-size: 28rpx;
font-weight: 600;
color: #1d2129;
}
.grid-value-row {
display: flex;
flex-direction: row;
align-items: baseline;
.amount-val {
font-size: 28rpx;
font-weight: 600;
color: #5147ff;
}
.amount-unit {
font-size: 24rpx;
color: #8c96a0;
margin-left: 4rpx;
}
}
}
}
.agent-footer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin: 0 -28rpx 0 -28rpx;
padding: 24rpx 28rpx;
background: #f8fafc;
border-top: 2rpx solid #e5e6eb;
.status-text {
display: flex;
flex-direction: row;
align-items: center;
gap: 8rpx;
.icon-char {
font-size: 26rpx;
}
.text {
font-size: 26rpx;
font-weight: 500;
}
&.status-active {
color: #00b42a;
}
&.status-expired {
color: #f53f3f;
}
}
.renew-btn {
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
background: #1e6deb;
padding: 0 36rpx;
border-radius: 12rpx;
.btn-text {
font-size: 26rpx;
color: #fff;
font-weight: 600;
}
&:active {
opacity: 0.8;
transform: scale(0.98);
}
}
}
}
}
</style>