You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
564 lines
22 KiB
564 lines
22 KiB
<template> |
|
<div class="container"> |
|
<header> |
|
<el-form :label-width="120"> |
|
<el-row> |
|
<el-col :span="6"> |
|
<el-form-item label="来信时间"> |
|
<el-date-picker v-model="query.mailTime" value-format="YYYY-MM-DD HH:mm:ss" |
|
type="datetimerange" format="YYYY-MM-DD HH:mm:ss" range-separator="~" |
|
start-placeholder="开始日期" end-placeholder="结束日期" @change="handleMailTimeQuery" /> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="信件来源"> |
|
<el-select v-model="query.source" placeholder="" clearable filterable> |
|
<el-option v-for="item in dictData.mail_source" :key="item.value" :label="item.name" |
|
:value="item.value" /> |
|
</el-select> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="来信人员"> |
|
<div class="flex gap"> |
|
<el-select v-model="query.contactField" style="width: 100px"> |
|
<el-option label="姓名" value="name" /> |
|
<el-option label="身份证" value="idCard" /> |
|
<el-option label="联系电话" value="phone" /> |
|
</el-select> |
|
<el-input v-model="query.contactFieldValue" :placeholder="placeholderText" clearable /> |
|
</div> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="信件等级"> |
|
<el-select v-model="query.mailLevel" placeholder="" clearable> |
|
<el-option v-for="item in dictData.mail_level" :key="item.value" :label="item.name" |
|
:value="item.value" /> |
|
</el-select> |
|
</el-form-item> |
|
</el-col> |
|
</el-row> |
|
<el-row> |
|
<el-col :span="6"> |
|
<el-form-item label="信件分类"> |
|
<el-tree-select v-model="query.mailCategory" :data="mailStore.mailCategorys" check-strictly |
|
clearable filterable /> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="信件状态"> |
|
<el-select v-model="query.mailState" placeholder="" clearable> |
|
<el-option v-for="item in dictData.mail_state" :key="item.value" :label="item.name" |
|
:value="item.value" /> |
|
</el-select> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="办理单位"> |
|
<el-tree-select class="flex-1" v-model="query.deptId" :data="optionsData.dept" clearable |
|
node-key="id" filterable :props="{ |
|
value: 'id', |
|
label: 'name', |
|
disabled(data: any) { |
|
return !!data.isStop |
|
} |
|
}" check-strictly placeholder="请选择上级部门" /> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="流程阶段"> |
|
<el-select v-model="query.flowKey" placeholder="" clearable multiple collapse-tags="true" |
|
filterable> |
|
<el-option v-for="item in optionsData.flowNodes" :key="item.key" :label="item.fullName" |
|
:value="item.key" /> |
|
</el-select> |
|
</el-form-item> |
|
</el-col> |
|
</el-row> |
|
<el-row> |
|
<el-col :span="6"> |
|
<el-form-item label="信件标签"> |
|
<el-select v-model="query.mailLabels" placeholder="请选择标签" multiple clearable filterable> |
|
<el-option v-for="item in optionsData.labels" :key="item.id" :label="item.labelName" |
|
:value="item.id" /> |
|
</el-select> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="信件统计"> |
|
<el-select v-model="query.countMails" placeholder="请选择统计方式" clearable> |
|
<el-option label="来信总数" value="1" /> |
|
<el-option label="已办结件" value="2" /> |
|
<el-option label="满意件" value="3" /> |
|
<el-option label="已解决件" value="4" /> |
|
</el-select> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="内容查询"> |
|
<el-input v-model="query.queryByContent" placeholder="请输入相关信件内容" clearable /> |
|
</el-form-item> |
|
</el-col> |
|
<el-col :span="6"> |
|
<el-form-item label="编号查询"> |
|
<el-input v-model="query.queryById" placeholder="请输入相关信件编号" clearable /> |
|
</el-form-item> |
|
</el-col> |
|
</el-row> |
|
<div style="display: flex; justify-content: space-between; margin-bottom: 20px;"> |
|
<div> |
|
<el-button type="primary" @click="checkMail">信件核对</el-button> |
|
<el-button type="primary" @click="outputSelectedMail" class="ml-4">信件导出</el-button> |
|
|
|
</div> |
|
<div> |
|
<el-button type="primary" @click="getList">查询</el-button> |
|
<el-button @click="reset">重置</el-button> |
|
</div> |
|
</div> |
|
</el-form> |
|
</header> |
|
<main v-loading="loading"> |
|
<div class="table-container"> |
|
<el-table :data="form" style="width: 100%" stripe ref="tableRef" |
|
@selection-change="handleSelectionChange" :row-key="rowKey"> |
|
<el-table-column type="selection" width="30" :reserve-selection="true" /> |
|
<el-table-column prop="mailTime" label="来信时间" align="center" width="160" /> |
|
<el-table-column label="信件来源" align="center" width="90"> |
|
<template #default="{ row }"> |
|
<span>{{ |
|
dictData.mail_source.filter( |
|
(item) => item.value === row.source |
|
)[0].name |
|
}}</span> |
|
</template> |
|
</el-table-column> |
|
<el-table-column prop="contactName" label="姓名" align="center" width="80" /> |
|
<el-table-column prop="contactPhone" label="联系电话" width="120" align="center" /> |
|
|
|
<el-table-column prop="mailCategory" label="信件分类" width="120" align="center" /> |
|
<el-table-column prop="content" label="信件内容" show-overflow-tooltip align="center" /> |
|
<el-table-column label="信件状态" width="90" align="center"> |
|
|
|
<template #default="{ row }"> |
|
<span>{{ getDictLable(dictData.mail_state, row.mailState) }}</span> |
|
</template> |
|
</el-table-column> |
|
<el-table-column prop="threeDeptName" label="办理单位" width="140" align="center" /> |
|
<el-table-column prop="currentOperator" label="当前处理对象" width="140" align="center" /> |
|
<el-table-column label="流程节点" width="120" align="center"> |
|
|
|
<template #default="{ row }"> |
|
<el-tag :type="getFlowTagType(row.flowName)" v-if="row.flowName">{{ row.flowName |
|
}}</el-tag> |
|
<el-tag type="danger" v-else>未签收</el-tag> |
|
</template> |
|
</el-table-column> |
|
<el-table-column label="流程限时" width="140" align="center"> |
|
|
|
<template #default="{ row }"> |
|
<div v-if="row.flowName !== '已办结'"> |
|
<div v-if="row.flowLimitedRemainingTime > 0" class="success"> |
|
<span class="mr-4">剩余</span> |
|
<span class="text">{{ formatTimeText(row.flowLimitedRemainingTime) }}</span> |
|
</div> |
|
<div v-if="row.flowLimitedRemainingTime < 0" class="error"> |
|
<span class="mr-4">超时</span> |
|
<span class="text">{{ formatTimeText(-row.flowLimitedRemainingTime) }}</span> |
|
</div> |
|
</div> |
|
</template> |
|
</el-table-column> |
|
<el-table-column label="信件等级" width="100" align="center"> |
|
|
|
<template #default="{ row }"> |
|
<mail-level :value="row.mailLevel" :list="dictData.mail_level" /> |
|
</template> |
|
</el-table-column> |
|
<el-table-column prop="mailLabels" label="信件标签" width="160" align="center" /> |
|
<el-table-column label="操作" width="120" fixed="right" align="center"> |
|
|
|
<template #default="{ row }"> |
|
<el-button type="primary" link @click="handleMail(row.id)">详情</el-button> |
|
<el-button type="primary" link @click="handleMailLabel(row.id)">标签</el-button> |
|
<el-button type="primary" link @click="handleTodoByChange(row.id)" |
|
v-show="handleMailCategory(row)">转为待办</el-button> |
|
<el-button type="primary" link @click="handleDelete(row.id)" |
|
v-show="IsdeleteMail(row)">删除</el-button> |
|
</template> |
|
</el-table-column> |
|
</el-table> |
|
</div> |
|
<div style="display: flex; justify-content: space-between; margin-top: 4px;"> |
|
<div style="display: flex; align-items: center;"> |
|
<el-checkbox v-model="checkAll" label="全选" style="margin-left: 15px;" :indeterminate="isCheckAll" |
|
@click="handleCheckAll">全选</el-checkbox> |
|
<span class="ml-4">({{ selectedCount }})条</span> |
|
</div> |
|
<div> |
|
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" |
|
:current-page="query.current" :page-sizes="[10, 15, 20, 40, 50]" :page-size="query.size" |
|
layout="total,sizes, prev, pager, next, jumper" :total="totalSize.total"> |
|
</el-pagination> |
|
</div> |
|
</div> |
|
</main> |
|
</div> |
|
<MailDialog v-model:show="showModel" :mail-id="activeMailId" :disabled="true" @update="getList" /> |
|
<MailLabel v-if="showLabel" v-model="showLabel" :mail-id="activeMailId" @close="showLabel = false" |
|
@update="getList" /> |
|
<MailCheck v-model:show="showCheck" @close="showCheck = false" /> |
|
<MailTodoByChangeVue v-model:show="showTodoByChange" :mail-id="activeMailId" @close="showTodoByChange = false" |
|
@update="getList" /> |
|
</template> |
|
|
|
<script lang="ts" setup> |
|
import MailDialog from "./components/MailDialog.vue"; |
|
import MailLabel from "./components/MailLabel.vue"; |
|
import MailCheck from "./components/MailCheck.vue"; |
|
import MailTodoByChangeVue from "./components/MailTodoByChange.vue"; |
|
import { getMails } from "@/api/work"; |
|
import { useDictData } from "@/hooks/useDictOptions"; |
|
import useMailStore from "@/stores/modules/mail"; |
|
import { formatTimeText, getDictLable, getFlowTagType } from "@/utils/util"; |
|
import { useDictOptions } from '@/hooks/useDictOptions' |
|
import { deptLists } from '@/api/org/department' |
|
import { labelLists } from '@/api/org/label' |
|
import { getFlowNodes } from '@/api/org/flowNode' |
|
import { ref, reactive, watch, onMounted, onUnmounted, nextTick } from "vue"; |
|
import { ElMessage, ElTable } from "element-plus"; |
|
import { getToken } from '@/utils/auth' |
|
import axios from 'axios' |
|
import { useRouterParamsStore } from "@/stores/modules/routerParams"; |
|
import { useRoute } from "vue-router"; |
|
import feedback from "@/utils/feedback"; |
|
import {deleteMail} from "@/api/mail"; |
|
|
|
const rowKey = "id"; |
|
const loading = ref(false) |
|
|
|
const tableRef = ref<InstanceType<typeof ElTable>>(); |
|
const mailStore = useMailStore(); |
|
mailStore.getMailCategorys(); |
|
const { dictData } = useDictData(["mail_source", "mail_level", "mail_state"]); |
|
const showLabel = ref(false); |
|
const showCheck = ref(false) |
|
|
|
const query = ref({ |
|
contactField: "name", |
|
size: 10, |
|
current: 1, |
|
}); |
|
const totalSize = reactive({ |
|
total: 0, |
|
pages: 0 |
|
}) |
|
|
|
const placeholderText = ref("请输入姓名") |
|
watch(() => query.value.contactField, (val, prevVal) => { |
|
if (val === "idCard") { |
|
placeholderText.value = "请输入身份证号"; |
|
} else if (val === "phone") { |
|
placeholderText.value = "请输入联系电话"; |
|
} else { |
|
placeholderText.value = "请输入姓名"; |
|
} |
|
}); |
|
|
|
let timeClock = null |
|
const updateCountdown = (second: number) => { |
|
form.value.forEach((item: any) => { |
|
if (item.flowLimitedRemainingTime > 0) { |
|
item.flowLimitedRemainingTime -= 1; |
|
} |
|
}); |
|
}; |
|
onMounted(() => { |
|
timeClock = setInterval(updateCountdown, 1000) |
|
}) |
|
onUnmounted(() => { |
|
clearInterval(timeClock); |
|
}); |
|
|
|
const route = useRoute() |
|
const useRouterParams = useRouterParamsStore() |
|
const loadingOnce = ref(true) |
|
watch(() => route.path, () => { |
|
console.log("route.path", route.path) |
|
if (route.path === '/work/query') { |
|
console.log("useRouterParams.params", useRouterParams.params) |
|
// 处理跳转路由参数 |
|
if (useRouterParams.params.flowKey) |
|
query.value.flowKey = useRouterParams.params.flowKey.split(',') |
|
else |
|
delete query.value.flowKey |
|
if (useRouterParams.params.mailState) |
|
query.value.mailState = useRouterParams.params.mailState |
|
else |
|
delete query.value.mailState |
|
//特定请求携带参数 |
|
if (useRouterParams.params.signDeptId) |
|
query.value.signDeptId = useRouterParams.params.signDeptId |
|
else |
|
delete query.value.signDeptId |
|
if (useRouterParams.params.signRoleId) |
|
query.value.signRoleId = useRouterParams.params.signRoleId |
|
else |
|
delete query.value.signRoleId |
|
if (useRouterParams.params.mailCategory) |
|
query.value.mailCategory = useRouterParams.params.mailCategory |
|
else |
|
delete query.value.mailCategory |
|
|
|
getList() |
|
useRouterParams.removeParams() |
|
} |
|
}) |
|
|
|
|
|
const checkAll = ref(false); |
|
const isCheckAll = ref(false); |
|
const selectedCount = ref(0); |
|
const solveCheckBox = ref([]) |
|
const handleSelectionChange = (selection: any) => { |
|
solveCheckBox.value = selection |
|
refreshCheckAll() |
|
selectedCount.value = tableRef.value.getSelectionRows().length |
|
} |
|
const handleCheckAll = () => { |
|
tableRef.value.toggleAllSelection() |
|
} |
|
const refreshCheckAll = () => { |
|
checkAll.value = (solveCheckBox.value.length === totalSize.total) ? true : false |
|
isCheckAll.value = (!checkAll.value && solveCheckBox.value.length > 0) ? true : false |
|
} |
|
|
|
const outputSelectedMail = () => { |
|
console.log("outputSelectedMail", solveCheckBox.value); |
|
const data = solveCheckBox.value.map((item: any) => item.id) |
|
console.log("data", data) |
|
|
|
axios.post('/lan-api/api/work/export', data, { |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
|
"Admin": getToken() |
|
}, |
|
responseType: 'blob' |
|
}).then((res: any) => { |
|
const url = window.URL.createObjectURL(new Blob([res.data])); |
|
const link = document.createElement('a'); |
|
link.href = url; |
|
link.setAttribute('download', 'data.xlsx'); // 根据需求修改文件名 |
|
document.body.appendChild(link); |
|
link.click(); |
|
document.body.removeChild(link); |
|
}).catch((err: any) => { |
|
console.log(err); |
|
}); |
|
} |
|
|
|
const exportLedger = () => { |
|
delete query.value.size |
|
delete query.value.current |
|
|
|
const data = query.value |
|
if(data.flowKey) |
|
data.flowKey = data.flowKey.join(',') |
|
if(data.mailLabels) |
|
data.mailLabels = data.mailLabels.join(',') |
|
|
|
console.log("exportLedger", data); |
|
axios.post('/lan-api/api/work/exportLedger', data, { |
|
headers: { |
|
'Content-Type': 'application/json', |
|
'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
|
"Admin": getToken() |
|
}, |
|
responseType: 'blob' |
|
}).then((res: any) => { |
|
const url = window.URL.createObjectURL(new Blob([res.data])); |
|
const link = document.createElement('a'); |
|
link.href = url; |
|
link.setAttribute('download', 'data.xlsx'); // 根据需求修改文件名 |
|
document.body.appendChild(link); |
|
link.click(); |
|
document.body.removeChild(link); |
|
}).catch((err: any) => { |
|
console.log(err); |
|
}); |
|
} |
|
|
|
|
|
const form = ref([]); |
|
const showModel = ref(false); |
|
const activeMailId = ref(""); |
|
|
|
function handleMail(mailId: any) { |
|
showModel.value = true; |
|
activeMailId.value = mailId; |
|
} |
|
|
|
const handleMailLabel = (mailId: any) => { |
|
showLabel.value = true; |
|
activeMailId.value = mailId; |
|
} |
|
|
|
const handleSizeChange = (size: any) => { |
|
query.value.size = size; |
|
getList(); |
|
refreshCheckAll() |
|
} |
|
|
|
const handleCurrentChange = (page: any) => { |
|
query.value.current = page; |
|
getList(); |
|
refreshCheckAll() |
|
} |
|
|
|
function getList() { |
|
if (loadingOnce.value) { |
|
// 处理跳转路由参数 |
|
if (useRouterParams.params.flowKey) |
|
query.value.flowKey = useRouterParams.params.flowKey.split(',') |
|
else |
|
delete query.value.flowKey |
|
if (useRouterParams.params.mailState) |
|
query.value.mailState = useRouterParams.params.mailState |
|
else |
|
delete query.value.mailState |
|
//特定请求携带参数 |
|
if (useRouterParams.params.signDeptId) |
|
query.value.signDeptId = useRouterParams.params.signDeptId |
|
else |
|
delete query.value.signDeptId |
|
if (useRouterParams.params.signRoleId) |
|
query.value.signRoleId = useRouterParams.params.signRoleId |
|
else |
|
delete query.value.signRoleId |
|
if (useRouterParams.params.mailCategory) |
|
query.value.mailCategory = useRouterParams.params.mailCategory |
|
else |
|
delete query.value.mailCategory |
|
} |
|
|
|
loading.value = true |
|
let source = "" |
|
if (query.value.mailLabels) { |
|
let strLabels = "" |
|
source = query.value.mailLabels |
|
for (let i = 0; i < query.value.mailLabels.length; i++) { |
|
if (i === query.value.mailLabels.length - 1) |
|
strLabels += query.value.mailLabels[i] |
|
else |
|
strLabels += query.value.mailLabels[i] + ',' |
|
} |
|
query.value.mailLabels = strLabels |
|
} |
|
getMails(query.value).then((data: any) => { |
|
console.log("data", data) |
|
form.value = data.records; |
|
totalSize.total = data.total; |
|
totalSize.pages = data.pages; |
|
query.value.mailLabels = source |
|
loading.value = false |
|
if (loadingOnce.value) { |
|
useRouterParams.removeParams() |
|
loadingOnce.value = !loadingOnce.value |
|
} |
|
//清除隐藏参数 |
|
delete query.value.signDeptId |
|
delete query.value.signRoleId |
|
}); |
|
} |
|
|
|
const { optionsData } = useDictOptions<{ |
|
dept: any[], |
|
labels: any[], |
|
flowNodes: any[] |
|
}>({ |
|
dept: { |
|
api: deptLists |
|
}, |
|
labels: { |
|
api: labelLists |
|
}, |
|
flowNodes: { |
|
api: getFlowNodes |
|
} |
|
}) |
|
function reset() { |
|
query.value = {} |
|
getList() |
|
} |
|
const checkMail = () => { |
|
showCheck.value = true |
|
console.log("checkMail", solveCheckBox.value) |
|
} |
|
const handleMailTimeQuery = (val: any) => { |
|
if (val) { |
|
query.value.mailTimeStart = val[0]; |
|
query.value.mailTimeEnd = val[1]; |
|
} else { |
|
delete query.value.mailTimeStart |
|
delete query.value.mailTimeEnd |
|
} |
|
} |
|
|
|
const showTodoByChange = ref(false) |
|
const handleTodoByChange = (mailId: any) => { |
|
showTodoByChange.value = true |
|
activeMailId.value = mailId |
|
} |
|
|
|
|
|
const handleDelete = async (mailId: any) => { |
|
if(mailId == ""||mailId == null){ |
|
return; |
|
} |
|
await feedback.confirm("确定要删除?"); |
|
await deleteMail({id:mailId}); |
|
feedback.msgSuccess("删除成功"); |
|
getList() |
|
}; |
|
|
|
|
|
|
|
const handleMailCategory = (row: any) => { |
|
const allowChangeList = ['终止类', '无效类'] |
|
return allowChangeList.includes(row.mailCategory) |
|
} |
|
|
|
|
|
const IsdeleteMail = (row: any) => { |
|
const allowChangeList = ['first_sign', 'first_distribute'] |
|
return allowChangeList.includes(row.flowKey) |
|
} |
|
|
|
getList() |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
.table-container { |
|
border: 1px solid rgba(198, 208, 251, 1); |
|
} |
|
|
|
.success .text { |
|
color: #128009; |
|
padding: 0 8px; |
|
height: 24px; |
|
line-height: 24px; |
|
text-align: center; |
|
} |
|
|
|
.error { |
|
background-color: #FF0000; |
|
color: #fff; |
|
padding: 0 8px; |
|
height: 24px; |
|
line-height: 24px; |
|
border-radius: 20px; |
|
text-align: center; |
|
} |
|
</style> |