App Marketplace
Expand Liferay's portfolio through apps from our partner and developer ecosystems to enhance your digital transformation.
未找到分面。
处理模板时发生错误。
Java method "com.liferay.commerce.context.BaseCommerceContextHttp.getAccountEntry()" threw an exception when invoked on com.liferay.commerce.context.BaseCommerceContextHttp object "com.liferay.commerce.context.BaseCommerceContextHttp@d835f7f"; see cause exception in the Java stack trace. ---- FTL stack trace ("~" means nesting-related): - Failed at: accountEntryId = commerceContext.getA... [in template "3192443#3192485#28231827" at line 118, column 49] ----
1<style type="text/css">
2 .adt-apps-search-results .app-search-results-card:hover {
3 color: var(--black);
4 }
5
6 .lfr-layout-structure-item-com-liferay-site-navigation-breadcrumb-web-portlet-sitenavigationbreadcrumbportlet {
7 background: #ffffff;
8 border-radius: 10px;
9 height: 40px;
10 padding: 0px 16px;
11 }
12
13 .adt-apps-search-results .card-image-title-container .image-container {
14 height: 3rem;
15 }
16
17 .adt-apps-search-results .card-image-title-container .title-container {
18 word-break: break-word;
19 word-wrap: break-word;
20 }
21
22 .adt-apps-search-results .cards-container .app-search-results-card .card-image-title-container .image-container .app-search-image {
23 height: 48px;
24 object-fit: contain;
25 width: 48px;
26 }
27
28 .adt-apps-search-results .labels .category-label-remainder:hover .category-names {
29 display: block;
30 }
31
32 .app-search-results-card {
33 border-radius: 10px;
34 border: 1px solid #E7EFFF;
35 display: flex;
36 height: 289px;
37 padding: 16px;
38 }
39
40 .banner__product-tag {
41 background-color: #e6ebf5;
42 color: #1c3667;
43 font-size: 0.8125rem;
44 white-space: nowrap;
45 width: fit-content;
46 }
47
48 .cards-container {
49 display: grid;
50 grid-column-gap: 1rem;
51 grid-row-gap: 1.5rem;
52 grid-template-columns: repeat(3, minmax(0, 1fr));
53 }
54
55 .card-image-title-container {
56 height: 48px;
57 margin-bottom: 18px;
58 }
59
60 .developer-name {
61 color: #54555F;
62 font-size: 13px;
63 font-weight: 400;
64 line-height: 16px;
65 }
66
67 .title-container {
68 font-size: 18px;
69 font-weight: 600;
70 line-height: 20px;
71 }
72
73 @media screen and (max-width: 599px) {
74 .adt-apps-search-results .cards-container {
75 grid-column-gap: .5rem;
76 grid-row-gap: .5rem;
77 grid-template-columns: 293px;
78 justify-content: center;
79 }
80
81 .adt-apps-search-results .app-search-results-card {
82 height: 281px;
83 }
84 }
85
86 @media screen and (min-width:600px) and (max-width: 899px) {
87 .adt-apps-search-results .cards-container {
88 grid-column-gap: .5rem;
89 grid-row-gap: 1.5rem;
90 grid-template-columns: repeat(2, minmax(0, 1fr));
91 }
92 }
93</style>
94
95<#if searchContainer?has_content>
96 <div class="color-neutral-3 d-md-block d-none pb-4 pt-2">
97 <strong class="color-black">
98 ${searchContainer.getTotal()}
99 </strong>
100 Applications Available
101 </div>
102</#if>
103
104<#if themeDisplay?has_content>
105 <#assign scopeGroupId = themeDisplay.getScopeGroupId() />
106</#if>
107
108<#assign
109 commerceContext = renderRequest.getAttribute("COMMERCE_CONTEXT")
110/>
111
112<div class="adt-apps-search-results">
113 <div class="cards-container pb-6">
114 <#if entries?has_content>
115 <#list entries as entry>
116 <#if entry?has_content>
117 <#assign
118 accountEntryId = commerceContext.getAccountEntry().getAccountEntryId()
119 channelId = commerceContext.getCommerceChannelId()
120 friendlyURL = cpContentHelper.getFriendlyURL(entry, themeDisplay)
121 portalURL = portalUtil.getLayoutURL(themeDisplay)
122 productId = entry.getCProductId()
123 product = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/"+ channelId +"/products/"+ productId +"?accountId=-1&images.accountId=-1&nestedFields=productSpecifications,categories,images")
124 productImage = cpContentHelper.getDefaultImageFileURL(accountEntryId, entry.getCPDefinitionId())
125 productName = entry.getName()
126 remainingCategoriesText = []
127 />
128 <#if product.categories?has_content && product.productSpecifications?has_content>
129 <#assign
130 productCategories = product.categories?filter(productCategory -> productCategory.vocabulary?replace(" ", "-") == "marketplace-app-category")![]
131 categoriesListSize = productCategories?size-1
132 productSpecifications = product.productSpecifications![]
133 />
134 </#if>
135
136 <#if product.description?has_content>
137 <#assign productDescription = stringUtil.shorten(htmlUtil.stripHtml(product.description!""), 150, "...") />
138 <#else>
139 <#assign productDescription = "" />
140 </#if>
141
142 <a class="app-search-results-card bg-white border-radius-medium d-flex flex-column mb-0 text-dark text-decoration-none" href=${friendlyURL}>
143 <div class="align-items-center card-image-title-container d-flex">
144 <div class="image-container mr-2 rounded">
145 <img alt="${productName}" class="app-search-image" src="${productImage}" />
146 </div>
147
148 <div>
149 <div class="title-container">
150 ${productName}
151 </div>
152
153 <#if productSpecifications?has_content>
154 <#assign productDeveloperName = productSpecifications?filter(item -> item.specificationKey == "developer-name") />
155 <#list productDeveloperName as developerNameItem>
156 <#if developerNameItem.value?has_content>
157 <#assign developerName = developerNameItem.value />
158 <#else>
159 <#assign developerName = "" />
160 </#if>
161
162 <div class="developer-name mt-1">
163 ${developerName}
164 </div>
165 </#list>
166 </#if>
167 </div>
168 </div>
169
170 <div class="d-flex flex-column font-size-paragraph-small h-100 justify-content-between">
171 <div class="font-weight-normal mb-2 text-break">
172 ${productDescription}
173 </div>
174
175 <div class="d-flex flex-column">
176 <#if productSpecifications?has_content>
177 <#assign productPriceModels = productSpecifications?filter(item -> item.specificationKey == "price-model") />
178 <#list productPriceModels as productPriceModel>
179 <#if productPriceModel.value?has_content>
180 <#assign priceModel = productPriceModel.value />
181 <#else>
182 <#assign priceModel = "" />
183 </#if>
184
185 <div class="font-weight-semi-bold mb-2 mt-1 text-capitalize">
186 ${priceModel}
187 </div>
188 </#list>
189 </#if>
190
191 <#if productCategories?has_content>
192 <#assign
193 principalCategory = productCategories[0]
194 remainingCategories = productCategories?filter(category -> category.name != principalCategory.name)
195 />
196
197 <#list remainingCategories as category>
198 <#assign remainingCategoriesText = remainingCategoriesText + [category.name] />
199 </#list>
200 </#if>
201
202 <#if principalCategory?has_content>
203 <div>
204 <span class="banner__product-tag rounded py-1 px-2 mr-2" title="${principalCategory.name}">
205 ${principalCategory.name}
206 </span>
207 <#if categoriesListSize?has_content && remainingCategoriesText?has_content>
208 <span class="banner__product-tag rounded py-1 px-2" title="${remainingCategoriesText?join('\n')}">
209 + ${categoriesListSize}
210 </span>
211 </#if>
212 </div>
213 </#if>
214 </div>
215 </div>
216 </a>
217 </#if>
218 </#list>
219 </#if>
220 </div>
221</div>