shuisheng 1 gadu atpakaļ
vecāks
revīzija
faeb7ba8e8

+ 3 - 3
package.json

@@ -16,6 +16,7 @@
     "deploy:prod": "node ./deploy/index.js --prod",
     "lint": "eslint --config ./.eslintrc.js . --ext .js,.jsx,.ts,.tsx,.vue --cache",
     "lint:fix": "eslint --config ./.eslintrc.js . --ext .js,.jsx,.ts,.tsx,.vue --cache --fix",
+    "oxclint": "pnpm dlx oxlint@latest",
     "prepare": "husky install",
     "prettier": "prettier --write .",
     "release": "standard-version",
@@ -24,8 +25,7 @@
     "start:preview": "cross-env VUE_APP_RELEASE_PROJECT_ENV=preview VUE_APP_RELEASE_PROJECT_NAME=billd-live webpack serve --config ./script/config/webpack.common.ts --env development",
     "start:prod": "cross-env VUE_APP_RELEASE_PROJECT_ENV=prod VUE_APP_RELEASE_PROJECT_NAME=billd-live webpack serve --config ./script/config/webpack.common.ts --env production",
     "start:stats": "cross-env WEBPACK_ANALYZER_SWITCH=true webpack serve --config ./script/config/webpack.common.ts --env development",
-    "typecheck": "tsc -p ./tsconfig.json --noEmit",
-    "oxclint": "pnpm dlx oxlint@latest"
+    "typecheck": "tsc -p ./tsconfig.json --noEmit"
   },
   "config": {
     "commitizen": {
@@ -55,7 +55,7 @@
     "pinia-plugin-persistedstate": "^3.2.0",
     "qiniu-js": "^3.4.2",
     "qrcode": "^1.5.3",
-    "socket.io-client": "^4.7.2",
+    "socket.io-client": "^4.8.0",
     "socket.io-msgpack-parser": "^3.0.2",
     "spark-md5": "^3.0.2",
     "video.js": "^8.3.0",

+ 21 - 21
pnpm-lock.yaml

@@ -66,8 +66,8 @@ importers:
         specifier: ^1.5.3
         version: 1.5.3
       socket.io-client:
-        specifier: ^4.7.2
-        version: 4.7.2
+        specifier: ^4.8.0
+        version: 4.8.0
       socket.io-msgpack-parser:
         specifier: ^3.0.2
         version: 3.0.2
@@ -3197,8 +3197,8 @@ packages:
     resolution: {integrity: sha512-OclLMSug+k2A0JKuf494im25ANRBVW8qsjmwbgX7lQ8P82H21PQ1PWkoYwb9y5yMBS69BPlwtzdIFClo3+7kOQ==}
     engines: {node: '>= 0.11.14'}
 
-  engine.io-client@6.5.2:
-    resolution: {integrity: sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==}
+  engine.io-client@6.6.1:
+    resolution: {integrity: sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw==}
 
   engine.io-parser@5.2.1:
     resolution: {integrity: sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==}
@@ -6133,8 +6133,8 @@ packages:
     resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
     engines: {node: '>=12'}
 
-  socket.io-client@4.7.2:
-    resolution: {integrity: sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==}
+  socket.io-client@4.8.0:
+    resolution: {integrity: sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw==}
     engines: {node: '>=10.0.0'}
 
   socket.io-msgpack-parser@3.0.2:
@@ -7014,20 +7014,20 @@ packages:
       utf-8-validate:
         optional: true
 
-  ws@8.11.0:
-    resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==}
+  ws@8.13.0:
+    resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==}
     engines: {node: '>=10.0.0'}
     peerDependencies:
       bufferutil: ^4.0.1
-      utf-8-validate: ^5.0.2
+      utf-8-validate: '>=5.0.2'
     peerDependenciesMeta:
       bufferutil:
         optional: true
       utf-8-validate:
         optional: true
 
-  ws@8.13.0:
-    resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==}
+  ws@8.17.1:
+    resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
     engines: {node: '>=10.0.0'}
     peerDependencies:
       bufferutil: ^4.0.1
@@ -7061,8 +7061,8 @@ packages:
   xmlchars@2.2.0:
     resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
 
-  xmlhttprequest-ssl@2.0.0:
-    resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==}
+  xmlhttprequest-ssl@2.1.1:
+    resolution: {integrity: sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==}
     engines: {node: '>=0.4.0'}
 
   xtend@4.0.2:
@@ -10363,13 +10363,13 @@ snapshots:
 
   end-or-error@1.0.1: {}
 
-  engine.io-client@6.5.2:
+  engine.io-client@6.6.1:
     dependencies:
       '@socket.io/component-emitter': 3.1.0
       debug: 4.3.4(supports-color@9.3.1)
       engine.io-parser: 5.2.1
-      ws: 8.11.0
-      xmlhttprequest-ssl: 2.0.0
+      ws: 8.17.1
+      xmlhttprequest-ssl: 2.1.1
     transitivePeerDependencies:
       - bufferutil
       - supports-color
@@ -13589,11 +13589,11 @@ snapshots:
       ansi-styles: 6.2.1
       is-fullwidth-code-point: 4.0.0
 
-  socket.io-client@4.7.2:
+  socket.io-client@4.8.0:
     dependencies:
       '@socket.io/component-emitter': 3.1.0
       debug: 4.3.4(supports-color@9.3.1)
-      engine.io-client: 6.5.2
+      engine.io-client: 6.6.1
       socket.io-parser: 4.2.4
     transitivePeerDependencies:
       - bufferutil
@@ -14637,10 +14637,10 @@ snapshots:
 
   ws@7.5.9: {}
 
-  ws@8.11.0: {}
-
   ws@8.13.0: {}
 
+  ws@8.17.1: {}
+
   xdg-basedir@4.0.0: {}
 
   xdg-trashdir@3.1.0:
@@ -14662,7 +14662,7 @@ snapshots:
   xmlchars@2.2.0:
     optional: true
 
-  xmlhttprequest-ssl@2.0.0: {}
+  xmlhttprequest-ssl@2.1.1: {}
 
   xtend@4.0.2: {}
 

+ 0 - 3
public/index.html

@@ -33,9 +33,6 @@
       src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-6064454674933772"
       crossorigin="anonymous"
     ></script>
-    <!-- <script>
-      (adsbygoogle = window.adsbygoogle || []).push({});
-    </script> -->
   </head>
 
   <body>

+ 78 - 0
src/assets/constant.scss

