feat: 任务反馈标签、照片选择修改

develop
wx-jincw 1 day ago
parent c2ce25de03
commit 96c8a1d506

@ -145,7 +145,7 @@ import { getToken } from "@/utils/auth";
import { formatDateStr } from "@/utils";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import { listTag } from "@/api/task/tag";
import { listTag } from "@/api/system/tag";
export default {
name: 'List',

@ -1,87 +1,65 @@
<template>
<div class="app-container" >
<div class="left-content">
<div style="margin-bottom: 20px;">图片目录</div>
<el-tree :data="cates" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
<el-dialog :close-on-click-modal="false" :close-on-press-escape="false" append-to-body :visible.sync="dialogVisible" title="选择图片"
width="80%">
<div class="app-container">
<div class="left-content">
<div style="margin-bottom: 20px;">图片目录</div>
<el-tree :data="cates" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</div>
<div class="right-content" v-loading="tableLoading">
<el-form :model="query" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="图片标题" prop="imageTitle">
<el-input v-model="query.imageTitle" placeholder="请输入图片标题" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="标签" prop="label">
<el-input v-model="query.label" placeholder="请输入标签" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="queryTable"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQueryTable"></el-button>
</el-form-item>
</el-form>
<el-table ref="multipleTable" tooltip-effect="dark" :data="tableData" height="500px" class="w100p" border
header-cell-class-name="duojibiaotou" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column align="center" label="图片" show-overflow-tooltip width="160" prop="taskTitle">
<template slot-scope="scope">
<img style="width: 160px;height: 100px;" :src="getImageUrl(scope.row)" />
<div class="image-name">{{ imageName(scope.row) }}</div>
</template>
</el-table-column>
<el-table-column label="图片标题" align="center" prop="imageTitle" min-width="100">
</el-table-column>
<el-table-column label="拍摄时间" align="center" prop="uploadTime" min-width="100">
</el-table-column>
</el-table>
<!-- 表格页脚 -->
<pagination v-show="total > 0" :total="total" :page.sync="page.pageNum" :limit.sync="page.pageSize"
@pagination="getTableList" />
</div>
<MyImageViewer ref="previewImage" :z-index="2000" :files="images" @change="imageEditChange"></MyImageViewer>
</div>
<div class="right-content" v-loading="tableLoading">
<el-form :model="query" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="图片标题" prop="imageTitle">
<el-input
v-model="query.imageTitle"
placeholder="请输入图片标题"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="标签" prop="label">
<el-input
v-model="query.label"
placeholder="请输入标签"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="queryTable"></el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQueryTable"></el-button>
</el-form-item>
</el-form>
<el-table
ref="multipleTable"
tooltip-effect="dark"
:data="tableData"
class="w100p"
border
header-cell-class-name="duojibiaotou"
>
<el-table-column
align="center"
label="图片"
show-overflow-tooltip
min-width="160"
prop="taskTitle"
>
<template slot-scope="scope">
<img style="width: 160px;height: 100px;" :src="getImageUrl(scope.row)" />
<div class="image-name">{{ imageName(scope.row) }}</div>
</template>
</el-table-column>
<el-table-column label="图片标题" align="center" prop="imageTitle" min-width="100">
</el-table-column>
<el-table-column label="拍摄时间" align="center" prop="uploadTime" min-width="100">
</el-table-column>
</el-table>
<!-- 表格页脚 -->
<pagination
v-show="total > 0"
:total="total"
:page.sync="page.pageNum"
:limit.sync="page.pageSize"
@pagination="getTableList"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirm"></el-button>
</div>
<MyImageViewer ref="previewImage" :z-index="2000"
:files="images" @change="imageEditChange"></MyImageViewer>
</div>
</el-dialog>
</template>
<script>
import ImageItem from '../list/components/ImageItem.vue';
import tableMixin from '../../../mixins/table-mixin';
import tableMixin from '@/mixins/table-mixin';
import { listCata } from "@/api/gallery/cata";
import { pageListImages } from "@/api/gallery/images";
import { getToken } from "@/utils/auth";
import { formatDateStr } from "@/utils";
export default {
name: 'List',
name: 'ImageChooseDialog',
components: {
ImageItem
},
mixins: [tableMixin],
pageInfo: {
@ -97,6 +75,7 @@ export default {
},
data() {
return {
dialogVisible: false,
cates: [],
defaultProps: {
children: 'children',
@ -107,7 +86,7 @@ export default {
imageTitle: null,
photoTime: null,// ,
uploadTime: formatDateStr(),
isOpen: this.isPerson ? 0:1,
isOpen: this.isPerson ? 0 : 1,
keyWords: '日常',
cataId: null,
},
@ -123,6 +102,7 @@ export default {
},
uploading: false,
switchType: false,
selections: [],
};
},
computed: {
@ -148,10 +128,14 @@ export default {
})
},
methods: {
open() {
this.dialogVisible = true;
},
MXCreated() {
this.query.isOpen = this.isPerson ? '0':'';
},
resetQueryTable() {
this.query.isOpen = this.isPerson ? '0' : '';
},
resetQueryTable() {
this.$refs.multipleTable?.clearSort();
this.tableSort = {};
this.page = {
@ -159,7 +143,7 @@ resetQueryTable() {
};
this.query = { ...this.MXPageInfo().defaultQuery };
this.query.isOpen = this.isPerson ? '0':'';
this.query.isOpen = this.isPerson ? '0' : '';
this.getTableList();
},
imageName(item) {
@ -174,7 +158,7 @@ resetQueryTable() {
url = item.file[0].attachFileUrl || item.imagePath;
}
if (url.indexOf("http") === 0) {
return url;
return url;
}
return process.env.VUE_APP_BASE_API + url;
},
@ -189,62 +173,26 @@ resetQueryTable() {
handleNodeClick(data) {
console.log(data);
if (this.query.cataId === data.id) {
this.query.cataId = null;
this.query.cataId = null;
} else {
this.query.cataId = data.id;
}
this.getTableList();
},
handleUpload() {
this.form = {
imageTitle: null,
photoTime: null,// ,
uploadTime: formatDateStr(),
isOpen: this.isPerson ? 0:1,
keyWords: '日常',
cataId: null,
};
this.imageUrl = '';
this.openLoad = true;
},
cancel() {
this.openLoad = false;
this.uploading = false;
handleSelectionChange(val) {
this.selections = val || [];
},
submitForm() {
if (!this.imageUrl) {
confirm() {
if (this.selections.length === 0) {
this.$message.error('请选择图片');
return;
}
this.$refs['form'].validate((valid) => {
if (valid) {
this.uploading = true;
this.$refs.upload.submit();
}
});
},
handleFileChange(file) {
this.imageUrl = URL.createObjectURL(file.raw);
},
handleFileSuccess(res, file) {
this.$message.success('上传成功');
this.openLoad = false;
this.uploading = false;
this.getTableList();
},
handleFileError() {
this.$message.error('上传失败');
this.uploading = false;
},
beforeAvatarUpload(file) {
const isImg = file.type.indexOf('image/') !== -1;
if (!isImg) {
this.$message.error('只能上传图片!');
}
return isImg;
}
this.$emit('confirm', this.selections);
this.dialogVisible = false;
//
this.$refs.multipleTable.clearSelection();
}
}
}
</script>
@ -253,8 +201,9 @@ resetQueryTable() {
.app-container {
display: flex;
}
.left-content {
width: 300px;
width: 200px;
padding: 15px;
border: #EEEEEE 1px solid;
border-radius: 8px;
@ -265,14 +214,14 @@ resetQueryTable() {
flex: 1;
margin-left: 10px;
}
.image-list {
display: flex;
flex-wrap: wrap;
.image-item {
width: 300px;
margin: 0 15px 15px 0;
}
}
.image-list {
display: flex;
flex-wrap: wrap;
.image-item {
width: 300px;
margin: 0 15px 15px 0;
}
}
</style>.

@ -0,0 +1,224 @@
<template>
<div class="image-chooser" v-loading="loading">
<div v-for="(item, i) in list" :key="item.id" class="image-item">
<img :src="imageUrl(item)" />
<i v-if="!readonly" class="el-icon-circle-close" @click.stop="removeImage(item, i)"></i>
</div>
<div class="image-item" v-loading="uploading" v-if="!readonly">
<el-popover
v-model="bubVisible"
placement="top"
trigger="click">
<el-button type="primary" size="small" @click="goChooseImage" plain>选择系统图库</el-button>
<el-upload
ref="upload"
class="image-uploader"
:action="uploadFileUrl"
:show-file-list="false"
:on-change="handleFileChange"
:on-success="handleFileSuccess"
:on-error="handleFileError"
:before-upload="beforeFileUpload"
:auto-upload="true"
:headers="headers"
:data="uploadData"
:limit="1" accept=".png,.jpg,.jpeg,.gif">
<el-button type="success" size="small" style="margin-top: 10px;width: 104px;" plain>上传图片</el-button>
</el-upload>
<div class="image-choose" slot="reference">
<i class="el-icon-plus"></i>
</div>
</el-popover>
</div>
<ImageChooseDialog ref="imageChooseDialog" @confirm="addImages"></ImageChooseDialog>
</div>
</template>
<script>
import { delImages, listImages } from "@/api/gallery/images";
import { getToken } from "@/utils/auth";
import { formatDateStr } from "@/utils";
import ImageChooseDialog from "./ImageChooseDialog";
export default {
name: 'ImageChooser',
components: {
ImageChooseDialog,
},
props: {
value: {
type: Array,
default: () => []
},
queryId: {
type: [String, Number],
default: ''
},
readonly: {
type: Boolean,
default: false
},
tag: {
type: Object,
default: () => ({})
},
taskName: {
type: String,
default: ''
}
},
model: {
prop: 'value',
event: 'change'
},
created() {
if (this.queryId) {
this.loading = true;
listImages({
feedbackId: this.queryId,
}).then(res => {
this.list = res.data || [];
this.loading = false;
}).catch(() => {
this.loading = false;
})
}
},
data () {
return {
uploadFileUrl: process.env.VUE_APP_BASE_API + "/gallery/images/upload", //
headers: {
Authorization: "Bearer " + getToken(),
},
list: [],
uploadData: {
imageTitle: this.taskName + '任务-' + this.tag.tagName + '图片',
photoTime: formatDateStr(),// ,
uploadTime: formatDateStr(),
isOpen: 1,
keyWords: '任务',
cataId: this.tag.saveDir,
},
uploading: false,
loading: false,
bubVisible: false
}
},
methods: {
imageUrl(item) {
let url = item.imagePath;
if (item.file?.length > 0) {
url = item.file[0].attachFileUrl || item.imagePath;
}
if (url.indexOf("http") === 0 || url.indexOf("blob:") === 0) {
return url;
}
return process.env.VUE_APP_BASE_API + url;
},
handleFileChange(file) {
},
beforeFileUpload() {
this.uploading = true;
},
handleFileSuccess(res, file) {
this.uploading = false;
if (res.code === 200) {
this.$message.success('上传成功');
console.log('上传成功;', res);
this.list.push({
imagePath: URL.createObjectURL(file.raw),
id: res.imageId,
_new: true,
});
this.$emit('change', this.list.map(item => item.id));
this.bubVisible = false;
} else {
this.$message.error('上传失败');
}
this.$refs.upload.clearFiles();
},
handleFileError() {
this.$message.error('上传失败');
this.uploading = false;
},
removeImage(item, i) {
if (item._new) {
this.loading = true;
delImages(item.id).then(() => {
this.$message.success('删除成功');
this.list.splice(i, 1);
this.$emit('change', this.list.map(item => item.id));
this.loading = false;
}).catch(() => {
this.loading = false;
})
} else {
this.list.splice(i, 1);
this.$emit('change', this.list.map(item => item.id));
}
},
goChooseImage() {
this.bubVisible = false;
this.$refs.imageChooseDialog.open();
},
addImages(list) {
this.list = this.list.concat(list);
this.$emit('change', this.list.map(item => item.id));
}
}
}
</script>
<style scoped lang="scss">
.image-chooser {
display: flex;
flex-wrap: wrap;
}
.image-item {
background: #f3f3f3;
width: 100px;
height: 100px;
border: 1px solid #eee;
border-radius: 8px;
position: relative;
img {
width: 100%;
height: 100%;
}
.el-icon-circle-close {
position: absolute;
top: 0;
right: 0;
display: none;
font-size: 22px;
color: #f56c6c;
cursor: pointer;
}
.image-choose {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 30px;
color: #ccc
}
}
.image-item:hover {
.el-icon-circle-close {
display: block;
}
}
.image-item + .image-item {
margin-left: 10px;
}
</style>

@ -226,6 +226,9 @@ const formRules = {
photoNum: [
{ required: true, message: "拍照数量要求不能为空", trigger: "blur" }
],
saveDir: [
{ required: true, message: "照片存放目录不能为空", trigger: "change" }
]
};
export default {

@ -9,12 +9,23 @@
<div style="height: 70vh;width:100%;overflow-y: scroll;overflow-x: hidden;" v-loading="loading">
<SectionTitle title="基本信息" desc="" extra=""></SectionTitle>
<Detail :info="info" style="margin-top: 10px;"></Detail>
<SectionTitle title="反馈信息" icon="el-icon-s-comment" :desc="`共${auditList.length}条反馈`" extra=""></SectionTitle>
<el-timeline v-if="auditList.length > 0" style="margin-top: 20px;">
<SectionTitle title="反馈信息" icon="el-icon-s-comment" :desc="`共${info.ctTaskTags.length}个标签任务`" extra="" style="margin-bottom: 20px;"></SectionTitle>
<el-card v-for="(taskTag, i) in info.ctTaskTags" :key="taskTag.id">
<div slot="header" class="clearfix">
<span>标签{{ i + 1 }}{{taskTag.tagName}}</span>
</div>
<el-timeline v-if="taskTag._auditList.length > 0">
<el-timeline-item v-for="(item, index) in taskTag._auditList" :key="getKey(item, index)" :timestamp="itemDate(item)" placement="top">
<el-card>
<AuditItem :info="info" :tag="taskTag" :item="item" @refresh="auditChange(taskTag)"></AuditItem>
</el-card>
</el-timeline-item>
</el-timeline>
</el-card>
<el-timeline v-if="auditList.length > 0">
<el-timeline-item v-for="(item, index) in auditList" :key="getKey(item, index)" :timestamp="itemDate(item)" placement="top">
<el-card>
<AuditItem :info="info" :item="item" @refresh="auditChange"></AuditItem>
<AuditItem :info="info" :item="item" @refresh="auditChange()"></AuditItem>
</el-card>
</el-timeline-item>
</el-timeline>
@ -70,18 +81,21 @@ export default {
this.isAuditChange = false;
this.dialogVisible = true;
this.info = { ...data };
this.getList();
this.info.ctTaskTags?.forEach((val) => {
this.getList(val);
});
this.getAuditFeedback();
},
closeVisible() {
this.dialogVisible = false;
},
getList() {
this.auditList = [];
getAuditFeedback() {
if (!this.info.id) {
return;
}
this.loading = true;
listFeedback({ taskId: this.info.taskId, taskBranchId: this.info.id, isPublish: this.isAudit ? '1':'' }).then(res => {
listFeedback({ taskTagId: -1, taskId: this.info.taskId, taskBranchId: this.info.id, isPublish: this.isAudit ? '1':'' }).then(res => {
this.loading = false;
const list = res.data || [];
@ -105,11 +119,48 @@ export default {
checkInfo: ''
});
}
}
this.auditList = list;
}).catch(err => {
this.loading = false;
});
},
getList(taskTag) {
if (!this.info.id) {
return;
}
this.loading = true;
listFeedback({ taskTagId: taskTag.id, taskId: this.info.taskId, taskBranchId: this.info.id, isPublish: this.isAudit ? '1':'' }).then(res => {
this.loading = false;
const list = res.data || [];
//
if (this.info.sdTaskOther?.status === '2') {
this.$set(taskTag, '_auditList', list);
return;
}
const currentDate = new Date();
const lastItem = list.length > 0 ? list[list.length - 1] : null;
if (this.isAudit) {
// if (!lastItem || lastItem.status === '1') {
// list.push({
// taskId: this.info.taskId,
// taskBranchId: this.info.id,
// branchCode: this.info.branchCode,
// checkUserId: this.$store.getters.userInfo.userId,
// checkUserName: this.$store.getters.userInfo.userName,
// checkUserDept: this.$store.getters.userInfo.dept.deptName,
// checkDate: currentDate,
// checkInfo: ''
// });
// }
} else {
if (!lastItem || lastItem.status === '-1') {
list.push({
taskId: this.info.taskId,
taskBranchId: this.info.id,
taskTagId: taskTag.id,
branchCode: this.info.branchCode,
userId: this.$store.getters.userInfo.userId,
userName: this.$store.getters.userInfo.userName,
@ -117,18 +168,21 @@ export default {
feedbackTime: currentDate,
taskDesc: '',
status: '0',
tags: this.info.ctTaskTags || [],
});
}
}
this.auditList = list;
this.$set(taskTag, '_auditList', list);
}).catch(err => {
this.loading = false;
});
},
auditChange() {
auditChange(taskTag) {
this.isAuditChange = true;
this.getList();
if (taskTag) {
this.getList(taskTag);
} else {
this.getAuditFeedback();
}
},
itemDate(item) {
let date = null;

@ -49,22 +49,25 @@
</el-descriptions-item>
</template>
<template v-if="editAble() || dialogForm.file">
<el-descriptions-item v-for="tagData in dialogForm.tags" :span="2" :key="tagData.id">
<template slot="label">
<i class="el-icon-paperclip"></i>
{{ tagData.tagName + '图片' }}
</template>
<el-form-item class="desc-form-item" label="" prop="fileId">
<FileUpload v-model="tagData.file" imageOnly :fileType="['png', 'jpg', 'jpeg']" :readonly="!editAble()"></FileUpload>
<div class="tk-images">
<img class="tk-image-item" v-for="file in imageList" :key="file.id" />
<div class="tk-image-item tk-image-select">
<i class="el-icon-plus"></i>
<div class="tk-image-title">选择图库图片</div>
</div>
</div>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item :span="2" v-if="!isAudit">
<template slot="label">
<i class="el-icon-paperclip"></i>
照片
</template>
<el-form-item class="desc-form-item" label="" prop="fileId">
<!-- <FileUpload v-model="dialogForm.file" :readonly="!editAble()"></FileUpload> -->
<ImageChooser v-model="dialogForm.imageIds" :queryId="dialogForm.id" :tag="tag" :taskName="info.taskTitle" :readonly="!editAble()"></ImageChooser>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item :span="2" v-else>
<template slot="label">
<i class="el-icon-paperclip"></i>
附件
</template>
<el-form-item class="desc-form-item" label="" prop="fileId">
<FileUpload v-model="dialogForm.file" :readonly="!editAble()"></FileUpload>
</el-form-item>
</el-descriptions-item>
</template>
</el-descriptions>
@ -88,10 +91,11 @@ import TableEditMixin from "@/mixins/table-edit-mixin";
import { addFeedback, updateFeedback } from "@/api/task/feedback";
// import { getDateStr } from "@/utils/util";
import FileUpload from "@/components/FileUpload";
import ImageChooser from "../../../../gallery/query/components/ImageChooser.vue";
export default {
name: 'AuditItem',
components: { FileUpload },
components: { FileUpload, ImageChooser },
mixins: [TableEditMixin],
pageInfo: {
defaultForm: {
@ -107,7 +111,11 @@ export default {
item: {
type: Object,
default: () => ({})
}
},
tag: {
type: Object,
default: () => ({})
},
},
computed: {
isAudit() {
@ -196,33 +204,4 @@ export default {
.desc-form-item {
margin: 0;
}
.tk-images {
display: flex;
flex-wrap: wrap;
margin-top: 10px;
.tk-image-item {
width: 100px;
height: 100px;
margin-right: 10px;
margin-bottom: 10px;
border: 1px solid #eee;
background-color: #f5f7fa;
border-radius: 10px;
}
.tk-image-select {
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
width: 100px;
height: 100px;
flex-direction: column;
.tk-image-title {
margin-top: 10px;
}
}
}
</style>

Loading…
Cancel
Save