소스 검색

客户端我的产品修改

“陈博论” 7 달 전
부모
커밋
44e6f82514
2개의 변경된 파일과 194개의 추가작업 그리고 84개의 파일을 삭제
  1. 3 2
      web/src/api/frontend/me.ts
  2. 191 82
      web/src/views/frontend/components/Me/purchaseProduct.vue

+ 3 - 2
web/src/api/frontend/me.ts

@@ -26,11 +26,12 @@ export function orderDetail(data: anyObj) {
   })
 }
 
-//产品列表
-export function purchasedList() {
+//产品列表(支持分页与查询)
+export function purchasedList(data?: anyObj) {
   return createAxios({
     url: '/api/invitation.product/purchasedList',
     method: 'get',
+    params: data,
   })
 }
 

+ 191 - 82
web/src/views/frontend/components/Me/purchaseProduct.vue

@@ -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;