| @@ -7,22 +7,27 @@ | |||
| <div class="content"> | |||
| <div class="title"> | |||
| <div class="title-l"> | |||
| <a :href="`/${data.OwnerName}/${data.Name}`"> | |||
| <a :href="`/${data.OwnerName}/${data.Name}`" :title="`${data.OwnerName}/${data.Name}`"> | |||
| <span class="title-1">{{ data.OwnerName }}</span> | |||
| <span class="title-1"> / </span> | |||
| <span class="title-2">{{ data.Name }}</span> | |||
| <span class="title-2" v-html="data.NameShow"></span> | |||
| </a> | |||
| </div> | |||
| <span class="title-r"> | |||
| <span class="t-item"><i class="ri-eye-line"></i><span>{{ data.NumWatches }}</span></span> | |||
| <span class="t-item"><i class="ri-star-line"></i><span>{{ data.NumStars }}</span></span> | |||
| <span class="t-item"><i class="ri-git-pull-request-line"></i><span>{{ data.NumForks }}</span></span> | |||
| <span class="t-item"> | |||
| <svg class="svg octicon-repo-forked" width="12" height="12" aria-hidden="true"> | |||
| <use xlink:href="#octicon-repo-forked"></use> | |||
| </svg> | |||
| <span>{{ data.NumForks }}</span></span> | |||
| </span> | |||
| </div> | |||
| <div class="descr">{{ data.Description }}</div> | |||
| <div class="descr" v-html="data.DescriptionShow"></div> | |||
| <div class="tags" v-if="data.Topics"> | |||
| <a v-for="(item, index) in data.Topics" :key="index" class="tag" | |||
| :href="`/explore/repos?q=&topic=${item}&sort=hot`">{{ item }}</a> | |||
| <a v-for="(item, index) in data.TopicsShow" :key="index" class="tag" | |||
| :class="(item.topic.toLocaleLowerCase() == topic.toLocaleLowerCase() ? 'tag-focus' : '')" | |||
| :href="`/explore/repos?q=&topic=${item.topic}&sort=hot`" v-html="item.topicShow"></a> | |||
| </div> | |||
| <div class="repo-datas"> | |||
| <span class="repo-datas-item" v-show="(data.DatasetCnt > 0)"> | |||
| @@ -68,8 +73,6 @@ | |||
| </template> | |||
| <script> | |||
| // import { addResQueue, updateResQueue } from '~/apis/modules/resources'; | |||
| // import { CLUSTERS, AI_CENTER, COMPUTER_RESOURCES, ACC_CARD_TYPE } from '~/const'; | |||
| import relativeTime from 'dayjs/plugin/relativeTime'; | |||
| import localizedFormat from 'dayjs/plugin/localizedFormat'; | |||
| import 'dayjs/locale/zh-cn'; | |||
| @@ -84,8 +87,8 @@ dayjs.extend(localizedFormat); | |||
| export default { | |||
| name: "ReposItem", | |||
| props: { | |||
| // visible: { type: Boolean, default: false }, | |||
| data: { type: Object, default: () => ({}) }, | |||
| topic: { type: String, default: '' } | |||
| }, | |||
| components: {}, | |||
| data() { | |||
| @@ -103,8 +106,7 @@ export default { | |||
| dayjs(unix * 1000).format('ddd, D MMM YYYY hh:mm:ss [CST]'); | |||
| } | |||
| }, | |||
| mounted() { | |||
| }, | |||
| mounted() { }, | |||
| }; | |||
| </script> | |||
| <style scoped lang="less"> | |||
| @@ -206,6 +208,11 @@ export default { | |||
| background: rgba(232, 232, 232, 0.6); | |||
| padding: 2px 6px; | |||
| margin-right: 8px; | |||
| &.tag-focus { | |||
| // background-color: rgb(245, 182, 110); | |||
| color: red; | |||
| } | |||
| } | |||
| .content .repo-datas { | |||
| @@ -2,7 +2,7 @@ | |||
| <div class="list-container"> | |||
| <div style="min-height:540px;" v-loading="loading"> | |||
| <div class="repos-item-container" v-for="(item, index) in list" :key="item.ID"> | |||
| <ReposItem :data="item"></ReposItem> | |||
| <ReposItem :data="item" :topic="topic"></ReposItem> | |||
| </div> | |||
| </div> | |||
| <div class="center"> | |||
| @@ -48,7 +48,20 @@ export default { | |||
| res = res.data; | |||
| this.loading = false; | |||
| if (res.Code == 0) { | |||
| this.list = res.Data.Repos || []; | |||
| const list = res.Data.Repos || []; | |||
| this.list = list.map((item) => { | |||
| return { | |||
| ...item, | |||
| NameShow: this.handlerSearchStr(item.Name, this.q), | |||
| DescriptionShow: this.handlerSearchStr(item.Description, this.q), | |||
| TopicsShow: (item.Topics || []).map((_item) => { | |||
| return { | |||
| topic: _item, | |||
| topicShow: this.handlerSearchStr(_item, this.q) | |||
| } | |||
| }), | |||
| } | |||
| }); | |||
| this.total = res.Data.Total; | |||
| this.$nextTick(() => { | |||
| if (typeof LetterAvatar != 'undefined') { | |||
| @@ -61,6 +74,10 @@ export default { | |||
| this.loading = false; | |||
| }); | |||
| }, | |||
| search() { | |||
| this.page = 1; | |||
| this.getListData(); | |||
| }, | |||
| currentChange(page) { | |||
| this.page = page; | |||
| this.getListData(); | |||
| @@ -68,6 +85,10 @@ export default { | |||
| sizeChange(pageSize) { | |||
| this.pageSize = pageSize; | |||
| this.getListData(); | |||
| }, | |||
| handlerSearchStr(oStr, searchKey) { | |||
| if (!searchKey) return oStr; | |||
| return oStr.replace(new RegExp(`(${searchKey})`, 'ig'), `<font color="red">$1</font>`); | |||
| } | |||
| }, | |||
| watch: {}, | |||
| @@ -3,7 +3,7 @@ | |||
| <div class="_repo_search"> | |||
| <div class="_repo_search_input_c"> | |||
| <div class="_repo_search_input"> | |||
| <input type="text" v-model="searchInputValue" placeholder="搜项目" /> | |||
| <input type="text" v-model="searchInputValue" placeholder="搜项目" @keyup.enter="search" /> | |||
| </div> | |||
| <div class="_repo_search_btn" @click="search"> | |||
| <svg xmlns="http://www.w3.org/2000/svg" | |||
| @@ -28,13 +28,15 @@ | |||
| </div> | |||
| </div> | |||
| <div class="_repo_search_label"> | |||
| <a v-if="type == 'square'" :href="`/explore/repos?q=${searchInputValue.trim()}&topic=${item}&sort=${sort}`" | |||
| <a v-if="type == 'square'" :href="`/explore/repos?q=${searchInputValue.trim()}&topic=${item.v}&sort=${sort}`" | |||
| :style="{ backgroundColor: topicColors[index % topicColors.length] }" v-for="(item, index) in topics" | |||
| :key="index">{{ item }}</a> | |||
| <a v-if="type == 'search'" | |||
| :href="`/explore/repos?q=${searchInputValue.trim()}&topic=${selectTopic == item ? '' : item}&sort=${sort}`" | |||
| :style="{ backgroundColor: selectTopic == item ? selectedColor : defaultColor, color: '#40485b' }" | |||
| v-for="(item, index) in topics" :key="index">{{ item }}</a> | |||
| :key="index">{{ item.v }}</a> | |||
| <a v-if="type == 'search'" href="javascript:;" @click="changeTopic({ k: '', v: '' })" | |||
| style="color:#40485b;font-weight:bold;" | |||
| :style="{ backgroundColor: selectTopic == '' ? selectedColor : defaultColor }">全部领域</a> | |||
| <a v-if="type == 'search'" href="javascript:;" @click="changeTopic(item)" style="color:#40485b;" | |||
| :style="{ backgroundColor: selectTopic.toLocaleLowerCase() == item.k ? selectedColor : defaultColor }" | |||
| v-for="(item, index) in topics" :key="index">{{ item.v }}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -68,30 +70,75 @@ export default { | |||
| defaultColor: '#F6F6F6', | |||
| selectedColor: '', | |||
| selectTopic: '', | |||
| topicOri: [], | |||
| topics: [], | |||
| }; | |||
| }, | |||
| methods: { | |||
| search() { | |||
| window.location.href = `/explore/repos?q=${this.searchInputValue}&sort=${this.sort}&topic=${this.selectTopic}`; | |||
| } | |||
| }, | |||
| watch: { | |||
| searchValue(nVal) { | |||
| this.searchInputValue = nVal; | |||
| setDefaultSearch(params) { | |||
| this.searchInputValue = params.q || ''; | |||
| this.selectTopic = params.topic || ''; | |||
| }, | |||
| topic(nVal) { | |||
| this.selectTopic = nVal; | |||
| changeTopic(topicItem) { | |||
| const index_ori = this.topicOri.findIndex((item) => { | |||
| return item.k == this.selectTopic.toLocaleLowerCase(); | |||
| }); | |||
| if (index_ori < 0 && this.selectTopic) { | |||
| const index = this.topics.findIndex((item) => { | |||
| return item.k == this.selectTopic.toLocaleLowerCase(); | |||
| }); | |||
| this.topics.splice(index, 1); | |||
| } | |||
| this.selectTopic = topicItem.v; | |||
| if (this.selectTopic && this.topics.indexOf(this.selectTopic) < 0) { | |||
| const index = this.topics.findIndex(item => { | |||
| return item.k == this.selectTopic.toLocaleLowerCase(); | |||
| }) | |||
| if (index < 0) { | |||
| this.topics.push({ | |||
| k: this.selectTopic.toLocaleLowerCase(), | |||
| v: this.selectTopic, | |||
| }); | |||
| } | |||
| } | |||
| this.search(); | |||
| }, | |||
| search() { | |||
| if (this.type == 'square') { | |||
| window.location.href = `/explore/repos?q=${this.searchInputValue}&sort=${this.sort}&topic=${this.selectTopic}`; | |||
| } else { | |||
| this.$emit('change', { | |||
| q: this.searchInputValue, | |||
| topic: this.selectTopic, | |||
| }); | |||
| } | |||
| } | |||
| }, | |||
| watch: {}, | |||
| mounted() { | |||
| getPromoteData('/repos/recommend_topics').then(res => { | |||
| const data = res.data; | |||
| try { | |||
| const topics = JSON.parse(data); | |||
| const topicsData = JSON.parse(data); | |||
| const topics = topicsData.map((item) => { | |||
| return { | |||
| k: item.toLocaleLowerCase(), | |||
| v: item, | |||
| } | |||
| }); | |||
| this.topicOri = JSON.parse(JSON.stringify(topics)); | |||
| this.topics = topics; | |||
| if (this.selectTopic && this.topics.indexOf(this.selectTopic) < 0) { | |||
| this.topics.push(this.selectTopic); | |||
| const selectTopic_key = this.selectTopic.toLocaleLowerCase(); | |||
| if (selectTopic_key) { | |||
| const index = this.topics.findIndex((item) => { | |||
| return item.k == selectTopic_key; | |||
| }); | |||
| if (index < 0) { | |||
| this.topics.push({ | |||
| k: this.selectTopic.toLocaleLowerCase(), | |||
| v: this.selectTopic, | |||
| }); | |||
| } | |||
| } | |||
| } catch (err) { | |||
| console.log(err); | |||
| @@ -1,13 +1,13 @@ | |||
| <template> | |||
| <div> | |||
| <div class="ui container"> | |||
| <SearchBar type="search" :sort="reposListSortType" :searchValue="reposListQurey" :topic="reposListTopic" | |||
| @search="changeSearch"></SearchBar> | |||
| <SearchBar ref="searchBarRef" type="search" :sort="reposListSortType" :searchValue="reposListQurey" | |||
| :topic="reposListTopic" @change="searchBarChange"></SearchBar> | |||
| </div> | |||
| <div class="ui container"> | |||
| <div class="ui grid"> | |||
| <div class="computer only ui two wide computer column"> | |||
| <ReposFilters ref="reposFiltersRef" @change="changeFilters" :defaultsort="reposListSortType"></ReposFilters> | |||
| <ReposFilters ref="reposFiltersRef" @change="filtersChange"></ReposFilters> | |||
| </div> | |||
| <div class="ui sixteen wide mobile twelve wide tablet ten wide computer column"> | |||
| <ReposList ref="reposListRef" :sort="reposListSortType" :q="reposListQurey" :topic="reposListTopic"> | |||
| @@ -53,26 +53,32 @@ export default { | |||
| ActiveOrgs, | |||
| }, | |||
| methods: { | |||
| changeFilters(condition) { | |||
| filtersChange(condition) { | |||
| this.reposListSortType = condition.key; | |||
| this.search(); | |||
| }, | |||
| changeSearch() { | |||
| searchBarChange(params) { | |||
| this.reposListQurey = params.q || ''; | |||
| this.reposListTopic = params.topic || ''; | |||
| this.search(); | |||
| }, | |||
| search() { | |||
| this.$nextTick(() => { | |||
| this.$refs.reposListRef.getListData(); | |||
| this.$refs.reposListRef.search(); | |||
| }); | |||
| } | |||
| }, | |||
| mounted() { | |||
| const urlParams = getUrlSearchParams(); | |||
| this.reposListQurey = urlParams.q; | |||
| this.reposListTopic = urlParams.topic; | |||
| this.reposListQurey = urlParams.q || ''; | |||
| this.reposListTopic = urlParams.topic || ''; | |||
| this.reposListSortType = urlParams.sort || 'mostpopular'; | |||
| this.search(); | |||
| this.$refs.reposFiltersRef.setDefaultFilter(this.reposListSortType); | |||
| this.$refs.searchBarRef.setDefaultSearch({ | |||
| q: this.reposListQurey, | |||
| topic: this.reposListTopic, | |||
| }); | |||
| }, | |||
| beforeDestroy() { }, | |||
| }; | |||
| @@ -4,8 +4,8 @@ | |||
| <SquareTop></SquareTop> | |||
| </div> | |||
| <div class="ui container"> | |||
| <SearchBar type="square" :sort="reposListSortType" :searchValue="reposListQurey" :topic="reposListTopic" | |||
| @search="changeSearch"></SearchBar> | |||
| <SearchBar ref="searchBarRef" type="square" :sort="``" :searchValue="reposListQurey" :topic="``" | |||
| @change="searchBarChange"></SearchBar> | |||
| </div> | |||
| <div class="recommend-repos-c"> | |||
| <RecommendRepos></RecommendRepos> | |||
| @@ -13,7 +13,7 @@ | |||
| <div class="ui container"> | |||
| <div class="ui grid"> | |||
| <div class="computer only ui two wide computer column"> | |||
| <ReposFilters ref="reposFiltersRef" @change="changeFilters" :defaultsort="reposListSortType"></ReposFilters> | |||
| <ReposFilters ref="reposFiltersRef" @change="filtersChange"></ReposFilters> | |||
| </div> | |||
| <div class="ui sixteen wide mobile twelve wide tablet ten wide computer column"> | |||
| <ReposList ref="reposListRef" :sort="reposListSortType" :q="reposListQurey" :topic="reposListTopic"> | |||
| @@ -60,19 +60,29 @@ export default { | |||
| ActiveOrgs, | |||
| }, | |||
| methods: { | |||
| changeFilters(condition) { | |||
| filtersChange(condition) { | |||
| this.reposListSortType = condition.key; | |||
| this.search(); | |||
| }, | |||
| changeSearch() { }, | |||
| searchBarChange(params) { | |||
| this.reposListQurey = params.q || ''; | |||
| this.reposListTopic = params.topic || ''; | |||
| this.search(); | |||
| }, | |||
| search() { | |||
| this.$nextTick(() => { | |||
| this.$refs.reposListRef.getListData(); | |||
| this.$refs.reposListRef.search(); | |||
| }); | |||
| } | |||
| }, | |||
| mounted() { | |||
| this.search(); | |||
| this.$nextTick(() => { | |||
| this.$refs.searchBarRef.setDefaultSearch({ | |||
| q: '', | |||
| topic: '', | |||
| }); | |||
| this.search(); | |||
| }); | |||
| }, | |||
| beforeDestroy() { }, | |||
| }; | |||