index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. <route lang="json">
  2. { "style": { "navigationStyle": "custom" } }
  3. </route>
  4. <script setup lang="ts">
  5. import Card from '@/components/card.vue'
  6. import SectionHeading from '@/components/section-heading.vue'
  7. import {
  8. getMaterialDetail,
  9. getByDictType,
  10. getMaterialHomePage,
  11. downloadMaterials,
  12. } from '../../../core/libs/requests'
  13. import NavbarEvo from '@/components/navbar-evo.vue'
  14. import { DictType } from '../../../core/libs/models'
  15. import { close, phone } from '../../../core/libs/svgs'
  16. import { handleCall, openLocation, previewImage } from '../../../core/utils/common'
  17. import router from '@designer-hub/assets/src/assets/svgs/router'
  18. import { isVideoUrl } from 'wot-design-uni/components/common/util'
  19. import { useUserStore } from '@/store'
  20. import { AnalysisEventType, useAnalysis } from '@/composables/analysis'
  21. import { usePermissions } from '@/composables/permissions'
  22. const dealerPanelState = ref(false)
  23. const { clickByPermission } = usePermissions()
  24. const userStore = useUserStore()
  25. const { option } = useAnalysis(true, false)
  26. const id = ref()
  27. const downloading = ref(false)
  28. const currentBanner = ref(0)
  29. const handleSwiperChange = ({ detail: { current, source } }) => {
  30. currentBanner.value = current
  31. }
  32. const { data, run: setData } = useRequest(() => getMaterialDetail({ id: id.value }))
  33. const { data: materialHomePageData, run: setMaterialHomePageData } = useRequest(
  34. () => getMaterialHomePage(id.value),
  35. { initialData: {} },
  36. )
  37. const { data: materialBrandLevels, run: setMaterialBrandLevels } = useRequest(
  38. () => getByDictType(DictType.memberMaterialsBrandLevel),
  39. { initialData: [] },
  40. )
  41. const { data: materialOperationTypes, run: setMaterialOperationTypes } = useRequest(
  42. () => getByDictType(DictType.memberMaterialsOperationType),
  43. { initialData: [] },
  44. )
  45. const { data: materialBrandTypes, run: setMaterialBrandTypes } = useRequest(
  46. () => getByDictType(DictType.memberMaterialsBrandType),
  47. { initialData: [] },
  48. )
  49. const { data: materialsManageBrands, run: setMaterialsManageBrands } = useRequest(
  50. () => getByDictType(DictType.materialsManageBrand),
  51. { initialData: [] },
  52. )
  53. const copy = (url) => {
  54. uni.setClipboardData({
  55. data: url,
  56. success: () => {
  57. console.log('已复制')
  58. downloadMaterials({ materialsId: id.value })
  59. },
  60. })
  61. }
  62. const handleDownload = async () => {
  63. downloading.value = true
  64. const { filePath } = await uni.downloadFile({
  65. url: data.value.agreementFileUrl,
  66. filePath: `${uni.env.USER_DATA_PATH}/${data.value.materialsName}的素材包.zip`,
  67. header: {
  68. 'Content-Type': 'application/x-zip-compressed',
  69. },
  70. })
  71. downloading.value = false
  72. await downloadMaterials({ materialsId: id.value })
  73. const { deviceType } = await uni.getDeviceInfo()
  74. if (deviceType === 'pc') {
  75. uni.saveFileToDisk({
  76. filePath,
  77. success: (res) => {
  78. console.log('saveFileToDisk success', res)
  79. },
  80. fail: (err) => {
  81. console.log('saveFileToDisk fail', err)
  82. },
  83. })
  84. } else {
  85. uni.openDocument({
  86. filePath,
  87. success: (res) => {
  88. console.log('openDocument success', res)
  89. },
  90. fail: (err) => {
  91. console.log('openDocument fail', err)
  92. },
  93. })
  94. }
  95. }
  96. onLoad(async (query: { id: number }) => {
  97. id.value = query.id
  98. await setData()
  99. option.value = {
  100. remark: `最近浏览品牌: ${data.value?.materialsName}`,
  101. }
  102. await setMaterialHomePageData()
  103. console.log(data.value)
  104. await Promise.all([
  105. setMaterialBrandLevels(),
  106. setMaterialBrandTypes(),
  107. setMaterialOperationTypes(),
  108. setMaterialsManageBrands(),
  109. ])
  110. })
  111. onShareAppMessage(() => ({
  112. title: data.value?.materialsName,
  113. imageUrl: data.value?.bannerUrl,
  114. }))
  115. onShareTimeline(() => ({
  116. title: data.value?.materialsName,
  117. imageUrl: data.value?.bannerUrl,
  118. }))
  119. </script>
  120. <template>
  121. <view class="flex-grow flex flex-col">
  122. <div
  123. class="w-full aspect-[1.16/1] bg-[url(https://image.zhuchaohui.com/zhucaohui/9da274c73312f5ff828b60457bf4a469e631c001a4bf1c1f355338887b19f035.png)] bg-[length:100%]"
  124. :style="{ backgroundImage: `url(${materialHomePageData?.bannerUrl})` }"
  125. ></div>
  126. <NavbarEvo transparent></NavbarEvo>
  127. <div class="flex flex-col gap-6 relative top--14 px-3.5">
  128. <Card>
  129. <div class="flex flex-col gap-4">
  130. <div class="flex gap-5">
  131. <wd-img
  132. round
  133. width="78"
  134. height="78"
  135. custom-class="border border-[#f2f2f2] border-solid"
  136. :src="data?.logoUrl"
  137. ></wd-img>
  138. <div class="flex flex-col gap-2.5">
  139. <div class="flex gap-2 items-center">
  140. <div class="text-black/90 text-lg font-normal font-['PingFang_SC']">
  141. <!-- IMOLA瓷砖 -->
  142. {{ data?.materialsName }}
  143. </div>
  144. <!-- <div-->
  145. <!-- class="w-[52px] h-[17px] px-2 bg-[#ef4343] rounded-[3px] justify-center items-center gap-2.5 inline-flex"-->
  146. <!-- >-->
  147. <!-- <div-->
  148. <!-- class="text-white text-[10px] font-normal font-['PingFang_SC'] leading-normal"-->
  149. <!-- >-->
  150. <!-- &lt;!&ndash; 自营品牌 &ndash;&gt;-->
  151. <!-- {{-->
  152. <!-- materialBrandLevels.find(({ value }) => value === String(data.materialsType))-->
  153. <!-- ?.label-->
  154. <!-- }}-->
  155. <!-- </div>-->
  156. <!-- </div>-->
  157. </div>
  158. <div class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]">
  159. {{
  160. materialBrandTypes.find(({ value }) => value === String(data?.brandType))?.label
  161. }}
  162. |
  163. {{
  164. materialOperationTypes.find(({ value }) => value === String(data?.manageType))
  165. ?.label
  166. }}
  167. </div>
  168. <div>
  169. <span
  170. class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-[10.18px]"
  171. >
  172. 经营品牌:
  173. </span>
  174. <span
  175. class="text-black/40 text-xs font-normal font-['PingFang_SC'] uppercase leading-[10.18px]"
  176. >
  177. <!-- imola / chedit -->
  178. {{
  179. materialsManageBrands.find(({ value }) => value === String(data?.manageBrand))
  180. ?.label
  181. }}
  182. </span>
  183. </div>
  184. <!-- <div class="flex gap-2.5">-->
  185. <!-- <div-->
  186. <!-- class="w-[77px] h-5 px-2 py-px bg-neutral-100 rounded-[3px] justify-center items-center gap-2.5 inline-flex"-->
  187. <!-- >-->
  188. <!-- <div-->
  189. <!-- class="text-black/60 text-[10px] font-normal font-['PingFang_SC'] leading-normal"-->
  190. <!-- >-->
  191. <!-- 积分比例:{{ data?.pointsExchangeRate }}%-->
  192. <!-- </div>-->
  193. <!-- </div>-->
  194. <!-- <div-->
  195. <!-- class="w-[92px] h-5 px-2 py-px bg-neutral-100 rounded-[3px] justify-center items-center gap-2.5 inline-flex"-->
  196. <!-- >-->
  197. <!-- <div-->
  198. <!-- class="text-black/60 text-[10px] font-normal font-['PingFang_SC'] leading-normal"-->
  199. <!-- >-->
  200. <!-- 门店打卡:{{ data?.clockPoints }}积分-->
  201. <!-- </div>-->
  202. <!-- </div>-->
  203. <!-- </div>-->
  204. </div>
  205. </div>
  206. <template
  207. v-for="({ shopAddr, shopName, shopContactPhone, ...shop }, i) in data?.shopList"
  208. :key="i"
  209. >
  210. <div class="bg-neutral-50 rounded-2.5 p-3.5 flex items-center">
  211. <div class="text-black/40 flex-1 border-r-2 border-r-[#f6f6f6] border-r-solid pr-4">
  212. <div class="text-black/90 text-lg font-normal font-['PingFang_SC'] leading-normal">
  213. {{ shopName }}
  214. </div>
  215. <div>
  216. <wd-icon name="location" size="15"></wd-icon>
  217. <span
  218. class="text-black/40 text-xs font-normal font-['PingFang_SC'] leading-normal"
  219. >
  220. {{ shopAddr }}
  221. </span>
  222. </div>
  223. </div>
  224. <wd-button
  225. type="text"
  226. size="small"
  227. custom-class=" bg-[#f2f2f2]! p-0! ml-4"
  228. @click="handleCall(shopContactPhone)"
  229. >
  230. <wd-img width="28" height="28" :src="phone"></wd-img>
  231. </wd-button>
  232. <wd-button
  233. type="text"
  234. size="small"
  235. custom-class=" bg-[#f2f2f2]! p-0! ml-4"
  236. @click="
  237. openLocation({
  238. latitude: shop.longitude,
  239. longitude: shop.latitude,
  240. name: shopName,
  241. address: shopAddr,
  242. })
  243. "
  244. >
  245. <wd-img width="28" height="28" :src="router"></wd-img>
  246. </wd-button>
  247. </div>
  248. </template>
  249. </div>
  250. </Card>
  251. <Card>
  252. <div class="flex flex-col gap-4">
  253. <div
  254. class="text-black/90 text-lg font-normal font-['PingFang_SC'] leading-[10.18px] pt-4"
  255. >
  256. 品牌介绍
  257. </div>
  258. <div
  259. v-if="(materialHomePageData.brandAdvantageUrl ?? '') !== ''"
  260. class="rounded-2xl overflow-hidden aspect-[1.72/1] whitespace-pre-wrap"
  261. >
  262. <!-- <wd-img
  263. width="100%"
  264. height="100%"
  265. :src="materialHomePageData.brandAdvantageUrl"
  266. mode="aspectFill"
  267. custom-class=""
  268. ></wd-img> -->
  269. <template v-if="isVideoUrl(materialHomePageData.brandAdvantageUrl)">
  270. <video class="w-full h-full" :src="materialHomePageData.brandAdvantageUrl"></video>
  271. </template>
  272. <template v-else>
  273. <wd-img
  274. width="100%"
  275. height="100%"
  276. :src="materialHomePageData.brandAdvantageUrl"
  277. mode="aspectFill"
  278. custom-class=""
  279. ></wd-img>
  280. </template>
  281. </div>
  282. <!-- <div class="text-black/90 text-base font-normal font-['PingFang_SC'] leading-[10.18px]">-->
  283. <!-- {{-->
  284. <!-- materialsManageBrands.find(({ value }) => value === String(data?.manageBrand))?.label-->
  285. <!-- }}-->
  286. <!-- </div>-->
  287. <div
  288. class="text-justify text-black/60 text-sm font-normal font-['PingFang_SC'] leading-[25px] whitespace-pre-wrap"
  289. >
  290. {{ materialHomePageData.brandAdvantageDesc }}
  291. </div>
  292. </div>
  293. </Card>
  294. <template v-if="materialHomePageData.productDOList?.length">
  295. <SectionHeading title="产品展示"></SectionHeading>
  296. </template>
  297. <template v-for="(it, index) in materialHomePageData.productDOList" :key="index">
  298. <div class="aspect-[1.66/1] rounded-2xl overflow-hidden relative">
  299. <swiper class="h-[55.7vw]" @change="handleSwiperChange">
  300. <template v-for="(img, index) in it?.productImgUrl?.split(',')" :key="img">
  301. <swiper-item class="h-full">
  302. <wd-img
  303. width="100%"
  304. height="100%"
  305. class=""
  306. :src="img"
  307. mode="aspectFill"
  308. @click="previewImage(index, it?.productImgUrl?.split(','))"
  309. />
  310. </swiper-item>
  311. </template>
  312. </swiper>
  313. <div
  314. class="absolute bottom-0 w-full h-[66px] bg-gradient-to-t from-black to-[#5e5e5e00] rounded-bl-2xl rounded-br-2xl flex items-center px-4.5"
  315. >
  316. <div class="text-white text-base font-normal font-['PingFang_SC'] leading-[10.18px]">
  317. {{ it.productTitleName }}
  318. </div>
  319. </div>
  320. <div class="absolute flex gap-1 dots">
  321. <template v-for="(img, i) in it?.productImgUrl?.split(',')" :key="i">
  322. <div
  323. class="w-1 h-1 rounded-full"
  324. :class="`${currentBanner === i ? 'bg-white bg-active' : 'bg-white/40'}`"
  325. ></div>
  326. </template>
  327. </div>
  328. </div>
  329. </template>
  330. <!-- <wd-button
  331. custom-class="w-full! rounded-lg!"
  332. :disabled="(data?.agreementFileUrl ?? '') === ''"
  333. :loading="downloading"
  334. @click="clickByPermission('download', () => handleDownload())"
  335. >
  336. {{ downloading ? '下载中...' : '下载所有素材包' }}
  337. </wd-button> -->
  338. <wd-button
  339. custom-class="w-full! rounded-lg!"
  340. :disabled="(data?.agreementFileUrl ?? '') === ''"
  341. @click="clickByPermission('download', () => (dealerPanelState = true))"
  342. >
  343. 下载所有素材包
  344. </wd-button>
  345. </div>
  346. <wd-overlay :show="dealerPanelState" @click="dealerPanelState = false">
  347. <view class="wrapper flex flex-col justify-end h-full">
  348. <div class="w-full flex justify-end mb-4">
  349. <div class="mr-3.5">
  350. <wd-button type="text" custom-class="w-8! h-8! p-0!" size="small">
  351. <wd-img :src="close" width="28" height="28" custom-class="vertical-bottom"></wd-img>
  352. </wd-button>
  353. </div>
  354. </div>
  355. <div class="bg-neutral-100 rounded-tl-2xl rounded-tr-2xl p-3.5" @click.stop="">
  356. <div class="deal-title">请复制以下链接,打开默认浏览器,粘贴到浏览器进行下载</div>
  357. <div class="deal-link">{{ materialHomePageData?.fodderList[0].fodderUrl }}</div>
  358. <wd-button custom-class="custom-shadow" @click="copy(data?.agreementFileUrl)">
  359. 复制链接
  360. </wd-button>
  361. </div>
  362. </view>
  363. </wd-overlay>
  364. </view>
  365. </template>
  366. <style scoped>
  367. .dots {
  368. bottom: 30rpx;
  369. left: 50%;
  370. transform: translateX(-50%);
  371. }
  372. .bg-active {
  373. width: 40rpx;
  374. }
  375. .deal-title {
  376. padding: 60rpx 0;
  377. font-size: 32rpx;
  378. font-weight: bold;
  379. text-align: center;
  380. }
  381. .deal-link {
  382. padding: 20rpx 30rpx;
  383. margin-bottom: 60rpx;
  384. font-size: 28rpx;
  385. color: rgba(0, 0, 0, 0.45);
  386. word-wrap: break-word;
  387. background-color: rgba(200, 200, 200, 0w);
  388. border-radius: 20rpx;
  389. }
  390. :deep(.custom-shadow) {
  391. width: 100% !important;
  392. }
  393. </style>