preview.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <template>
  2. <div class="editor-preview-wrapper">
  3. <div class="top">
  4. <div class="card-container">
  5. <div class="font">
  6. Preview: <span>{{ installStatus ? 'After' : 'Before' }}</span> DeNet Installed
  7. </div>
  8. <!-- 安装之后的卡片样式 -->
  9. <div class="content-after" v-show="installStatus" :style="{ 'width': reviewCanvasParams.width + 'px' }">
  10. <div class="head" :style="{ 'zoom': reviewCanvasParams.zoom }">
  11. <img :src="userInfo.avatarUrl" class="avatar" />
  12. <div class="article-wrapper">
  13. <div class="nickname">
  14. {{ userInfo.name }}
  15. </div>
  16. <div class="name">
  17. @{{ userInfo.nickName }}
  18. </div>
  19. </div>
  20. </div>
  21. <div class="after-cover-wrapper" :style="{ 'zoom': reviewCanvasParams.zoom }">
  22. <install-card :pre_view="true" :iframe_url="previewData.convertUrl"></install-card>
  23. </div>
  24. </div>
  25. <!-- 安装之前的卡片样式 -->
  26. <div class="content-before" v-show="!installStatus"
  27. :style="{ 'width': reviewCanvasParams.width + 'px' }">
  28. <div class="head" :style="{ 'zoom': reviewCanvasParams.zoom }">
  29. <img :src="userInfo.avatarUrl" class="avatar" />
  30. <div class="article-wrapper">
  31. <div class="nickname">
  32. {{ userInfo.name }}
  33. </div>
  34. <div class="name">
  35. @{{ userInfo.nickName }}
  36. </div>
  37. </div>
  38. </div>
  39. <div class="card-wrapper" :style="{ 'zoom': reviewCanvasParams.zoom }">
  40. <img class="cover" v-if="previewData.linkImagePath && previewData.appId"
  41. :src="previewData.linkImagePath" />
  42. <iframe class="iframe" :src="previewData.convertUrl" scrolling="no" v-else></iframe>
  43. <div class="bottom-bar">
  44. <div class="site-url">DeNet.me</div>
  45. <div class="desc">
  46. <template v-if="previewData.appId">
  47. {{ previewData.currentApp.linkTitle }}
  48. </template>
  49. <template v-else>
  50. {{ previewData.currentApp.defaultTit ? defaultLinkTitle :
  51. previewData.currentApp.name
  52. }}
  53. </template>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. <div class="setting">
  60. <div class="font">Settings</div>
  61. <slot></slot>
  62. </div>
  63. </div>
  64. <div class="bottom">
  65. <div class="btn" @click="publishHandler">NEXT</div>
  66. </div>
  67. </div>
  68. </template>
  69. <script setup>
  70. import { ref, defineEmits, reactive, defineProps, onMounted, nextTick, onUnmounted, watch } from "vue";
  71. import { message } from "ant-design-vue";
  72. import installCard from '@/view/content/tool-box/index.vue'
  73. import { postPublish } from "@/http/publishApi";
  74. import { getChromeStorage, setChromeStorage } from "@/uilts/chromeExtension"
  75. import { getUser } from "@/http/publishApi"
  76. import Report from "@/log-center/log"
  77. let installStatus = ref(false);
  78. let userInfo = ref({});
  79. let submitIng = ref(false);
  80. let reviewCanvasParams = reactive({
  81. width: 620,
  82. zoom: 1
  83. });
  84. let timer = ref(null);
  85. let loadingHide = null;
  86. const props = defineProps({
  87. previewData: {
  88. type: Object,
  89. default: () => {
  90. return {
  91. convertUrl: '',
  92. originUrl: '',
  93. appId: ''
  94. }
  95. }
  96. },
  97. screenshotWebsiteData: {
  98. type: Object,
  99. default: () => {
  100. return {
  101. url: '',
  102. status: ''
  103. }
  104. }
  105. },
  106. defaultLinkTitle: {
  107. type: String,
  108. default: ''
  109. },
  110. showCom: {
  111. type: String,
  112. default: 'EDITOR'
  113. },
  114. certNftProjectId: {
  115. type: String,
  116. default: ''
  117. },
  118. hasNft: {
  119. type: Boolean,
  120. default: false
  121. }
  122. })
  123. watch(() => props.screenshotWebsiteData,
  124. (newVal) => {
  125. let { appId } = props.previewData;
  126. if (loadingHide && (!appId || appId && !props.previewData.linkImagePath) && (newVal.url || newVal.status)) {
  127. loadingHide();
  128. loadingHide = null;
  129. submitPublish();
  130. }
  131. },
  132. {
  133. deep: true
  134. })
  135. watch(() => props.showCom,
  136. (newVal) => {
  137. if (newVal == 'EDITOR' && loadingHide) {
  138. loadingHide();
  139. loadingHide = null;
  140. }
  141. },
  142. {
  143. deep: true
  144. })
  145. const emits = defineEmits(["publishFinish"]);
  146. const getUserInfo = (cb) => {
  147. getChromeStorage('userInfo', (res) => {
  148. if (res) {
  149. userInfo.value = res;
  150. }
  151. cb && cb(res);
  152. })
  153. }
  154. const getUserName = (screenName) => {
  155. getUser({
  156. params: {
  157. screenName
  158. }
  159. }).then(res => {
  160. console.log(res);
  161. if (res.code == 0) {
  162. userInfo.value.name = res.data.name || ''
  163. }
  164. });
  165. }
  166. const calcPreviewCanvasParams = () => {
  167. nextTick(() => {
  168. let containerDom = document.querySelector('.card-container');
  169. let domHeight = containerDom && containerDom.offsetHeight || 490;
  170. const canvasHeight = 780, canvasWidth = 620;
  171. if (domHeight < canvasHeight) {
  172. //比例: 高 / 宽
  173. let hWRatio = canvasHeight / canvasWidth;
  174. //缩小宽度 = 高度 / 比例
  175. let width = canvasWidth / hWRatio;
  176. if (width > canvasWidth) {
  177. width = canvasWidth;
  178. }
  179. //缩小比例
  180. let zoom = width / canvasWidth;
  181. if (zoom > 1) {
  182. zoom = 1;
  183. }
  184. reviewCanvasParams.width = width;
  185. reviewCanvasParams.zoom = zoom;
  186. } else {
  187. reviewCanvasParams.width = canvasWidth;
  188. reviewCanvasParams.zoom = 1;
  189. }
  190. });
  191. }
  192. const publishHandler = () => {
  193. let { appId } = props.previewData;
  194. if (loadingHide) {
  195. return;
  196. }
  197. if ((!appId || appId && !props.previewData.linkImagePath) && (!props.screenshotWebsiteData.url && !props.screenshotWebsiteData.status)) {
  198. loadingHide = message.loading('loading...', 0);
  199. return;
  200. }
  201. submitPublish();
  202. }
  203. const submitPublish = () => {
  204. let { convertUrl, originUrl, appId, currentApp } = props.previewData;
  205. if (submitIng.value) {
  206. return;
  207. }
  208. setHistoryData(currentApp);
  209. let linkTitle = currentApp.name ? currentApp.name : currentApp.defaultTit;
  210. let postBizData = {
  211. convertUrl,
  212. originUrl,
  213. appId,
  214. linkTitle: !appId ? linkTitle : '',
  215. linkImagePath: props.screenshotWebsiteData.url
  216. };
  217. if (props.certNftProjectId !== '') {
  218. postBizData['certNftProjectId'] = props.certNftProjectId;
  219. }
  220. let data = {
  221. params: {
  222. postBizData: JSON.stringify(postBizData),
  223. postSrc: 1, // 1 twitter
  224. postType: 3, //3 Tool box
  225. },
  226. };
  227. submitIng.value = true;
  228. Report.reportLog({
  229. pageSource: Report.pageSource.previewPage,
  230. businessType: Report.businessType.pageView,
  231. objectType: Report.objectType.confirmButton
  232. }, {
  233. 'type': Report.bizType.ToolBox,
  234. 'post-editor-url': convertUrl,
  235. 'has-nft': props.hasNft
  236. })
  237. postPublish(data).then((res) => {
  238. submitIng.value = false;
  239. if (res.code == 0) {
  240. let publishRes = res.data;
  241. emits("publishFinish", { publishRes });
  242. } else {
  243. }
  244. }).catch((err) => {
  245. submitIng.value = false;
  246. console.log(err);
  247. });
  248. }
  249. const setHistoryData = async (params) => {
  250. const maxLength = 9;
  251. let { list = [] } = await getChromeStorage('toolBoxAppHistoryData') || {};
  252. if (list.length) {
  253. let hasSite = list.find(item => item.defaultUrl == params.defaultUrl);
  254. if (hasSite) {
  255. return;
  256. }
  257. list.unshift(params);
  258. if (list.length > maxLength) {
  259. list.length = maxLength;
  260. }
  261. setChromeStorage({
  262. toolBoxAppHistoryData: JSON.stringify({
  263. list: list
  264. })
  265. })
  266. } else {
  267. setChromeStorage({
  268. toolBoxAppHistoryData: JSON.stringify({
  269. list: [params]
  270. })
  271. })
  272. }
  273. };
  274. onMounted(() => {
  275. calcPreviewCanvasParams();
  276. getUserInfo((res) => {
  277. if (res) {
  278. getUserName(res.nickName);
  279. }
  280. clearInterval(timer.value);
  281. timer.value = setInterval(() => {
  282. installStatus.value = !installStatus.value;
  283. }, 3000)
  284. });
  285. window.addEventListener('resize', function () {
  286. calcPreviewCanvasParams();
  287. })
  288. })
  289. onUnmounted(() => {
  290. clearInterval(timer.value);
  291. })
  292. </script>
  293. <style lang="scss" scoped>
  294. .editor-preview-wrapper {
  295. width: 100%;
  296. height: 100%;
  297. .top {
  298. width: 100%;
  299. height: calc(100% - 80px);
  300. display: flex;
  301. justify-content: space-between;
  302. padding: 20px 40px;
  303. box-sizing: border-box;
  304. .card-container {
  305. height: 100%;
  306. margin-right: 32px;
  307. .content-after,
  308. .content-before {
  309. position: relative;
  310. }
  311. .head {
  312. position: absolute;
  313. z-index: 1100;
  314. top: 20px;
  315. left: 17px;
  316. display: flex;
  317. .avatar {
  318. width: 47px;
  319. height: 47px;
  320. border-radius: 50%;
  321. object-fit: cover;
  322. margin-right: 13px;
  323. }
  324. .article-wrapper {
  325. display: flex;
  326. .nickname {
  327. font-weight: 500;
  328. }
  329. .nickname,
  330. .name {
  331. font-size: 15px;
  332. }
  333. .name {
  334. color: #566370;
  335. margin-left: 7px;
  336. }
  337. }
  338. }
  339. .content-after {
  340. background: url('@/assets/img/img-tool-box-preview-after.png');
  341. width: 387px;
  342. height: calc(100% - 30px);
  343. overflow: hidden;
  344. background-size: cover;
  345. background-repeat: no-repeat;
  346. border: 1px solid #E6E6E6;
  347. border-radius: 13px;
  348. box-sizing: border-box;
  349. .after-cover-wrapper {
  350. position: absolute;
  351. z-index: 100;
  352. top: 108px;
  353. left: 78px;
  354. width: 425px;
  355. height: 458px;
  356. border-radius: 10px;
  357. // border: 1px solid #D1D9DD;
  358. }
  359. }
  360. .content-before {
  361. background: url('@/assets/img/img-tool-box-preview-before.png');
  362. background-size: cover;
  363. background-repeat: no-repeat;
  364. height: calc(100% - 30px);
  365. overflow: hidden;
  366. border: 1px solid #E6E6E6;
  367. border-radius: 13px;
  368. box-sizing: border-box;
  369. .card-wrapper {
  370. width: 448px;
  371. height: 300px;
  372. border: 1px solid #E6E6E6;
  373. background: #ffffff;
  374. box-sizing: border-box;
  375. overflow: hidden;
  376. position: relative;
  377. box-sizing: border-box;
  378. border-radius: 16px;
  379. left: 70px;
  380. top: 90px;
  381. .iframe {
  382. height: calc(100% - 71px);
  383. width: 100%;
  384. border: none;
  385. pointer-events: none;
  386. cursor: default;
  387. }
  388. .cover {
  389. height: calc(100% - 73px);
  390. width: 100%;
  391. object-fit: cover;
  392. }
  393. .bottom-bar {
  394. width: 100%;
  395. height: 73px;
  396. padding: 10px 10px 0 13px;
  397. border-top: 1px solid rgba(0, 0, 0, 0.3);
  398. .site-url {
  399. color: #566370;
  400. font-size: 14px;
  401. line-height: 20px;
  402. }
  403. .desc {
  404. font-weight: 500;
  405. font-size: 15px;
  406. line-height: 21px;
  407. font-weight: 500;
  408. }
  409. }
  410. }
  411. }
  412. }
  413. .font {
  414. height: 30px;
  415. font-weight: 600;
  416. font-size: 20px;
  417. span {
  418. color: #1D9BF0;
  419. }
  420. }
  421. .setting {
  422. flex: 1;
  423. }
  424. }
  425. .bottom {
  426. width: 100%;
  427. height: 80px;
  428. box-shadow: 0px -1px 0px #ECECEC;
  429. box-sizing: border-box;
  430. border-bottom-left-radius: 16px;
  431. display: flex;
  432. align-items: center;
  433. justify-content: flex-end;
  434. .btn {
  435. width: 200px;
  436. height: 50px;
  437. background: #1D9BF0;
  438. border-radius: 10000px;
  439. display: flex;
  440. align-items: center;
  441. justify-content: center;
  442. font-weight: 700;
  443. font-size: 18px;
  444. color: #fff;
  445. margin-right: 30px;
  446. cursor: pointer;
  447. }
  448. }
  449. }
  450. </style>