index.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <template>
  2. <div class="page-container">
  3. <PageTitle title="专属采购方案" />
  4. <!-- Tab切换 -->
  5. <StatusTabs v-model="activeTab" :tabs="tabs" type="pill" />
  6. <!-- 方案列表 -->
  7. <div v-loading="loading" class="plan-grid">
  8. <div v-for="(item, index) in planList" :key="index" class="plan-card">
  9. <div class="plan-image" @click="onPath(`/plan_info?id=${item.id}`)">
  10. <el-image :src="item.image" fit="cover">
  11. <template #error
  12. ><div class="image-placeholder">
  13. <el-icon :size="40"><Picture /></el-icon></div
  14. ></template>
  15. </el-image>
  16. </div>
  17. <div class="plan-info">
  18. <div class="plan-name">{{ item.name }}</div>
  19. <div class="plan-desc">{{ item.description }}</div>
  20. <div class="plan-link" @click="onPath(`/plan_info?id=${item.id}`)">
  21. 了解详情 <el-icon><ArrowRight /></el-icon>
  22. </div>
  23. </div>
  24. </div>
  25. </div>
  26. <el-empty v-if="planList.length === 0" description="暂无采购方案" />
  27. <!-- 分页 -->
  28. <TablePagination
  29. v-if="planList.length > 0"
  30. v-model:page="queryParams.pageNum"
  31. v-model:page-size="queryParams.pageSize"
  32. :total="total"
  33. @change="handleQuery"
  34. />
  35. </div>
  36. </template>
  37. <script setup lang="ts">
  38. import { ref, reactive, watch } from 'vue';
  39. import { Picture, ArrowRight } from '@element-plus/icons-vue';
  40. import { ElMessage } from 'element-plus';
  41. import { PageTitle, StatusTabs, TablePagination } from '@/components';
  42. import { getProcurementProgramProductList } from '@/api/goods/index';
  43. import { onPath } from '@/utils/siteConfig';
  44. // 采购方案类型映射
  45. const typeMap: Record<string, string> = {
  46. purchase: '1', // 采购方案
  47. exclusive: '2' // 专属采购方案
  48. // collection: '3' // 收藏的采购方案
  49. };
  50. const activeTab = ref('purchase');
  51. const tabs = [
  52. { key: 'purchase', label: '采购方案' },
  53. { key: 'exclusive', label: '专属采购方案' }
  54. // { key: 'collection', label: '收藏的采购方案' }
  55. ];
  56. const queryParams = reactive({ pageNum: 1, pageSize: 10 });
  57. const total = ref(0);
  58. const planList = ref<any[]>([]);
  59. const loading = ref(false);
  60. // 加载数据
  61. const loadData = async () => {
  62. loading.value = true;
  63. try {
  64. const params = {
  65. pageNum: queryParams.pageNum,
  66. pageSize: queryParams.pageSize,
  67. type: typeMap[activeTab.value]
  68. };
  69. const res = await getProcurementProgramProductList(params);
  70. // 根据实际接口返回结构调整
  71. const data = res.data || res;
  72. if (data && data.rows) {
  73. planList.value = data.rows.map((item: any) => ({
  74. id: item.id,
  75. name: item.tweetsTitle,
  76. description: item.programDescribe || item.subtitle,
  77. image: item.coverImage,
  78. // 保留原始数据以便详情页使用
  79. rawData: item
  80. }));
  81. total.value = data.total || 0;
  82. } else if (Array.isArray(data)) {
  83. planList.value = data.map((item: any) => ({
  84. id: item.id,
  85. name: item.tweetsTitle,
  86. description: item.programDescribe || item.subtitle,
  87. image: item.coverImage,
  88. rawData: item
  89. }));
  90. total.value = data.length;
  91. } else {
  92. planList.value = [];
  93. total.value = 0;
  94. }
  95. } catch (error) {
  96. ElMessage.error('获取采购方案列表失败');
  97. planList.value = [];
  98. total.value = 0;
  99. } finally {
  100. loading.value = false;
  101. }
  102. };
  103. watch(
  104. activeTab,
  105. () => {
  106. queryParams.pageNum = 1;
  107. loadData();
  108. },
  109. { immediate: true }
  110. );
  111. const handleQuery = () => {
  112. loadData();
  113. };
  114. const handleDetail = (item: any) => {
  115. // 可以跳转到详情页或打开弹窗
  116. ElMessage.info('查看方案详情:' + item.name);
  117. };
  118. </script>
  119. <style scoped lang="scss">
  120. .plan-grid {
  121. display: grid;
  122. grid-template-columns: repeat(3, 1fr);
  123. gap: 20px;
  124. }
  125. .plan-card {
  126. border-radius: 8px;
  127. overflow: hidden;
  128. background: #fff;
  129. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  130. .plan-image {
  131. height: 180px;
  132. background: #f5f5f5;
  133. .el-image {
  134. width: 100%;
  135. height: 100%;
  136. }
  137. .image-placeholder {
  138. width: 100%;
  139. height: 100%;
  140. display: flex;
  141. align-items: center;
  142. justify-content: center;
  143. background: linear-gradient(135deg, #ffe4c4 0%, #ffd4a3 100%);
  144. color: #e60012;
  145. }
  146. }
  147. .plan-info {
  148. padding: 15px;
  149. .plan-name {
  150. font-size: 15px;
  151. font-weight: 500;
  152. color: #333;
  153. margin-bottom: 8px;
  154. overflow: hidden;
  155. text-overflow: ellipsis;
  156. white-space: nowrap;
  157. }
  158. .plan-desc {
  159. font-size: 13px;
  160. color: #999;
  161. margin-bottom: 10px;
  162. overflow: hidden;
  163. text-overflow: ellipsis;
  164. white-space: nowrap;
  165. }
  166. .plan-link {
  167. display: flex;
  168. align-items: center;
  169. gap: 5px;
  170. font-size: 13px;
  171. color: #e60012;
  172. cursor: pointer;
  173. &:hover {
  174. text-decoration: underline;
  175. }
  176. }
  177. }
  178. }
  179. </style>