|
|
@@ -2,109 +2,158 @@
|
|
|
<div class="me-purchase-product">
|
|
|
<div class="product-header">
|
|
|
<h2 class="product-title">我的产品({{ productsNum }})</h2>
|
|
|
+ <div class="product-filters">
|
|
|
+ <el-input
|
|
|
+ v-model="queryParams.product_name"
|
|
|
+ placeholder="请输入产品名称"
|
|
|
+ clearable
|
|
|
+ class="filter-item"
|
|
|
+ @clear="handleSearch"
|
|
|
+ @keyup.enter.native="handleSearch"
|
|
|
+ ></el-input>
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.status"
|
|
|
+ placeholder="状态"
|
|
|
+ clearable
|
|
|
+ class="filter-item"
|
|
|
+ @change="handleSearch"
|
|
|
+ >
|
|
|
+ <el-option label="有效" :value="1" />
|
|
|
+ <el-option label="已过期" :value="2" />
|
|
|
+ <el-option label="已用完" :value="3" />
|
|
|
+ </el-select>
|
|
|
+ <el-button type="primary" @click="handleSearch">搜索</el-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+
|
|
|
<div class="product-content">
|
|
|
- <el-empty v-if="products.length == 0" description="暂无产品">
|
|
|
+ <el-empty v-if="products.length === 0" description="暂无产品">
|
|
|
<el-button type="primary" @click="gotoBuy">去购买</el-button>
|
|
|
</el-empty>
|
|
|
- <div v-else class="product-grid">
|
|
|
- <div v-for="item in products" :key="item.usage_id" class="product-card" :class="{ 'expired': item.status != 1 }"
|
|
|
- @click="handleProductClick(item)">
|
|
|
- <!-- 状态标签 -->
|
|
|
- <div class="status-badge" :class="getStatusClass(item.status)">
|
|
|
- {{ getStatusText(item.status) }}
|
|
|
- </div>
|
|
|
|
|
|
- <!-- 产品图片 -->
|
|
|
- <div class="product-image-wrapper">
|
|
|
- <img :src="item.image" :alt="item.product_name">
|
|
|
- <div class="product-type-badge" :class="item.product_type === 1 ? 'web' : 'software'">
|
|
|
- <el-icon v-if="item.product_type == 1">
|
|
|
- <Link />
|
|
|
- </el-icon>
|
|
|
- <el-icon v-else>
|
|
|
- <Monitor />
|
|
|
- </el-icon>
|
|
|
- <span>{{ item.product_type == 1 ? '网页' : '软件' }}</span>
|
|
|
+ <div v-else>
|
|
|
+ <div class="product-grid">
|
|
|
+ <div
|
|
|
+ v-for="item in products"
|
|
|
+ :key="item.usage_id"
|
|
|
+ class="product-card"
|
|
|
+ :class="{ expired: item.status !== 1 }"
|
|
|
+ @click="handleProductClick(item)"
|
|
|
+ >
|
|
|
+ <!-- 状态标签 -->
|
|
|
+ <div class="status-badge" :class="getStatusClass(item.status)">
|
|
|
+ {{ getStatusText(item.status) }}
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <!-- 产品信息 -->
|
|
|
- <div class="product-info">
|
|
|
- <div class="product-main">
|
|
|
- <!-- 左侧:产品基本信息 -->
|
|
|
- <div class="product-main-left">
|
|
|
- <div class="product-name" :title="item.product_name">{{ item.product_name }}</div>
|
|
|
-
|
|
|
- <!-- 套餐信息 -->
|
|
|
- <div class="package-info">
|
|
|
- <el-tag size="small" type="primary" effect="plain">{{ item.package_type_text }}</el-tag>
|
|
|
- <el-tag size="small" type="warning" effect="plain">{{ item.card_type_text }}</el-tag>
|
|
|
- </div>
|
|
|
+ <!-- 产品图片 -->
|
|
|
+ <div class="product-image-wrapper">
|
|
|
+ <img :src="item.image" :alt="item.product_name" />
|
|
|
+ <div class="product-type-badge" :class="item.product_type === 1 ? 'web' : 'software'">
|
|
|
+ <el-icon v-if="item.product_type == 1">
|
|
|
+ <Link />
|
|
|
+ </el-icon>
|
|
|
+ <el-icon v-else>
|
|
|
+ <Monitor />
|
|
|
+ </el-icon>
|
|
|
+ <span>{{ item.product_type == 1 ? '网页' : '软件' }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <!-- 使用情况 -->
|
|
|
- <div class="usage-info">
|
|
|
- <!-- 次卡显示剩余次数 -->
|
|
|
- <div v-if="item.card_type == 1" class="usage-item">
|
|
|
- <el-icon>
|
|
|
- <Tickets />
|
|
|
- </el-icon>
|
|
|
- <span>剩余次数: <strong>{{ item.remaining_times }}</strong></span>
|
|
|
+ <!-- 产品信息 -->
|
|
|
+ <div class="product-info">
|
|
|
+ <div class="product-main">
|
|
|
+ <!-- 左侧:产品基本信息 -->
|
|
|
+ <div class="product-main-left">
|
|
|
+ <div class="product-name" :title="item.product_name">
|
|
|
+ {{ item.product_name }}
|
|
|
</div>
|
|
|
|
|
|
- <!-- 积分卡显示剩余积分 -->
|
|
|
- <div v-if="item.card_type == 2" class="usage-item">
|
|
|
- <el-icon>
|
|
|
- <Coin />
|
|
|
- </el-icon>
|
|
|
- <span>剩余积分: <strong>{{ item.remaining_points }}</strong></span>
|
|
|
+ <!-- 套餐信息 -->
|
|
|
+ <div class="package-info">
|
|
|
+ <el-tag size="small" type="primary" effect="plain">
|
|
|
+ {{ item.package_type_text }}
|
|
|
+ </el-tag>
|
|
|
+ <el-tag size="small" type="warning" effect="plain">
|
|
|
+ {{ item.card_type_text }}
|
|
|
+ </el-tag>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 日期卡显示到期时间 -->
|
|
|
- <div v-if="[3, 4, 5, 6, 7].includes(item.card_type)" class="usage-item">
|
|
|
- <el-icon>
|
|
|
- <Calendar />
|
|
|
- </el-icon>
|
|
|
- <span>{{ item.display_info }}</span>
|
|
|
+ <!-- 使用情况 -->
|
|
|
+ <div class="usage-info">
|
|
|
+ <!-- 次卡显示剩余次数 -->
|
|
|
+ <div v-if="item.card_type == 1" class="usage-item">
|
|
|
+ <el-icon>
|
|
|
+ <Tickets />
|
|
|
+ </el-icon>
|
|
|
+ <span>剩余次数: <strong>{{ item.remaining_times }}</strong></span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 积分卡显示剩余积分 -->
|
|
|
+ <div v-if="item.card_type == 2" class="usage-item">
|
|
|
+ <el-icon>
|
|
|
+ <Coin />
|
|
|
+ </el-icon>
|
|
|
+ <span>剩余积分: <strong>{{ item.remaining_points }}</strong></span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 日期卡显示到期时间 -->
|
|
|
+ <div v-if="[3, 4, 5, 6, 7].includes(item.card_type)" class="usage-item">
|
|
|
+ <el-icon>
|
|
|
+ <Calendar />
|
|
|
+ </el-icon>
|
|
|
+ <span>{{ item.display_info }}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <!-- 右侧:席位信息(企业套餐)- 仅日期卡显示(次卡/积分卡不展示“已分配”相关信息) -->
|
|
|
- <div
|
|
|
- v-if="item.package_type == 2 && item.total_seats && [3, 4, 5, 6, 7].includes(item.card_type)"
|
|
|
- class="product-main-right"
|
|
|
- >
|
|
|
- <div class="seats-info">
|
|
|
- <div class="seats-row">
|
|
|
- <div class="seats-label">席位</div>
|
|
|
- <div class="seats-value">
|
|
|
- <span class="seats-number strong">{{ item.assigned_seats || 0 }}</span>
|
|
|
- <span class="seats-split">/</span>
|
|
|
- <span class="seats-number">{{ item.total_seats }}</span>
|
|
|
+ <!-- 右侧:席位信息(企业套餐)- 仅日期卡显示 -->
|
|
|
+ <div
|
|
|
+ v-if="item.package_type == 2 && item.total_seats && [3, 4, 5, 6, 7].includes(item.card_type)"
|
|
|
+ class="product-main-right"
|
|
|
+ >
|
|
|
+ <div class="seats-info">
|
|
|
+ <div class="seats-row">
|
|
|
+ <div class="seats-label">席位</div>
|
|
|
+ <div class="seats-value">
|
|
|
+ <span class="seats-number strong">{{ item.assigned_seats || 0 }}</span>
|
|
|
+ <span class="seats-split">/</span>
|
|
|
+ <span class="seats-number">{{ item.total_seats }}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <!-- 底部信息 -->
|
|
|
- <div class="product-footer">
|
|
|
- <div class="buy-info">
|
|
|
- <el-icon>
|
|
|
- <ShoppingCart />
|
|
|
- </el-icon>
|
|
|
- <span>{{ formatDate(item.buy_time) }}</span>
|
|
|
- </div>
|
|
|
- <div v-if="item.is_allocated == 1" class="allocated-badge">
|
|
|
- <el-icon>
|
|
|
- <Share />
|
|
|
- </el-icon>
|
|
|
- <span>已分配</span>
|
|
|
+ <!-- 底部信息 -->
|
|
|
+ <div class="product-footer">
|
|
|
+ <div class="buy-info">
|
|
|
+ <el-icon>
|
|
|
+ <ShoppingCart />
|
|
|
+ </el-icon>
|
|
|
+ <span>{{ formatDate(item.buy_time) }}</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="item.is_allocated == 1" class="allocated-badge">
|
|
|
+ <el-icon>
|
|
|
+ <Share />
|
|
|
+ </el-icon>
|
|
|
+ <span>已分配</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ <div class="product-pagination">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="queryParams.page"
|
|
|
+ v-model:page-size="queryParams.pageSize"
|
|
|
+ :page-sizes="[6, 12, 24, 48]"
|
|
|
+ :total="productsNum || 0"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ @size-change="handleSizeChange"
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -169,20 +218,64 @@ const products = ref<ProductItem[]>([])
|
|
|
// 企业信息
|
|
|
const companyInfo = ref<CompanyInfo | null>(null)
|
|
|
// 产品数量
|
|
|
-const productsNum = ref()
|
|
|
+const productsNum = ref<number>(0)
|
|
|
+
|
|
|
+// 查询与分页参数
|
|
|
+const queryParams = ref<{
|
|
|
+ page: number
|
|
|
+ pageSize: number
|
|
|
+ product_name: string
|
|
|
+ status: number | undefined
|
|
|
+}>({
|
|
|
+ page: 1,
|
|
|
+ pageSize: 6,
|
|
|
+ product_name: '',
|
|
|
+ status: undefined
|
|
|
+})
|
|
|
|
|
|
// 获取列表
|
|
|
const getList = async () => {
|
|
|
try {
|
|
|
- const res = await purchasedList()
|
|
|
+ const params: any = {
|
|
|
+ page: queryParams.value.page,
|
|
|
+ pageSize: queryParams.value.pageSize
|
|
|
+ }
|
|
|
+
|
|
|
+ if (queryParams.value.product_name) {
|
|
|
+ params.product_name = queryParams.value.product_name
|
|
|
+ }
|
|
|
+ if (queryParams.value.status) {
|
|
|
+ params.status = queryParams.value.status
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await purchasedList(params)
|
|
|
products.value = res.data.products || []
|
|
|
companyInfo.value = res.data.company_info || null
|
|
|
- productsNum.value = res.data.total
|
|
|
+ productsNum.value = res.data.total || 0
|
|
|
} catch (error) {
|
|
|
ElMessage.error('获取产品列表失败')
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 搜索
|
|
|
+const handleSearch = () => {
|
|
|
+ queryParams.value.page = 1
|
|
|
+ getList()
|
|
|
+}
|
|
|
+
|
|
|
+// 分页大小变更
|
|
|
+const handleSizeChange = (size: number) => {
|
|
|
+ queryParams.value.pageSize = size
|
|
|
+ queryParams.value.page = 1
|
|
|
+ getList()
|
|
|
+}
|
|
|
+
|
|
|
+// 当前页变更
|
|
|
+const handleCurrentChange = (page: number) => {
|
|
|
+ queryParams.value.page = page
|
|
|
+ getList()
|
|
|
+}
|
|
|
+
|
|
|
// 跳转购买
|
|
|
const gotoBuy = () => {
|
|
|
router.push('/')
|
|
|
@@ -283,6 +376,16 @@ onMounted(() => {
|
|
|
color: #303133;
|
|
|
}
|
|
|
|
|
|
+ .product-filters {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+
|
|
|
+ .filter-item {
|
|
|
+ width: 200px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
.company-info {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
@@ -308,6 +411,12 @@ onMounted(() => {
|
|
|
gap: 24px;
|
|
|
}
|
|
|
|
|
|
+ .product-pagination {
|
|
|
+ margin-top: 24px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ }
|
|
|
+
|
|
|
.product-card {
|
|
|
position: relative;
|
|
|
cursor: pointer;
|