discover.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. <template>
  2. <div class="pcPages" :style="warpCss">
  3. <div class="discover-bos" :style="boxCss">
  4. <!-- 头部 -->
  5. <div class="home-title flex-row-between" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
  6. <div>
  7. <span :style="titleCss" class="title1 mr-[10px]">{{ componentData.title }}</span>
  8. <span :style="subtitleCss">{{ componentData.subtitle }}</span>
  9. </div>
  10. <div class="title-more flex-row-start">
  11. <div class="ml-[10px]" v-for="(item, index) in componentData.labelList" :key="index">{{ item.title }}</div>
  12. </div>
  13. </div>
  14. <!-- 中间区域 -->
  15. <div class="discover-box">
  16. <el-image
  17. class="discover-image"
  18. :src="componentData.imageUrl ? componentData.imageUrl : figure"
  19. :fit="componentData.imageUrl ? (componentData.imgType == 1 ? 'fill' : componentData.imgType == 2 ? 'contain' : 'cover') : 'cover'"
  20. :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}"
  21. />
  22. <div class="plan-bos" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
  23. <div class="plan-head">方案推荐</div>
  24. <div v-for="(item, index) in componentData.planList" :key="index" class="plan-list">
  25. <el-image
  26. class="plan-image"
  27. :src="item.imageUrl ? item.imageUrl : figure"
  28. :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
  29. :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
  30. />
  31. <div class="plan-box flex-column-between">
  32. <div class="plan-title ellipsis">{{ item.title }}</div>
  33. <div class="plan-subtitle">{{ item.subtitle }}</div>
  34. </div>
  35. </div>
  36. </div>
  37. <div class="detect-bos" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
  38. <div class="detect-head">发现</div>
  39. <div class="detect-box">
  40. <div class="detect-two">
  41. <div class="detect-list" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
  42. <div class="detect-item">
  43. <div class="detect-title ellipsis">{{ componentData.detectList[0].title }}</div>
  44. <div class="detect-subtitle mt-[6px] h-[32px]">{{ componentData.detectList[0].subtitle }}</div>
  45. <div class="detect-btn" :style="{ backgroundColor: componentData.boxColor }">立即进入</div>
  46. </div>
  47. <el-image
  48. class="detect-image"
  49. :src="componentData.detectList[0].imageUrl ? componentData.detectList[0].imageUrl : figure"
  50. :fit="componentData.detectList[0].imgType == 1 ? 'fill' : componentData.detectList[0].imgType == 2 ? 'contain' : 'cover'"
  51. :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
  52. />
  53. </div>
  54. <div class="detect-list" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
  55. <div class="detect-item">
  56. <div class="detect-title ellipsis">{{ componentData.detectList[1].title }}</div>
  57. <div class="detect-subtitle mt-[6px] h-[32px]">{{ componentData.detectList[1].subtitle }}</div>
  58. <div class="detect-btn" :style="{ backgroundColor: componentData.boxColor }">立即进入</div>
  59. </div>
  60. <el-image
  61. class="detect-image"
  62. :src="componentData.detectList[1].imageUrl ? componentData.detectList[1].imageUrl : figure"
  63. :fit="componentData.detectList[1].imgType == 1 ? 'fill' : componentData.detectList[1].imgType == 2 ? 'contain' : 'cover'"
  64. :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
  65. />
  66. </div>
  67. </div>
  68. <div class="detect-one flex-column-between" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
  69. <div>
  70. <div class="detect-title ellipsis">{{ componentData.detectList[2].title }}</div>
  71. <div class="detect-subtitle mt-[6px]">{{ componentData.detectList[2].subtitle }}</div>
  72. </div>
  73. <el-image
  74. class="detect-img"
  75. :src="componentData.detectList[2].imageUrl ? componentData.detectList[2].imageUrl : figure"
  76. :fit="componentData.detectList[2].imgType == 1 ? 'fill' : componentData.detectList[2].imgType == 2 ? 'contain' : 'cover'"
  77. :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
  78. />
  79. </div>
  80. </div>
  81. </div>
  82. </div>
  83. <!-- 底部 -->
  84. <div class="discover-foot">
  85. <div class="discover-tab" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
  86. <div class="tab-head" :style="{ color: componentData.boxColor }">采购导航</div>
  87. <div class="tab-bos">
  88. <div v-for="(item, index) in componentData.tabList" :key="index" class="tab-list flex-row-center">
  89. {{ item.title }}
  90. </div>
  91. </div>
  92. </div>
  93. <template v-for="(item, index) in dataList" :key="index">
  94. <div
  95. v-if="Number(index) < 4"
  96. class="goods-bos flex-column-between"
  97. :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}"
  98. >
  99. <img
  100. class="goods-img"
  101. :src="item.productImage ? item.productImage : figure"
  102. alt=""
  103. :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
  104. />
  105. <div>
  106. <div class="goods-name">{{ item.itemName || '商品名称' }}</div>
  107. <div class="goods-price" :style="{ color: componentData.boxColor }">¥{{ item.memberPrice || '0.00' }}</div>
  108. </div>
  109. </div>
  110. </template>
  111. </div>
  112. </div>
  113. </div>
  114. </template>
  115. <script setup lang="ts">
  116. import figure from '@/assets/images/figure.png';
  117. import usePcdiyStore from '@/store/modules/pcdiy';
  118. import { listBase } from '@/api/pmsProduct/base';
  119. import { getCustomerProductPage } from '@/api/diy/index';
  120. const diyStore = usePcdiyStore();
  121. const props = defineProps<{
  122. index: number; // 确保声明 index 为可选属性
  123. row?: any;
  124. }>();
  125. const componentData = props.row ? props.row : diyStore.componentList[props.index];
  126. const dataList = ref<any>([{}, {}, {}, {}]);
  127. onMounted(() => {
  128. getDataList();
  129. });
  130. const getDataList = () => {
  131. dataList.value = [{}, {}, {}, {}];
  132. if (componentData.goodsIds.length > 0) {
  133. const apiFunc = diyStore.clientId && diyStore.clientId !== 'undefined' ? getCustomerProductPage : listBase;
  134. const queryParams = {
  135. pageNum: 1,
  136. pageSize: 10,
  137. ids: componentData.goodsIds.join(','),
  138. customerId: ''
  139. };
  140. if (diyStore.clientId && diyStore.clientId != 'undefined') {
  141. queryParams.customerId = diyStore.clientId;
  142. } else {
  143. delete queryParams.customerId;
  144. }
  145. apiFunc(queryParams).then((res) => {
  146. if (res.code == 200) {
  147. dataList.value = res.rows;
  148. }
  149. });
  150. }
  151. };
  152. watch(
  153. () => componentData.goodsIds,
  154. () => {
  155. getDataList();
  156. },
  157. { deep: true } // 5. 数组变化需要 deep 监听
  158. );
  159. const warpCss = computed(() => {
  160. let style = '';
  161. style += 'position:relative;';
  162. //背景颜色
  163. if (componentData.pageStartBgColor) {
  164. if (componentData.pageStartBgColor && componentData.pageEndBgColor)
  165. style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
  166. else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
  167. else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
  168. }
  169. //背景图片
  170. if (componentData.componentBgUrl) {
  171. style += `background-image:url('${componentData.componentBgUrl}');`;
  172. style += 'background-size: cover;background-repeat: no-repeat;';
  173. }
  174. //边距
  175. if (componentData.padding) {
  176. if (componentData.padding.top > 0) {
  177. style += 'padding-top:' + componentData.padding.top + 'px' + ';';
  178. }
  179. if (componentData.padding.bottom > 0) {
  180. style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
  181. }
  182. style += 'padding-right:' + componentData.padding.both + 'px' + ';';
  183. style += 'padding-left:' + componentData.padding.both + 'px' + ';';
  184. }
  185. //圆角
  186. if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
  187. if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
  188. if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
  189. if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
  190. //间距
  191. if (componentData.margin) {
  192. if (componentData.margin.top > 0) {
  193. style += 'margin-top:' + componentData.margin.top + 'px' + ';';
  194. }
  195. if (componentData.margin.bottom > 0) {
  196. style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
  197. }
  198. }
  199. return style;
  200. });
  201. //组件样式
  202. const boxCss = computed(() => {
  203. let style = '';
  204. if (componentData.componentStartBgColor && componentData.componentEndBgColor)
  205. style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
  206. else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
  207. else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
  208. if (componentData.number) style += 'flex:' + `0 0 calc((100% - ${(componentData.number - 1) * 10}px) / ${componentData.number})` + ';';
  209. return style;
  210. });
  211. // 标题样式
  212. const titleCss = computed(() => {
  213. let style = '';
  214. if (componentData.titleColor) style += 'color:' + componentData.titleColor + ';';
  215. if (componentData.titleSize) style += 'font-size:' + componentData.titleSize + 'px;';
  216. if (componentData.titleWeight) style += 'font-weight:' + componentData.titleWeight + ';';
  217. return style;
  218. });
  219. // 副标题样式
  220. const subtitleCss = computed(() => {
  221. let style = '';
  222. if (componentData.subtitleColor) style += 'color:' + componentData.subtitleColor + ';';
  223. if (componentData.subtitleSize) style += 'font-size:' + componentData.subtitleSize + 'px;';
  224. return style;
  225. });
  226. </script>
  227. <style lang="scss" scoped>
  228. .pcPages {
  229. width: 1200px;
  230. margin: 0 auto;
  231. .discover-bos {
  232. width: 100%;
  233. .home-title {
  234. width: 100%;
  235. background-color: #ffffff;
  236. padding: 15px 20px;
  237. .title-more {
  238. font-size: 14px;
  239. color: #333333;
  240. }
  241. }
  242. }
  243. //中间区域
  244. .discover-box {
  245. height: 340px;
  246. width: 100%;
  247. margin-top: 10px;
  248. display: flex;
  249. gap: 10px;
  250. .discover-image {
  251. width: 230px;
  252. height: 340px;
  253. }
  254. // 方案
  255. .plan-bos {
  256. flex: 1;
  257. height: 340px;
  258. background: #ffffff;
  259. padding: 0px 15px;
  260. display: flex;
  261. flex-direction: column;
  262. min-width: 0;
  263. .plan-head {
  264. font-weight: 600;
  265. font-size: 16px;
  266. color: #101828;
  267. height: 50px;
  268. line-height: 50px;
  269. }
  270. .plan-list {
  271. flex: 1;
  272. display: flex;
  273. border-bottom: 1px solid #e5e7eb;
  274. cursor: pointer;
  275. width: 100%;
  276. margin-bottom: 14px;
  277. &:last-child {
  278. border-bottom: none;
  279. margin-bottom: 0;
  280. }
  281. .plan-image {
  282. width: 72px;
  283. height: 72px;
  284. margin-right: 10px;
  285. }
  286. .plan-box {
  287. height: 72px;
  288. flex: 1;
  289. padding: 8px 0px 8px 5px;
  290. width: 0;
  291. .plan-title {
  292. font-weight: 600;
  293. font-size: 14px;
  294. color: #101828;
  295. }
  296. .plan-subtitle {
  297. height: 34px;
  298. font-weight: 400;
  299. font-size: 12px;
  300. color: #364153;
  301. display: -webkit-box;
  302. -webkit-line-clamp: 2;
  303. line-clamp: 2;
  304. /* 添加标准属性 */
  305. -webkit-box-orient: vertical;
  306. overflow: hidden;
  307. text-overflow: ellipsis;
  308. }
  309. }
  310. }
  311. }
  312. .detect-bos {
  313. width: 470px;
  314. height: 340px;
  315. background: #ffffff;
  316. padding: 0px 15px 15px 15px;
  317. .detect-head {
  318. font-weight: 600;
  319. font-size: 16px;
  320. color: #101828;
  321. height: 50px;
  322. line-height: 50px;
  323. }
  324. .detect-box {
  325. display: flex;
  326. gap: 10px;
  327. .detect-title {
  328. font-weight: 600;
  329. font-size: 14px;
  330. color: #101828;
  331. }
  332. .detect-subtitle {
  333. font-weight: 400;
  334. font-size: 12px;
  335. color: #364153;
  336. display: -webkit-box;
  337. -webkit-line-clamp: 2;
  338. line-clamp: 2;
  339. /* 添加标准属性 */
  340. -webkit-box-orient: vertical;
  341. overflow: hidden;
  342. text-overflow: ellipsis;
  343. }
  344. .detect-two {
  345. flex: 1;
  346. width: 0;
  347. .detect-list {
  348. width: 100%;
  349. height: 132.5px;
  350. border: 1px solid #e5e7eb;
  351. margin-top: 10px;
  352. padding: 25px 10px;
  353. display: flex;
  354. gap: 10px;
  355. &:first-child {
  356. margin-top: 0;
  357. }
  358. .detect-item {
  359. flex: 1;
  360. width: 0;
  361. .detect-btn {
  362. width: 68px;
  363. height: 24px;
  364. text-align: center;
  365. line-height: 24px;
  366. font-size: 12px;
  367. color: #ffffff;
  368. margin-top: 12px;
  369. }
  370. }
  371. .detect-image {
  372. height: 72px;
  373. width: 72px;
  374. }
  375. }
  376. }
  377. .detect-one {
  378. width: 180px;
  379. height: 275px;
  380. border: 1px solid #e5e7eb;
  381. background-color: #ffffff;
  382. padding: 25px 10px;
  383. .detect-img {
  384. height: 124px;
  385. width: 124px;
  386. margin: 0 auto;
  387. }
  388. }
  389. }
  390. }
  391. }
  392. //底部
  393. .discover-foot {
  394. display: flex;
  395. gap: 10px;
  396. margin-top: 10px;
  397. .discover-tab {
  398. width: 230px;
  399. height: 310px;
  400. background: #ffffff;
  401. padding: 0 15px 15px 15px;
  402. .tab-head {
  403. font-weight: 600;
  404. font-size: 16px;
  405. height: 50px;
  406. line-height: 50px;
  407. }
  408. .tab-bos {
  409. display: flex;
  410. flex-wrap: wrap;
  411. justify-content: space-between;
  412. gap: 10px 0;
  413. .tab-list {
  414. width: 94px;
  415. height: 32px;
  416. background: #f4f4f4;
  417. font-size: 14px;
  418. color: #101828;
  419. border-radius: 4px 4px 4px 4px;
  420. }
  421. }
  422. }
  423. .goods-bos {
  424. flex: 0 0 calc((100% - 270px) / 4);
  425. width: 0;
  426. background: #ffffff;
  427. height: 310px;
  428. padding: 15px 20px;
  429. .goods-img {
  430. width: 100%;
  431. height: 190px;
  432. }
  433. .goods-name {
  434. width: 100%;
  435. display: -webkit-box;
  436. -webkit-line-clamp: 3;
  437. line-clamp: 3;
  438. /* 添加标准属性 */
  439. -webkit-box-orient: vertical;
  440. overflow: hidden;
  441. text-overflow: ellipsis;
  442. font-size: 14px;
  443. color: #101828;
  444. height: 57px;
  445. }
  446. .goods-price {
  447. font-size: 16px;
  448. margin-top: 5px;
  449. }
  450. }
  451. }
  452. }
  453. </style>