@@ -43,17 +43,95 @@ $header-height: 60px;
   &::-webkit-scrollbar {
     width: 8px;
     height: 0px;
+    border-radius: 0px;
     background: rgba(0, 0, 0, 0);
+  }
+
+  // 滚动条轨道
+  &::-webkit-scrollbar-track {
     border-radius: 0px;
+    background: rgba(0, 0, 0, 0);
+    box-shadow: rgba(0, 0, 0, 0);
+  }
+
+  // 滚动条上的滚动滑块
+  &::-webkit-scrollbar-thumb {
+    border-radius: 3px;
+    background: #e0e0e0;
+  }
+}
+
+// 自定义滚动条:https://developer.mozilla.org/zh-CN/docs/Web/CSS/::-webkit-scrollbar
+%customScrollbarHide {
+  // 整个滚动条
+  &::-webkit-scrollbar {
+    width: 8px;
+    height: 0px;
+    border-radius: 0px;
+    background: rgba(0, 0, 0, 0);
   }
 
   // 滚动条轨道
   &::-webkit-scrollbar-track {
+    border-radius: 0px;
+    background: rgba(0, 0, 0, 0);
     box-shadow: rgba(0, 0, 0, 0);
+  }
+
+  // 滚动条上的滚动滑块
+  &::-webkit-scrollbar-thumb {
+    border-radius: 3px;
+    background: transparent;
+  }
+}
+
+// 自定义横向滚动条:https://developer.mozilla.org/zh-CN/docs/Web/CSS/::-webkit-scrollbar
+%customHengScrollbar {
+  /* 滚动条的宽度 */
+  &::-webkit-scrollbar {
+    width: 8px;
+    height: 4px;
+  }
+
+  /* 滚动条的滑块 */
+  &::-webkit-scrollbar-thumb {
+    background-color: #888;
+    border-radius: 3px;
+  }
+}
+
+// 自定义横向滚动条:https://developer.mozilla.org/zh-CN/docs/Web/CSS/::-webkit-scrollbar
+%customHengScrollbarHide {
+  /* 滚动条的宽度 */
+  &::-webkit-scrollbar {
+    width: 8px;
+    height: 4px;
+  }
+
+  /* 滚动条的滑块 */
+  &::-webkit-scrollbar-thumb {
+    background-color: transparent;
+    border-radius: 3px;
+  }
+}
+
+// 自定义滚动条:https://developer.mozilla.org/zh-CN/docs/Web/CSS/::-webkit-scrollbar
+%customMiniScrollbar {
+  // 整个滚动条
+  &::-webkit-scrollbar {
+    width: 4px;
+    height: 0px;
     border-radius: 0px;
     background: rgba(0, 0, 0, 0);
   }
 
+  // 滚动条轨道
+  &::-webkit-scrollbar-track {
+    border-radius: 0px;
+    background: rgba(0, 0, 0, 0);
+    box-shadow: rgba(0, 0, 0, 0);
+  }
+
   // 滚动条上的滚动滑块
   &::-webkit-scrollbar-thumb {
     border-radius: 3px;

+ 31 - 58
src/constant.ts

@@ -1,20 +1,19 @@
 import { MediaTypeEnum } from '@/interface';
-import { prodDomain } from '@/spec-config';
+import { prodDomain, QINIU_KODO } from '@/spec-config';
 import { LiveRoomTypeEnum } from '@/types/ILiveRoom';
 
 export const QQ_CLIENT_ID = `101958191`;
 export const QQ_OAUTH_URL = `https://graph.qq.com/oauth2.0`;
 export const QQ_REDIRECT_URI = `https://live.${prodDomain}/oauth/qq_login`;
 
-export const WECHAT_GZH_APPID = `wxbd243c01ac5ad1b7`; // 公众号
-export const WECHAT_GZH_OAUTH_URL = `https://open.weixin.qq.com/connect/oauth2/authorize?`;
-
 export const WECHAT_REDIRECT_URI = `https://live.${prodDomain}/oauth/wechat_login`;
 
 export const QRCODE_LOGIN_URI = `https://live.${prodDomain}/qrcodeLogin`;
 
 export const AUTHOR_GITHUB = `https://github.com/galaxy-s10`;
 
+export const PROJECT_NAME = 'billd-live';
+
 export const AUTHOR_INFO = {
   github: 'https://github.com/galaxy-s10',
   wechat: 'shuisheng9905',
@@ -25,21 +24,6 @@ export const appBuildInfo =
   // @ts-ignore
   process.env.BilldHtmlWebpackPlugin as BilldHtmlWebpackPluginLog;
 
-export const WEBSOCKET_URL =
-  process.env.NODE_ENV === 'development'
-    ? `ws://localhost:4300` // `ws://localhost:4300`
-    : `wss://srs-pull.${prodDomain}`;
-
-export const HOME_WEBSOCKET_URL =
-  process.env.NODE_ENV === 'development'
-    ? `ws://localhost:4300/home` // `ws://localhost:4300`
-    : `wss://srs-pull.${prodDomain}/home`;
-
-export const AXIOS_BASEURL =
-  process.env.NODE_ENV === 'development'
-    ? `/api`
-    : `https://live-api.${prodDomain}`;
-
 export const COOKIE_DOMAIN =
   process.env.NODE_ENV === 'development' ? undefined : `.${prodDomain}`;
 
@@ -56,17 +40,6 @@ export const URL_PARAMS = {
   goodsType: 'goodsType',
 };
 
-export const QINIU_RESOURCE = {
-  domain: `resource.${prodDomain}`,
-  url: `https://resource.${prodDomain}`,
-  bucket: 'hssblog',
-  prefix: {
-    'billd-live/image/': 'billd-live/image/',
-    'billd-live/msg-image/': 'billd-live/msg-image/',
-    'billd-live/live-preview/': 'billd-live/live-preview/',
-  },
-};
-
 export const COMMON_URL = {
   apifox: `https://apifox.com/apidoc/shared-c7556b54-17b2-494e-a039-572d83f103ed/`,
   admin: `https://live-admin.${prodDomain}`,
@@ -76,7 +49,7 @@ export const COMMON_URL = {
   download: {
     live: {
       flutter: {
-        android: `${QINIU_RESOURCE.url}/billd-live/download/billd-live-v0.0.4.apk`,
+        android: `${QINIU_KODO.hssblog.url}/billd-live/download/billd-live-v0.0.4.apk`,
         github: 'https://github.com/galaxy-s10/billd-live-flutter',
       },
       reactNative: {
@@ -95,8 +68,8 @@ export const COMMON_URL = {
     },
     desk: {
       electron: {
-        windows: `${QINIU_RESOURCE.url}/billd-desk-electron/download/billd-desk-win-latest.exe`,
-        macOS: `${QINIU_RESOURCE.url}/billd-desk-electron/download/billd-desk-mac-latest.dmg`,
+        windows: `${QINIU_KODO.hssblog.url}/billd-desk-electron/download/billd-desk-win-latest.exe`,
+        macOS: `${QINIU_KODO.hssblog.url}/billd-desk-electron/download/billd-desk-mac-latest.dmg`,
         github: 'https://github.com/galaxy-s10/billd-desk-electron',
       },
       flutter: {
@@ -238,127 +211,127 @@ export const liveRoomTypeEnumMap = {
 
 export const sliderList = [
   {
-    img: `${QINIU_RESOURCE.url}/billd-live/image/a4039f86e5352bcfccaddecc4b72a1df.webp`,
+    img: `${QINIU_KODO.hssblog.url}/billd-live/image/a4039f86e5352bcfccaddecc4b72a1df.webp`,
     txt: 'SRS',
     link: 'https://ossrs.net',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/c3c342f6852706e0b70d011e8753d2d6.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/c3c342f6852706e0b70d011e8753d2d6.webp`,
     txt: 'FFmpeg',
     link: 'https://ffmpeg.org',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/0214acde5f5f5e3caf278ce446cc4414.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/0214acde5f5f5e3caf278ce446cc4414.webp`,
     txt: 'WebRTC',
     link: 'https://github.com/webrtc',
   },
   {
-    img: `${QINIU_RESOURCE.url}/billd-live/image/1277df4371045310acbc4bf2fc0811b8.webp`,
+    img: `${QINIU_KODO.hssblog.url}/billd-live/image/1277df4371045310acbc4bf2fc0811b8.webp`,
     txt: 'Vue3',
     link: 'https://vuejs.org',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/dd907463af7fdec395e5f6d088b0308b.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/dd907463af7fdec395e5f6d088b0308b.webp`,
     txt: 'Pinia',
     link: 'https://pinia.vuejs.org',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/9d54ed9673f2ca4ffc78fc6348f2b736.png`,
+    img: `${QINIU_KODO.hssblog.url}/image/9d54ed9673f2ca4ffc78fc6348f2b736.png`,
     txt: 'TypeScript',
     link: 'https://www.typescriptlang.org',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/a6473eed036e5d35ca2c9f7118c974cd.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/a6473eed036e5d35ca2c9f7118c974cd.webp`,
     txt: 'Vite4',
     link: 'https://vitejs.dev',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/627105f0e5674018cb03c8da036ae5d5.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/627105f0e5674018cb03c8da036ae5d5.webp`,
     txt: 'Webpack5',
     link: 'https://webpack.js.org',
   },
   {
-    img: `${QINIU_RESOURCE.url}/billd-live/image/5304af2ea6864369df3ba895d20e3d14.png`,
+    img: `${QINIU_KODO.hssblog.url}/billd-live/image/5304af2ea6864369df3ba895d20e3d14.png`,
     txt: 'swc',
     link: 'https://swc.rs',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/dd8ffe33c22723381a3664684eaca237.png`,
+    img: `${QINIU_KODO.hssblog.url}/image/dd8ffe33c22723381a3664684eaca237.png`,
     txt: 'esbuild',
     link: 'https://esbuild.github.io',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/f6b9f5cfade1d96634dddb0b89b056be.png`,
+    img: `${QINIU_KODO.hssblog.url}/image/f6b9f5cfade1d96634dddb0b89b056be.png`,
     txt: 'Pnpm',
     link: 'https://pnpm.io',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/89fadfed21f1dd6389dfeb227b3d1ca6.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/89fadfed21f1dd6389dfeb227b3d1ca6.webp`,
     txt: 'naive-ui',
     link: 'https://www.naiveui.com',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/5ce36cab3d6b23974625900dc4cf39a3.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/5ce36cab3d6b23974625900dc4cf39a3.webp`,
     txt: 'Node',
     link: 'https://nodejs.org',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/0dcabc80c616240edc3111450fbf79aa.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/0dcabc80c616240edc3111450fbf79aa.webp`,
     txt: 'socket.io',
     link: 'https://socket.io',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/2009474c455813d487803e2acfcbb4af.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/2009474c455813d487803e2acfcbb4af.webp`,
     txt: 'mysql',
     link: 'https://www.mysql.com/',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/e66deaf779edb2a94e91f9b0f2995f6d.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/e66deaf779edb2a94e91f9b0f2995f6d.webp`,
     txt: 'redis',
     link: 'https://redis.io',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/fd783552a400643c611c62e9200bb429.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/fd783552a400643c611c62e9200bb429.webp`,
     txt: 'Sequelize',
     link: 'https://sequelize.org',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/dce3470845321ce654d09ce811837749.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/dce3470845321ce654d09ce811837749.webp`,
     txt: '腾讯云云直播 CSS',
     link: 'https://cloud.tencent.com/product/css',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/074835fbbaf976992e78bc6a585530e6.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/074835fbbaf976992e78bc6a585530e6.webp`,
     txt: '阿里云轻量服务器',
     link: 'https://www.aliyun.com',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/9a934ebf993f5d3b4146f050f7071518.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/9a934ebf993f5d3b4146f050f7071518.webp`,
     txt: '七牛云对象存储',
     link: 'https://www.qiniu.com',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/e247f6fd39320051d236f3f844b9056f.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/e247f6fd39320051d236f3f844b9056f.webp`,
     txt: '支付宝当面付',
     link: 'https://opendocs.alipay.com/open/194',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/d5eb237bd54bc4e729186115e89e5935.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/d5eb237bd54bc4e729186115e89e5935.webp`,
     txt: 'Docker',
     link: 'https://www.docker.com',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/92a6f3e295634ddd21b6b8034fa3b25f.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/92a6f3e295634ddd21b6b8034fa3b25f.webp`,
     txt: 'Jenkins',
     link: 'https://www.jenkins.io',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/354823b72eb805264c940f5232d824fe.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/354823b72eb805264c940f5232d824fe.webp`,
     txt: 'PM2',
     link: 'https://github.com/Unitech/pm2',
   },
   {
-    img: `${QINIU_RESOURCE.url}/image/d4417f70fa36edbc62b5aa3840cbf25f.webp`,
+    img: `${QINIU_KODO.hssblog.url}/image/d4417f70fa36edbc62b5aa3840cbf25f.webp`,
     txt: 'bilibili',
     link: 'https://www.bilibili.com',
   },

+ 1 - 2
src/hooks/use-login.ts

@@ -8,12 +8,11 @@ import {
   QQ_CLIENT_ID,
   QQ_OAUTH_URL,
   QQ_REDIRECT_URI,
-  WECHAT_GZH_APPID,
-  WECHAT_GZH_OAUTH_URL,
   WECHAT_REDIRECT_URI,
 } from '@/constant';
 import LoginModalCpt from '@/hooks/loginModal/index.vue';
 import { PlatformEnum } from '@/interface';
+import { WECHAT_GZH_APPID, WECHAT_GZH_OAUTH_URL } from '@/spec-config';
 import { useAppStore } from '@/store/app';
 import { useUserStore } from '@/store/user';
 import { clearThirdLoginInfo, setThirdLoginInfo } from '@/utils/cookie';

+ 2 - 2
src/hooks/use-upload.ts

@@ -8,7 +8,7 @@ import {
   fetchUploadMergeChunk,
   fetchUploadProgress,
 } from '@/api/qiniuData';
-import { QINIU_RESOURCE } from '@/constant';
+import { QINIU_KODO } from '@/spec-config';
 import { getHash, splitFile } from '@/utils';
 
 export async function useUpload({
@@ -147,7 +147,7 @@ export async function useQiniuJsUpload({
             console.log('complete', res);
             resolve({
               flag: true,
-              resultUrl: `${QINIU_RESOURCE.url}/${res.key as string}`,
+              resultUrl: `${QINIU_KODO.hssblog.url}/${res.key as string}`,
             });
           },
         });

+ 2 - 1
src/hooks/use-websocket.ts

@@ -4,7 +4,7 @@ import { computed, h, onUnmounted, ref, watch } from 'vue';
 import { useRoute } from 'vue-router';
 
 import { fetchVerifyPkKey } from '@/api/liveRoom';
-import { THEME_COLOR, WEBSOCKET_URL } from '@/constant';
+import { THEME_COLOR } from '@/constant';
 import { useRTCParams } from '@/hooks/use-rtcParams';
 import { useTip } from '@/hooks/use-tip';
 import { useWebRtcLive } from '@/hooks/webrtc/live';
@@ -19,6 +19,7 @@ import {
   WsMessageContentTypeEnum,
 } from '@/interface';
 import router, { routerName } from '@/router';
+import { WEBSOCKET_URL } from '@/spec-config';
 import { useAppStore } from '@/store/app';
 import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';

+ 2 - 1
src/locales/zh/layout.ts

@@ -1,3 +1,4 @@
+import { PROJECT_NAME } from '@/constant';
 import { nameSpaceWrap } from '@/locales/util';
 
 export default nameSpaceWrap('layout', {
@@ -33,7 +34,7 @@ export default nameSpaceWrap('layout', {
   guide: '快速上手',
   apiDoc: '接口文档',
   bilibiliTutorial: 'b站教程',
-  vipCourses: 'billd-live付费课',
+  vipCourses: `${PROJECT_NAME}付费课`,
 
   faq: '常见问题',
   team: '团队',

+ 62 - 0
src/spec-config.ts

@@ -1 +1,63 @@
 export const prodDomain = 'hsslive.cn';
+export const headTitle = prodDomain.split('.')[0];
+
+export const QQ_CLIENT_ID = '101934585';
+export const QQ_OAUTH_URL =
+  'https://graph.qq.com/oauth2.0/authorize?response_type=code&';
+
+export const GITHUB_CLIENT_ID = '8c2c07b574ae70ecfa9d';
+export const GITHUB_OAUTH_URL = 'https://github.com/login/oauth/authorize?';
+
+export const WECHAT_GZH_APPID = `wxbd243c01ac5ad1b7`; // 公众号
+export const WECHAT_GZH_OAUTH_URL = `https://open.weixin.qq.com/connect/oauth2/authorize?`;
+
+export const TENCENTCLOUD_APPID = 1324073273; // 腾讯云APPID
+export const TENCENTCLOUD_COS = {
+  [`res-${TENCENTCLOUD_APPID}`]: {
+    url: `https://res.${prodDomain}`,
+    Bucket: `res-${TENCENTCLOUD_APPID}`,
+    Region: 'ap-mumbai',
+    StorageClass: 'STANDARD',
+    prefix: {
+      'common/': 'common/',
+      'images/': 'images/',
+      'msg-images/': 'msg-images/',
+    },
+  },
+};
+
+export const QINIU_KODO = {
+  hssblog: {
+    domain: `resource.${prodDomain}`,
+    url: `http://resource.${prodDomain}/`,
+    bucket: 'hssblog',
+    prefix: {
+      'billd-live/image/': 'billd-live/image/',
+      'billd-live/msg-image/': 'billd-live/msg-image/',
+      'billd-live/live-preview/': 'billd-live/live-preview/',
+    },
+  },
+  'hss-backup': {
+    domain: `backup.${prodDomain}`,
+    url: `http://backup.${prodDomain}/`,
+    bucket: 'hss-backup',
+    prefix: {
+      'billd-live/mysql/': 'billd-live/mysql/',
+    },
+  },
+};
+
+export const WEBSOCKET_URL =
+  process.env.NODE_ENV === 'development'
+    ? `ws://localhost:4300` // `ws://localhost:4300`
+    : `wss://srs-pull.${prodDomain}`;
+
+export const AXIOS_BASEURL =
+  process.env.NODE_ENV === 'development'
+    ? `/api`
+    : `https://live-api.${prodDomain}`;
+
+export enum REDIS_DATABASE {
+  blog,
+  live,
+}

+ 23 - 6
src/utils/google-ad.ts

@@ -1,12 +1,29 @@
 export const initAdsbygoogle = () => {
   try {
-    // @ts-ignore
-    if (!window.adsbygoogle) {
+    window.onload = () => {
       // @ts-ignore
-      window.adsbygoogle = [];
-    }
-    // @ts-ignore
-    window.adsbygoogle.push({});
+      if (!window.adsbygoogle) {
+        // @ts-ignore
+        window.adsbygoogle = [];
+      }
+      // @ts-ignore
+      // if (!window.adsbygoogle.loaded) {
+      // @ts-ignore
+      window.adsbygoogle?.push?.({});
+      // }
+    };
+
+    // const adsenseUnitLength = document.getElementsByClassName('adsbygoogle');
+    // for (let i = 0; i < adsenseUnitLength.length; i += 1) {
+    //   // @ts-ignore
+    //   if (window.adsbygoogle) {
+    //     // @ts-ignore
+    //     // if (!window.adsbygoogle.loaded) {
+    //     // @ts-ignore
+    //     (adsbygoogle = window.adsbygoogle || []).push({});
+    //     // }
+    //   }
+    // }
   } catch (error) {
     console.error('initAdsbygoogle错误');
     console.log(error);

+ 0 - 10
src/utils/index.ts

@@ -20,16 +20,6 @@ export function handleStrEllipsis(str: string, maxlen: number) {
   }
 }
 
-export const googleAd = () => {
-  const el = document.createElement('script');
-  el.src =
-    'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-6064454674933772';
-  const head = document.getElementsByTagName('head')[0];
-  el.async = true;
-  el.crossOrigin = 'anonymous';
-  head.appendChild(el);
-};
-
 /**
  * music,该曲目应被视为包含音乐。设置该值时 MediaStreamTrack.kind的值必须为"audio"。
  * speech,该轨道应被视为包含语音数据。设置该值时 MediaStreamTrack.kind的值必须为"audio"。

+ 5 - 5
src/utils/network/webSocket.ts

@@ -3,7 +3,7 @@ import { Socket, io } from 'socket.io-client';
 import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';
 import {
-  IWsFormat,
+  IReqWsFormat,
   WsConnectStatusEnum,
   WsMsgTypeEnum,
 } from '@/types/websocket';
@@ -69,11 +69,11 @@ export class WebSocketClass {
     }
     prettierSendWsMsg({ requestId, msgType, data });
     const userStore = useUserStore();
-    const sendData: IWsFormat<any> = {
+    const sendData: IReqWsFormat<any> = {
       request_id: requestId,
-      socket_id: this.socketIo.id,
-      user_info: userStore.userInfo,
-      user_token: userStore.token || undefined,
+      socket_id: this.socketIo.id || '',
+      user_info: userStore.userInfo || {},
+      user_token: userStore.token || '',
       time: +new Date(),
       data: data || {},
     };

+ 1 - 1
src/utils/request.ts

@@ -1,6 +1,6 @@
 import axios, { Axios, AxiosRequestConfig } from 'axios';
 
-import { AXIOS_BASEURL } from '@/constant';
+import { AXIOS_BASEURL } from '@/spec-config';
 import { useUserStore } from '@/store/user';
 import { getToken } from '@/utils/localStorage/user';
 

+ 4 - 2
src/views/about/author/index.vue

@@ -1,7 +1,9 @@
 <template>
   <div class="author-wrap">
     <h1 class="title">作者</h1>
-    <p class="desc">主业前端开发,兴趣使然,故业余时间开发了billd-live。</p>
+    <p class="desc">
+      主业前端开发,兴趣使然,故业余时间开发了{{ PROJECT_NAME }}。
+    </p>
     <div class="hr"></div>
     <div class="info">
       <div class="title">微信二维码</div>
@@ -17,7 +19,7 @@
 </template>
 
 <script lang="ts" setup>
-import { AUTHOR_INFO } from '@/constant';
+import { AUTHOR_INFO, PROJECT_NAME } from '@/constant';
 </script>
 
 <style lang="scss" scoped>

+ 8 - 6
src/views/about/group/index.vue

@@ -8,7 +8,7 @@
     <div class="content">
       <p class="red">进群硬性门槛</p>
       <p>
-        1. 本地运行billd-live项目的前台:
+        1. 本地运行{{ PROJECT_NAME }}项目的前台:
         <span
           class="link"
           @click="openToTarget('https://github.com/galaxy-s10/billd-live')"
@@ -17,7 +17,7 @@
         </span>
       </p>
       <p>
-        2. 本地运行billd-live项目的后台:
+        2. 本地运行{{ PROJECT_NAME }}项目的后台:
         <span
           class="link"
           @click="
@@ -28,7 +28,7 @@
         </span>
       </p>
       <p>
-        3. 本地运行billd-live项目的后端:
+        3. 本地运行{{ PROJECT_NAME }}项目的后端:
         <span
           class="link"
           @click="
@@ -51,7 +51,9 @@
       <p>
         5.
         如果你想进群,那就先运行起来项目,不要求正常的运行起来,但起码要运行。然后截图发我确认。
-        微信群的初衷是希望让对billd-live感兴趣且热衷开源的人有个交流的地方,
+        微信群的初衷是希望让对{{
+          PROJECT_NAME
+        }}感兴趣且热衷开源的人有个交流的地方,
         如果连运行都懒得运行,那么很抱歉,道不同不相为谋。
       </p>
     </div>
@@ -74,7 +76,7 @@
         </span>
       </p>
       <p>
-        2. 付费:考虑billd-live付费课:
+        2. 付费:考虑{{ PROJECT_NAME }}付费课:
         <span
           class="link"
           @click="openToTarget(COMMON_URL.payCoursesArticle)"
@@ -114,7 +116,7 @@
 <script lang="ts" setup>
 import { openToTarget } from 'billd-utils';
 
-import { AUTHOR_INFO, COMMON_URL } from '@/constant';
+import { AUTHOR_INFO, COMMON_URL, PROJECT_NAME } from '@/constant';
 import { getHostnameUrl } from '@/utils';
 </script>
 

+ 7 - 3
src/views/about/team/index.vue

@@ -2,14 +2,18 @@
   <div class="team-wrap">
     <h1 class="title">认识团队</h1>
     <p class="desc">
-      billd-live目前是个人开发,暂时没有贡献者,但以后可能会有,以下是目前部分团队成员的个人信息。
+      {{
+        PROJECT_NAME
+      }}目前是个人开发,暂时没有贡献者,但以后可能会有,以下是目前部分团队成员的个人信息。
     </p>
     <div class="hr"></div>
     <div class="core-team">
       <div class="info">
         <h2 class="title">核心团队成员</h2>
         <div class="desc">
-          核心团队成员是那些积极参与维护一个或多个核心项目的人。他们对billd-live
+          核心团队成员是那些积极参与维护一个或多个核心项目的人。他们对{{
+            PROJECT_NAME
+          }}
           的生态系统做出了重大贡献,并对项目及其用户的成功做出了长期的承诺。
         </div>
       </div>
@@ -129,7 +133,7 @@ import {
 import { openToTarget } from 'billd-utils';
 import { ref } from 'vue';
 
-import { URL_PARAMS } from '@/constant';
+import { PROJECT_NAME, URL_PARAMS } from '@/constant';
 import { GoodsTypeEnum } from '@/interface';
 import router, { routerName } from '@/router';
 import { prodDomain } from '@/spec-config';

+ 75 - 71
src/views/doc/ad/index.vue

@@ -2,7 +2,9 @@
   <div class="ad-wrap">
     <h1 class="title">广告位招租</h1>
     <h3 class="title">
-      billd-live服务器:阿里云轻量服务器:2核cpu、2GB内存、30M带宽(香港)
+      {{
+        PROJECT_NAME
+      }}服务器:阿里云轻量服务器:2核cpu、2GB内存、30M带宽(香港)
     </h3>
 
     <div class="ad-list">
@@ -38,77 +40,79 @@
 import { openToTarget } from 'billd-utils';
 import { ref } from 'vue';
 
+import { PROJECT_NAME } from '@/constant';
+
 const list = ref([
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/tencent-1.jpg'),
-  //   name: '【腾讯云】个人开发者 买赠福利专区 买即送 个人开发者专享免费服务器3个月!',
-  //   list: [
-  //     '【腾讯云】:1年轻量服务器 2核cpu、2G内存、4M带宽、50G系统盘(上海/广州/北京),132元!',
-  //     '【腾讯云】:1年轻量服务器 2核cpu、4G内存、5M带宽、60G系统盘(上海/广州/北京),198元!',
-  //   ],
-  //   url: 'https://cloud.tencent.com/act/cps/redirect?redirect=35916&cps_key=ebe55ad4d940d688bcde548b101dff5f',
-  // },
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/tencent-2.png'),
-  //   name: '【腾讯云】爆品抢先购,预热专属折上折券限时领!',
-  //   list: [
-  //     '【腾讯云】:1年轻量服务器 2核cpu、2G内存、3M带宽、40G系统盘(上海/广州/北京),95元!',
-  //     '【腾讯云】:1年轻量服务器 2核cpu、4G内存、5M带宽、60G系统盘(上海/广州/北京),168元!',
-  //     '【腾讯云】:3年轻量服务器 2核cpu、2G内存、4M带宽、50G系统盘(上海/广州/北京),396元!',
-  //     '【腾讯云】:3年轻量服务器 2核cpu、4G内存、5M带宽、60G系统盘(上海/广州/北京),628元!',
-  //   ],
-  //   url: 'https://cloud.tencent.com/act/cps/redirect?redirect=35864&cps_key=ebe55ad4d940d688bcde548b101dff5f',
-  // },
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/tencent-3.jpg'),
-  //   name: '【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。',
-  //   list: [
-  //     '【腾讯云】满200减100,仅用于非促销新购云服务器、MySQL数据库',
-  //     '【腾讯云】满500减250,仅用于非促销新购云服务器、MySQL数据库',
-  //     '【腾讯云】满1000减500,仅用于非促销新购云服务器、MySQL数据库',
-  //     '【腾讯云】满2000减1000,仅用于非促销新购云服务器、MySQL数据库',
-  //   ],
-  //   url: 'https://cloud.tencent.com/act/cps/redirect?redirect=35834&cps_key=ebe55ad4d940d688bcde548b101dff5f',
-  // },
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/aliyun-1.png'),
-  //   name: '云小站特惠超底价',
-  //   url: 'https://www.aliyun.com/minisite/goods?userCode=41m2k6bt',
-  // },
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/aliyun-2.jpg'),
-  //   name: '云服务器t6 2核2G低至10.14元/月',
-  //   url: 'https://www.aliyun.com/daily-act/ecs/activity_share?userCode=41m2k6bt',
-  // },
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/qiniu-1.jpg'),
-  //   name: '新人免费 CDN(全球2000+节点无盲区覆盖,注册即可免费使用)',
-  //   url: 'https://s.qiniu.com/Q7zqeq',
-  // },
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/qiniu-2.jpg'),
-  //   name: '对象存储新人好礼(10年专注云存储,注册即可免费使用)',
-  //   url: 'https://s.qiniu.com/iQR7Jz',
-  // },
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/qiniu-3.jpg'),
-  //   name: '新人免费试用(多款云产品长期免费使用,注册即享超值赠送)',
-  //   url: 'https://s.qiniu.com/JnIbyq',
-  // },
-  // {
-  //   // eslint-disable-next-line
-  //   cover: require('@/assets/img/ad/qiniu-4.jpg'),
-  //   name: '新人免费云主机(注册免费领取 4核8G 云服务器,享免费数据迁移服务)',
-  //   url: 'https://s.qiniu.com/B3i63y',
-  // },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/tencent-1.jpg'),
+    name: '【腾讯云】个人开发者 买赠福利专区 买即送 个人开发者专享免费服务器3个月!',
+    list: [
+      '【腾讯云】:1年轻量服务器 2核cpu、2G内存、4M带宽、50G系统盘(上海/广州/北京),132元!',
+      '【腾讯云】:1年轻量服务器 2核cpu、4G内存、5M带宽、60G系统盘(上海/广州/北京),198元!',
+    ],
+    url: 'https://cloud.tencent.com/act/cps/redirect?redirect=35916&cps_key=ebe55ad4d940d688bcde548b101dff5f',
+  },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/tencent-2.png'),
+    name: '【腾讯云】爆品抢先购,预热专属折上折券限时领!',
+    list: [
+      '【腾讯云】:1年轻量服务器 2核cpu、2G内存、3M带宽、40G系统盘(上海/广州/北京),95元!',
+      '【腾讯云】:1年轻量服务器 2核cpu、4G内存、5M带宽、60G系统盘(上海/广州/北京),168元!',
+      '【腾讯云】:3年轻量服务器 2核cpu、2G内存、4M带宽、50G系统盘(上海/广州/北京),396元!',
+      '【腾讯云】:3年轻量服务器 2核cpu、4G内存、5M带宽、60G系统盘(上海/广州/北京),628元!',
+    ],
+    url: 'https://cloud.tencent.com/act/cps/redirect?redirect=35864&cps_key=ebe55ad4d940d688bcde548b101dff5f',
+  },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/tencent-3.jpg'),
+    name: '【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。',
+    list: [
+      '【腾讯云】满200减100,仅用于非促销新购云服务器、MySQL数据库',
+      '【腾讯云】满500减250,仅用于非促销新购云服务器、MySQL数据库',
+      '【腾讯云】满1000减500,仅用于非促销新购云服务器、MySQL数据库',
+      '【腾讯云】满2000减1000,仅用于非促销新购云服务器、MySQL数据库',
+    ],
+    url: 'https://cloud.tencent.com/act/cps/redirect?redirect=35834&cps_key=ebe55ad4d940d688bcde548b101dff5f',
+  },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/aliyun-1.png'),
+    name: '云小站特惠超底价',
+    url: 'https://www.aliyun.com/minisite/goods?userCode=41m2k6bt',
+  },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/aliyun-2.jpg'),
+    name: '云服务器t6 2核2G低至10.14元/月',
+    url: 'https://www.aliyun.com/daily-act/ecs/activity_share?userCode=41m2k6bt',
+  },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/qiniu-1.jpg'),
+    name: '新人免费 CDN(全球2000+节点无盲区覆盖,注册即可免费使用)',
+    url: 'https://s.qiniu.com/Q7zqeq',
+  },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/qiniu-2.jpg'),
+    name: '对象存储新人好礼(10年专注云存储,注册即可免费使用)',
+    url: 'https://s.qiniu.com/iQR7Jz',
+  },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/qiniu-3.jpg'),
+    name: '新人免费试用(多款云产品长期免费使用,注册即享超值赠送)',
+    url: 'https://s.qiniu.com/JnIbyq',
+  },
+  {
+    // eslint-disable-next-line
+    // cover: require('@/assets/img/ad/qiniu-4.jpg'),
+    name: '新人免费云主机(注册免费领取 4核8G 云服务器,享免费数据迁移服务)',
+    url: 'https://s.qiniu.com/B3i63y',
+  },
 ]);
 </script>
 

+ 19 - 15
src/views/doc/faq/index.vue

@@ -5,7 +5,7 @@
       <div class="hr"></div>
       <div class="list">
         <div class="item">
-          <h2>如何本地运行billd-live?</h2>
+          <h2>如何本地运行{{ PROJECT_NAME }}?</h2>
           <p>
             一: 仔细看完
             <span
@@ -14,7 +14,7 @@
                 openToTarget('https://github.com/galaxy-s10/billd-live#readme')
               "
             >
-              billd-live的README
+              {{ PROJECT_NAME }}的README
             </span>
           </p>
           <p>
@@ -29,9 +29,9 @@
         </div>
         <div class="hr"></div>
         <div class="item">
-          <h2>billd-live是什么?</h2>
+          <h2>{{ PROJECT_NAME }}是什么?</h2>
           <p>
-            billd-live
+            {{ PROJECT_NAME }}
             是一个web端的直播平台,目前支持使用WebRTC、SRS、腾讯云云直播进行直播:
           </p>
           <p>- 原生WebRTC一对多直播</p>
@@ -42,9 +42,9 @@
         </div>
         <div class="hr"></div>
         <div class="item">
-          <h2>谁在维护billd-live?</h2>
+          <h2>谁在维护{{ PROJECT_NAME }}?</h2>
           <p>
-            billd-live 是由
+            {{ PROJECT_NAME }}是由
             <a
               :href="AUTHOR_INFO.github"
               target="_blank"
@@ -57,8 +57,12 @@
         </div>
         <div class="hr"></div>
         <div class="item">
-          <h2>billd-live使用了什么技术栈?</h2>
-          <p>billd-live是一个偏前端的全栈项目,几乎所有技术栈都是前端相关。</p>
+          <h2>{{ PROJECT_NAME }}使用了什么技术栈?</h2>
+          <p>
+            {{
+              PROJECT_NAME
+            }}是一个偏前端的全栈项目,几乎所有技术栈都是前端相关。
+          </p>
           <p>
             前端相关:Typescript、Vue3、<a
               target="_blank"
@@ -91,7 +95,7 @@
         </div>
         <div class="hr"></div>
         <div class="item">
-          <h2>obs/ffmpeg推流到billd-live失败</h2>
+          <h2>obs/ffmpeg推流到{{ PROJECT_NAME }}失败</h2>
           <p>
             服务器性能有限,限制了推流码率为:<b>3000kbps</b>,超过则会导致推流失败!
           </p>
@@ -105,11 +109,11 @@
     </div>
     <div class="aside">
       <div class="title">本页目录</div>
-      <div class="item">如何本地运行billd-live?</div>
-      <div class="item">billd-live是什么?</div>
-      <div class="item">谁在维护billd-live?</div>
-      <div class="item">billd-live使用了什么技术栈?</div>
-      <div class="item">obs/ffmpeg推流到billd-live失败</div>
+      <div class="item">如何本地运行{{ PROJECT_NAME }}?</div>
+      <div class="item">{{ PROJECT_NAME }}是什么?</div>
+      <div class="item">谁在维护{{ PROJECT_NAME }}?</div>
+      <div class="item">{{ PROJECT_NAME }}使用了什么技术栈?</div>
+      <div class="item">obs/ffmpeg推流到{{ PROJECT_NAME }}失败</div>
       <div class="item">如何参与贡献?</div>
     </div>
   </div>
@@ -118,7 +122,7 @@
 <script lang="ts" setup>
 import { openToTarget } from 'billd-utils';
 
-import { AUTHOR_INFO, COMMON_URL } from '@/constant';
+import { AUTHOR_INFO, COMMON_URL, PROJECT_NAME } from '@/constant';
 </script>
 
 <style lang="scss" scoped>

+ 566 - 0
src/views/doc/privatizationDeployment/index.vue

@@ -0,0 +1,566 @@
+<template>
+  <div class="privatizationDeployment-wrap">
+    <h2 class="title">
+      <div
+        v-for="(item, index) in detail[currentTab].slogan"
+        :key="index"
+      >
+        {{ item }}
+      </div>
+    </h2>
+    <div class="tab">
+      <div
+        v-for="(item, index) in tab"
+        :key="index"
+        class="item"
+        :class="{ active: item.id === currentTab }"
+        @click="currentTab = item.id"
+      >
+        {{ item.txt }}
+      </div>
+    </div>
+    <div class="list">
+      <div
+        class="item"
+        :class="{ [item['color']]: 1 }"
+        v-for="(item, index) in detail[currentTab].list"
+        :key="index"
+      >
+        <div class="name">{{ item.name }}</div>
+        <div class="desc">{{ item.desc }}</div>
+        <div class="price">
+          <span class="t1">{{ item.price.left }}</span>
+          <span class="t2">{{ item.price.center }}</span>
+          <span class="t3">{{ item.price.right }}</span>
+        </div>
+        <div class="feat">
+          <div
+            v-if="item.tip !== ''"
+            class="feat-item tip"
+          >
+            {{ item.tip }}
+          </div>
+          <div
+            class="feat-item"
+            v-for="(iten, indey) in item.feat"
+            :key="indey"
+          >
+            <div
+              :class="{
+                done: iten.status === 'done',
+                todo: iten.status === 'todo',
+              }"
+            ></div>
+            <div class="txt">{{ iten.txt }}</div>
+          </div>
+        </div>
+        <div
+          class="btn"
+          @click="handleClick(item.btn)"
+        >
+          {{ item.btn.txt }}
+        </div>
+      </div>
+    </div>
+  </div>
+  <n-modal v-model:show="showContach">
+    <n-card
+      style="width: 400px"
+      title="联系方式"
+      role="dialog"
+      closable
+      @close="showContach = false"
+    >
+      <div>
+        <div>微信:</div>
+        <img
+          src="@/assets/img/my-wechat.webp"
+          alt=""
+          style="width: 300px"
+        />
+        <div>微信号: {{ AUTHOR_INFO.wechat }}</div>
+        <div>qq:{{ AUTHOR_INFO.qq }}</div>
+        <p>添加时请备注:私有化部署+用途</p>
+      </div>
+    </n-card>
+  </n-modal>
+</template>
+
+<script lang="ts" setup>
+import { openToTarget } from 'billd-utils';
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { AUTHOR_INFO, COMMON_URL, PROJECT_NAME } from '@/constant';
+import { routerName } from '@/router';
+
+const router = useRouter();
+const showContach = ref(false);
+const currentTab = ref<'personal' | 'openSource' | 'customized' | string>(
+  'openSource'
+);
+
+const tab = ref([
+  {
+    id: 'personal',
+    txt: '个人版',
+  },
+  {
+    id: 'openSource',
+    txt: '开源版',
+  },
+  {
+    id: 'customized',
+    txt: '定制版',
+  },
+]);
+
+const detail = ref({
+  personal: {
+    slogan: ['欢迎使用billd直播~'],
+    list: [
+      {
+        color: 'blue',
+        name: 'VIP',
+        desc: '适用于个人用户简单体验',
+        price: {
+          left: '¥',
+          center: '0',
+          right: '',
+        },
+        tip: '',
+        feat: [
+          {
+            status: 'done',
+            txt: 'SRS直播',
+          },
+          {
+            status: 'done',
+            txt: '打PK直播',
+          },
+          {
+            status: 'done',
+            txt: 'WebRTC直播',
+          },
+          {
+            status: 'done',
+            txt: 'WebRTC会议',
+          },
+        ],
+        btn: {
+          type: 'push',
+          link: routerName.push,
+          txt: '免费体验',
+        },
+      },
+      {
+        color: 'green',
+        name: 'SVIP',
+        desc: '适用于个人用户中度体验',
+        price: {
+          left: '¥',
+          center: '10',
+          right: '元/月',
+        },
+        tip: '涵盖VIP全部功能',
+        feat: [
+          {
+            status: 'done',
+            txt: '转推b站',
+          },
+          {
+            status: 'done',
+            txt: '转推虎牙',
+          },
+          {
+            status: 'done',
+            txt: '去广告',
+          },
+        ],
+        btn: {
+          type: 'toast',
+          link: '即将上线~',
+          txt: '立即购买',
+        },
+      },
+      {
+        color: 'orange',
+        name: 'ADMIN',
+        desc: '适用于个人用户深度体验',
+        price: {
+          left: '¥',
+          center: '50',
+          right: '元/月',
+        },
+        tip: '涵盖SVIP全部功能',
+        feat: [
+          {
+            status: 'done',
+            txt: 'Msr直播',
+          },
+          {
+            status: 'done',
+            txt: '腾讯云直播(CDN)',
+          },
+          {
+            status: 'done',
+            txt: '腾讯云打PK(CDN)',
+          },
+        ],
+        btn: {
+          type: 'toast',
+          link: '即将上线~',
+          txt: '立即购买',
+        },
+      },
+    ],
+  },
+  openSource: {
+    slogan: ['billd直播开源至今,累计收获1k+ star', '值得信赖,欢迎部署~'],
+    list: [
+      {
+        color: 'blue',
+        name: 'Github',
+        desc: '适用于个人学习/测试用途',
+        price: {
+          left: '¥',
+          center: '0',
+          right: '',
+        },
+        tip: '',
+        feat: [
+          {
+            status: 'done',
+            txt: '源码开源,自行部署',
+          },
+          {
+            status: 'done',
+            txt: '直播前台(Web)',
+          },
+          {
+            status: 'done',
+            txt: '直播后台(Web)',
+          },
+          {
+            status: 'done',
+            txt: '直播安卓端(Flutter)',
+          },
+          {
+            status: 'todo',
+            txt: '直播苹果端(Flutter)',
+          },
+          {
+            status: 'todo',
+            txt: '直播客户端(Electron)',
+          },
+        ],
+        btn: {
+          type: 'link',
+          link: 'https://github.com/galaxy-s10/billd-live',
+          txt: '立即部署',
+        },
+      },
+      {
+        color: 'green',
+        name: '私有化部署',
+        desc: '适用于个人/企业自建直播平台',
+        price: {
+          left: '¥',
+          center: 'XXXX',
+          right: '起',
+        },
+        tip: '涵盖Github全部/部分功能',
+        feat: [
+          {
+            status: 'done',
+            txt: '无门槛,全程专人负责部署',
+          },
+          {
+            status: 'done',
+            txt: '本地服务器部署',
+          },
+          {
+            status: 'done',
+            txt: '快速上线',
+          },
+        ],
+        btn: {
+          type: 'showContact',
+          link: '',
+          txt: '立即咨询',
+        },
+      },
+    ],
+  },
+  customized: {
+    slogan: ['billd直播支持定制化', '立即定制自己的个性化直播间~'],
+    list: [
+      {
+        color: 'blue',
+        name: '在线咨询',
+        desc: '咨询/答疑服务',
+        price: {
+          left: '¥',
+          center: '50',
+          right: '元/小时',
+        },
+        tip: '',
+        feat: [
+          {
+            status: 'done',
+            txt: '一对一解答',
+          },
+        ],
+        btn: {
+          type: 'showContact',
+          link: '',
+          txt: '立即咨询',
+        },
+      },
+      {
+        color: 'green',
+        name: '付费课程',
+        desc: '适用于前端/音视频小白',
+        price: {
+          left: '¥',
+          center: '399',
+          right: '元',
+        },
+        tip: '',
+        feat: [
+          {
+            status: 'done',
+            txt: '一对一解答(4小时)',
+          },
+          {
+            status: 'done',
+            txt: '能够搭建最基础的直播间',
+          },
+          {
+            status: 'done',
+            txt: '单独的代码仓库',
+          },
+          {
+            status: 'done',
+            txt: '视频讲解',
+          },
+          {
+            status: 'done',
+            txt: `${PROJECT_NAME}付费课微信群`,
+          },
+        ],
+        btn: {
+          type: 'link',
+          link: COMMON_URL.payCoursesArticle,
+          txt: '了解详情',
+        },
+      },
+      {
+        color: 'orange',
+        name: '私有化部署',
+        desc: '适用于个人/企业自建直播平台',
+        price: {
+          left: '¥',
+          center: 'XXXX',
+          right: '起',
+        },
+        tip: '',
+        feat: [
+          {
+            status: 'done',
+            txt: '无门槛,全程专人负责部署',
+          },
+          {
+            status: 'done',
+            txt: '本地服务器部署',
+          },
+          {
+            status: 'done',
+            txt: '快速上线',
+          },
+          {
+            status: 'done',
+            txt: '定制化功能',
+          },
+        ],
+        btn: {
+          type: 'showContact',
+          link: '',
+          txt: '立即咨询',
+        },
+      },
+    ],
+  },
+});
+
+function handleClick(item) {
+  if (item.type === 'link') {
+    openToTarget(item.link);
+  } else if (item.type === 'push') {
+    const url = router.resolve({
+      name: item.link,
+    });
+    openToTarget(url.href);
+  } else if (item.type === 'buy') {
+    console.log('buy');
+  } else if (item.type === 'toast') {
+    window.$message.info(item.link);
+  } else if (item.type === 'showContact') {
+    showContach.value = true;
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.privatizationDeployment-wrap {
+  height: calc(100vh - $layout-head-h);
+  background-color: #f4f8ff;
+  .title {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    box-sizing: border-box;
+    margin: 0 auto;
+    width: 1200px;
+    height: 180px;
+    // background-color: red;
+    text-align: center;
+    font-size: 40px;
+  }
+  .tab {
+    display: flex;
+    justify-content: center;
+    margin: 0 auto;
+    padding: 8px 0;
+    width: 320px;
+    border-radius: 40px;
+    background: white;
+    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
+
+    user-select: none;
+    .item {
+      padding: 4px 25px;
+      border-radius: 40px;
+      color: #686e88;
+      font-weight: 700;
+      font-size: 16px;
+      cursor: pointer;
+      &.active {
+        background-color: $theme-color-gold;
+        color: white;
+      }
+    }
+  }
+  .list {
+    display: flex;
+    justify-content: center;
+    margin: 50px auto 0;
+    width: 1200px;
+    .item {
+      box-sizing: border-box;
+      margin: 0 10px;
+      padding: 20px 20px;
+      width: 240px;
+      // border: 1px solid #dde6ed;
+      border-radius: 2px;
+      border-top-left-radius: 4px;
+      border-top-right-radius: 4px;
+      background-color: white;
+      font-size: 14px;
+
+      &.blue {
+        border-top: 7px solid #38c0ff;
+      }
+      &.green {
+        border-top: 7px solid #30d1aa;
+      }
+      &.orange {
+        border-top: 7px solid #ffbd33;
+      }
+      .name {
+        padding: 10px 0 0;
+        height: 40px;
+        text-align: center;
+        font-size: 30px;
+        line-height: 1;
+      }
+      .desc {
+        margin-top: 10px;
+        height: 40px;
+        color: #88898d;
+        text-align: center;
+        // background-color: red;
+      }
+      .price {
+        display: flex;
+        align-items: flex-end;
+        justify-content: center;
+        height: 45px;
+        color: #88898d;
+        text-align: center;
+        .t1 {
+          color: #272727;
+          font-weight: 600;
+          font-size: 16px;
+        }
+        .t2 {
+          color: #272727;
+          font-size: 40px;
+          line-height: 36px;
+        }
+        .t3 {
+          color: #2c2c2c;
+          font-size: 16px;
+        }
+        // background-color: red;
+      }
+      .feat {
+        margin-top: 30px;
+        height: 200px;
+        .feat-item {
+          display: flex;
+          align-items: center;
+          margin-bottom: 10px;
+          &.tip {
+            color: #88898d;
+          }
+          .todo,
+          .done {
+            margin-right: 10px;
+            width: 18px;
+            height: 18px;
+            text-align: center;
+          }
+          .todo {
+            position: relative;
+            &::after {
+              color: #ffc049;
+              content: '-';
+              text-align: center;
+              font-size: 16px;
+            }
+          }
+          .done {
+            @include setBackground('@/assets/img/check.png');
+          }
+        }
+      }
+      .btn {
+        margin: 0 auto;
+        padding: 8px 0;
+        width: 160px;
+        border: 1px solid $theme-color-gold;
+        border-radius: 4px;
+        color: $theme-color-gold;
+        text-align: center;
+        font-size: 16px;
+        cursor: pointer;
+        &:hover {
+          background-color: $theme-color-gold;
+          color: white;
+        }
+      }
+    }
+  }
+}
+</style>

+ 3 - 3
src/views/home/index.vue

@@ -465,10 +465,10 @@ function changeLiveRoom(item: ILive) {
 async function getLiveRoomList() {
   try {
     const res = await fetchLiveList({
-      orderName: 'created_at',
-      orderBy: 'desc',
+      // orderName: 'created_at',
+      // orderBy: 'desc',
       childOrderName: 'priority,name',
-      childOrderBy: 'asc,asc',
+      childOrderBy: 'desc,asc',
       // status: 0,
       // is_show: 0,
       // cdn: 0,

+ 2 - 2
src/views/privatizationDeployment/index.vue

@@ -91,7 +91,7 @@ import { openToTarget } from 'billd-utils';
 import { ref } from 'vue';
 import { useRouter } from 'vue-router';
 
-import { AUTHOR_INFO, COMMON_URL } from '@/constant';
+import { AUTHOR_INFO, COMMON_URL, PROJECT_NAME } from '@/constant';
 import { routerName } from '@/router';
 
 const router = useRouter();
@@ -346,7 +346,7 @@ const detail = ref({
           },
           {
             status: 'done',
-            txt: 'billd-live付费课微信群',
+            txt: `${PROJECT_NAME}付费课微信群`,
           },
         ],
         btn: {

+ 3 - 2
src/views/pull/index.vue

@@ -451,7 +451,7 @@ import { fetchGoodsList } from '@/api/goods';
 import { fetchLiveRoomOnlineUser } from '@/api/live';
 import { fetchFindLiveRoom, fetchLiveRoomBilibili } from '@/api/liveRoom';
 import { fetchGetWsMessageList } from '@/api/wsMessage';
-import { liveRoomTypeEnumMap, QINIU_RESOURCE } from '@/constant';
+import { liveRoomTypeEnumMap } from '@/constant';
 import { emojiArray } from '@/emoji';
 import { commentAuthTip, loginTip } from '@/hooks/use-login';
 import { useFullScreen, usePictureInPicture } from '@/hooks/use-play';
@@ -471,6 +471,7 @@ import {
   WsMessageMsgIsVerifyEnum,
 } from '@/interface';
 import router, { routerName } from '@/router';
+import { QINIU_KODO } from '@/spec-config';
 import { useAppStore } from '@/store/app';
 import { useNetworkStore } from '@/store/network';
 import { useUserStore } from '@/store/user';
@@ -890,7 +891,7 @@ async function uploadChange() {
       msgLoading.value = true;
       msgIsFile.value = WsMessageMsgIsFileEnum.yes;
       const res = await useQiniuJsUpload({
-        prefix: QINIU_RESOURCE.prefix['billd-live/msg-image/'],
+        prefix: QINIU_KODO.hssblog.prefix['billd-live/msg-image/'],
         file: fileList[0],
       });
       if (res?.resultUrl) {

+ 4 - 8
src/views/push/index.vue

@@ -489,12 +489,7 @@ import { useRoute } from 'vue-router';
 import { fetchLiveRoomOnlineUser } from '@/api/live';
 import { fetchUpdateMyLiveRoom } from '@/api/liveRoom';
 import { fetchGetWsMessageList } from '@/api/wsMessage';
-import {
-  QINIU_RESOURCE,
-  THEME_COLOR,
-  liveRoomTypeEnumMap,
-  mediaTypeEnumMap,
-} from '@/constant';
+import { THEME_COLOR, liveRoomTypeEnumMap, mediaTypeEnumMap } from '@/constant';
 import { emojiArray } from '@/emoji';
 import { commentAuthTip, loginTip } from '@/hooks/use-login';
 import { usePush } from '@/hooks/use-push';
@@ -509,6 +504,7 @@ import {
   WsMessageMsgIsShowEnum,
   WsMessageMsgIsVerifyEnum,
 } from '@/interface';
+import { QINIU_KODO } from '@/spec-config';
 import { AppRootState, useAppStore } from '@/store/app';
 import { useCacheStore } from '@/store/cache';
 import { useNetworkStore } from '@/store/network';
@@ -876,7 +872,7 @@ async function uploadChange() {
       msgLoading.value = true;
       msgIsFile.value = WsMessageMsgIsFileEnum.yes;
       const res = await useQiniuJsUpload({
-        prefix: QINIU_RESOURCE.prefix['billd-live/msg-image/'],
+        prefix: QINIU_KODO.hssblog.prefix['billd-live/msg-image/'],
         file: fileList[0],
       });
       if (res?.resultUrl) {
@@ -1324,7 +1320,7 @@ async function uploadLivePreview() {
   const base64 = generateBase64(pushCanvasRef.value!);
   const file = base64ToFile(base64, `tmp.webp`);
   const uploadRes = await useQiniuJsUpload({
-    prefix: QINIU_RESOURCE.prefix['billd-live/live-preview/'],
+    prefix: QINIU_KODO.hssblog.prefix['billd-live/live-preview/'],
     file,
   });
   if (uploadRes.flag && uploadRes.resultUrl) {

+ 19 - 9
src/views/sponsors/index.vue

@@ -1,22 +1,30 @@
 <template>
   <div class="sponsors-wrap">
     <div class="content">
-      <h1 class="title">成为billd-live的赞助者</h1>
+      <h1 class="title">成为{{ PROJECT_NAME }}的赞助者</h1>
       <div class="desc">
-        目前billd-live仅仅是作者业余时间开发以及维护,需要投入非常多时间以及精力,
-        你的赞助将会为billd-live提供经济支持。
+        目前{{
+          PROJECT_NAME
+        }}仅仅是作者业余时间开发以及维护,需要投入非常多时间以及精力,
+        你的赞助将会为{{ PROJECT_NAME }}提供经济支持。
       </div>
       <div class="hr"></div>
       <div class="list">
         <div class="item">
-          <h2>以企业名义赞助billd-live</h2>
-          <p>如果你是企业用户,并且从billd-live中受益,请考虑捐赠以示感谢。</p>
+          <h2>以企业名义赞助{{ PROJECT_NAME }}</h2>
+          <p>
+            如果你是企业用户,并且从{{
+              PROJECT_NAME
+            }}中受益,请考虑捐赠以示感谢。
+          </p>
         </div>
         <div class="hr"></div>
         <div class="item">
-          <h2>以个人名义赞助billd-live</h2>
+          <h2>以个人名义赞助{{ PROJECT_NAME }}</h2>
           <p>
-            如果你是个人用户,并且从billd-live中受益,请考虑捐赠以示感谢——就当是偶尔请我们喝杯咖啡。
+            如果你是个人用户,并且从{{
+              PROJECT_NAME
+            }}中受益,请考虑捐赠以示感谢——就当是偶尔请我们喝杯咖啡。
           </p>
         </div>
         <div class="hr"></div>
@@ -87,8 +95,8 @@
     </div>
     <div class="aside">
       <div class="title">本页目录</div>
-      <div class="item">以个人名义赞助billd-live</div>
-      <div class="item">以企业名义赞助billd-live</div>
+      <div class="item">以个人名义赞助{{ PROJECT_NAME }}</div>
+      <div class="item">以企业名义赞助{{ PROJECT_NAME }}</div>
       <div class="item">赞助等级</div>
       <div class="item">当前赞助商</div>
     </div>
@@ -99,6 +107,8 @@
 import { openToTarget } from 'billd-utils';
 import { ref } from 'vue';
 
+import { PROJECT_NAME } from '@/constant';
+
 // 铂金赞助
 const platinumList = ref([
   {

+ 13 - 2
test/test.js

@@ -1,2 +1,13 @@
-let a = [1, 3, 4];
-console.log(a.join(','));
+async function demo() {
+  let res1 = await Promise.resolve('123');
+  return res1;
+}
+
+async function main() {
+  const res = await Promise.all([demo()]);
+  const res1 = await Promise.resolve(demo());
+  console.log(res);
+  console.log(res1);
+}
+
+main();