index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. <template>
  2. <div class="privatizationDeployment-wrap">
  3. <h2 class="title">
  4. <div
  5. v-for="(item, index) in detail[currentTab].slogan"
  6. :key="index"
  7. >
  8. {{ item }}
  9. </div>
  10. </h2>
  11. <div class="tab">
  12. <div
  13. v-for="(item, index) in tab"
  14. :key="index"
  15. class="item"
  16. :class="{ active: item.id === currentTab }"
  17. @click="currentTab = item.id"
  18. >
  19. {{ item.txt }}
  20. </div>
  21. </div>
  22. <div class="list">
  23. <div
  24. class="item"
  25. :class="{ [item['color']]: 1 }"
  26. v-for="(item, index) in detail[currentTab].list"
  27. :key="index"
  28. >
  29. <div class="name">{{ item.name }}</div>
  30. <div class="desc">{{ item.short_desc }}</div>
  31. <div class="price">
  32. <span class="t1">{{ item.price.left }}</span>
  33. <span class="t2">{{ item.price.center }}</span>
  34. <span class="t3">{{ item.price.right }}</span>
  35. </div>
  36. <div class="feat">
  37. <div
  38. v-if="item.tip !== ''"
  39. class="feat-item tip"
  40. >
  41. {{ item.tip }}
  42. </div>
  43. <div
  44. class="feat-item"
  45. v-for="(iten, indey) in item.feat"
  46. :key="indey"
  47. >
  48. <div
  49. :class="{
  50. done: iten.status === 'done',
  51. todo: iten.status === 'todo',
  52. }"
  53. ></div>
  54. <div class="txt">{{ iten.txt }}</div>
  55. </div>
  56. </div>
  57. <div
  58. class="btn"
  59. @click="handleClick(item.btn)"
  60. >
  61. {{ item.btn.txt }}
  62. </div>
  63. </div>
  64. </div>
  65. </div>
  66. <n-modal v-model:show="showContach">
  67. <n-card
  68. style="width: 400px"
  69. title="联系方式"
  70. role="dialog"
  71. closable
  72. @close="showContach = false"
  73. >
  74. <div>
  75. <div>微信:</div>
  76. <img
  77. src="@/assets/img/my-wechat.webp"
  78. alt=""
  79. style="width: 300px"
  80. />
  81. <div>微信号: {{ AUTHOR_INFO.wechat }}</div>
  82. <div>qq:{{ AUTHOR_INFO.qq }}</div>
  83. <p>添加时请备注:私有化部署+用途</p>
  84. </div>
  85. </n-card>
  86. </n-modal>
  87. </template>
  88. <script lang="ts" setup>
  89. import { openToTarget } from 'billd-utils';
  90. import { ref } from 'vue';
  91. import { useRouter } from 'vue-router';
  92. import { AUTHOR_INFO, COMMON_URL, PROJECT_NAME } from '@/constant';
  93. import { routerName } from '@/router';
  94. const router = useRouter();
  95. const showContach = ref(false);
  96. const currentTab = ref<'personal' | 'openSource' | 'customized' | string>(
  97. 'openSource'
  98. );
  99. const tab = ref([
  100. {
  101. id: 'personal',
  102. txt: '个人版',
  103. },
  104. {
  105. id: 'openSource',
  106. txt: '开源版',
  107. },
  108. {
  109. id: 'customized',
  110. txt: '定制版',
  111. },
  112. ]);
  113. const detail = ref({
  114. personal: {
  115. slogan: ['欢迎使用billd直播~'],
  116. list: [
  117. {
  118. color: 'blue',
  119. name: 'VIP',
  120. desc: '适用于个人用户简单体验',
  121. price: {
  122. left: '¥',
  123. center: '0',
  124. right: '',
  125. },
  126. tip: '',
  127. feat: [
  128. {
  129. status: 'done',
  130. txt: 'SRS直播',
  131. },
  132. {
  133. status: 'done',
  134. txt: '打PK直播',
  135. },
  136. {
  137. status: 'done',
  138. txt: 'WebRTC直播',
  139. },
  140. {
  141. status: 'done',
  142. txt: 'WebRTC会议',
  143. },
  144. ],
  145. btn: {
  146. type: 'push',
  147. link: routerName.push,
  148. txt: '免费体验',
  149. },
  150. },
  151. {
  152. color: 'green',
  153. name: 'SVIP',
  154. desc: '适用于个人用户中度体验',
  155. price: {
  156. left: '¥',
  157. center: '10',
  158. right: '元/月',
  159. },
  160. tip: '涵盖VIP全部功能',
  161. feat: [
  162. {
  163. status: 'done',
  164. txt: '转推b站',
  165. },
  166. {
  167. status: 'done',
  168. txt: '转推虎牙',
  169. },
  170. {
  171. status: 'done',
  172. txt: '去广告',
  173. },
  174. ],
  175. btn: {
  176. type: 'toast',
  177. link: '即将上线~',
  178. txt: '立即购买',
  179. },
  180. },
  181. {
  182. color: 'orange',
  183. name: 'ADMIN',
  184. desc: '适用于个人用户深度体验',
  185. price: {
  186. left: '¥',
  187. center: '50',
  188. right: '元/月',
  189. },
  190. tip: '涵盖SVIP全部功能',
  191. feat: [
  192. {
  193. status: 'done',
  194. txt: 'Msr直播',
  195. },
  196. {
  197. status: 'done',
  198. txt: '腾讯云直播(CDN)',
  199. },
  200. {
  201. status: 'done',
  202. txt: '腾讯云打PK(CDN)',
  203. },
  204. ],
  205. btn: {
  206. type: 'toast',
  207. link: '即将上线~',
  208. txt: '立即购买',
  209. },
  210. },
  211. ],
  212. },
  213. openSource: {
  214. slogan: ['billd直播开源至今,累计收获1.3k+ star', '值得信赖,欢迎部署~'],
  215. list: [
  216. {
  217. color: 'blue',
  218. name: 'Github',
  219. desc: '适用于个人学习/测试用途',
  220. price: {
  221. left: '¥',
  222. center: '0',
  223. right: '',
  224. },
  225. tip: '',
  226. feat: [
  227. {
  228. status: 'done',
  229. txt: '源码开源,自行部署',
  230. },
  231. {
  232. status: 'done',
  233. txt: '直播前台(Web)',
  234. },
  235. {
  236. status: 'done',
  237. txt: '直播后台(Web)',
  238. },
  239. {
  240. status: 'done',
  241. txt: '直播安卓端(Flutter)',
  242. },
  243. {
  244. status: 'todo',
  245. txt: '直播苹果端(Flutter)',
  246. },
  247. {
  248. status: 'todo',
  249. txt: '直播客户端(Electron)',
  250. },
  251. ],
  252. btn: {
  253. type: 'link',
  254. link: 'https://github.com/galaxy-s10/billd-live',
  255. txt: '立即部署',
  256. },
  257. },
  258. {
  259. color: 'green',
  260. name: '私有化部署',
  261. desc: '适用于个人/企业自建直播平台',
  262. price: {
  263. left: '¥',
  264. center: 'XXXX',
  265. right: '起',
  266. },
  267. tip: '涵盖Github全部/部分功能',
  268. feat: [
  269. {
  270. status: 'done',
  271. txt: '无门槛,全程专人负责部署',
  272. },
  273. {
  274. status: 'done',
  275. txt: '本地服务器部署',
  276. },
  277. {
  278. status: 'done',
  279. txt: '快速上线',
  280. },
  281. ],
  282. btn: {
  283. type: 'showContact',
  284. link: '',
  285. txt: '立即咨询',
  286. },
  287. },
  288. ],
  289. },
  290. customized: {
  291. slogan: ['billd直播支持定制化', '立即定制自己的个性化直播间~'],
  292. list: [
  293. {
  294. color: 'blue',
  295. name: '在线咨询',
  296. desc: '咨询/答疑服务',
  297. price: {
  298. left: '¥',
  299. center: '50',
  300. right: '元/小时',
  301. },
  302. tip: '',
  303. feat: [
  304. {
  305. status: 'done',
  306. txt: '一对一解答',
  307. },
  308. ],
  309. btn: {
  310. type: 'showContact',
  311. link: '',
  312. txt: '立即咨询',
  313. },
  314. },
  315. {
  316. color: 'green',
  317. name: '付费课程',
  318. desc: '适用于前端/音视频小白',
  319. price: {
  320. left: '¥',
  321. center: '399',
  322. right: '元',
  323. },
  324. tip: '',
  325. feat: [
  326. {
  327. status: 'done',
  328. txt: '一对一解答(4小时)',
  329. },
  330. {
  331. status: 'done',
  332. txt: '能够搭建最基础的直播间',
  333. },
  334. {
  335. status: 'done',
  336. txt: '单独的代码仓库',
  337. },
  338. {
  339. status: 'done',
  340. txt: '视频讲解',
  341. },
  342. {
  343. status: 'done',
  344. txt: `${PROJECT_NAME}付费课微信群`,
  345. },
  346. ],
  347. btn: {
  348. type: 'link',
  349. link: COMMON_URL.payCoursesArticle,
  350. txt: '了解详情',
  351. },
  352. },
  353. {
  354. color: 'orange',
  355. name: '私有化部署',
  356. desc: '适用于个人/企业自建直播平台',
  357. price: {
  358. left: '¥',
  359. center: 'XXXX',
  360. right: '起',
  361. },
  362. tip: '',
  363. feat: [
  364. {
  365. status: 'done',
  366. txt: '无门槛,全程专人负责部署',
  367. },
  368. {
  369. status: 'done',
  370. txt: '本地服务器部署',
  371. },
  372. {
  373. status: 'done',
  374. txt: '快速上线',
  375. },
  376. {
  377. status: 'done',
  378. txt: '定制化功能',
  379. },
  380. ],
  381. btn: {
  382. type: 'showContact',
  383. link: '',
  384. txt: '立即咨询',
  385. },
  386. },
  387. ],
  388. },
  389. });
  390. function handleClick(item) {
  391. if (item.type === 'link') {
  392. openToTarget(item.link);
  393. } else if (item.type === 'push') {
  394. const url = router.resolve({
  395. name: item.link,
  396. });
  397. openToTarget(url.href);
  398. } else if (item.type === 'buy') {
  399. console.log('buy');
  400. } else if (item.type === 'toast') {
  401. window.$message.info(item.link);
  402. } else if (item.type === 'showContact') {
  403. showContach.value = true;
  404. }
  405. }
  406. </script>
  407. <style lang="scss" scoped>
  408. .privatizationDeployment-wrap {
  409. height: calc(100vh - $layout-head-h);
  410. background-color: #f4f8ff;
  411. .title {
  412. display: flex;
  413. flex-direction: column;
  414. justify-content: center;
  415. box-sizing: border-box;
  416. margin: 0 auto;
  417. width: 1200px;
  418. height: 180px;
  419. // background-color: red;
  420. text-align: center;
  421. font-size: 40px;
  422. }
  423. .tab {
  424. display: flex;
  425. justify-content: center;
  426. margin: 0 auto;
  427. padding: 8px 0;
  428. width: 320px;
  429. border-radius: 40px;
  430. background: white;
  431. box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
  432. user-select: none;
  433. .item {
  434. padding: 4px 25px;
  435. border-radius: 40px;
  436. color: #686e88;
  437. font-weight: 700;
  438. font-size: 16px;
  439. cursor: pointer;
  440. &.active {
  441. background-color: $theme-color-gold;
  442. color: white;
  443. }
  444. }
  445. }
  446. .list {
  447. display: flex;
  448. justify-content: center;
  449. margin: 50px auto 0;
  450. width: 1200px;
  451. .item {
  452. box-sizing: border-box;
  453. margin: 0 10px;
  454. padding: 20px 20px;
  455. width: 240px;
  456. // border: 1px solid #dde6ed;
  457. border-radius: 2px;
  458. border-top-left-radius: 4px;
  459. border-top-right-radius: 4px;
  460. background-color: white;
  461. font-size: 14px;
  462. &.blue {
  463. border-top: 7px solid #38c0ff;
  464. }
  465. &.green {
  466. border-top: 7px solid #30d1aa;
  467. }
  468. &.orange {
  469. border-top: 7px solid #ffbd33;
  470. }
  471. .name {
  472. padding: 10px 0 0;
  473. height: 40px;
  474. text-align: center;
  475. font-size: 30px;
  476. line-height: 1;
  477. }
  478. .desc {
  479. margin-top: 10px;
  480. height: 40px;
  481. color: #88898d;
  482. text-align: center;
  483. // background-color: red;
  484. }
  485. .price {
  486. display: flex;
  487. align-items: flex-end;
  488. justify-content: center;
  489. height: 45px;
  490. color: #88898d;
  491. text-align: center;
  492. .t1 {
  493. color: #272727;
  494. font-weight: 600;
  495. font-size: 16px;
  496. }
  497. .t2 {
  498. color: #272727;
  499. font-size: 40px;
  500. line-height: 36px;
  501. }
  502. .t3 {
  503. color: #2c2c2c;
  504. font-size: 16px;
  505. }
  506. // background-color: red;
  507. }
  508. .feat {
  509. margin-top: 30px;
  510. height: 200px;
  511. .feat-item {
  512. display: flex;
  513. align-items: center;
  514. margin-bottom: 10px;
  515. &.tip {
  516. color: #88898d;
  517. }
  518. .todo,
  519. .done {
  520. margin-right: 10px;
  521. width: 18px;
  522. height: 18px;
  523. text-align: center;
  524. }
  525. .todo {
  526. position: relative;
  527. &::after {
  528. color: #ffc049;
  529. content: '-';
  530. text-align: center;
  531. font-size: 16px;
  532. }
  533. }
  534. .done {
  535. @include setBackground('@/assets/img/check.png');
  536. }
  537. }
  538. }
  539. .btn {
  540. margin: 0 auto;
  541. padding: 8px 0;
  542. width: 160px;
  543. border: 1px solid $theme-color-gold;
  544. border-radius: 4px;
  545. color: $theme-color-gold;
  546. text-align: center;
  547. font-size: 16px;
  548. cursor: pointer;
  549. &:hover {
  550. background-color: $theme-color-gold;
  551. color: white;
  552. }
  553. }
  554. }
  555. }
  556. }
  557. </style>