♻️ refactored code
This commit is contained in:
@@ -14,78 +14,37 @@
|
||||
<span style="font-size: 14px;color: #333333">{{ route.query.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ImageToolbar :selected="imageStore.selected" :imageList="images"/>
|
||||
<ImageToolbar :selected="imageStore.selected" :imageList="imageList"/>
|
||||
<div class="people-album-detail-info">
|
||||
<span style="font-size: 14px;color: #999999">共{{ imageStore.countTotalImages(images) }}张照片</span>
|
||||
<span style="font-size: 14px;color: #999999">共{{ imageStore.countTotalImages(imageList) }}张照片</span>
|
||||
</div>
|
||||
<div class="people-album-detail-list">
|
||||
<div style="width:100%;height:100%;" v-if="images &&images.length !== 0">
|
||||
<div v-for="(itemList, index) in images" :key="index">
|
||||
<span style="margin-left: 10px;font-size: 13px">{{ itemList.date }}</span>
|
||||
<AImagePreviewGroup>
|
||||
<Vue3JustifiedLayout v-model:list="itemList.list" :options="options">
|
||||
<template #default="{ item }">
|
||||
<CheckCard :key="index"
|
||||
class="photo-item"
|
||||
margin="0"
|
||||
border-radius="0"
|
||||
v-model="imageStore.selected"
|
||||
:showHoverCircle="true"
|
||||
:iconSize="20"
|
||||
:showSelectedEffect="true"
|
||||
:value="item.id">
|
||||
<AImage :src="item.thumbnail"
|
||||
:alt="item.file_name"
|
||||
:key="index"
|
||||
:height="200"
|
||||
:previewMask="false"
|
||||
:preview="{
|
||||
src: item.url,
|
||||
}"
|
||||
loading="lazy"/>
|
||||
</CheckCard>
|
||||
</template>
|
||||
</Vue3JustifiedLayout>
|
||||
</AImagePreviewGroup>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-content">
|
||||
<AEmpty :image="empty" :image-style="{width: '100%', height: '100%'}">
|
||||
<template #description>
|
||||
<span style="color: #999999;font-size: 16px;font-weight: 500;line-height: 1.5;">
|
||||
暂无照片,快去上传吧
|
||||
</span>
|
||||
</template>
|
||||
</AEmpty>
|
||||
</div>
|
||||
<ImageWaterfallList :image-list="imageList"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Vue3JustifiedLayout from "vue3-justified-layout";
|
||||
import 'vue3-justified-layout/dist/style.css';
|
||||
import {getFaceSamplesDetailList} from "@/api/storage";
|
||||
import ImageToolbar from "@/views/Photograph/ImageToolbar/ImageToolbar.vue";
|
||||
import ImageToolbar from "@/components/ImageToolbar/ImageToolbar.vue";
|
||||
import useStore from "@/store";
|
||||
import empty from "@/assets/svgs/empty.svg";
|
||||
|
||||
import ImageWaterfallList from "@/components/ImageWaterfallList/ImageWaterfallList.vue";
|
||||
|
||||
|
||||
const imageStore = useStore().image;
|
||||
const images = ref<any[]>([]);
|
||||
const imageList = ref<any[]>([]);
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const upload = useStore().upload;
|
||||
|
||||
const options = reactive({
|
||||
targetRowHeight: 200 // 高度
|
||||
});
|
||||
|
||||
async function getAlbumList(id: number) {
|
||||
imageStore.imageListLoading = true;
|
||||
const res: any = await getFaceSamplesDetailList(id, upload.storageSelected?.[0], upload.storageSelected?.[1]);
|
||||
if (res && res.code === 200) {
|
||||
images.value = res.data.records;
|
||||
imageList.value = res.data.records;
|
||||
}
|
||||
imageStore.imageListLoading = false;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
@@ -3,70 +3,37 @@
|
||||
<div class="people-album-header">
|
||||
<ADropdown trigger="click">
|
||||
<AButton type="text" size="large" class="people-album-button">
|
||||
{{ selectedKey === '0' ? '人 物' : '已隐藏' }}
|
||||
{{ imageStore.faceSelectedKey === '0' ? '人 物' : '已隐藏' }}
|
||||
<DownOutlined class="people-album-icon"/>
|
||||
</AButton>
|
||||
<template #overlay>
|
||||
<AMenu selectable :selectedKeys="[selectedKey]" @select="handleSelect">
|
||||
<AMenu selectable :selectedKeys="[imageStore.faceSelectedKey]" @select="handleSelect">
|
||||
<AMenuItem key="0">人 物</AMenuItem>
|
||||
<AMenuItem key="1">已隐藏</AMenuItem>
|
||||
</AMenu>
|
||||
</template>
|
||||
</ADropdown>
|
||||
<span class="people-album-count">共<span style="color: #0e87cc">{{ faceList.length }}</span>位</span>
|
||||
<span class="people-album-count">共<span style="color: #0e87cc">{{ imageStore.faceList.length }}</span>位</span>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div class="people-album-toolbar" v-show="selected.length !== 0">
|
||||
<div class="people-album-toolbar-left">
|
||||
<AButton type="text" shape="circle" size="large" class="people-album-toolbar-btn" @click="cancelSelectPeople">
|
||||
<template #icon>
|
||||
<CloseOutlined class="people-album-toolbar-icon"/>
|
||||
</template>
|
||||
</AButton>
|
||||
<span style="font-size: 16px;font-weight: bold">
|
||||
已选择 {{ selected.length }} 个人物
|
||||
</span>
|
||||
<AButton type="text" shape="default" class="people-album-toolbar-btn" size="middle" @click="selectAllPeople">
|
||||
全选
|
||||
</AButton>
|
||||
</div>
|
||||
<div class="people-album-toolbar-right">
|
||||
|
||||
<AButton type="text" shape="default" size="middle" class="people-album-toolbar-btn"
|
||||
:disabled="selected.length !== 2" v-if="selectedKey === '0'">
|
||||
<template #icon>
|
||||
<BlockOutlined class="people-album-toolbar-icon"/>
|
||||
</template>
|
||||
合并人物
|
||||
</AButton>
|
||||
|
||||
<AButton type="text" shape="default" size="middle" class="people-album-toolbar-btn" @click="hiddenFace">
|
||||
<template #icon>
|
||||
<EyeInvisibleOutlined class="people-album-toolbar-icon"/>
|
||||
</template>
|
||||
{{ selectedKey === '0' ? '隐藏人物' : '取消隐藏' }}
|
||||
</AButton>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<PeopleAlbumToolbar :face-list="imageStore.faceList"/>
|
||||
<div class="people-album-container">
|
||||
<ASpin :spinning="loading" size="large" wrapperClassName="spin-container">
|
||||
<div class="people-album-content" v-if="faceList.length !== 0">
|
||||
<Spin :spinning="imageStore.faceListLoading" size="large" indicator="spin-dot">
|
||||
<div class="people-album-content" v-if="imageStore.faceList.length !== 0">
|
||||
<CheckCard
|
||||
v-for="(item, index) in faceList"
|
||||
v-for="(item, index) in imageStore.faceList"
|
||||
:key="index"
|
||||
@click="handleClick(item.id, item.face_name, item.face_image)"
|
||||
class="photo-item"
|
||||
margin="0"
|
||||
border-radius="0"
|
||||
v-model="selected"
|
||||
v-model="imageStore.faceSelected"
|
||||
:showHoverCircle="true"
|
||||
:background-color="'transparent'"
|
||||
:iconSize="20"
|
||||
:showSelectedEffect="false"
|
||||
:value="item.id">
|
||||
<div class="people-album-item"
|
||||
:class="{ 'selected-item': selected.includes(item.id) }"
|
||||
:class="{ 'selected-item': imageStore.faceSelected.includes(item.id) }"
|
||||
@mouseover="item.showButton = true"
|
||||
@mouseleave="item.showButton = false">
|
||||
<div class="people-album-item-avatar">
|
||||
@@ -115,7 +82,7 @@
|
||||
</CheckCard>
|
||||
|
||||
</div>
|
||||
<div v-else class="empty-content">
|
||||
<div v-if="!imageStore.imageListLoading&& imageStore.faceList.length === 0" class="empty-content">
|
||||
<AEmpty :image="empty" :image-style="{width: '100%', height: '100%'}">
|
||||
<template #description>
|
||||
<span style="color: #999999;font-size: 16px;font-weight: 500;line-height: 1.5;">
|
||||
@@ -124,49 +91,32 @@
|
||||
</template>
|
||||
</AEmpty>
|
||||
</div>
|
||||
</ASpin>
|
||||
</Spin>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {getFaceSamplesList, modifyFaceSampleName, modifyFaceTypeBatch} from "@/api/storage";
|
||||
import {modifyFaceSampleName} from "@/api/storage";
|
||||
import empty from "@/assets/svgs/empty.svg";
|
||||
import useStore from "@/store";
|
||||
import PeopleAlbumToolbar from "@/views/Album/PeopleAlbum/PeopleAlbumToolbar.vue";
|
||||
|
||||
|
||||
const faceList = ref<any[]>([]);
|
||||
const addNameInputValue = ref<string>('');
|
||||
const selectedKey = ref<string>('0');
|
||||
const loading = ref<boolean>(false);
|
||||
const selected = ref<any[]>([]);
|
||||
|
||||
/**
|
||||
* 获取人脸列表
|
||||
*/
|
||||
async function getFaceList(type: number = 0) {
|
||||
loading.value = true;
|
||||
faceList.value = [];
|
||||
const res: any = await getFaceSamplesList(type);
|
||||
if (res && res.code === 200 && res.data.faces) {
|
||||
faceList.value = res.data.faces.map(face => ({
|
||||
...face,
|
||||
showButton: false,
|
||||
showInput: false,
|
||||
}));
|
||||
}
|
||||
loading.value = false;
|
||||
}
|
||||
const imageStore = useStore().image;
|
||||
|
||||
function showAddNameInput(index: number) {
|
||||
if (faceList.value[index]) {
|
||||
faceList.value[index].showInput = true;
|
||||
faceList.value[index].showButton = false;
|
||||
if (imageStore.faceList[index]) {
|
||||
imageStore.faceList[index].showInput = true;
|
||||
imageStore.faceList[index].showButton = false;
|
||||
}
|
||||
}
|
||||
|
||||
function hideAddNameInput(index: number) {
|
||||
if (faceList.value[index]) {
|
||||
faceList.value[index].showInput = false;
|
||||
faceList.value[index].showButton = false;
|
||||
if (imageStore.faceList[index]) {
|
||||
imageStore.faceList[index].showInput = false;
|
||||
imageStore.faceList[index].showButton = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +129,7 @@ async function modifyFaceName(id: number, index: number) {
|
||||
if (!addNameInputValue.value.trim()) return;
|
||||
const res: any = await modifyFaceSampleName(id, addNameInputValue.value);
|
||||
if (res && res.code === 200) {
|
||||
faceList.value[index].face_name = res.data.face_name;
|
||||
imageStore.faceList[index].face_name = res.data.face_name;
|
||||
addNameInputValue.value = '';
|
||||
hideAddNameInput(index);
|
||||
}
|
||||
@@ -190,35 +140,10 @@ async function modifyFaceName(id: number, index: number) {
|
||||
* @param key
|
||||
*/
|
||||
function handleSelect({key}) {
|
||||
selectedKey.value = key;
|
||||
getFaceList(parseInt(key));
|
||||
imageStore.faceSelectedKey = key;
|
||||
imageStore.getFaceList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 全选
|
||||
*/
|
||||
function selectAllPeople() {
|
||||
selected.value = faceList.value.map((item) => item.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消选择
|
||||
*/
|
||||
function cancelSelectPeople() {
|
||||
selected.value = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏人物
|
||||
*/
|
||||
async function hiddenFace() {
|
||||
if (selected.value.length === 0) return;
|
||||
const res: any = await modifyFaceTypeBatch(selected.value, selectedKey.value === '0' ? 1 : 0);
|
||||
if (res && res.code === 200) {
|
||||
await getFaceList();
|
||||
selected.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -229,12 +154,12 @@ const router = useRouter();
|
||||
* @param name
|
||||
* @param thumb
|
||||
*/
|
||||
function handleClick(id: number, name: string | null,thumb: string | null) {
|
||||
function handleClick(id: number, name: string | null, thumb: string | null) {
|
||||
router.push({path: route.path + `/${id}`, query: {name: name, thumb: thumb}});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getFaceList();
|
||||
imageStore.getFaceList();
|
||||
});
|
||||
|
||||
|
||||
@@ -283,57 +208,6 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
|
||||
.people-album-toolbar {
|
||||
position: fixed;
|
||||
width: calc(100% - 220px);
|
||||
height: 70px;
|
||||
top: 70px;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-image: linear-gradient(45deg, #5789ff, #5c7bff 100%);
|
||||
color: #fff;
|
||||
box-shadow: 0 3px 10px 0 rgba(0, 0, 0, .06);
|
||||
padding: 0 20px;
|
||||
|
||||
.people-album-toolbar-left {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.people-album-toolbar-right {
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.people-album-toolbar-icon {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.people-album-toolbar-btn {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.people-album-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
127
src/views/Album/PeopleAlbum/PeopleAlbumToolbar.vue
Normal file
127
src/views/Album/PeopleAlbum/PeopleAlbumToolbar.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div class="people-album-toolbar" v-show="imageStore.faceSelected.length !== 0">
|
||||
<div class="people-album-toolbar-left">
|
||||
<AButton type="text" shape="circle" size="large" class="people-album-toolbar-btn" @click="cancelSelectPeople">
|
||||
<template #icon>
|
||||
<CloseOutlined class="people-album-toolbar-icon"/>
|
||||
</template>
|
||||
</AButton>
|
||||
<span style="font-size: 16px;font-weight: bold">
|
||||
已选择 {{ imageStore.faceSelected.length }} 个人物
|
||||
</span>
|
||||
<AButton type="text" shape="default" class="people-album-toolbar-btn" size="middle" @click="selectAllPeople">
|
||||
全选
|
||||
</AButton>
|
||||
</div>
|
||||
<div class="people-album-toolbar-right">
|
||||
|
||||
<AButton type="text" shape="default" size="middle" class="people-album-toolbar-btn"
|
||||
:disabled="imageStore.faceSelected.length !== 2" v-if="imageStore.faceSelectedKey === '0'">
|
||||
<template #icon>
|
||||
<BlockOutlined class="people-album-toolbar-icon"/>
|
||||
</template>
|
||||
合并人物
|
||||
</AButton>
|
||||
|
||||
<AButton type="text" shape="default" size="middle" class="people-album-toolbar-btn" @click="hiddenFace">
|
||||
<template #icon>
|
||||
<EyeInvisibleOutlined class="people-album-toolbar-icon"/>
|
||||
</template>
|
||||
{{ imageStore.faceSelectedKey === '0' ? '隐藏人物' : '取消隐藏' }}
|
||||
</AButton>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import useStore from "@/store";
|
||||
import {modifyFaceTypeBatch} from "@/api/storage";
|
||||
|
||||
const props = defineProps({
|
||||
faceList: {
|
||||
type: Array as PropType<any[]>,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
const imageStore = useStore().image;
|
||||
|
||||
/**
|
||||
* 全选
|
||||
*/
|
||||
function selectAllPeople() {
|
||||
imageStore.faceSelected = props.faceList.map((item) => item.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消选择
|
||||
*/
|
||||
function cancelSelectPeople() {
|
||||
imageStore.faceSelected = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏人物
|
||||
*/
|
||||
async function hiddenFace() {
|
||||
if (imageStore.faceSelected.length === 0) return;
|
||||
const res: any = await modifyFaceTypeBatch(imageStore.faceSelected, imageStore.faceSelectedKey === '0' ? 1 : 0);
|
||||
if (res && res.code === 200) {
|
||||
await imageStore.getFaceList();
|
||||
imageStore.faceSelected= [];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.people-album-toolbar {
|
||||
position: fixed;
|
||||
width: calc(100% - 220px);
|
||||
height: 70px;
|
||||
top: 70px;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-image: linear-gradient(45deg, #5789ff, #5c7bff 100%);
|
||||
color: #fff;
|
||||
box-shadow: 0 3px 10px 0 rgba(0, 0, 0, .06);
|
||||
padding: 0 20px;
|
||||
|
||||
.people-album-toolbar-left {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.people-album-toolbar-right {
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.people-album-toolbar-icon {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.people-album-toolbar-btn {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user