- 给拖拽表格添加属性
- onMounted生命周期执行该方法
const rowDrag = function () {
// 要拖拽元素的父容器
const tbody = document.querySelector(
".draggable .el-table__body-wrapper tbody"
);
if (!tbody) return;
Sortable.create(tbody as HTMLElement, {
// 可被拖拽的子元素
draggable: ".draggable .el-table__row",
onEnd(event: SortableEvent) {
console.log("event", event);
if (event.oldIndex !== undefined && event.newIndex !== undefined) {
const currRow = tableData.value.splice(event.oldIndex, 1)[0];
tableData.value.splice(event.newIndex, 0, currRow);
}
},
});
};
- 引入文件 import { default as Sortable, SortableEvent } from "sortablejs";
完整代码:
<template>
<div class="warp-card">
<div class="breadcrumb">
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<a type="primary" href="/homepage">Home</a>
</el-breadcrumb-item>
<el-breadcrumb-item>Issue Details</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="form-content" ref="headerRef" id="queryForm">
<!-- 按钮操作区 -->
<div
style="text-align: right; margin-bottom: 10px"
v-if="route.query.record"
>
<el-button
type="primary"
@click="recordDeleteAction(recordData?.id)"
title="Delete"
>
<el-icon>
<Delete />
</el-icon>
<span style="margin-left: 2px">Delete</span>
</el-button>
<!-- <el-button
type="primary"
@click="goAction(recordData?.id)"
title="Edit"
>
<el-icon>
<Edit />
</el-icon>
<span style="margin-left: 2px">Edit</span>
</el-button> -->
<template v-if="isPublish">
<el-button
type="primary"
@click="changeIssueStatus(recordData?.id)"
title="Open"
>
<el-icon>
<Open />
</el-icon>
<span style="margin-left: 2px">IsIssue Published Toggle</span>
</el-button>
</template>
<template v-else>
<el-button
type="primary"
@click="changeIssueStatus(recordData?.id)"
title="TurnOff"
>
<el-icon>
<TurnOff />
</el-icon>
<span style="margin-left: 2px">IsIssue Published Toggle</span>
</el-button>
</template>
</div>
<el-form
ref="ruleFormRef"
:model="ruleForm"
:rules="rules"
label-width="350px"
class="demo-ruleForm"
:size="formSize"
status-icon
>
<div class="form-main">
<div class="card-box">
<div class="card-title">
<h3>Event Details({{ detailTitle }})</h3>
</div>
<div class="form-item">
<el-row class="table-tools">
<el-col :span="24" style="text-align: right">
<el-button
type="primary"
@click="scheduleBtn"
v-if="showSendIssue"
>Schedule Paper to This Issue</el-button
>
<template v-if="tableData.length > 0">
<el-button
@click="issueBtn"
type="primary"
v-if="showSendIssue"
>Send to Production</el-button
>
<el-button type="primary" @click="downLoad()">
<el-icon>
<Download />
</el-icon>
</el-button>
<el-button
@click="saveTable()"
type="primary"
v-if="showSaveTable"
>Save Table</el-button
>
</template>
<el-button @click="goBack()"
><el-icon><ArrowLeft /></el-icon>Back</el-button
>
</el-col>
</el-row>
<el-table
class="draggable"
id="myTable"
ref="dragTable"
border
row-key="id"
:data="tableData"
style="width: 100%; margin-top: 10px"
v-draggable="draggableOptions"
>
<el-table-column prop="aid" label="ID" width="180">
<template #default="scope">
<div style="text-align: left">
<el-text
style="cursor: pointer"
type="primary"
@click="goPage(scope.row)"
>
<svg-icon icon-class="export" />
{{ scope.row.aid }}
</el-text>
</div>
</template>
</el-table-column>
<el-table-column prop="articleType" label="Type" width="180">
<template #default="scope">
<span class="ellipsis-line">{{
scope.row.article.articleType
}}</span>
</template>
</el-table-column>
<el-table-column prop="title" label="Title" min-width="180">
<template #default="scope">
<span class="ellipsis-line">{{
scope.row.article.title
}}</span>
</template>
</el-table-column>
<el-table-column prop="section" label="Section" min-width="180">
<template #default="scope">
<span>{{ scope.row.section.title }}</span>
</template>
</el-table-column>
<el-table-column
prop="articleContributorCountry"
label="CA Country"
width="160"
>
<template #default="scope">
<span class="ellipsis-line">{{
scope.row.article.articleContributorCountry
}}</span>
</template>
</el-table-column>
<el-table-column prop="online" label="Online" width="80">
<template #default="scope">
<span>{{ scope.row.online ? "Y" : "N" }}</span>
</template>
</el-table-column>
<el-table-column prop="state" label="Published?" width="100">
<template #default="scope">
<span>{{ scope.row.state ? "Y" : "N" }}</span>
</template>
</el-table-column>
<el-table-column label="GA" width="60">
<template #default="scope">
<span>{{ scope.row.graphicalAbstract ? "Y" : "N" }}</span>
</template>
</el-table-column>
<el-table-column prop="supplementaryFile" label="SF" width="60">
<template #default="scope">
<span>{{ scope.row.supplementaryFile ? "Y" : "N" }}</span>
</template>
</el-table-column>
<el-table-column label="Action">
<template #default="scope">
<el-button type="text" @click="deleteAction(scope.row.aid)">
<el-icon><Delete /></el-icon>
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</el-form>
<!-- 父组件把数据给子组件 -->
<issuePie :pieTableDatas="pieTableDatas"></issuePie>
</div>
</div>
<div class="schedule-modal">
<el-dialog
v-model="dialogVisible"
title="Schedule Paper to This Issue"
width="80%"
>
<template #default>
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="ID: " prop="id">
<el-input
placeholder="Please input"
v-model="formInline.aid"
@keydown.enter="onSearch"
/>
</el-form-item>
<el-form-item>
<el-button @click="onSearch" type="primary">Search</el-button>
<el-button @click="onClear">Clear</el-button>
</el-form-item>
</el-form>
<el-button @click="scheduleToIssue" type="primary"
>Schedule to Issue</el-button
>
<div class="selected">
<img src="~@/assets/i.png" alt="" />
Selected {{ (multipleSelection && multipleSelection.length) || 0 }}
</div>
<el-table
v-loading="loading"
ref="multipleTableRef"
:data="scheduleTableData"
style="width: 100%"
@selection-change="handleSelectionChange"
:header-cell-style="headerCellStyle"
border
stripe
>
<el-table-column type="selection" width="40" />
<el-table-column label="ID" prop="id" width="90">
<template #default="scope">
<div style="text-align: left">
<el-text
style="cursor: pointer"
type="primary"
@click="goPage(scope.row)"
>
<svg-icon icon-class="export" />
{{ scope.row.aid }}
</el-text>
</div>
</template>
</el-table-column>
<el-table-column
label="Title"
prop="article_title"
min-width="300"
show-overflow-tooltip
>
</el-table-column>
<el-table-column label="Status" prop="status" width="210">
<template #default="scope">
<span v-html="scope.row.state"></span>
</template>
</el-table-column>
<el-table-column label="Journal" prop="journal_title" width="80">
</el-table-column>
<el-table-column label="Article Type" prop="articleType" width="110">
</el-table-column>
<el-table-column
label="Section"
width="75"
prop="section_title"
show-overflow-tooltip
>
</el-table-column>
<el-table-column
label="Name"
prop="name"
width="150"
show-overflow-tooltip
>
<template #default="scope">
<div v-for="item in scope.row.contributorNames">
<div
:title="item"
style="
display: flex;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
>
{{ item }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="Email" prop="state" width="90">
<template #default="scope">
<div
v-for="(items, index) in scope.row.contributorEmails"
style="text-align: left"
>
<div class="overhiddle" :title="items">
{{ items }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="Affiliation" prop="city" width="90">
<template #default="scope">
<div v-if="scope.row.contributorAffiliatoins">
<div
v-for="(items, index) in scope.row.contributorAffiliatoins"
style="text-align: left"
>
<div class="overhiddle" :title="items">
{{ items }}
</div>
</div>
</div>
</template>
</el-table-column>
</el-table>
<div style="text-align: right">
<pagination
@pagination="handleQuery"
v-if="total > 0"
v-model:limit="queryParams.pageSize"
v-model:page="queryParams.pageNum"
v-model:total="total"
/>
</div>
<el-dialog
v-model="innerVisible"
width="50%"
title="Confirm Information"
append-to-body
>
<div
v-if="
checkArticleDatas.repeatAuthorTips &&
checkArticleDatas.repeatAuthorTips.length
"
>
<h3>Repeat Author Tips:</h3>
<div v-for="item in checkArticleDatas.repeatAuthorTips">
{{ item }}
</div>
</div>
<div
v-if="
checkArticleDatas.repeatInstitutionTips &&
checkArticleDatas.repeatInstitutionTips.length
"
>
<h3>Repeat Institution Tips:</h3>
<div v-for="item in checkArticleDatas.repeatInstitutionTips">
{{ item }}
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="innerVisible = false">Cancel</el-button>
<el-button type="primary" @click="confirmInfos">
Confirm
</el-button>
</div>
</template></el-dialog
>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref, nextTick } from "vue";
import type { FormInstance, FormRules } from "element-plus";
import { default as Sortable, SortableEvent } from "sortablejs";
import { useRouter, useRoute } from "vue-router";
import SvgIcon from "@/components/SvgIcon/index.vue";
import issuePie from "@/views/editorialReports/components/issuePie.vue";
import {
getTable,
addTable,
deleteTable,
deleteIssue,
send,
getArticleList,
checkArticleSameAuthorAndAffiliation,
saveBatch,
setIssueStatus,
} from "@/api/issueManagment";
import {
ElMessage,
ElMessageBox,
UploadRequestOptions,
UploadUserFile,
} from "element-plus";
import { uploadFileApi } from "@/api/review/review";
import { downloadExcelFile } from "@/utils/table";
import Pagination from "@/components/Pagination/index.vue";
const router = useRouter();
const route = useRoute();
const sortList = ref([]);
const pageId = route.query.id;
const detailTitle = route.query.title;
const journal = route.query.jjd;
const fileList = ref<UploadUserFile[]>([]);
let tableData = ref([]);
let showSaveTable = ref(false);
let showSendIssue = ref(false);
// 行拖拽
const rowDrag = function () {
// 要拖拽元素的父容器
const tbody = document.querySelector(
".draggable .el-table__body-wrapper tbody"
);
if (!tbody) return;
Sortable.create(tbody as HTMLElement, {
// 可被拖拽的子元素
draggable: ".draggable .el-table__row",
onEnd(event: SortableEvent) {
console.log("event", event);
if (event.oldIndex !== undefined && event.newIndex !== undefined) {
const currRow = tableData.value.splice(event.oldIndex, 1)[0];
tableData.value.splice(event.newIndex, 0, currRow);
}
},
});
};
let recordData: any = reactive({});
/**
*调用接口
*/
const isPublish = ref(false);
let pieTableDatas = ref(null); // 定义变量
onMounted(() => {
recordData = route.query.record
? JSON.parse(route.query.record)
: {
publish: false,
};
isPublish.value = recordData?.publish;
getTableDatas();
rowDrag();
});
const getTableDatas = async () => {
getTable({ id: pageId }).then((res) => {
pieTableDatas.value = res.data; //接口数据放到变量里
tableData.value = res.data.issueArticleNumberList;
showSaveTable.value = res.data.showSaveTable;
showSendIssue.value = res.data.showSendIssue;
});
};
const saveTable = () => {
let ids = [];
tableData.value.map(function (items) {
ids.push(items.aid);
});
addTable(ids).then((res) => {
ElMessage({
message: "save successful.",
type: "success",
});
});
};
/**
*删除
*/
const deleteAction = (id) => {
ElMessageBox.confirm("Are you sure to delete? ", "Confirmation", {
confirmButtonText: "Confirm",
cancelButtonText: "Cancel",
type: "warning",
})
.then(() => {
deleteTable({ aid: id }).then((res) => {
getTableDatas();
ElMessage({
type: "success",
message: "Delete completed",
});
});
})
.catch(() => {
ElMessage({
type: "info",
message: "Delete canceled",
});
});
};
/**
*下载
*/
// Example usage:
const downLoad = () => {
const table = document.getElementById("myTable");
downloadExcelFile(table, "myTable.xlsx");
};
const goBack = () => {
router.go(-1);
};
const issueBtn = () => {
send({
issueId: pageId,
}).then((res) => {
if (res.code == 2000) {
ElMessage({
type: "success",
message: res.message,
});
}
});
};
const dialogVisible = ref(false);
const scheduleTableData = ref([]);
const scheduleBtn = () => {
dialogVisible.value = true;
getPapersList();
};
const getPapersList = () => {
loading.value = true;
getArticleList({
pageSize: queryParams.pageSize,
pageNumber: queryParams.pageNum,
issueId: pageId,
aid: formInline.aid,
}).then((res) => {
loading.value = false;
scheduleTableData.value = res.data.content;
total.value = res.data.total;
});
};
const multipleTableRef = ref();
const multipleSelection = ref([]);
const handleSelectionChange = (val) => {
multipleSelection.value = val;
};
const formInline = reactive({
aid: "",
});
const handleQuery = () => {
getPapersList();
};
const total = ref(0);
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
});
const loading = ref(false);
const onSearch = () => {
queryParams.pageNum = 1;
queryParams.pageSize = 10;
getPapersList();
};
const onClear = () => {
formInline.aid = "";
queryParams.pageNum = 1;
queryParams.pageSize = 10;
getPapersList();
};
const checkArticleDatas = reactive({
repeatAuthorTips: [],
repeatInstitutionTips: [],
repeatResult: false,
});
const scheduleToIssue = () => {
let aidList: any = [];
if (multipleSelection.value && multipleSelection.value.length == 0) {
return ElMessage({
type: "error",
message: "Please select at least one piece of data",
});
}
multipleSelection.value.forEach((item) => {
aidList.push(item.aid);
});
console.log("外面的 tableData", tableData.value);
console.log("里面的 选中的", multipleSelection.value);
// ---------------整理数据
let newArr: any = [];
tableData.value.forEach((item: any) => {
newArr.push({
aid: item.aid,
articleType: item.article.articleType,
});
});
multipleSelection.value.forEach((item: any) => {
newArr.push({
aid: item.aid,
articleType: item.articleType,
});
});
// ---------------整理数据
if (checkReviewCount(newArr)) {
// 点击Schedule To Issue 校验所选内容articletype为Review的是否超过50%,
// 超过,关闭已开启弹窗,并打开二次弹窗提醒“
dialogVisible.value = false;
ElMessageBox.confirm(
"The selected content has been reviewed more than 50%. Please confirm and continue with the schedule.",
"Confirmation",
{
confirmButtonText: "Confirm",
cancelButtonText: "Cancel",
type: "warning",
}
)
.then(() => {
dialogVisible.value = false;
checkArticleSameAuthorAndAffiliation({
aidList: aidList,
IssueId: pageId,
}).then((res) => {
checkArticleDatas.repeatAuthorTips = res.data.repeatAuthorTips;
checkArticleDatas.repeatInstitutionTips =
res.data.repeatInstitutionTips;
checkArticleDatas.repeatResult = res.data.repeatResult;
getTableDatas();
if (checkArticleDatas.repeatResult) {
innerVisible.value = true;
} else {
confirmInfos();
}
});
})
.catch(() => {
ElMessage({
type: "info",
message: "canceled",
});
dialogVisible.value = true;
});
} else {
// 未超过,添加成功提示,
checkArticleSameAuthorAndAffiliation({
aidList: aidList,
IssueId: pageId,
}).then((res) => {
checkArticleDatas.repeatAuthorTips = res.data.repeatAuthorTips;
checkArticleDatas.repeatInstitutionTips = res.data.repeatInstitutionTips;
checkArticleDatas.repeatResult = res.data.repeatResult;
getTableDatas();
if (checkArticleDatas.repeatResult) {
innerVisible.value = true;
} else {
confirmInfos();
}
});
}
};
// 校验所选内容articletype为Review的是否超过50%
const checkReviewCount = (data) => {
const total = data.length;
const reviewCount = data.filter(
(item) => item.articleType == "Review"
).length;
return reviewCount > total / 2;
};
const goPage = (datas) => {
let routeData = router.resolve({
path: "/papersMain/page",
query: { id: datas.aid },
});
window.open(routeData.href, "_blank");
};
const headerCellStyle = () => {
return {
backgroundColor: "#f5f7fa",
};
};
const innerVisible = ref(false);
const confirmInfos = () => {
let articleListParams: any = [];
multipleSelection.value.forEach((item) => {
articleListParams.push({
aid: item.aid,
issueId: pageId,
title: item.article_title,
authors: item.contributorNames.join(","),
});
});
saveBatch({
articleListParams: articleListParams,
}).then((res) => {
if (res.code == 2000) {
ElMessage({
type: "success",
message: res.message,
});
getTableDatas();
} else {
ElMessage({
type: "error",
message: res.message,
});
}
innerVisible.value = false;
dialogVisible.value = false;
});
};
const recordDeleteAction = (id) => {
ElMessageBox.confirm("Are you sure to delete? ", "Confirmation", {
confirmButtonText: "Confirm",
cancelButtonText: "Cancel",
type: "warning",
})
.then(() => {
deleteIssue({ issueId: id }).then((res) => {
ElMessage({
type: "success",
message: "Delete completed",
});
goBack();
});
})
.catch(() => {
ElMessage({
type: "info",
message: "Delete canceled",
});
});
};
const goAction = async (id) => {
router.push({
path: "issueAction",
query: {
id: id ? id : "",
},
});
};
const changeIssueStatus = (id) => {
setIssueStatus({ issueId: id }).then((res) => {
isPublish.value = !isPublish.value;
ElMessage({
type: "success",
message: "success",
});
});
};
</script>
<style scoped>
.dialog-footer button:first-child {
margin-right: 10px;
}
.demo-form-inline .el-input {
--el-input-width: 220px;
}
.selected {
display: flex;
align-items: center;
padding-left: 8px;
width: 100%;
height: 30px;
background-color: #e6f7ff;
border: 1px solid #c8ecff;
margin-top: 10px;
border-radius: 3px;
font-weight: 500;
margin-bottom: 10px;
img {
margin-right: 5px;
}
}
.cardBox {
.list {
max-height: 75px;
overflow: hidden;
}
.down {
display: block;
}
.up {
display: none;
}
&.authHeight {
.list {
height: auto;
max-height: inherit;
}
.down {
display: none;
}
.up {
display: block;
}
}
}
</style>