邃芒慧语、照片说话(PC) https://photo.metavatar.cc/
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 

916 рядки
22 KiB

  1. <template>
  2. <div class="page flex justify-around">
  3. <!-- 左侧栏 -->
  4. <div class="left">
  5. <!-- 顶部 -->
  6. <!-- 有图片时 -->
  7. <div class="left-top" v-show="!showUploadBtn">
  8. <el-row class="justify-between">
  9. <!-- title框 -->
  10. <div class="flex justify-between" style="width: 300px">
  11. <el-input
  12. v-model="title"
  13. :placeholder="$t('createVideo.typeTitle')"
  14. />
  15. <el-icon class="icon-edit"><i-ep-edit /></el-icon>
  16. </div>
  17. <!-- 上传按钮 -->
  18. <div class="btnBox" v-show="submitImgBtn">
  19. <button class="uploadBtn">
  20. {{ $t("createVideo.reselect") }}
  21. <input
  22. accept="image/*"
  23. type="file"
  24. @click="e.target.value = null"
  25. @change="lookImg"
  26. />
  27. </button>
  28. <button class="uploadBtn" @click="changeFile">
  29. {{ $t("createVideo.sureUpload") }}
  30. </button>
  31. </div>
  32. </el-row>
  33. <!-- 中间展示大图 -->
  34. <div class="bigImg inmiddle">
  35. <img :src="imgUrl" alt="" class="inmiddle" />
  36. </div>
  37. </div>
  38. <!-- 没有图片时 -->
  39. <div class="left-top" v-show="showUploadBtn">
  40. <!-- 中间展示大图 -->
  41. <div class="noImg">
  42. <my-loading
  43. style="margin-top: 150px"
  44. :isLoading="compressionImgLoad"
  45. ></my-loading>
  46. <div v-if="!compressionImgLoad" class="trueImg inmiddle">
  47. <div class="icon">✔</div>
  48. </div>
  49. <div v-if="!compressionImgLoad" class="upload inmiddle">
  50. +
  51. <input
  52. accept="image/*"
  53. type="file"
  54. @click="e.target.value = null"
  55. @change="lookImg"
  56. />
  57. </div>
  58. <div v-if="!compressionImgLoad" class="falseImg inmiddle">
  59. <div><div class="icon">×</div></div>
  60. <div><div class="icon">×</div></div>
  61. <div><div class="icon">×</div></div>
  62. </div>
  63. </div>
  64. </div>
  65. <!-- 底部 -->
  66. <div class="left-bottom">
  67. <div class="tab flex">
  68. <div
  69. class="pointer"
  70. :class="showFace == 0 ? 'tabAvtive' : ''"
  71. @click="ChangeShowFaceList(0)"
  72. >
  73. {{ $t("createVideo.availableMould") }}
  74. </div>
  75. <div
  76. class="pointer"
  77. :class="showFace == 1 ? 'tabAvtive' : ''"
  78. @click="ChangeShowFaceList(1)"
  79. >
  80. {{ $t("createVideo.personalWarehouse") }}
  81. </div>
  82. </div>
  83. <div class="faceList">
  84. <!-- 上传图片组件 -->
  85. <div
  86. v-if="showFace == 1"
  87. class="faceItem"
  88. @click="showUploadBtn = true"
  89. >
  90. <span class="uploadImg">+ </span>
  91. </div>
  92. <my-loading :isLoading="feceItemLoading"></my-loading>
  93. <!-- face列表 -->
  94. <div
  95. :class="faceItemActive == item.id ? 'faceItemActive' : ''"
  96. class="faceItem pointer"
  97. @click="setImgUrl(item.material, item.id)"
  98. v-for="item in AiFaceList"
  99. :key="item.id"
  100. >
  101. <!-- <div class="img"></div> -->
  102. <img :src="item.material" alt="" />
  103. <p>{{ item.title }}</p>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. <!-- 右侧栏 -->
  109. <div class="right">
  110. <el-tabs type="border-card" class="tabs">
  111. <!-- ----------------------------- 1 -->
  112. <el-tab-pane :label="$t('createVideo.typeScript')">
  113. <div class="card1">
  114. <div class="text">
  115. <el-input
  116. v-model="title"
  117. :placeholder="$t('createVideo.typeTitle')"
  118. />
  119. <el-button type="primary">
  120. {{ $t("createVideo.confirm") }}
  121. </el-button>
  122. <!-- 文本域 -->
  123. <el-input
  124. id="textInputId"
  125. v-model="textareaContent"
  126. :rows="15"
  127. type="textarea"
  128. :placeholder="$t('createVideo.aiText')"
  129. />
  130. <div @click="insertIcon">🕗</div>
  131. </div>
  132. <p>{{ $t("createVideo.languages") }}</p>
  133. <el-select
  134. v-model="language"
  135. placeholder="Select"
  136. style="width: 100%"
  137. >
  138. <el-option
  139. v-for="item in languageOptions"
  140. :key="item.value"
  141. :label="item.label"
  142. :value="item.value"
  143. />
  144. </el-select>
  145. <p>{{ $t("createVideo.voices") }}</p>
  146. <el-select
  147. v-model="language"
  148. placeholder="Select"
  149. style="width: 100%"
  150. >
  151. <el-option
  152. v-for="item in soundOptions"
  153. :key="item.value"
  154. :label="item.label"
  155. :value="item.value"
  156. />
  157. </el-select>
  158. <p>{{ $t("createVideo.styles") }}</p>
  159. <el-select
  160. v-model="language"
  161. placeholder="Select"
  162. style="width: 100%"
  163. >
  164. <el-option
  165. v-for="item in soundStyleOptions"
  166. :key="item.value"
  167. :label="item.label"
  168. :value="item.value"
  169. />
  170. </el-select>
  171. <el-button color="#000" type="primary">{{
  172. $t("createVideo.generateVideo")
  173. }}</el-button>
  174. </div>
  175. </el-tab-pane>
  176. <!-- ------------------------ 2 -->
  177. <el-tab-pane :label="$t('createVideo.uploadAudio')">
  178. <div class="card2">
  179. <!-- 上传视频 -->
  180. <p>
  181. <el-icon class="icon-VideoCamera"><i-ep-VideoCamera /></el-icon>
  182. 上传视频
  183. </p>
  184. <div class="uploadVideo">
  185. +
  186. <input type="file" ref="fileInput" @change="handleFileChange" />
  187. <video
  188. v-if="videoSrc"
  189. :src="videoSrc"
  190. ref="videoPlayer"
  191. controls
  192. ></video>
  193. </div>
  194. <!-- 录制MP3上传语音 -->
  195. <p>
  196. <el-icon class="icon-Mic"><i-ep-Mic /></el-icon>
  197. 录制音频
  198. </p>
  199. <div
  200. class="uploadAudio"
  201. :class="audioUrl ? 'uploadAudioAvtion' : ''"
  202. >
  203. <div class="btnBox">
  204. <button
  205. class="pointer"
  206. :disabled="!isRecording"
  207. @click="startRecording"
  208. >
  209. 开始录音
  210. </button>
  211. <button
  212. class="pointer"
  213. @click="stopRecording"
  214. :disabled="isRecording"
  215. >
  216. 停止录音
  217. </button>
  218. </div>
  219. <!-- <button @click="playRecording">播放录音</button> -->
  220. <audio v-if="audioUrl" controls :src="audioUrl"></audio>
  221. <button v-if="audioUrl" @click="uploadAudio" class="pointer">
  222. 上传音频
  223. </button>
  224. </div>
  225. <el-button color="#000" type="primary">{{
  226. $t("createVideo.generateVideo")
  227. }}</el-button>
  228. </div>
  229. </el-tab-pane>
  230. <!-- ----------------------- 3 -->
  231. <el-tab-pane v-if="false" :label="$t('createVideo.aiScript')">
  232. <div class="card3">
  233. <div class="text">
  234. <el-input
  235. v-model="title"
  236. :placeholder="$t('createVideo.typeTitle')"
  237. />
  238. <el-button type="primary">
  239. {{ $t("createVideo.confirm") }}
  240. </el-button>
  241. <el-input
  242. v-model="title"
  243. :rows="15"
  244. type="textarea"
  245. :placeholder="$t('createVideo.aiText')"
  246. />
  247. <el-icon :size="20">
  248. <Edit />
  249. </el-icon>
  250. </div>
  251. <p>{{ $t("createVideo.languages") }}</p>
  252. <el-select
  253. v-model="language"
  254. placeholder="Select"
  255. style="width: 100%"
  256. >
  257. <el-option
  258. v-for="item in languageOptions"
  259. :key="item.value"
  260. :label="item.label"
  261. :value="item.value"
  262. />
  263. </el-select>
  264. <p>{{ $t("createVideo.voices") }}</p>
  265. <el-select
  266. v-model="language"
  267. placeholder="Select"
  268. style="width: 100%"
  269. >
  270. <el-option
  271. v-for="item in languageOptions"
  272. :key="item.value"
  273. :label="item.label"
  274. :value="item.value"
  275. />
  276. </el-select>
  277. <p>{{ $t("createVideo.styles") }}</p>
  278. <el-select
  279. v-model="language"
  280. placeholder="Select"
  281. style="width: 100%"
  282. >
  283. <el-option
  284. v-for="item in languageOptions"
  285. :key="item.value"
  286. :label="item.label"
  287. :value="item.value"
  288. />
  289. </el-select>
  290. <el-button type="primary">{{
  291. $t("createVideo.generateVideo")
  292. }}</el-button>
  293. </div>
  294. </el-tab-pane>
  295. </el-tabs>
  296. </div>
  297. </div>
  298. </template>
  299. <script setup>
  300. import { getCurrentInstance } from "vue";
  301. import {
  302. personPhotoList,
  303. awsImgUpload,
  304. videoUpload,
  305. saveImgApi,
  306. } from "@/apis/createVideo";
  307. import Recorder from "js-audio-recorder"; //mp3插件
  308. import imageCompression from "browser-image-compression"; //压缩图片插件
  309. //#region 头像区的逻辑
  310. // 获取AI头像
  311. const AiFaceList = ref([]);
  312. const feceItemLoading = ref(false);
  313. function getAiFaceList(pageNum, pageSize) {
  314. feceItemLoading.value = true;
  315. personPhotoList(pageNum, pageSize)
  316. .then((res) => {
  317. AiFaceList.value = res.data.list;
  318. feceItemLoading.value = false;
  319. })
  320. .catch((err) => {
  321. feceItemLoading.value = false;
  322. console.log(err, "err");
  323. });
  324. }
  325. // 选择显示的face列表
  326. const showFace = ref("0");
  327. function ChangeShowFaceList(index) {
  328. showFace.value = index;
  329. }
  330. const faceItemActive = ref(); //高亮处理
  331. // 点击aifece
  332. function setImgUrl(url, id) {
  333. faceItemActive.value = id;
  334. showUploadBtn.value = false;
  335. submitImgBtn.value = false;
  336. imgUrl.value = url;
  337. }
  338. //#endregion ------------------------------
  339. //#region 预览图片
  340. const compressionImgLoad = ref(false);
  341. async function lookImg(e) {
  342. // 压缩配置
  343. compressionImgLoad.value = true;
  344. const options = {
  345. maxSizeMB: 2, // 最大压缩大小为 1MB
  346. useWebWorker: true, // 使用 Web Worker 进行压缩,提高性能
  347. };
  348. const compressedFile = await imageCompression(e.target.files[0], options);
  349. imgUrl.value = URL.createObjectURL(compressedFile);
  350. imgData.value = compressedFile;
  351. showUploadBtn.value = false;
  352. submitImgBtn.value = true;
  353. compressionImgLoad.value = false;
  354. }
  355. //#endregion ------------------
  356. // 标题
  357. const title = ref("");
  358. //#region 上传图片
  359. const imgUrl = ref(""); //图片回显路径
  360. const imgData = ref(""); // 上传图片文件
  361. const showUploadBtn = ref(false); //上传图片+号的显示隐藏
  362. const submitImgBtn = ref(false); //右上角俩按钮显示与隐藏
  363. // 上传图片
  364. async function changeFile() {
  365. imgUrl.value = URL.createObjectURL(imgData.value);
  366. let formData = new FormData();
  367. const timestamp = Date.now();
  368. formData.append("file", imgData.value, timestamp + ".png");
  369. try {
  370. const res = await awsImgUpload(formData);
  371. if (res.code == 200) {
  372. ElMessage.success("上传成功!");
  373. } else {
  374. ElMessage.error("上传失败!");
  375. }
  376. const res2 = await saveImgApi({ material: res.data.url });
  377. } catch (error) {
  378. ElMessage.error(error);
  379. }
  380. }
  381. //#endregion ---------------------------
  382. //#region card1的逻辑
  383. const textareaContent = ref("");
  384. function insertIcon() {
  385. const textarea = document.getElementById("textInputId");
  386. const icon = "🕗"; // 这里使用了一个星星作为示例图标,你可以替换为你自己的图标
  387. // 获取光标位置
  388. const startPos = textarea.selectionStart;
  389. const endPos = textarea.selectionEnd;
  390. console.log(startPos);
  391. console.log(endPos);
  392. // 在光标位置插入图标
  393. textareaContent.value =
  394. textareaContent.value.substring(0, startPos) +
  395. icon +
  396. textareaContent.value.substring(endPos, textareaContent.value.length);
  397. // 设置光标位置为插入图标后的位置
  398. const newCursorPos = startPos + icon.length;
  399. textarea.setSelectionRange(newCursorPos, newCursorPos);
  400. textarea.focus();
  401. }
  402. const language = ref("");
  403. const sound = ref("");
  404. const soundStyle = ref("");
  405. const languageOptions = reactive([
  406. {
  407. value: "0",
  408. label: "中文",
  409. },
  410. {
  411. value: "1",
  412. label: "English",
  413. },
  414. ]);
  415. const soundOptions = reactive([
  416. {
  417. value: "0",
  418. label: "老人",
  419. },
  420. {
  421. value: "1",
  422. label: "小孩",
  423. },
  424. ]);
  425. const soundStyleOptions = reactive([
  426. {
  427. value: "0",
  428. label: "生气",
  429. },
  430. {
  431. value: "1",
  432. label: "抑郁",
  433. },
  434. ]);
  435. //#endregion
  436. //#region 录制MP3上传语音
  437. const parameter = {
  438. sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
  439. sampleRate: 8000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
  440. numChannels: 1, // 声道,支持 1 或 2, 默认是1
  441. };
  442. const recorder = new Recorder(parameter);
  443. const isRecording = ref(true);
  444. const audioUrl = ref(null);
  445. const audioData = ref("");
  446. const startRecording = async () => {
  447. try {
  448. await recorder.start();
  449. console.log("Recording started");
  450. isRecording.value = false;
  451. } catch (error) {
  452. console.error(error);
  453. }
  454. };
  455. const stopRecording = async () => {
  456. try {
  457. const recording = await recorder.stop();
  458. audioUrl.value = URL.createObjectURL(recorder.getWAVBlob());
  459. audioData.value = recorder.getWAVBlob();
  460. isRecording.value = true;
  461. } catch (error) {
  462. console.error(error);
  463. }
  464. };
  465. const playRecording = () => {
  466. if (audioUrl.value) {
  467. const audio = new Audio(audioUrl.value);
  468. audio.play();
  469. }
  470. };
  471. async function uploadAudio(params) {
  472. let formData = new FormData();
  473. const timestamp = Date.now();
  474. formData.append("file", audioData.value, timestamp + ".mp3");
  475. try {
  476. const res = await videoUpload(formData);
  477. ElMessage.success("上传成功!");
  478. } catch (error) {
  479. ElMessage.error(error);
  480. }
  481. }
  482. //#endregion ------------------------------------
  483. //#region 上传视频功能
  484. const fileInput = ref(null);
  485. const videoSrc = ref(null);
  486. const handleFileChange = () => {
  487. const file = fileInput.value.files[0];
  488. if (file) {
  489. const videoUrl = URL.createObjectURL(file);
  490. videoSrc.value = videoUrl;
  491. }
  492. };
  493. //#endregion --------------------------------------
  494. // $t在script中的使用
  495. const {
  496. appContext: {
  497. config: { globalProperties },
  498. },
  499. } = getCurrentInstance();
  500. const string = "createVideo.typeScript";
  501. const t = globalProperties.$t(string);
  502. onMounted(() => {
  503. getAiFaceList(1, 100);
  504. });
  505. </script>
  506. <style lang="scss" scoped>
  507. .page {
  508. // height: 1200px;
  509. height: calc(100vh - 80px);
  510. padding: 20px 0 0 40px;
  511. background-color: #fff;
  512. border-radius: 25px 0 0;
  513. }
  514. .left {
  515. width: 70%;
  516. height: 80%;
  517. :deep(.el-input__wrapper) {
  518. border: none;
  519. border-bottom: 2px solid #000;
  520. border-radius: 0;
  521. box-shadow: none;
  522. }
  523. .el-icon.icon-edit {
  524. width: 35px;
  525. height: 35px;
  526. font-size: 35px;
  527. color: #8c939d;
  528. text-align: center;
  529. }
  530. &-top {
  531. position: relative;
  532. width: 100%;
  533. // height: 65%;
  534. height: 600px;
  535. .uploadBtn {
  536. position: relative;
  537. padding: 5px 10px;
  538. margin-left: 10px;
  539. border-radius: 5px;
  540. transition: all 0.3s;
  541. &:hover {
  542. background-color: #000;
  543. color: #fff;
  544. }
  545. }
  546. .bigImg {
  547. display: flex;
  548. align-items: center;
  549. justify-content: space-between;
  550. width: 80%;
  551. height: 88%;
  552. margin-top: 20px;
  553. img {
  554. max-width: 100%;
  555. max-height: 100%;
  556. }
  557. }
  558. .noImg {
  559. position: relative;
  560. width: 100%;
  561. height: 100%;
  562. border: 1px solid #000;
  563. .trueImg {
  564. top: 60px;
  565. width: 100px;
  566. height: 100px;
  567. background-color: green;
  568. border-radius: 50%;
  569. }
  570. .el-upload {
  571. position: absolute;
  572. top: 0;
  573. left: 0;
  574. width: 100%;
  575. height: 100%;
  576. opacity: 0;
  577. }
  578. .upload {
  579. top: 200px;
  580. width: 100px;
  581. height: 100px;
  582. font-size: 50px;
  583. line-height: 100px;
  584. text-align: center;
  585. background-color: pink;
  586. border-radius: 50%;
  587. }
  588. .falseImg {
  589. top: 350px;
  590. // background-color: #795562;
  591. display: flex;
  592. justify-content: space-evenly;
  593. width: 500px;
  594. height: 100px;
  595. > div {
  596. position: relative;
  597. width: 100px;
  598. height: 100px;
  599. background-color: #ccc;
  600. border-radius: 50%;
  601. }
  602. }
  603. }
  604. // 公共类名
  605. input {
  606. position: absolute;
  607. top: 0;
  608. left: 0;
  609. width: 100%;
  610. height: 100%;
  611. opacity: 0;
  612. }
  613. .icon {
  614. position: absolute;
  615. right: 2px;
  616. width: 30px;
  617. height: 30px;
  618. font-size: 20px;
  619. font-weight: 700;
  620. line-height: 26px;
  621. text-align: center;
  622. border: 2px solid #000;
  623. border-radius: 50%;
  624. }
  625. }
  626. &-bottom {
  627. width: 100%;
  628. height: 32%;
  629. margin-top: 10px;
  630. .tab {
  631. padding: 10px;
  632. > div {
  633. margin-right: 20px;
  634. padding: 5px 10px;
  635. transition: all 0.3s;
  636. border-radius: 5px;
  637. &:hover {
  638. background-color: #000;
  639. color: #fff;
  640. }
  641. }
  642. .tabAvtive {
  643. background-color: #000;
  644. color: #fff;
  645. }
  646. }
  647. .ai {
  648. width: 100%;
  649. }
  650. .faceList {
  651. padding: 3px;
  652. display: flex;
  653. flex-wrap: wrap;
  654. justify-content: flex-start;
  655. width: 100%;
  656. height: 160px;
  657. overflow-y: scroll;
  658. .faceItem {
  659. position: relative;
  660. margin-right: 13px;
  661. margin-bottom: 10px;
  662. width: 150px;
  663. height: 150px;
  664. padding: 0 25px;
  665. line-height: 150px;
  666. text-align: center;
  667. border-radius: 50%;
  668. background-color: #fbf8f8;
  669. border: 2px solid #fff;
  670. box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 3px 3px;
  671. overflow: hidden;
  672. input {
  673. position: absolute;
  674. top: 0;
  675. left: 0;
  676. width: 100%;
  677. height: 100%;
  678. opacity: 0;
  679. }
  680. .uploadImg {
  681. line-height: 145px;
  682. font-size: 50px;
  683. font-weight: 700;
  684. text-align: center;
  685. }
  686. p {
  687. height: 30px;
  688. }
  689. img {
  690. width: 100%;
  691. }
  692. .img {
  693. width: 100px;
  694. height: 100px;
  695. border-radius: 50%;
  696. }
  697. }
  698. .faceItemActive {
  699. background: linear-gradient(
  700. 270deg,
  701. rgb(201, 113, 255) 24.97%,
  702. rgb(92, 121, 252) 100%
  703. );
  704. // border: 2px solid #fff;
  705. // box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 3px 3px;
  706. }
  707. }
  708. }
  709. }
  710. .right {
  711. width: 25%;
  712. height: 100%;
  713. background-color: green;
  714. :deep(.el-tabs--border-card) {
  715. font-size: 20px;
  716. border: none;
  717. }
  718. .tabs {
  719. height: 100%;
  720. .card1 {
  721. .text {
  722. padding: 10px;
  723. border: 1px solid #000;
  724. .el-button {
  725. float: right;
  726. margin-top: 10px;
  727. }
  728. :deep(.el-textarea__inner) {
  729. resize: none;
  730. box-shadow: none;
  731. }
  732. }
  733. p {
  734. margin: 10px 0;
  735. }
  736. > .el-button {
  737. width: 100%;
  738. height: 50px;
  739. margin-top: 10px;
  740. }
  741. :deep(.el-input .is-focus) {
  742. // box-shadow: none !important;
  743. // box-shadow: 0 0 0 1px #000 !important;
  744. }
  745. }
  746. .card2 {
  747. padding: 10px;
  748. .el-icon {
  749. // color: red;
  750. vertical-align: text-top;
  751. }
  752. > div {
  753. position: relative;
  754. margin-top: 10px;
  755. width: 100%;
  756. border: #000 1px solid;
  757. border-radius: 10px;
  758. overflow: hidden;
  759. transition: all 0.3s;
  760. box-shadow: #00000026 2px 2px 2px 2px;
  761. &:hover {
  762. transform: translateY(-10px);
  763. }
  764. }
  765. .uploadAudio {
  766. padding: 20px;
  767. // margin-top: 30px;
  768. margin-bottom: 20px;
  769. height: 70px;
  770. .btnBox {
  771. display: flex;
  772. justify-content: space-between;
  773. margin-bottom: 10px;
  774. }
  775. audio {
  776. height: 50px;
  777. width: 100%;
  778. }
  779. button {
  780. border-radius: 10px;
  781. height: 30px;
  782. line-height: 22px;
  783. padding: 5px 10px;
  784. background-color: #fff;
  785. transition: all 0.3s;
  786. &:hover {
  787. background-color: #000;
  788. color: #fff;
  789. }
  790. }
  791. }
  792. .uploadAudioAvtion {
  793. height: 170px;
  794. }
  795. .uploadVideo {
  796. text-align: center;
  797. margin-bottom: 20px;
  798. height: 100px;
  799. font-size: 50px;
  800. font-weight: 700;
  801. line-height: 100px;
  802. input {
  803. position: absolute;
  804. width: 100%;
  805. height: 100%;
  806. opacity: 0;
  807. }
  808. video {
  809. width: 100%;
  810. height: 100%;
  811. }
  812. }
  813. > .el-button {
  814. width: 100%;
  815. height: 50px;
  816. margin-top: 10px;
  817. // background-color: #000;
  818. }
  819. }
  820. .card3 {
  821. .text {
  822. padding: 10px;
  823. border: 1px solid #000;
  824. .el-button {
  825. float: right;
  826. margin-top: 10px;
  827. }
  828. :deep(.el-textarea__inner) {
  829. resize: none;
  830. box-shadow: none;
  831. }
  832. }
  833. p {
  834. margin: 10px 0;
  835. }
  836. > .el-button {
  837. width: 100%;
  838. height: 50px;
  839. margin-top: 10px;
  840. }
  841. }
  842. :deep(.el-tabs__item.is-active) {
  843. color: #909393;
  844. background-color: #000;
  845. }
  846. :deep(.el-tabs__nav) {
  847. width: 100%;
  848. }
  849. :deep(.el-tabs__item) {
  850. width: 34%;
  851. }
  852. :deep(.el-tabs__item:hover) {
  853. color: #909393;
  854. }
  855. :deep(.el-tabs__content) {
  856. height: calc(100% - 60px);
  857. padding: 0;
  858. }
  859. }
  860. }
  861. </style>