|
@@ -1,826 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="works con">
|
|
|
- <div class="back-top" @click="onClickBackTop" v-show="isShowBackTopBtn">
|
|
|
- <i class="iconfont icon-top"></i>
|
|
|
- </div>
|
|
|
- <div class="tab">
|
|
|
- <span
|
|
|
- >{{ myWorks }}
|
|
|
- {{ workTotalNum !== undefined ? `(${workTotalNum})` : "" }}</span
|
|
|
- >
|
|
|
- <div class="tab-r">
|
|
|
- <div class="filter">
|
|
|
- <div
|
|
|
- :class="{ active: isFilterFocus }"
|
|
|
- @focusin="onFilterFocus"
|
|
|
- @focusout="onFilterBlur"
|
|
|
- >
|
|
|
- <i class="iconfont iconworks_search search"></i>
|
|
|
- <input type="text" :placeholder="search" v-model="searchKey" />
|
|
|
- <i
|
|
|
- v-if="searchKey"
|
|
|
- @click="searchKey = ''"
|
|
|
- class="iconfont icon-toast_red del"
|
|
|
- ></i>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="mask" v-show="isShowMask"></div>
|
|
|
- <!-- 断网时,输入关键字触发网络请求后,骨架图的隐藏会触发v-infinite-scroll,原因未知。进而导致循环触发,因此list为空时要禁用v-infinite-scroll -->
|
|
|
- <ul
|
|
|
- class="w-list"
|
|
|
- v-if="!(list.length === 0 && !hasMoreData)"
|
|
|
- v-infinite-scroll="requestMoreData"
|
|
|
- :infinite-scroll-disabled="
|
|
|
- !hasMoreData || isRequestingMoreData || list.length === 0
|
|
|
- "
|
|
|
- ref="w-list-ref"
|
|
|
- @scroll.self="onWorkListScroll"
|
|
|
- >
|
|
|
- <!-- <li class="add-work" @click="add">
|
|
|
- <div class="wrapper">
|
|
|
- <div class="add-con">
|
|
|
- <div>
|
|
|
- <i class="iconfont icon-works_add"></i>
|
|
|
- </div>
|
|
|
- <span>{{ create }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </li> -->
|
|
|
- <!-- 骨架图 -->
|
|
|
- <template v-if="isRequestingMoreData && list.length === 0">
|
|
|
- <li v-for="index in 19" :key="index">
|
|
|
- <div class="wrapper">
|
|
|
- <workCardSkeleton></workCardSkeleton>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- </template>
|
|
|
- <li
|
|
|
- v-for="(item, i) in list"
|
|
|
- :key="i"
|
|
|
- :class="{ 'has-more-data': hasMoreData }"
|
|
|
- >
|
|
|
- <div class="wrapper">
|
|
|
- <div class="li-hover">
|
|
|
- <span class="lipreview" @click="handlePreview(item)">{{
|
|
|
- preview
|
|
|
- }}</span>
|
|
|
- <ul class="oper">
|
|
|
- <li class="comfirmhover" @click="edit(item)">
|
|
|
- <i class="iconfont icon-works_editor"></i>{{ edittips }}
|
|
|
- </li>
|
|
|
- <li class="comfirmhover" @click="openShare(item)">
|
|
|
- <i class="iconfont icon-works_share"></i>{{ share }}
|
|
|
- </li>
|
|
|
- <li class="cancelhover" @click="del(item, i)">
|
|
|
- <i class="iconfont icon-works_delete"></i>{{ deltips }}
|
|
|
- </li>
|
|
|
- </ul>
|
|
|
- </div>
|
|
|
- <div class="img" @click="handlePreview(item)">
|
|
|
- <img class="real" :src="item.icon || $thumb" alt="" />
|
|
|
- </div>
|
|
|
- <div class="li-info">
|
|
|
- <div>
|
|
|
- <span class="shenglve tttttt" :title="item.name || no_title">{{
|
|
|
- item.name || no_title
|
|
|
- }}</span>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <span>{{ item.createTime.split(" ")[0] }}</span>
|
|
|
- <div :title="item.visit">
|
|
|
- <i class="iconfont icon-works_look"></i
|
|
|
- >{{ item.visit > 10000 ? "1w+" : item.visit }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </li>
|
|
|
- <div
|
|
|
- class="work-list-loading-wrapper"
|
|
|
- v-show="isRequestingMoreData && list.length !== 0"
|
|
|
- >
|
|
|
- <img
|
|
|
- class="work-list-loading"
|
|
|
- :src="require('@/assets/images/icons/work-list-loading.gif')"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </ul>
|
|
|
- <div
|
|
|
- class="nodata"
|
|
|
- v-if="list.length == 0 && !hasMoreData && lastestUsedSearchKey"
|
|
|
- >
|
|
|
- <img :src="$noresult" alt="" />
|
|
|
- <span>{{ no_search_result }}~</span>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- class="nodata"
|
|
|
- v-if="list.length == 0 && !hasMoreData && !lastestUsedSearchKey"
|
|
|
- >
|
|
|
- <img :src="config.empty" alt="" />
|
|
|
- <span>{{ no_works }}</span>
|
|
|
- <button @click="add" class="upload-btn-in-table">{{ create }}</button>
|
|
|
- </div>
|
|
|
- <share
|
|
|
- :show="showShare"
|
|
|
- :item="shareItem"
|
|
|
- @close="showShare = false"
|
|
|
- ></share>
|
|
|
- <preview
|
|
|
- v-if="showItem"
|
|
|
- :name="showItem.name"
|
|
|
- :show="showPreview"
|
|
|
- :ifr="`./show.html?id=${showItem.id}&lang=${$lang}`"
|
|
|
- :dark="false"
|
|
|
- @close="showPreview = false"
|
|
|
- />
|
|
|
- <div class="dialog" style="z-index: 1000" v-if="isShowMaterialSelector">
|
|
|
- <MaterialSelector
|
|
|
- :isDarkTheme="false"
|
|
|
- :title="select_material"
|
|
|
- :selectableType="['pano', '3D']"
|
|
|
- :isMultiSelection="true"
|
|
|
- initialMaterialType="pano"
|
|
|
- @cancel="isShowMaterialSelector = false"
|
|
|
- @submit="handleSubmitFromMaterialSelector"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script>
|
|
|
-import share from "../popup/share";
|
|
|
-import preview from "@/components/preview";
|
|
|
-import workCardSkeleton from "@/components/workCardSkeleton.vue";
|
|
|
-import config from "@/config";
|
|
|
-import { debounce } from "@/utils/other.js";
|
|
|
-import MaterialSelector from "@/components/materialSelector.vue";
|
|
|
-import { mapGetters } from "vuex";
|
|
|
-import { i18n } from "@/lang";
|
|
|
-import { $waiting } from "@/components/shared/loading";
|
|
|
-
|
|
|
-import {
|
|
|
- addWorks,
|
|
|
- getCamWorksList,
|
|
|
- delWorks,
|
|
|
- getPanoInfo,
|
|
|
- saveWorks,
|
|
|
-} from "@/api";
|
|
|
-
|
|
|
-export default {
|
|
|
- components: {
|
|
|
- share,
|
|
|
- preview,
|
|
|
- workCardSkeleton,
|
|
|
- MaterialSelector,
|
|
|
- },
|
|
|
- computed: {
|
|
|
- ...mapGetters(["info"]),
|
|
|
- },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- myWorks: i18n.t("material.works.my"),
|
|
|
- create: i18n.t("material.works.create"),
|
|
|
- search: i18n.t("material.works.search"),
|
|
|
- preview: i18n.t("material.works.preview"),
|
|
|
- edittips: i18n.t("material.works.edit"),
|
|
|
- share: i18n.t("material.works.share"),
|
|
|
- deltips: i18n.t("material.works.delete"),
|
|
|
- no_works: i18n.t("material.works.no_works"),
|
|
|
- no_title: i18n.t("gather.no_title"),
|
|
|
- no_search_result: i18n.t("gather.no_search_result"),
|
|
|
- select_material: i18n.t("gather.select_material"),
|
|
|
-
|
|
|
- config,
|
|
|
- list: [],
|
|
|
- workTotalNum: undefined,
|
|
|
- hasMoreData: true,
|
|
|
- isRequestingMoreData: false,
|
|
|
-
|
|
|
- searchKey: "",
|
|
|
- // 因为searchKey的变化经过debounce、异步请求的延时,才会反映到数据列表的变化上,所以是否显示、显示哪种无数据提示,也要等到数据列表变化后,根据数据列表是否为空,以及引发本次变化的那个searchKey瞬时值来决定。本变量就是用来保存那个瞬时值。
|
|
|
- lastestUsedSearchKey: "",
|
|
|
- isFilterFocus: false,
|
|
|
-
|
|
|
- showShare: false,
|
|
|
- showPreview: false,
|
|
|
- showItem: "",
|
|
|
- shareItem: "",
|
|
|
-
|
|
|
- isBackingTop: false,
|
|
|
- isShowBackTopBtn: false,
|
|
|
-
|
|
|
- isShowMask: false,
|
|
|
-
|
|
|
- isShowMaterialSelector: false,
|
|
|
- newWorkId: "",
|
|
|
- };
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- this.requestMoreData();
|
|
|
- },
|
|
|
- watch: {
|
|
|
- searchKey: {
|
|
|
- handler: function (val) {
|
|
|
- if (val.length > 0) {
|
|
|
- this.selectedList = [];
|
|
|
- }
|
|
|
- this.refreshListDebounced();
|
|
|
- },
|
|
|
- immediate: false,
|
|
|
- },
|
|
|
- },
|
|
|
- methods: {
|
|
|
- onFilterFocus() {
|
|
|
- this.isFilterFocus = true;
|
|
|
- },
|
|
|
- onFilterBlur() {
|
|
|
- this.isFilterFocus = false;
|
|
|
- },
|
|
|
- refreshListDebounced: debounce(
|
|
|
- function () {
|
|
|
- this.list = [];
|
|
|
- this.isRequestingMoreData = false;
|
|
|
- this.hasMoreData = true;
|
|
|
- this.requestMoreData();
|
|
|
- },
|
|
|
- 500,
|
|
|
- false
|
|
|
- ),
|
|
|
- openShare(data) {
|
|
|
- console.log(data);
|
|
|
- getPanoInfo(data.id, (data) => {
|
|
|
- if (data.scenes.length <= 0) {
|
|
|
- return this.$msg.warning(this.$i18n.t("material.works.no_link"));
|
|
|
- }
|
|
|
- this.showShare = true;
|
|
|
- this.shareItem = data;
|
|
|
- });
|
|
|
- },
|
|
|
-
|
|
|
- handlePreview(item) {
|
|
|
- getPanoInfo(item.id, (data) => {
|
|
|
- if (data.scenes.length <= 0) {
|
|
|
- return this.$msg.warning(this.$i18n.t("material.works.no_link"));
|
|
|
- }
|
|
|
- this.showItem = {
|
|
|
- ...item,
|
|
|
- ...data,
|
|
|
- };
|
|
|
- this.showPreview = true;
|
|
|
- });
|
|
|
- },
|
|
|
- add() {
|
|
|
- // 新建作品,弹窗让用户给作品选择素材。
|
|
|
- $waiting.show();
|
|
|
- addWorks({}, (res) => {
|
|
|
- $waiting.hide();
|
|
|
- this.newWorkId = res.data.id;
|
|
|
- this.isShowMaterialSelector = true;
|
|
|
- });
|
|
|
- },
|
|
|
- handleSubmitFromMaterialSelector(selected) {
|
|
|
- $waiting.show();
|
|
|
- // 拿新作品的初始数据
|
|
|
- getPanoInfo(
|
|
|
- this.newWorkId,
|
|
|
- // 拿到了。
|
|
|
- (data) => {
|
|
|
- // 往里边添加用户选中的素材。
|
|
|
- this.$store.commit("SetInfo", data);
|
|
|
- console.log("selected", selected);
|
|
|
- for (const [key, item] of Object.entries(selected)) {
|
|
|
- if (item.materialType === "pano") {
|
|
|
- let newScene = {
|
|
|
- icon: item.icon,
|
|
|
- sceneCode: item.sceneCode,
|
|
|
- sceneTitle: item.name,
|
|
|
- category: this.info.catalogs[0].id,
|
|
|
- type: "pano",
|
|
|
- id: "s_" + this.$randomWord(true, 8, 8),
|
|
|
- };
|
|
|
-
|
|
|
- console.log("key", key);
|
|
|
- if (Number(key) === 0) {
|
|
|
- //新建时开天空mask
|
|
|
- newScene = Object.assign(newScene, this.info.scenes[0]);
|
|
|
- newScene.customMask.sky.isShow = true;
|
|
|
- this.info.scenes[0] = newScene;
|
|
|
- } else {
|
|
|
- newScene = Object.assign(newScene, {
|
|
|
- customMask: this.info.scenes[0].customMask,
|
|
|
- initVisual: this.info.scenes[0].initVisual,
|
|
|
- });
|
|
|
- newScene.customMask.sky.isShow = true;
|
|
|
- this.info.scenes.push(newScene);
|
|
|
- }
|
|
|
- } else if (item.materialType === "3D") {
|
|
|
- let newScene = {
|
|
|
- icon: item.thumb,
|
|
|
- sceneCode: item.num,
|
|
|
- sceneTitle: item.sceneName,
|
|
|
- category: this.info.catalogs[0].id,
|
|
|
- type: "4dkk",
|
|
|
- id: "s_" + this.$randomWord(true, 8, 8),
|
|
|
- };
|
|
|
- if (Number(key) === 0) {
|
|
|
- this.info.scenes[0] = null;
|
|
|
- this.info.scenes[0] = newScene;
|
|
|
- } else {
|
|
|
- this.info.scenes.push(newScene);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 保存新作品
|
|
|
- saveWorks(
|
|
|
- {
|
|
|
- id: this.newWorkId,
|
|
|
- password: "",
|
|
|
- someData: {
|
|
|
- ...this.info,
|
|
|
- status: 1,
|
|
|
- icon: this.info.scenes[0].icon,
|
|
|
- },
|
|
|
- },
|
|
|
- // 保存成功
|
|
|
- () => {
|
|
|
- $waiting.hide();
|
|
|
- // 隐藏素材选择弹窗
|
|
|
- this.isShowMaterialSelector = false;
|
|
|
-
|
|
|
- // 刷新作品列表
|
|
|
- this.list = [];
|
|
|
- this.isRequestingMoreData = false;
|
|
|
- this.hasMoreData = true;
|
|
|
- this.requestMoreData()
|
|
|
- .then(() => {
|
|
|
- // 刷新成功
|
|
|
-
|
|
|
- // 弹出提示窗口
|
|
|
- this.$confirm({
|
|
|
- title: this.$i18n.t("tips_code.tips"),
|
|
|
- content: this.$i18n.t("material.works.had_created"),
|
|
|
- okText: this.$i18n.t("material.works.goto_preview"),
|
|
|
- ok: () => {
|
|
|
- this.handlePreview(this.list[0]);
|
|
|
- this.newWorkId = "";
|
|
|
- this.$store.commit("SetInfo", {});
|
|
|
- },
|
|
|
- ok2Text: this.$i18n.t("material.works.continue_edit"),
|
|
|
- ok2: () => {
|
|
|
- window.open(
|
|
|
- `./edit.html?id=${this.newWorkId}&lang=${this.$lang}`
|
|
|
- );
|
|
|
- this.newWorkId = "";
|
|
|
- this.$store.commit("SetInfo", {});
|
|
|
- },
|
|
|
- });
|
|
|
- })
|
|
|
- .catch(() => {
|
|
|
- this.$msg.message(
|
|
|
- this.$i18n.t("material.works.had_created_but_no_link")
|
|
|
- );
|
|
|
- console.error("已成功新建作品,但刷新作品列表失败。");
|
|
|
- });
|
|
|
- },
|
|
|
- // 保存失败,删除新建的作品。
|
|
|
- (error) => {
|
|
|
- $waiting.hide();
|
|
|
- console.error("保存失败:", error);
|
|
|
- delWorks(this.newWorkId);
|
|
|
- this.newWorkId = "";
|
|
|
- this.$store.commit("SetInfo", {});
|
|
|
- }
|
|
|
- );
|
|
|
- },
|
|
|
- // 没拿到,删除新建的作品。
|
|
|
- (error) => {
|
|
|
- console.error("没拿到新建的作品数据:", error);
|
|
|
- delWorks(this.newWorkId);
|
|
|
- this.newWorkId = "";
|
|
|
- }
|
|
|
- );
|
|
|
- },
|
|
|
- edit(item) {
|
|
|
- const from = this.$route.name;
|
|
|
- window.open(`./edit.html?id=${item.id}&lang=${this.$lang}&from=${from}`);
|
|
|
- },
|
|
|
- del(item, index) {
|
|
|
- this.$confirm({
|
|
|
- title: this.$i18n.t("material.works.delete_work"),
|
|
|
- content: this.$i18n.t("material.works.comfirm_delete"),
|
|
|
- ok: () => {
|
|
|
- $waiting.show();
|
|
|
-
|
|
|
- delWorks(item.id, () => {
|
|
|
- this.$msg.success(this.$i18n.t("gather.delete_success"));
|
|
|
- this.isRequestingMoreData = true;
|
|
|
- const lastestUsedSearchKey = this.searchKey;
|
|
|
- getCamWorksList(
|
|
|
- {
|
|
|
- pageNum: this.list.length,
|
|
|
- pageSize: 1,
|
|
|
- searchKey: this.searchKey,
|
|
|
- },
|
|
|
- (data) => {
|
|
|
- $waiting.hide();
|
|
|
- this.list.splice(index, 1);
|
|
|
- this.list = this.list.concat(data.data.list);
|
|
|
- if (this.list.length === data.data.total) {
|
|
|
- this.hasMoreData = false;
|
|
|
- }
|
|
|
- this.isRequestingMoreData = false;
|
|
|
- this.lastestUsedSearchKey = lastestUsedSearchKey;
|
|
|
- if (!lastestUsedSearchKey) {
|
|
|
- this.workTotalNum = data.data.total;
|
|
|
- }
|
|
|
- // TODO: 这是干啥呢?
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$bus.emit("refreshTips");
|
|
|
- });
|
|
|
- },
|
|
|
- () => {
|
|
|
- $waiting.hide();
|
|
|
- this.lastestUsedSearchKey = lastestUsedSearchKey;
|
|
|
- this.isRequestingMoreData = false;
|
|
|
- }
|
|
|
- );
|
|
|
- });
|
|
|
- },
|
|
|
- });
|
|
|
- },
|
|
|
- requestMoreData() {
|
|
|
- this.isRequestingMoreData = true;
|
|
|
- const lastestUsedSearchKey = this.searchKey;
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- getCamWorksList(
|
|
|
- {
|
|
|
- pageNum: Math.floor(this.list.length / config.PAGE_SIZE) + 1,
|
|
|
- pageSize: config.PAGE_SIZE,
|
|
|
- searchKey: this.searchKey,
|
|
|
- },
|
|
|
- (data) => {
|
|
|
- this.list = this.list.concat(data.data.list);
|
|
|
- if (this.list.length === data.data.total) {
|
|
|
- this.hasMoreData = false;
|
|
|
- }
|
|
|
- this.isRequestingMoreData = false;
|
|
|
- this.lastestUsedSearchKey = lastestUsedSearchKey;
|
|
|
- if (!lastestUsedSearchKey) {
|
|
|
- this.workTotalNum = data.data.total;
|
|
|
- }
|
|
|
- // TODO: 这是干啥呢?
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$bus.emit("refreshTips");
|
|
|
- });
|
|
|
- resolve();
|
|
|
- },
|
|
|
- () => {
|
|
|
- this.isRequestingMoreData = false;
|
|
|
- this.lastestUsedSearchKey = lastestUsedSearchKey;
|
|
|
- reject();
|
|
|
- }
|
|
|
- );
|
|
|
- });
|
|
|
- },
|
|
|
- onClickBackTop() {
|
|
|
- if (this.isBackingTop) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this.isBackingTop = true;
|
|
|
-
|
|
|
- const startTime = Date.now();
|
|
|
- const totalScroll = this.$refs["w-list-ref"].scrollTop;
|
|
|
- const fn = () => {
|
|
|
- if (this.$refs["w-list-ref"].scrollTop === 0) {
|
|
|
- this.isBackingTop = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const nowTime = Date.now();
|
|
|
- const assumeScrollTop =
|
|
|
- totalScroll - ((nowTime - startTime) * totalScroll) / 500;
|
|
|
- this.$refs["w-list-ref"].scrollTop =
|
|
|
- assumeScrollTop > 0 ? assumeScrollTop : 0;
|
|
|
- requestAnimationFrame(fn);
|
|
|
- };
|
|
|
- requestAnimationFrame(fn);
|
|
|
- },
|
|
|
- onWorkListScroll(e) {
|
|
|
- if (e.target.scrollTop >= 30) {
|
|
|
- !this.isShowMask && (this.isShowMask = true);
|
|
|
- } else {
|
|
|
- this.isShowMask && (this.isShowMask = false);
|
|
|
- }
|
|
|
-
|
|
|
- if (e.target.scrollTop >= 600) {
|
|
|
- this.isShowBackTopBtn = true;
|
|
|
- } else {
|
|
|
- this.isShowBackTopBtn = false;
|
|
|
- }
|
|
|
- },
|
|
|
- },
|
|
|
-};
|
|
|
-</script>
|
|
|
-
|
|
|
-<style lang="less" scoped>
|
|
|
-.works {
|
|
|
- width: 100%;
|
|
|
- flex-direction: column;
|
|
|
- position: relative;
|
|
|
-
|
|
|
- .back-top {
|
|
|
- position: absolute;
|
|
|
- right: -80px;
|
|
|
- bottom: 30px;
|
|
|
- width: 60px;
|
|
|
- height: 60px;
|
|
|
- border-radius: 8px;
|
|
|
- background-color: #fff;
|
|
|
- z-index: 1;
|
|
|
- color: #c8c9cc;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- color: #323233;
|
|
|
- }
|
|
|
-
|
|
|
- cursor: pointer;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- i {
|
|
|
- font-size: 20px;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .tab {
|
|
|
- flex: 0 0 auto;
|
|
|
- width: 100%;
|
|
|
- display: flex;
|
|
|
- background: #fff;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- padding: 20px 30px;
|
|
|
-
|
|
|
- > span {
|
|
|
- font-size: 18px;
|
|
|
- font-weight: bold;
|
|
|
- }
|
|
|
-
|
|
|
- .tab-r {
|
|
|
- align-items: center;
|
|
|
- display: flex;
|
|
|
-
|
|
|
- .ui-button {
|
|
|
- margin-right: 20px;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .mask {
|
|
|
- position: absolute;
|
|
|
- width: 100%;
|
|
|
- top: 200px;
|
|
|
- height: 30px;
|
|
|
- background: linear-gradient(rgb(239, 242, 244), rgba(255, 255, 255, 0));
|
|
|
- z-index: 1;
|
|
|
- pointer-events: none;
|
|
|
- }
|
|
|
-
|
|
|
- .w-list {
|
|
|
- flex: 1 1 auto;
|
|
|
- overflow: auto;
|
|
|
- margin-top: 22px;
|
|
|
- padding-top: 8px;
|
|
|
- @gap: 20px;
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
- align-content: flex-start;
|
|
|
- // 让宽度和视口等宽,为了保证鼠标列表显示区域以外时列表也能响应滚轮事件。
|
|
|
- margin-left: calc((100vw - 100%) / -2);
|
|
|
- padding-left: calc((100vw - 100%) / 2);
|
|
|
- margin-right: calc((100vw - 100%) / -2);
|
|
|
- padding-right: calc((100vw - 100%) / 2);
|
|
|
-
|
|
|
- &::-webkit-scrollbar {
|
|
|
- width: 0;
|
|
|
- height: 0;
|
|
|
- }
|
|
|
-
|
|
|
- > li {
|
|
|
- width: calc((100% - @gap * 4) / 5);
|
|
|
- height: 322px;
|
|
|
- margin-bottom: @gap;
|
|
|
- margin-right: @gap;
|
|
|
-
|
|
|
- &:nth-of-type(5n) {
|
|
|
- margin-right: 0;
|
|
|
- }
|
|
|
-
|
|
|
- // 因为有个“创建作品”card占着空间,每次拿20个数据,每行五个,又不想每次拿到数据后最后一行只有一个card,所以把最后那个card隐藏掉。
|
|
|
- &:last-of-type.has-more-data {
|
|
|
- display: none;
|
|
|
- }
|
|
|
-
|
|
|
- .wrapper {
|
|
|
- height: 100%;
|
|
|
- background: #fff;
|
|
|
- position: relative;
|
|
|
- border-radius: 6px;
|
|
|
- overflow: hidden;
|
|
|
-
|
|
|
- .li-hover {
|
|
|
- display: none;
|
|
|
- width: 100%;
|
|
|
- height: 240px;
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 0;
|
|
|
- z-index: 99;
|
|
|
- background: rgba(0, 0, 0, 0.6);
|
|
|
-
|
|
|
- .lipreview {
|
|
|
- position: absolute;
|
|
|
- top: 50%;
|
|
|
- left: 50%;
|
|
|
- transform: translate(-50%, -50%);
|
|
|
- color: #fff;
|
|
|
- display: inline-block;
|
|
|
- line-height: 40px;
|
|
|
- height: 40px;
|
|
|
- width: 100px;
|
|
|
- text-align: center;
|
|
|
- border-radius: 22px;
|
|
|
- cursor: pointer;
|
|
|
- background-color: transparent;
|
|
|
- border: 1px solid #fff;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- border: none;
|
|
|
- background: #1983f6;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .oper {
|
|
|
- display: flex;
|
|
|
- justify-content: space-around;
|
|
|
- align-items: center;
|
|
|
- position: absolute;
|
|
|
- bottom: 10px;
|
|
|
- left: 0;
|
|
|
- width: 100%;
|
|
|
-
|
|
|
- > li {
|
|
|
- color: #fff;
|
|
|
- font-size: 13px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- cursor: pointer;
|
|
|
-
|
|
|
- > i {
|
|
|
- font-size: 20px;
|
|
|
- margin-right: 4px;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .img {
|
|
|
- width: 100%;
|
|
|
- height: 240px;
|
|
|
- position: relative;
|
|
|
- overflow: hidden;
|
|
|
- cursor: pointer;
|
|
|
-
|
|
|
- .real {
|
|
|
- height: 100%;
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 50%;
|
|
|
- transform: translateX(-50%);
|
|
|
- z-index: 0;
|
|
|
- transition: all ease 0.3s;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .li-info {
|
|
|
- font-size: 14px;
|
|
|
- padding: 10px;
|
|
|
-
|
|
|
- > div {
|
|
|
- text-align: left;
|
|
|
-
|
|
|
- &:first-of-type {
|
|
|
- > span {
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 10px;
|
|
|
- display: inline-block;
|
|
|
- text-overflow: ellipsis;
|
|
|
- overflow: hidden;
|
|
|
- white-space: nowrap;
|
|
|
- cursor: pointer;
|
|
|
- color: #323233;
|
|
|
- font-size: 16px;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- &:last-of-type {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
-
|
|
|
- > span {
|
|
|
- font-size: 14px;
|
|
|
- color: #969799;
|
|
|
- }
|
|
|
-
|
|
|
- > div {
|
|
|
- color: #969799;
|
|
|
-
|
|
|
- i {
|
|
|
- margin-right: 6px;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- &:hover {
|
|
|
- .wrapper {
|
|
|
- box-shadow: 0px 2px 12px 0px rgba(50, 50, 51, 0.12);
|
|
|
- transform: translateY(-6px);
|
|
|
-
|
|
|
- .li-hover {
|
|
|
- display: block;
|
|
|
- }
|
|
|
-
|
|
|
- .img {
|
|
|
- .real {
|
|
|
- height: 108%;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .add-work {
|
|
|
- .wrapper {
|
|
|
- .add-con {
|
|
|
- position: absolute;
|
|
|
- top: 50%;
|
|
|
- left: 50%;
|
|
|
- transform: translate(-50%, -50%);
|
|
|
- text-align: center;
|
|
|
-
|
|
|
- div {
|
|
|
- width: 60px;
|
|
|
- height: 60px;
|
|
|
- border-radius: 50%;
|
|
|
- background: linear-gradient(144deg, #00aefb 0%, #0076f6 100%);
|
|
|
- position: relative;
|
|
|
- cursor: pointer;
|
|
|
- margin: 0 auto;
|
|
|
-
|
|
|
- > i {
|
|
|
- font-size: 16px;
|
|
|
- position: absolute;
|
|
|
- top: 50%;
|
|
|
- left: 50%;
|
|
|
- transform: translate(-50%, -50%);
|
|
|
- color: #fff;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- span {
|
|
|
- color: #333333;
|
|
|
- display: inline-block;
|
|
|
- margin-top: 8px;
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .work-list-loading-wrapper {
|
|
|
- width: 100%;
|
|
|
- margin-top: 20px;
|
|
|
- margin-bottom: 22px;
|
|
|
-
|
|
|
- .work-list-loading {
|
|
|
- display: block;
|
|
|
- margin: 0 auto;
|
|
|
- width: 50px;
|
|
|
- height: 8px;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|
|
|
-
|
|
|
-<style lang="less" scoped>
|
|
|
-@import "../style.less";
|
|
|
-</style>
|