局长信箱-内网端(前端)
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

<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>