index.vue 12 KB

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