| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- <template>
- <el-dialog
- title="Bilibili视频检索"
- :visible.sync="dialogVisible"
- :append-to-body="true"
- width="660px"
- :before-close="handleClose"
- class="dialog_diy bilibili-search-dialog"
- >
- <div style="box-sizing:border-box;padding:15px" v-loading="loading" element-loading-text="正在检索中,请稍等...">
- <!-- 搜索和筛选区域 -->
- <div class="search-filter-box">
- <div class="search-item">
- <div class="search-input-wrapper">
- <el-input
- class="inputC"
- placeholder="搜索视频关键字(如需搜索多个可,隔开)"
- v-model="searchKeyword"
- @keyup.enter.native="handleSearch"
- ></el-input>
- <div class="search_img" @click="handleSearch">
- <img src="../../../../assets/icon/search.png" alt />
- </div>
- </div>
- </div>
- <div class="filter-item">
- <el-select v-model="navActive" @change="navClick" placeholder="综合排序" class="sort-select">
- <el-option label="综合排序" :value="0"></el-option>
- <el-option label="最多播放" :value="1"></el-option>
- <el-option label="最新发布" :value="2"></el-option>
- <el-option label="最多弹幕" :value="3"></el-option>
- <el-option label="最多收藏" :value="4"></el-option>
- </el-select>
- </div>
- <div class="add-item">
- <el-button type="primary" @click="batchAdd" :disabled="selectedVideos.length === 0">加入</el-button>
- </div>
- </div>
- <!-- 视频列表 -->
- <div class="Box">
- <div
- class="video_box video_box2"
- :class="{ 'selected': isVideoSelected(item) }"
- v-for="(item, index) in paginatedData"
- :key="index"
- @click="toggleVideoSelection(item)"
- >
- <div class="video-checkbox" @click.stop>
- <el-checkbox
- :value="isVideoSelected(item)"
- @change="toggleVideoSelection(item)"
- ></el-checkbox>
- </div>
- <span class="name" v-html="item.title"></span>
- <span class="detail">{{ item.description || '' }}</span>
- <div class="video-info">
- <span class="author">作者:{{ item.author || '' }}</span>
- <span class="duration">时长:{{ item.duration || '' }}</span>
- </div>
- <div class="tag" v-if="item.tag && typeof item.tag === 'string' && item.tag.split(',').length > 0">
- <el-tooltip :content="tag" placement="top" effect="dark" v-for="(tag, index) in item.tag.split(',').slice(0, 5)" :key="index">
- <span>{{ tag }}</span>
- </el-tooltip>
- </div>
- <div class="external-link" @click.stop="openUrl(item.bvid)" title="查看">
- <svg t="1755224440400" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4991" width="16" height="16">
- <path d="M853.333 469.333a42.667 42.667 0 0 0-42.666 42.667v256a42.667 42.667 0 0 1-42.667 42.667H256a42.667 42.667 0 0 1-42.667-42.667V256a42.667 42.667 0 0 1 42.667-42.667h256a42.667 42.667 0 0 0 0-85.333H256a128 128 0 0 0-128 128v512a128 128 0 0 0 128 128h512a128 128 0 0 0 128-128V512a42.667 42.667 0 0 0-42.667-42.667z" fill="#909399" p-id="4992"></path>
- <path d="M682.667 213.333h270.933v270.933a42.667 42.667 0 1 0 85.334 0V170.667a42.667 42.667 0 0 0-42.667-42.667H682.667a42.667 42.667 0 0 0 0 85.333z" fill="#909399" p-id="4993"></path>
- <path d="M894.293 174.293a42.667 42.667 0 0 0-60.586 0L591.147 417.707a42.667 42.667 0 0 0 60.586 60.586L894.293 234.88a42.667 42.667 0 0 0 0-60.587z" fill="#909399" p-id="4994"></path>
- </svg>
- </div>
- </div>
- <div v-if="data.length == 0" class="no_data">暂无数据</div>
- </div>
- <!-- 分页控件 -->
- <div class="pagination-box" v-if="data.length > 0">
- <el-button
- :disabled="currentPage === 1"
- @click="prevPage"
- size="small"
- >←上一页</el-button>
- <span class="page-info">第 {{ currentPage }} / {{ totalPages }} 页</span>
- <el-button
- :disabled="currentPage >= totalPages"
- @click="nextPage"
- size="small"
- >下一页→</el-button>
- </div>
- </div>
- <span slot="footer" class="dialog-footer">
- <el-button @click="handleClose">关 闭</el-button>
- </span>
- </el-dialog>
- </template>
- <script>
- import _ from "lodash";
- export default {
- name: "BilibiliSearchDialog",
- props: {
- visible: {
- type: Boolean,
- default: false
- },
- courseName: {
- type: String,
- default: ""
- },
- grade: {
- type: String,
- default: ""
- }
- },
- data() {
- return {
- dialogVisible: false,
- searchKeyword: "",
- loading: false,
- data: [],
- navActive: 0,
- selectedVideos: [], // 选中的视频列表
- currentPage: 1, // 当前页码
- pageSize: 20, // 每页显示数量
- totalPages: 1 // 总页数
- };
- },
- watch: {
- visible(newVal) {
- this.dialogVisible = newVal;
- if (newVal) {
- this.initDialog();
- }
- },
- dialogVisible(newVal) {
- this.$emit('update:visible', newVal);
- }
- },
- methods: {
- handleClose() {
- this.dialogVisible = false;
- this.selectedVideos = [];
- this.searchKeyword = "";
- this.data = [];
- this.currentPage = 1;
- },
- initDialog() {
- this.selectedVideos = [];
- // 默认以课程标题和已选择的年级为关键词
- let keywords = [];
- if (this.courseName) {
- keywords.push(this.courseName);
- }
- if (this.grade) {
- // 如果grade是多个年级用逗号分隔的,也需要处理
- keywords.push(this.grade);
- }
- this.searchKeyword = keywords.join(',');
- this.data = [];
- this.currentPage = 1;
- if (this.searchKeyword) {
- this.handleSearch();
- }
- },
- // 搜索视频
- async handleSearch() {
- if (!this.searchKeyword) {
- this.$message.error("请输入关键字");
- return;
- }
- try {
- this.loading = true;
- let keywords = [];
- if (this.searchKeyword.split(",").length > 1) {
- keywords = this.searchKeyword.split(",");
- } else {
- keywords = this.searchKeyword.split(",");
- }
- this.data = [];
- let data2 = [];
- for (var a = 0; a < keywords.length; a++) {
- let _data = await this.searchBilibili(keywords[a]);
- data2[a] = _data;
- }
- this.data = _.flatMap(_.zip(...data2), (pair) => pair.filter(value => value !== undefined));
- this.currentPage = 1;
- this.updateTotalPages();
- this.loading = false;
- } catch (error) {
- console.log(error);
- this.loading = false;
- this.$message.error("搜索失败,请重试");
- }
- },
- // Bilibili搜索接口
- searchBilibili(keyword) {
- return new Promise((resolve, reject) => {
- this.ajax.post(`https://gpt4.cocorobo.cn/get_network_search`, {
- engine: "bilibiliNew",
- keyword: keyword,
- page: 1,
- page_size: 20,
- order: this.navActive,
- duration: 0,
- }).then(response => {
- console.log(response);
- resolve(response.data.FunctionResponse || []);
- }).catch((error) => {
- console.log(error);
- resolve([]);
- });
- });
- },
- // 切换排序方式
- navClick(value) {
- if (this.navActive == value) {
- return;
- }
- this.navActive = value;
- if (this.searchKeyword) {
- this.handleSearch();
- }
- },
- // 打开视频链接
- openUrl(bvid) {
- window.open(`//www.bilibili.com/video/${bvid}`);
- },
- // 添加单个视频
- addSingleVideo(item) {
- const videoTitle = item.title.replace(/<[^>]*>?/gm, ''); // 移除HTML标签
- const videoData = {
- name: "链接",
- title: item.title.replace(/<[^>]*>?/gm, ''),
- url: `//player.bilibili.com/player.html?isOutside=true&bvid=${item.bvid}`,
- id: new Date().getTime(),
- bvid: item.bvid,
- type: 75 // B站视频使用type 75
- };
- this.$emit('addVideo', videoData);
- this.$message.success('加入成功');
- // 添加成功后关闭弹窗
- this.handleClose();
- },
- // 检查视频是否被选中
- isVideoSelected(item) {
- return this.selectedVideos.some(v => v.bvid === item.bvid);
- },
- // 切换视频选择状态
- toggleVideoSelection(item) {
- const index = this.selectedVideos.findIndex(v => v.bvid === item.bvid);
- if (index > -1) {
- this.selectedVideos.splice(index, 1);
- } else {
- this.selectedVideos.push(item);
- }
- },
- // 批量添加选中的视频
- batchAdd() {
- if (this.selectedVideos.length === 0) {
- this.$message.warning('请先选择要添加的视频');
- return;
- }
- this.selectedVideos.forEach(video => {
- const videoTitle = video.title.replace(/<[^>]*>?/gm, ''); // 移除HTML标签
- const videoData = {
- name: "链接",
- title: video.title.replace(/<[^>]*>?/gm, ''),
- url: `//player.bilibili.com/player.html?isOutside=true&bvid=${video.bvid}`,
- id: new Date().getTime(),
- bvid: video.bvid,
- type: 75 // B站视频使用type 75
- };
- this.$emit('addVideo', videoData);
- });
- this.$message.success(`成功添加 ${this.selectedVideos.length} 个视频`);
- this.selectedVideos = [];
- // 批量添加成功后关闭弹窗
- this.handleClose();
- },
- // 清空选择
- clearSelection() {
- this.selectedVideos = [];
- },
- // 更新总页数
- updateTotalPages() {
- this.totalPages = Math.ceil(this.data.length / this.pageSize);
- },
- // 上一页
- prevPage() {
- if (this.currentPage > 1) {
- this.currentPage--;
- }
- },
- // 下一页
- nextPage() {
- if (this.currentPage < this.totalPages) {
- this.currentPage++;
- }
- }
- },
- computed: {
- // 获取当前页的数据
- paginatedData() {
- const start = (this.currentPage - 1) * this.pageSize;
- const end = start + this.pageSize;
- return this.data.slice(start, end);
- }
- }
- };
- </script>
- <style scoped>
- .dialog_diy>>>.el-dialog {
- height: auto;
- margin: 50px auto 0 !important;
- }
- .dialog_diy>>>.el-dialog__header {
- background: #454545 !important;
- padding: 15px 20px;
- }
- .dialog_diy>>>.el-dialog__body {
- height: calc(100% - 124px);
- box-sizing: border-box;
- padding: 0px;
- }
- .dialog_diy>>>.el-dialog__title {
- color: #fff;
- }
- .dialog_diy>>>.el-dialog__headerbtn {
- top: 19px;
- }
- .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close {
- color: #fff;
- }
- .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close:hover {
- color: #fff;
- }
- .dialog_diy>>>.el-dialog__body,
- .dialog_diy>>>.el-dialog__footer {
- background: #fafafa;
- }
- /* 搜索和筛选区域 */
- .search-filter-box {
- display: flex;
- align-items: center;
- gap: 15px;
- margin-bottom: 15px;
- padding: 10px 0;
- }
- .search-item {
- flex: 1;
- display: flex;
- align-items: center;
- gap: 10px;
- }
- .search-label {
- min-width: 80px;
- font-size: 14px;
- color: #606266;
- text-align: right;
- }
- .search-input-wrapper {
- flex: 1;
- position: relative;
- }
- .inputC>>>.el-input__inner {
- padding-right: 35px;
- height: 40px;
- line-height: 40px;
- }
- .search_img {
- width: 20px;
- height: 20px;
- position: absolute;
- right: 10px;
- top: 50%;
- transform: translateY(-50%);
- cursor: pointer;
- z-index: 10;
- }
- .search_img>img {
- width: 100%;
- height: 100%;
- }
- .filter-item {
- width: 150px;
- }
- .sort-select {
- width: 100%;
- }
- .add-item {
- width: 80px;
- }
- .Box {
- width: 100%;
- height: 500px;
- overflow: auto;
- display: flex;
- flex-direction: row;
- justify-content: flex-start;
- flex-wrap: wrap;
- padding: 5px;
- box-sizing: border-box;
- }
- .video_box {
- width: calc(50% - 10px);
- margin-right: 10px;
- display: flex;
- flex-direction: column;
- margin-bottom: 15px;
- cursor: pointer;
- }
- .video_box2 {
- box-shadow: 0px 0px 4px 2px #d2d2d282;
- padding: 10px;
- box-sizing: border-box;
- border-radius: 5px;
- position: relative;
- background: #fff;
- cursor: pointer;
- transition: all 0.2s;
- border: 2px solid transparent;
- }
- .video_box2:hover {
- box-shadow: 0px 0px 8px 4px #d2d2d282;
- transform: translateY(-2px);
- }
- .video_box2.selected {
- border: 2px solid #409eff;
- /* box-shadow: 0px 0px 8px 4px rgba(64, 158, 255, 0.3); */
- }
- .video-checkbox {
- position: absolute;
- top: 8px;
- right: 8px;
- z-index: 10;
- background: rgba(255, 255, 255, 0.95);
- padding: 2px;
- border-radius: 4px;
- }
- .video-thumbnail {
- width: 100%;
- height: 120px;
- background: #f0f0f0;
- border-radius: 4px;
- margin-bottom: 8px;
- margin-top: 5px;
- }
- .video_box>.detail {
- color: #cecece;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 3;
- line-clamp: 3;
- overflow: hidden;
- text-overflow: ellipsis;
- margin: 0 0 5px;
- }
- .video_box>.name {
- color: #000;
- margin: 5px 0 8px 0;
- font-weight: bold;
- font-size: 14px;
- min-height: 22px;
- max-height: 44px;
- line-height: 22px;
- overflow: hidden;
- text-overflow: ellipsis;
- display: block;
- white-space: normal;
- word-break: break-all;
- /* 强制换行成两行,如果内容过多则省略号,且不会折成一行 */
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 2;
- width: calc(100% - 20px);
- }
- .video-info {
- display: flex;
- flex-direction: column;
- gap: 5px;
- margin-bottom: 8px;
- font-size: 12px;
- color: #909399;
- }
- .video_box>.author {
- margin: 0;
- width: 100%;
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .video-info .duration {
- margin: 0;
- width: 100%;
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .video_box>.tag {
- display: flex;
- flex-wrap: nowrap;
- margin-top: auto;
- width: calc(100% - 24px);
- }
- .video_box>.tag>span {
- background: #eef3fb;
- color: #0061ff;
- padding: 5px 10px;
- border-radius: 15px;
- font-size: 0.9em;
- margin: 0 5px 0 0;
- max-width: 100%;
- overflow: hidden;
- box-sizing: border-box;
- text-overflow: ellipsis;
- white-space: nowrap;
- text-align: center;
- }
- .external-link {
- position: absolute;
- bottom: 10px;
- right: 10px;
- width: 24px;
- height: 24px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- border-radius: 4px;
- transition: background 0.2s;
- }
- .external-link:hover {
- background: rgba(0, 0, 0, 0.05);
- }
- .external-link svg {
- width: 16px;
- height: 16px;
- }
- .no_data {
- height: 500px;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 100%;
- }
- .pagination-box {
- display: flex;
- justify-content: center;
- align-items: center;
- margin: 20px 0;
- gap: 15px;
- }
- .page-info {
- font-size: 14px;
- color: #606266;
- }
- @media screen and (max-width: 1080px) {
- .video_box {
- width: calc(100% / 3 - 10px) !important;
- }
- }
- @media screen and (max-width: 760px) {
- .video_box {
- width: calc(100% / 2 - 10px) !important;
- }
- }
- </style>
|