feat: 图片生成任务、反馈、合成

develop
wx-jincw 5 days ago
parent a3d67c7ce5
commit 8689887f41

@ -60,3 +60,12 @@ export function exportImages(query) {
params: query
})
}
// 合并图库图片
export function imageToGroup(data) {
return request({
url: '/gallery/images/generateImage',
method: 'post',
data: data
})
}

@ -60,3 +60,12 @@ export function exportFeedback(query) {
params: query
})
}
// 图片任务反馈
export function addImageFeedback(data) {
return request({
url: '/task/feedback/addByImage',
method: 'post',
data: data
})
}

@ -60,3 +60,12 @@ export function exportImages(query) {
params: query
})
}
// 根据图片生成任务
export function generateTasks(data) {
return request({
url: '/gallery/images/generateTasks',
method: 'post',
data: data
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

@ -0,0 +1,600 @@
<template>
<div class="cart-container">
<el-popover
placement="top"
width="500"
trigger="click">
<div class="cart-panel" :style="{'--current-color': theme}">
<div class="image-area" v-show="!chooseTask">
<div class="cart-title">图片购物车</div>
<div class="image-list">
<div v-for="(item, index) in list" :key="index" class="image-item" :class="{'image-item-active': item._check}" @click="imageClick(item)">
<img :src="imageUrl(item)" alt="" class="image">
<el-checkbox class="checkbox" v-model="item._check" @change="handleCheckChange"></el-checkbox>
<div class="image-delete" @click.stop="deleteImage(index)">
<i class="el-icon-delete"></i>
</div>
</div>
</div>
<div class="cart-tool">
<div style="margin-right: 16px;">
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">{{list.filter(val => val._check).length}}</el-checkbox>
</div>
<el-dropdown @command="handleImageCommand" v-loading="genImaging">
<span class="el-dropdown-link">
图片合并<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="nineGrid">九宫格</el-dropdown-item>
<el-dropdown-item command="fourGrid">四宫格</el-dropdown-item>
<el-dropdown-item command="horizontalMerge">水平合并</el-dropdown-item>
<el-dropdown-item command="verticalMerge">垂直合并</el-dropdown-item>
<el-dropdown-item command="video">生成视频</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button type="warning" size="small" plain @click="clear"></el-button>
<el-button type="info" size="small" v-loading="taskCreating" plain @click.stop="goCreateTask"></el-button>
<el-button type="primary" size="small" plain @click.stop="addToTask">反馈到任务<i class="el-icon-right"></i></el-button>
</div>
</div>
<div class="image-area task-area" v-show="chooseTask">
<div class="cart-title" @click="goBack"><i class="el-icon-back"></i>返回</div>
<div class="task-list" v-loading="loadingTask">
<el-table
ref="multipleTable"
tooltip-effect="dark"
:data="taskList"
border
height="460"
>
<el-table-column
align="center"
label="任务名称"
show-overflow-tooltip
min-width="160"
prop="taskTitle"
/>
<el-table-column label="任务类型" align="center" prop="taskType" min-width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.task_type" :value="scope.row.taskType"/>
</template>
</el-table-column>
<el-table-column
align="center"
label="任务内容"
show-overflow-tooltip
min-width="160"
prop="taskContent"
/>
<el-table-column
align="center"
label="发布单位"
show-overflow-tooltip
min-width="160"
prop="branchName"
>
</el-table-column>
<el-table-column
align="center"
label="发布部门"
show-overflow-tooltip
min-width="160"
prop="deptName"
>
</el-table-column>
<el-table-column
align="center"
label="发布人"
show-overflow-tooltip
min-width="160"
prop="taskInitiator"
>
</el-table-column>
<el-table-column
align="center"
label="任务期限"
show-overflow-tooltip
min-width="200"
prop="startToEndDate"
>
</el-table-column>
<el-table-column label="任务状态" align="center" prop="taskStatus" min-width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.task_status" :value="scope.row.taskStatus"/>
</template>
</el-table-column>
<el-table-column
align="center"
label="状态"
show-overflow-tooltip
min-width="90"
>
<template v-slot="{ row }">
<template v-if="row.sdTaskOther && row.sdTaskOther.status === '2'">
<el-tag
type="success">已办结</el-tag>
</template>
<template v-else-if="row.sdTaskOtherFeedbackByCreate">
<el-tag v-if="row.sdTaskOtherFeedbackByCreate.status === '1'"
>已反馈</el-tag
>
<el-tag
v-else-if="row.sdTaskOtherFeedbackByCreate.status === '2'"
type="success"
>已通过</el-tag
>
<el-tag
v-else-if="row.sdTaskOtherFeedbackByCreate.status === '-1'"
type="danger"
>驳回</el-tag
>
<el-tag v-else type="info">未反馈</el-tag>
</template>
<el-tag v-else type="info">未反馈</el-tag>
</template>
</el-table-column>
<el-table-column width="80px" align="center" label="操作" fixed="right">
<template slot-scope="scope">
<el-link
class="table-opretar"
type="primary"
@click="confirmAddToTask(scope.row)"
>确定反馈</el-link
>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<div v-show="visible" slot="reference" class="cart-content" ref="cartContent" :class="{'playAnimation': isAnimation}">
<el-badge :value="list.length" class="item">
<div class="cart-btn">
<i class="el-icon-shopping-cart-full"></i>
</div>
</el-badge>
</div>
</el-popover>
<transition
appear
@before-enter="beforeEnter"
@enter="afterEnter"
@after-leave="animationEnd"
>
<div class="ball" v-show="showBall" :style="ballStyle">
<i class="el-icon-shopping-cart-full"></i>
</div>
</transition>
<AuditDialog ref="editDialog" ></AuditDialog>
</div>
</template>
<script>
import { mapState } from 'vuex';
import { pageListByUser } from "@/api/task/branch";
import { addImageFeedback } from "@/api/task/feedback";
import { generateTasks } from "@/api/task/images";
import { imageToGroup } from "@/api/gallery/images";
import AuditDialog from "@/views/task-distribut/send/other-task/components/AuditDialog";
export default {
name: 'PhotoCart',
dicts: ['task_type','task_status'],
components: {
AuditDialog
},
data () {
return {
list: [
// {
// id: 1,
// url: '',
// _check: true
// },
// {
// id: 2,
// url: '',
// _check: true
// },
// {
// id: 3,
// url: '',
// _check: true
// },
// {
// id: 4,
// url: '',
// _check: true
// },
// {
// id: 5,
// url: '',
// _check: true
// },
// {
// id: 6,
// url: '',
// _check: true
// },
// {
// id: 7,
// url: '',
// _check: true
// },
],
isIndeterminate: false,
checkAll: true,
visible: false,
chooseTask: false,
loadingTask: false,
taskList: [],
ballStyle: {},
isAnimation: false,
addX: 0,
addY: 0,
showBall: false,
taskCreating: false,
genImaging: false,
}
},
computed: {
...mapState({
theme: state => state.settings.theme,
}),
},
mounted() {
this.$eventBus.$on('addImageToCart', this.addImageToCart);
},
beforeDestroy() {
this.$eventBus.$off('addImageToCart', this.addImageToCart);
},
methods: {
addImageToCart({ item, x, y }) {
if (this.list.some(val => val.id === item.id)) {
return;
}
this.addX = x;
this.addY = y;
this.list.push({
...item,
_check: true
});
this.visible = true;
this.ballStyle = {
left: x - 20 + 'px',
top: y - 20 + 'px'
};
this.showBall = true;
},
imageUrl(item) {
let url = item.imagePath;
if (item.file?.length > 0) {
url = item.file[0].attachFileUrl || item.imagePath;
}
if (url.indexOf("http") === 0) {
return url;
}
return process.env.VUE_APP_BASE_API + url;
},
handleCheckAllChange(val) {
this.list.forEach(item => {
item._check = val;
});
this.isIndeterminate = false;
},
handleCheckChange(val) {
this.updateCheckAllState();
},
imageClick(item) {
item._check = !item._check;
this.updateCheckAllState();
},
updateCheckAllState() {
this.checkAll = this.list.every(item => item._check);
this.isIndeterminate = this.list.some(item => item._check) && !this.checkAll;
},
checkVisible() {
if (this.list.length === 0) {
setTimeout(() => {
this.visible = false;
}, 500);
}
},
deleteImage(index) {
this.list.splice(index, 1);
this.checkVisible();
},
clear() {
this.$confirm('确定清空图片购物车吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.list = [];
this.checkAll = true;
this.isIndeterminate = false;
this.visible = false;
}).catch(() => {});
},
goCreateTask() {
if (this.list.some(val => val._check) === false) {
this.$message.warning('请至少选择一张图片');
return;
}
const images = this.list.filter(val => val._check);
const ids = images.map(val => val.id);
this.taskCreating = true;
generateTasks({
ids,
}).then(res => {
this.taskCreating = false;
const list = this.list.filter(val => !val._check);
this.list = list;
this.$refs.editDialog.open(res.data || {}, images);
this.checkVisible();
}).catch(e => {
this.taskCreating = false;
});
},
addToTask() {
if (this.list.some(val => val._check) === false) {
this.$message.warning('请至少选择一张图片');
return;
}
this.taskList = [];
this.chooseTask = true;
this.loadingTask = true;
pageListByUser({
isPublish: "1",
taskStatus: 0,
pageNum: 1,
pageSize: 100,
}).then(res => {
this.loadingTask = false;
this.taskList = res.rows || [];
}).catch(err => {
this.loadingTask = false;
});
},
goBack() {
this.chooseTask = false;
},
confirmAddToTask(task) {
this.loadingTask = true;
const ids = this.list.filter(val => val._check).map(val => val.id);
addImageFeedback({
imageIds: ids,
taskId: task.id,
}).then(res => {
this.loadingTask = false;
this.chooseTask = false;
if (res.data && res.data.length > 0) {
if (ids.length === res.data.length) {
this.$message.error(`反馈失败,所选图片与任务标签不符合`);
} else {
this.$message.warning(`图片已反馈到任务中,其中${res.data.length}张图片标签不符合`);
}
} else {
this.$message.success('图片已反馈到任务中');
}
const list = this.list.filter(val => {
if (val._check) {
if (res.data && res.data.length > 0) {
return res.data.includes(val.id);
}
return false;
}
return true;
});
this.list = list;
this.checkVisible();
}).catch(err => {
this.loadingTask = false;
});
},
handleImageCommand(command) {
this.genImaging = true;
const ids = this.list.filter(val => val._check).map(val => val.id);
imageToGroup({
ids,
imageType: command,
}).then(res => {
this.genImaging = false;
}).catch(e => {
this.genImaging = false;
});
},
animationEnd() {
this.isAnimation = true;
setTimeout(() => {
this.isAnimation = false;
}, 500);
console.log('动画结束了');
},
beforeEnter(el) {
el.style.transform = `translate3d(${0}px,${0}px,0)`
console.log('动画开始了', this.addX, this.addY);
},
afterEnter(el) {
const rect = this.$refs.cartContent.getBoundingClientRect();
console.log('afterEnter',rect);
el.style.transform = `translate3d(${rect.left - this.addX + rect.width / 2}px,${rect.top - this.addY + rect.height / 2}px,0)`
el.style.transition = 'transform .3s cubic-bezier(1,0,1,0)'
// el.style.transition = 'transform .3s linear'
this.showBall = false;
}
}
}
</script>
<style lang="scss" scoped>
.playAnimation{
animation: cartScale 0.5s ease-in-out;
}
//
@keyframes cartScale {
0%{
transform: scale(1);
}
20%{
transform: scale(1.2);
}
60%{
transform: scale(0.8);
}
80%{
transform: scale(1.1);
}
100%{
transform: scale(1);
}
}
.cart-container {
position: fixed;
z-index: 1001;
left: 32px;
bottom: 40px;
.el-dropdown-link {
cursor: pointer;
color: #409EFF;
margin-right: 10px;
}
}
.ball {
position: fixed;
z-index: 1001;
width: 40px;
height: 40px;
border-radius: 50%;
// background-color: var(--current-color);
background-color: white;
border: 1px solid #d3d4d6;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
color: #909399;
}
.cart-panel {
width: 100%;
height: 500px;
.cart-title {
font-size: 26px;
font-weight: 500;
}
.image-area {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.image-list {
height: 0;
flex: 1;
overflow-y: auto;
display: flex;
padding-top: 10px;
padding-left: 20px;
flex-wrap: wrap;
.image-item {
margin-right: 10px;
margin-bottom: 10px;
width: 200px;
height: 180px;
position: relative;
border-radius: 5px;
border: 1px solid #eee;
.image-delete {
position: absolute;
top: 0;
right: 0;
width: 30px;
height: 30px;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 2px;
display: none;
justify-content: center;
align-items: center;
font-size: 20px;
color: white;
}
.image {
width: 100%;
height: 100%;
}
.checkbox {
position: absolute;
top: 0;
left: 0;
}
}
.image-item:hover {
.image-delete {
display: flex;
}
}
.image-item-active {
border: 1px solid var(--current-color);
}
}
.cart-tool {
display: flex;
align-items: center;
justify-content: flex-end;
}
}
.task-area {
.task-list {
height: 0;
flex: 1;
overflow-y: auto;
}
}
}
.cart-content {
width: 56px;
height: 56px;
.cart-btn {
width: 56px;
height: 56px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
background-color: white;
box-shadow: inset 0px -1px 2px rgba(0, 0, 0, 0.3);
.el-icon-shopping-cart-full {
color: var(--current-color);
font-size: 28px;
}
}
}
</style>

@ -15,6 +15,7 @@
<script>
import logoImg from '@/assets/logo/logo.png'
import logoWhiteImg from '@/assets/logo/logo_.png'
import variables from '@/assets/styles/variables.scss'
export default {
@ -31,12 +32,14 @@ export default {
},
sideTheme() {
return this.$store.state.settings.sideTheme
},
logo() {
return this.$store.state.settings.sideTheme === 'theme-green' ? logoWhiteImg : logoImg
}
},
data() {
return {
title: process.env.VUE_APP_TITLE,
logo: logoImg
}
}
}
@ -66,8 +69,8 @@ export default {
width: 100%;
& .sidebar-logo {
width: 32px;
height: 32px;
width: 40px;
height: 40px;
vertical-align: middle;
margin-right: 12px;
}

@ -12,6 +12,7 @@
<settings/>
</right-panel>
</div>
<PhotoCart></PhotoCart>
</div>
</template>
@ -21,6 +22,7 @@ import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
import variables from '@/assets/styles/variables.scss'
import PhotoCart from '@/components/PhotoCart/index.vue'
export default {
name: 'Layout',
@ -30,7 +32,8 @@ export default {
RightPanel,
Settings,
Sidebar,
TagsView
TagsView,
PhotoCart
},
mixins: [ResizeMixin],
computed: {

@ -53,6 +53,7 @@ Vue.prototype.selectDictLabel = selectDictLabel
Vue.prototype.selectDictLabels = selectDictLabels
Vue.prototype.download = download
Vue.prototype.handleTree = handleTree
Vue.prototype.$eventBus = new Vue()
// 全局组件挂载
Vue.component('DictTag', DictTag)

@ -6,8 +6,12 @@
<div class="info-title">{{ item.imageTitle }}</div>
<div class="info-date">{{ item.uploadTime }}</div>
<div class="info-tag">
<el-tag size="small" >{{item.isOpen == 1 ? '公开':'私有'}}</el-tag>
<el-tag size="small" v-if="item.keyWords" style="margin-left: 3px;">{{ item.keyWords }}</el-tag>
<div style="display: flex;width: 0;;flex: 1;">
<el-tag size="small" >{{item.isOpen == 1 ? '公开':'私有'}}</el-tag>
<el-tag size="small" v-if="item.keyWords" style="margin-left: 3px;">{{ item.keyWords }}</el-tag>
</div>
<el-button ref="addCart" type="info" icon="el-icon-shopping-cart-full" circle plain style="margin-left: 5px;font-size: 16px;" @click.stop="addToCart"></el-button>
</div>
</div>
</div>
@ -41,7 +45,16 @@ export default {
}
},
methods: {
addToCart(e) {
// console.log(this.$refs.addCart);
const rect = this.$refs.addCart.$el.getBoundingClientRect();
// console.log(e);
this.$eventBus.$emit('addImageToCart', {
item: this.item,
x: rect.x + rect.width / 2,
y: rect.y + rect.height / 2,
});
}
}
}
</script>
@ -85,7 +98,7 @@ export default {
color: #409EFF;
padding: 0 5px 4px;
display: flex;
justify-content: flex-end;
align-items: flex-end;
}
}

@ -32,7 +32,7 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getTableList"></right-toolbar>
</el-row>
<div class="image-list">
<ImageItem v-for="(item, index) in tableData" :key="index" :item="item" class="image-item" @goDetail="showImageViewer($event, index)"></ImageItem>
<ImageItem v-for="(item, index) in tableData" :key="index" :item="item" class="image-item" @goDetail="showImageViewer($event, index, item)"></ImageItem>
</div>
<!-- 表格页脚 -->
<pagination
@ -256,8 +256,9 @@ resetQueryTable() {
imageEditChange() {
this.getTableList();
},
showImageViewer(event, index) {
showImageViewer(event, index, item) {
console.log('showImageViewer');
this.$refs.previewImage.open(index);
},

@ -216,6 +216,7 @@
/>
</el-card>
<AuditDialog ref="editDialog" :isAudit="!isPublish" @refresh="getTableList"></AuditDialog>
<!-- <ImageChooseDialog ref="imageChoose" @confirm="imageChooseConfirm"></ImageChooseDialog> -->
</div>
</template>
@ -226,11 +227,13 @@ import TableMixin from "@/mixins/table-mixin";
import { pageListByUser } from "@/api/task/branch";
import { addByUser, deleteByUser } from "@/api/task/branch";
import { listUser } from "@/api/system/user";
// import ImageChooseDialog from "../../gallery/query/components/ImageChooseDialog.vue";
export default {
name: "MyTask",
components: {
AuditDialog,
// ImageChooseDialog
},
dicts: ['task_type','task_status'], //
mixins: [TableMixin],
@ -338,6 +341,9 @@ export default {
} catch (error) {
this.$message.error('任务撤回失败:' + error.message);
}
},
imageChooseConfirm(list) {
}
},
};

Loading…
Cancel
Save