index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. <template>
  2. <div class="denet-toolbox" @click.stop="clickHead" ref="dom_toolbox" :class="{ 'pre-view': pre_view }">
  3. <div class="head" @click.stop="clickHead">
  4. <span></span>
  5. <div v-show="state.show_btn && state.status == ''">
  6. <icon-svg :icon="'固定'" @clickStop="clickFixed" :class="'fixed'"></icon-svg>
  7. <icon-svg :icon="'放大'" @clickStop="clickFull" :class="'full'"></icon-svg>
  8. </div>
  9. </div>
  10. <div class="content" v-if="pre_view">
  11. <iframe :src="iframe_url" frameborder="0"></iframe>
  12. </div>
  13. <div class="content" v-else>
  14. <iframe :src="state.iframe_url" v-show="state.status == ''" ref="dom_iframe" frameborder="0"
  15. allow="camera *;microphone *"></iframe>
  16. <!-- 网页错误 -->
  17. <div class="state" v-show="state.status == '网页错误'">
  18. <img :src="require('@/assets/img/icon-page-fail.png')" alt />
  19. <div>Oops, this link is invalid</div>
  20. </div>
  21. <!-- 加载 -->
  22. <div class="state" v-show="state.status == '加载'">
  23. <img :src="require('@/assets/img/icon-loading-gray.png')" alt class="icon-loading" />
  24. </div>
  25. <!-- 关闭 -->
  26. <div class="state" v-show="state.status == '关闭'">
  27. </div>
  28. <!-- 固定右上角 -->
  29. <div class="state" v-show="state.status == '固定右上角'">
  30. <img :src="require('@/assets/img/icon-fixed-gray.png')" alt />
  31. <div>Pinned to the top right</div>
  32. </div>
  33. </div>
  34. <!-- alert -->
  35. <div class="alert" v-show="state.show_alert">
  36. <div class="back" @click.stop="clickCancel"></div>
  37. <div class="confirm">
  38. <div class="check">
  39. <input :id="state.checkbox_id" type='checkbox' v-model="state.checkbox" />
  40. <label :for="state.checkbox_id">Don't remind</label>
  41. </div>
  42. <div class="title">Web Page Progress May Reset</div>
  43. <div class="handle">
  44. <div class="cancel" @click.stop="clickCancel">Cancel</div>
  45. <div class="continue" @click.stop="clickContinue">Continue</div>
  46. </div>
  47. </div>
  48. </div>
  49. </div>
  50. </template>
  51. <script setup>
  52. import { getChromeStorage, setChromeStorage, httpContentToBack, defineProps } from "@/uilts/chromeExtension";
  53. import { guid } from "@/uilts/help";
  54. import { sendEventInfo } from "@/uilts/event";
  55. import { onMounted, reactive, ref } from "vue";
  56. import { $ } from "@/uilts/help";
  57. import IconSvg from '@/view/components/icon-svg.vue'
  58. let dom_toolbox = ref(null)
  59. let dom_iframe = ref(null)
  60. let state = reactive({
  61. status: '', //
  62. show_alert: false,
  63. show_btn: true,
  64. list: [],
  65. checkbox: false,
  66. checkbox_id: `denet-${guid()}`,
  67. postId: '',
  68. tweetId: '',
  69. detail: {},
  70. handle_type: ''
  71. })
  72. let dom = {}
  73. let props = defineProps({
  74. pre_view: {
  75. type: Boolean,
  76. default: false,
  77. },
  78. iframe_url: {
  79. type: String,
  80. default: ''
  81. }
  82. })
  83. window.addEventListener("onEvent", e => {
  84. let info = e.detail
  85. switch (info.event_type) {
  86. // 事件传输
  87. case 'ToolBox_Fixed_Close':
  88. if (info.data.tweetId == state.tweetId) {
  89. state.show_btn = true
  90. state.status = ''
  91. state.iframe_url = info.data.url
  92. }
  93. break
  94. }
  95. });
  96. const clickHead = () => {
  97. //
  98. }
  99. const clickContinue = () => {
  100. if (state.checkbox) {
  101. setChromeStorage({ fullCheck: JSON.stringify({ fullCheck: 1 }) })
  102. }
  103. if (state.handle_type == '全屏') {
  104. handleFull()
  105. } else {
  106. handleFixed()
  107. }
  108. state.show_alert = false
  109. }
  110. onMounted(() => {
  111. if (props.pre_view) {
  112. return
  113. }
  114. if (dom_toolbox.value) {
  115. state.dom_root = dom_toolbox.value.closest('div[data-tweet-id]')
  116. if (state.dom_root) {
  117. state.postId = state.dom_root.dataset.postId || ''
  118. state.tweetId = state.dom_root.dataset.tweetId || ''
  119. }
  120. }
  121. try {
  122. dom.fixed = $('#denet-tool-box-fixed')
  123. if (dom.fixed && dom.fixed.style.display == 'block') {
  124. if (dom.fixed.dataset.tweetId == state.tweetId) {
  125. state.status = '固定右上角'
  126. return
  127. }
  128. }
  129. } catch (error) {
  130. console.log(error)
  131. }
  132. getDetail()
  133. })
  134. // detail函数
  135. const getDetail = () => {
  136. state.status = '加载'
  137. httpContentToBack({
  138. url: `/post/getDetail`,
  139. params: {
  140. postId: state.postId
  141. }
  142. }, (res) => {
  143. if (res && res.code == 0) {
  144. state.detail = JSON.parse(res.data.postBizData)
  145. console.log('postBizData', state.detail)
  146. // 加载iframe
  147. let iframe = dom_iframe.value
  148. // state.detail.convertUrl = 'https://www.bilibili.com'
  149. // iframe.onerror = () => {
  150. // state.status = '网页错误'
  151. // }
  152. // iframe.onload = function () {
  153. // if (state.status != '固定右上角') {
  154. // state.status = ''
  155. // }
  156. // }
  157. setTimeout(() => {
  158. state.iframe_url = state.detail.convertUrl
  159. state.status = ''
  160. }, 1000)
  161. } else {
  162. state.status = '网页错误'
  163. }
  164. })
  165. }
  166. const clickCancel = () => {
  167. state.show_alert = false
  168. }
  169. const clickFixed = () => {
  170. state.handle_type = '固定'
  171. getChromeStorage('fullCheck', (res) => {
  172. if (res && res.fullCheck) {
  173. // 固定
  174. handleFixed()
  175. } else {
  176. state.show_alert = true
  177. }
  178. })
  179. }
  180. // 固定
  181. const handleFull = () => {
  182. if (state.status || !state.iframe_url) {
  183. return
  184. }
  185. // 切换状态
  186. state.status = '关闭'
  187. state.status = '固定右上角'
  188. // 操作全屏dom
  189. dom.fixed.style.cssText = `
  190. width:100%;
  191. height: 100%;
  192. position: fixed;
  193. right: 0px;
  194. top: 0px;
  195. display:block;`
  196. dom.fixed.dataset.tweetId = state.tweetId
  197. state.show_btn = false
  198. sendEventInfo({
  199. event_type: 'ToolBox_To_Full',
  200. data: {
  201. iframe_url: state.iframe_url,
  202. tweetId: state.tweetId,
  203. }
  204. })
  205. // 清除当前iframe src
  206. state.iframe_url = ''
  207. }
  208. // 全屏
  209. const handleFixed = () => {
  210. // 切换状态
  211. state.show_btn = false
  212. state.status = '固定右上角'
  213. // 操作全屏dom
  214. dom.fixed.style.cssText = `
  215. display:block;
  216. width: 505px;
  217. height: 544px;
  218. position: fixed;
  219. right: 10px;
  220. top: 10px;`
  221. dom.fixed.dataset.tweetId = state.tweetId
  222. sendEventInfo({
  223. event_type: 'ToolBox_To_Fixed',
  224. data: {
  225. iframe_url: state.iframe_url,
  226. tweetId: state.tweetId
  227. }
  228. })
  229. // 清除当前iframe src
  230. state.iframe_url = ''
  231. }
  232. const clickFull = () => {
  233. state.handle_type = '全屏'
  234. getChromeStorage('fullCheck', (res) => {
  235. if (res && res.fullCheck) {
  236. // 全屏
  237. handleFull()
  238. } else {
  239. state.show_alert = true
  240. }
  241. })
  242. }
  243. </script>
  244. <style lang="scss">
  245. .pre-view {
  246. pointer-events: none;
  247. cursor: default;
  248. }
  249. .denet-toolbox {
  250. width: 100%;
  251. height: 100%;
  252. filter: drop-shadow(0px 4px 20px rgba(0, 0, 0, 0.2));
  253. border-radius: 12px;
  254. overflow: hidden;
  255. position: relative;
  256. .alert {
  257. text-align: center;
  258. position: absolute;
  259. top: 0;
  260. left: 0;
  261. width: 100%;
  262. height: 100%;
  263. .back {
  264. background: #000000;
  265. opacity: 0.8;
  266. position: absolute;
  267. top: 0;
  268. left: 0;
  269. width: 100%;
  270. height: 100%;
  271. cursor: auto;
  272. }
  273. .confirm {
  274. position: absolute;
  275. width: 355px;
  276. height: 180px;
  277. background: #FFFFFF;
  278. border-radius: 20px;
  279. top: 173px;
  280. left: 50%;
  281. margin-left: -180px;
  282. .title {
  283. font-weight: 600;
  284. font-size: 18px;
  285. color: #000000;
  286. margin-bottom: 34px;
  287. }
  288. .check {
  289. color: #899099;
  290. font-weight: 400;
  291. font-size: 14px;
  292. margin: 12px 15px 32px 0;
  293. text-align: right;
  294. align-content: center;
  295. justify-content: flex-end;
  296. display: flex;
  297. line-height: 17px;
  298. input {
  299. margin-right: 8px;
  300. }
  301. label {
  302. line-height: 19px;
  303. }
  304. }
  305. .handle {
  306. display: flex;
  307. justify-content: center;
  308. align-items: center;
  309. div {
  310. font-weight: 600;
  311. font-size: 16px;
  312. width: 156px;
  313. height: 47px;
  314. line-height: 47px;
  315. cursor: pointer;
  316. border-radius: 1000px;
  317. user-select: none;
  318. }
  319. .cancel {
  320. color: #000000;
  321. background: rgba(56, 154, 255, 0.01);
  322. border: 1px solid #E6E6E6;
  323. }
  324. .continue {
  325. background: #1D9BF0;
  326. font-weight: 600;
  327. margin-left: 11px;
  328. color: #FFFFFF;
  329. }
  330. }
  331. }
  332. }
  333. .head {
  334. width: 100%;
  335. height: 40px;
  336. background: #373737;
  337. display: flex;
  338. align-items: center;
  339. justify-content: space-between;
  340. div {
  341. display: flex;
  342. justify-content: center;
  343. }
  344. span {
  345. color: #FFFFFF;
  346. font-style: normal;
  347. font-weight: 500;
  348. font-size: 14px;
  349. margin-left: 16px;
  350. }
  351. svg {
  352. width: 20px;
  353. height: 20px;
  354. cursor: pointer;
  355. }
  356. .full {
  357. margin-right: 16px;
  358. }
  359. .fixed {
  360. margin-right: 20px;
  361. }
  362. }
  363. .content {
  364. width: 100%;
  365. height: calc(100% - 40px);
  366. background: #686868;
  367. display: flex;
  368. align-items: center;
  369. justify-content: center;
  370. iframe {
  371. width: 100%;
  372. height: 100%;
  373. }
  374. .state {
  375. text-align: center;
  376. img {
  377. margin-bottom: 14px;
  378. }
  379. .icon-loading {
  380. animation: loading 1s infinite linear;
  381. }
  382. div {
  383. margin-bottom: 40px;
  384. color: #8E8E8E;
  385. text-align: center;
  386. font-weight: 500;
  387. font-size: 22px;
  388. }
  389. }
  390. }
  391. }
  392. @keyframes loading {
  393. from {
  394. transform: rotate(0deg);
  395. }
  396. to {
  397. transform: rotate(360deg);
  398. }
  399. }
  400. </style>