Browse Source

不满意信件流程完善

master
21819 2 years ago
parent
commit
81309e8bf0
  1. 46
      src/utils/util.ts
  2. 26
      src/views/work/Dissatisfied.vue
  3. 64
      src/views/work/components/AppealProgress.vue
  4. 89
      src/views/work/components/HandleAppeal.vue
  5. 228
      src/views/work/components/HandleOverrule.vue
  6. 2
      src/views/work/components/LaunchAppeal.vue
  7. 85
      src/views/work/components/OverruleReason.vue

46
src/utils/util.ts

@ -1,6 +1,7 @@
import { isObject } from '@vue/shared'
import { cloneDeep } from 'lodash'
import moment from 'moment'
import { listSecond } from '@/api/org/department'
/**
* @description
@ -325,3 +326,48 @@ export function validatorPhone(rule: object, phonenumber: string, callback: any)
}
callback()
}
export function getAppealType(appealState: String) {
switch (appealState) {
case '1':
return 'primary'
case '2':
return 'success'
case '3':
return 'danger'
default:
break;
}
}
export function getAppealName(appealState: String) {
switch (appealState) {
case '0': return '未审诉'
case '1': return '申诉中'
case '2': return '申诉成功'
case '3': return '已驳回'
}
}
export function getAppealDept(handlingDept) {
if (handlingDept === 1) {
return Promise.resolve('市局专班');
} else {
return new Promise((resolve, reject) => {
listSecond().then((res) => {
for (let item of res) {
if (item.id === handlingDept) {
resolve(item.name);
return;
}
}
resolve(null); // 如果循环结束都没找到,resolve为null
}).catch((err) => {
console.error(err);
reject(err); // 如果请求失败,reject这个promise
});
});
}
}

26
src/views/work/Dissatisfied.vue

@ -117,7 +117,16 @@
<el-tag type="danger" v-else>未签收</el-tag>
</template>
</el-table-column>
<el-table-column prop="appealState" label="申诉状态" />
<el-table-column prop="appealState" label="申诉状态">
<template #default="{ row }">
<el-text :type="getAppealType(row.appealState)">{{ getAppealName(row.appealState)
}}</el-text>
<el-text type="info" v-if="['1', '3'].includes(row.appealState)">
({{ appealDepts[row.handlingDept] || '加载中...' }})
</el-text>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
@ -156,7 +165,7 @@ import useMailStore from "@/stores/modules/mail";
import { getDissatisfied } from "@/api/work";
import { ref, reactive } from "vue";
import { useDictData } from "@/hooks/useDictOptions";
import { getDictLable, getFlowTagType } from "@/utils/util";
import { getDictLable, getFlowTagType, getAppealType, getAppealDept, getAppealName } from "@/utils/util";
import { useDictOptions } from '@/hooks/useDictOptions'
import { deptLists } from '@/api/org/department'
@ -189,6 +198,17 @@ const showAppealProgress = ref(false);
const showOverruleReason = ref(false);
const showHandleAppeal = ref(false);
const appealDepts = ref({});
watchEffect(() => {
for (const data of dissatisfied.value) {
if (['1', '3'].includes(data.appealState) && !appealDepts.value[data.handlingDept]) {
getAppealDept(data.handlingDept).then(deptName => {
appealDepts.value[data.handlingDept] = deptName;
});
}
}
});
function handleDetail(mailId) {
showModel.value = true;
activeMailId.value = mailId;
@ -248,4 +268,4 @@ const handleAppeal = (mailId: any) => {
.table-container {
border: 1px solid rgba(198, 208, 251, 1);
}
</style>./components/Lauch.vue./components/AppealProgress.vue
</style>

64
src/views/work/components/AppealProgress.vue

@ -3,7 +3,7 @@
style="--el-dialog-padding-primary: 10px">
<template #header="" style="display: flex;align-items: center;justify-content: space-between;">
<div class="dialog-header">
<span class="dialog-title">不满意信件申诉</span>
<span class="dialog-title">不满意信件申诉处理</span>
</div>
</template>
<div class="dialog-body">
@ -11,22 +11,22 @@
<el-col :span="4">
<span class="main-label">申诉中</span>
</el-col>
<el-col :span="16">
<el-col :span="20">
<el-steps :active="active" class="steps" ref="steps">
<el-step title="提交申诉"></el-step>
<el-step title="二级专班审批"></el-step>
<el-step title="市局专班审批"></el-step>
<el-step :status="stepStatus[0]" title="提交申诉"></el-step>
<el-step :status="stepStatus[1]" title="二级专班审批"></el-step>
<el-step :status="stepStatus[2]" title="市局专班审批"></el-step>
</el-steps>
</el-col>
</el-row>
<el-divider />
<span class="main-label">申诉理由</span>
<div class="mt-20">
<span>{{ }}</span>
<span class="info-content">{{ appealReason }}</span>
</div>
<span class="main-label">相关附件</span>
<div class="mt-20 mb-20">
<FileList :files="fileList" />
</div>
<div style="display: flex;justify-content: flex-end;">
<el-button type="primary" @click="handleSubmit">关闭窗口</el-button>
@ -37,8 +37,8 @@
<script lang="ts" setup>
import { ElSteps } from 'element-plus';
import { ref, defineProps } from 'vue'
import { watch } from 'vue'
import { ref, defineProps, watch } from 'vue'
import { getAppeal } from '@/api/work/appeal'
const props = defineProps({
show: {
type: Boolean,
@ -58,12 +58,26 @@ watch(
() => props.show,
(val) => {
visible.value = val;
getDetail()
}
);
const active = ref(0)
const getDetail = () => {
getAppeal({ id: props.mailId }).then((res) => {
stepStatus.value = []
appealReason.value = res.appealReason
fileList.value = JSON.parse(res.attachments)
active.value = res.step - 1
if (res.appealState === '3')
stepStatus.value[active.value] = 'error'
console.log(res)
}).catch((err) => { console.log(err) })
}
const active = ref(3)
const appealReason = ref('')
const fileList = ref([])
const steps = ref<InstanceType<typeof ElSteps>>()
const stepStatus = ref([])
const handleSubmit = () => {
visible.value = false;
@ -121,6 +135,20 @@ const handleSubmit = () => {
width: 100%;
}
.info-content {
display: block;
background-color: #FAFBFF;
margin: 20px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #333333;
line-height: 32px;
text-align: left;
font-style: normal;
}
.el-upload__inner {
display: flex;
justify-content: center;
@ -132,7 +160,7 @@ $publicColor: #162582;
$publicHeight: 35px;
.steps {
width: 80%;
width: 100%;
margin: auto 0;
height: $publicHeight;
@ -147,10 +175,14 @@ $publicHeight: 35px;
}
}
.el-step__main {
width: 200px;
}
.el-step__line {
background-color: rgba(0, 0, 0, 0.15);
margin-right: 30px;
margin-left: 105px;
margin-right: 10px;
margin-left: 135px;
top: 50%;
height: 1px;
}
@ -164,7 +196,7 @@ $publicHeight: 35px;
}
.el-step__title.is-wait {
width: 410%;
width: 100%;
color: #999999;
}

89
src/views/work/components/HandleAppeal.vue

@ -3,7 +3,7 @@
style="--el-dialog-padding-primary: 10px">
<template #header="" style="display: flex;align-items: center;justify-content: space-between;">
<div class="dialog-header">
<span class="dialog-title">不满意信件申诉</span>
<span class="dialog-title">不满意信件申诉处理</span>
</div>
</template>
<div class="dialog-body">
@ -11,35 +11,38 @@
<el-col :span="4">
<span class="main-label">申诉中</span>
</el-col>
<el-col :span="16">
<el-col :span="20">
<el-steps :active="active" class="steps" ref="steps">
<el-step title="提交申诉"></el-step>
<el-step title="二级专班审批"></el-step>
<el-step title="市局专班审批"></el-step>
<el-step :status="stepStatus[0]" title="提交申诉"></el-step>
<el-step :status="stepStatus[1]" title="二级专班审批"></el-step>
<el-step :status="stepStatus[2]" title="市局专班审批"></el-step>
</el-steps>
</el-col>
</el-row>
<el-divider />
<span class="main-label">申诉理由</span>
<div class="mt-20">
<span>{{ }}</span>
<span class="info-content">{{ appealReason }}</span>
</div>
<span class="main-label">相关附件</span>
<div class="mt-20 mb-20">
<FileList :files="fileList" />
</div>
<div style="display: flex;justify-content: flex-end;">
<el-button type="danger" @click="handleSubmit">驳回申诉</el-button>
<el-button type="primary" @click="handleSubmit">通过申诉</el-button>
<el-button type="danger" @click="handleOverrule">驳回申诉</el-button>
<el-button type="primary" @click="handleApprovedSubmit">通过申诉</el-button>
</div>
</div>
</el-dialog>
<HandleOverrule v-model:show="showAppeal" :mail-id="activeMailId" @update="getDetail" />
</template>
<script lang="ts" setup>
import { ElSteps } from 'element-plus';
import { ref, defineProps } from 'vue'
import { watch } from 'vue'
import { ElSteps, ElMessage } from 'element-plus';
import { ref, defineProps, watch } from 'vue'
import { getAppeal } from '@/api/work/appeal'
import { approved } from '@/api/work/appeal'
import HandleOverrule from './HandleOverrule.vue'
const props = defineProps({
show: {
type: Boolean,
@ -59,14 +62,44 @@ watch(
() => props.show,
(val) => {
visible.value = val;
getDetail()
}
);
const active = ref(1)
const getDetail = () => {
getAppeal({ id: props.mailId }).then((res) => {
stepStatus.value = []
appealReason.value = res.appealReason
fileList.value = JSON.parse(res.attachments)
active.value = res.step - 1
if (res.appealState === '3')
stepStatus.value[active.value] = 'error'
console.log(res)
emits("update");
}).catch((err) => { console.log(err) })
}
const active = ref(3)
const appealReason = ref('')
const fileList = ref([])
const steps = ref<InstanceType<typeof ElSteps>>()
const stepStatus = ref([])
const showAppeal = ref(false)
const activeMailId = ref(props.mailId)
const handleSubmit = () => {
const handleOverrule = () => {
visible.value = false;
showAppeal.value = true;
activeMailId.value = props.mailId;
}
const handleApprovedSubmit = () => {
approved({ id: props.mailId }).then(() => {
visible.value = false;
ElMessage.success('申诉已通过');
emits("update");
}).catch((err) => {
ElMessage.error('申诉失败');
console.log(err)
})
}
</script>
@ -121,6 +154,20 @@ const handleSubmit = () => {
width: 100%;
}
.info-content {
display: block;
background-color: #FAFBFF;
margin: 20px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #333333;
line-height: 32px;
text-align: left;
font-style: normal;
}
.el-upload__inner {
display: flex;
justify-content: center;
@ -132,7 +179,7 @@ $publicColor: #162582;
$publicHeight: 35px;
.steps {
width: 80%;
width: 100%;
margin: auto 0;
height: $publicHeight;
@ -147,10 +194,14 @@ $publicHeight: 35px;
}
}
.el-step__main {
width: 200px;
}
.el-step__line {
background-color: rgba(0, 0, 0, 0.15);
margin-right: 30px;
margin-left: 105px;
margin-right: 10px;
margin-left: 135px;
top: 50%;
height: 1px;
}
@ -164,7 +215,7 @@ $publicHeight: 35px;
}
.el-step__title.is-wait {
width: 410%;
width: 100%;
color: #999999;
}

228
src/views/work/components/HandleOverrule.vue

@ -0,0 +1,228 @@
<template>
<el-dialog v-model="visible" width="50vw" top="4vh" class="dialog-header-nopadding" align-center
style="--el-dialog-padding-primary: 10px">
<template #header="" style="display: flex;align-items: center;justify-content: space-between;">
<div class="dialog-header">
<span class="dialog-title">不满意信件申诉驳回</span>
</div>
</template>
<div class="dialog-body">
<el-form ref="formRef" :model="form" :rules="rules" style="width: 100%">
<el-form-item label="信件信息" prop="appealReason" required
style="display: flex;flex-direction: column;justify-content: start;">
<template #label>
<span class="main-label" style="text-align: left; width: 100%">不满意信件申诉驳回理由</span>
</template>
<el-row style="width: 100%">
<el-input type="textarea" v-model="form.appealReason" placeholder="请输入不满意信件申诉驳回理由"
:autosize="{ minRows: 4, maxRows: 10 }" resize="none" />
</el-row>
</el-form-item>
</el-form>
<div style="height: 20vh;"></div>
<div style="display: flex;justify-content: flex-end;">
<el-button type="primary" @click="handleSubmit">提交</el-button>
</div>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, defineProps, watch, reactive } from 'vue'
import type { FormInstance, FormRules } from "element-plus";
import { ElMessage } from 'element-plus';
import { overrule } from '@/api/work/appeal';
const props = defineProps({
show: {
type: Boolean,
default: false
},
mailId: {
type: String,
default: ''
}
})
const emits = defineEmits(["update:show", "update"]);
const visible = ref(props.show)
watch(visible, (val) => {
emits("update:show", val);
});
watch(
() => props.show,
(val) => {
visible.value = val;
}
);
interface FormAppeal {
appealReason: string;
}
const form = ref({
mailId: '',
appealReason: ''
})
const formRef = ref<FormInstance>();
const rules = reactive<FormRules<FormAppeal>>({
appealReason: [
{ required: true, message: '请输入驳回理由', trigger: 'blur' },
{ min: 10, message: '驳回理由不能少于10个字', trigger: 'blur' },
{ max: 1000, message: '驳回理由不能多于1000个字', trigger: 'blur' }
]
})
const handleSubmit = async () => {
if (!formRef.value) return
await formRef.value.validate((valid, fields) => {
if (!valid) {
ElMessage.error('请输入驳回理由')
} else {
form.value.mailId = props.mailId
overrule(form.value).then(() => {
ElMessage.success('驳回成功');
emits('update:show', false);
emits("update");
}).catch((err) => {
ElMessage.error('驳回失败,请稍后重试');
console.log(err)
})
}
})
}
</script>
<style lang="scss" scoped>
.dialog-header {
height: 60px;
display: flex;
align-items: center;
justify-self: center;
}
.dialog-title {
margin-left: 20px;
height: 22px;
font-size: 16px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 22px;
}
.dialog-body {
margin-left: 20px;
margin-right: 20px;
}
.main-label {
width: 100%;
height: 22px;
font-size: 20px;
font-family: PingFang-SC, PingFang-SC;
font-weight: bold;
color: #333333;
line-height: 22px;
}
.main-content {
width: 100%;
height: 22px;
font-size: 20px;
font-family: PingFang-SC, PingFang-SC;
font-weight: bold;
color: #162582;
line-height: 22px;
}
.title-label {
margin-bottom: 20px;
}
.info-input {
width: 100%;
}
.info-content {
display: block;
background-color: #FAFBFF;
margin: 20px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #333333;
line-height: 32px;
text-align: left;
font-style: normal;
}
.el-upload__inner {
display: flex;
justify-content: center;
align-items: center;
}
//
$publicColor: #162582;
$publicHeight: 35px;
.steps {
width: 100%;
margin: auto 0;
height: $publicHeight;
::v-deep .el-step {
height: 100%;
.el-step__icon.is-text {
background-color: $publicColor;
.el-step__icon-inner {
color: #FFFFFF;
}
}
.el-step__main {
width: 200px;
}
.el-step__line {
background-color: rgba(0, 0, 0, 0.15);
margin-right: 10px;
margin-left: 135px;
top: 50%;
height: 1px;
}
.el-step__title {
color: #333333;
width: 100%;
position: absolute;
top: calc((100% - 135%)/2);
left: calc(0% + 30px);
}
.el-step__title.is-wait {
width: 100%;
color: #999999;
}
.el-step__head.is-wait {
.el-step__icon.is-text {
background: #FFF;
.el-step__icon-inner {
color: #CCCCCC;
}
}
}
.el-step__head.is-error {
.el-step__icon.is-text {
background-color: #FF0000;
border: 0px;
}
}
}
}
</style>

2
src/views/work/components/LaunchAppeal.vue

@ -79,6 +79,8 @@ const formRef = ref<FormInstance>()
const rules = ref<FormRules>({
appealReason: [
{ required: true, message: '请输入申诉理由', trigger: 'blur' },
{ min: 10, message: '申诉理由不能少于10个字', trigger: 'blur' },
{ max: 1000, message: '申诉理由不能多于1000个字', trigger: 'blur' }
]
})

85
src/views/work/components/OverruleReason.vue

@ -3,7 +3,7 @@
style="--el-dialog-padding-primary: 10px">
<template #header="" style="display: flex;align-items: center;justify-content: space-between;">
<div class="dialog-header">
<span class="dialog-title">不满意信件申诉</span>
<span class="dialog-title">不满意信件申诉处理</span>
</div>
</template>
<div class="dialog-body">
@ -11,35 +11,43 @@
<el-col :span="4">
<span class="main-label">申诉中</span>
</el-col>
<el-col :span="16">
<el-col :span="20">
<el-steps :active="active" class="steps" ref="steps">
<el-step title="提交申诉"></el-step>
<el-step title="二级专班审批"></el-step>
<el-step title="市局专班审批"></el-step>
<el-step :status="stepStatus[0]" title="提交申诉"></el-step>
<el-step :status="stepStatus[1]" title="二级专班审批"></el-step>
<el-step :status="stepStatus[2]" title="市局专班审批"></el-step>
</el-steps>
</el-col>
</el-row>
<el-divider />
<div v-if="overruleReason">
<span class="main-label">驳回理由</span>
<div class="mt-20">
<span class="info-content">{{ overruleReason }}</span>
</div>
</div>
<span class="main-label">申诉理由</span>
<div class="mt-20">
<span>{{ }}</span>
<span class="info-content">{{ appealReason }}</span>
</div>
<span class="main-label">相关附件</span>
<div class="mt-20 mb-20">
<FileList :files="fileList" />
</div>
<div style="display: flex;justify-content: flex-end;">
<el-button type="primary" plain @click="handleSubmit">重新申诉</el-button>
<el-button type="primary" plain @click="reSubmit">重新申诉</el-button>
<el-button type="primary" @click="handleSubmit">关闭窗口</el-button>
</div>
</div>
</el-dialog>
<LaunchAppeal v-model:show="showAppeal" :mail-id="activeMailId" @update="getDetail" />
</template>
<script lang="ts" setup>
import { ElSteps } from 'element-plus';
import { ref, defineProps } from 'vue'
import { watch } from 'vue'
import { ref, defineProps, watch } from 'vue'
import { getAppeal } from '@/api/work/appeal'
import LaunchAppeal from "./LaunchAppeal.vue";
const props = defineProps({
show: {
type: Boolean,
@ -59,16 +67,41 @@ watch(
() => props.show,
(val) => {
visible.value = val;
getDetail()
}
);
const active = ref(1)
const getDetail = () => {
getAppeal({ id: props.mailId }).then((res) => {
stepStatus.value = []
appealReason.value = res.appealReason
overruleReason.value = res.overruleReason
fileList.value = JSON.parse(res.attachments)
active.value = res.step - 1
if (res.appealState === '3')
stepStatus.value[active.value] = 'error'
console.log(res)
emits("update");
}).catch((err) => { console.log(err) })
}
const active = ref(3)
const appealReason = ref('')
const overruleReason = ref('')
const fileList = ref([])
const steps = ref<InstanceType<typeof ElSteps>>()
const stepStatus = ref([])
const showAppeal = ref(false)
const activeMailId = ref(props.mailId)
const handleSubmit = () => {
visible.value = false;
}
const reSubmit = () => {
visible.value = false;
showAppeal.value = true;
activeMailId.value = props.mailId;
emits("update");
}
</script>
<style lang="scss" scoped>
@ -122,6 +155,20 @@ const handleSubmit = () => {
width: 100%;
}
.info-content {
display: block;
background-color: #FAFBFF;
margin: 20px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #333333;
line-height: 32px;
text-align: left;
font-style: normal;
}
.el-upload__inner {
display: flex;
justify-content: center;
@ -133,7 +180,7 @@ $publicColor: #162582;
$publicHeight: 35px;
.steps {
width: 80%;
width: 100%;
margin: auto 0;
height: $publicHeight;
@ -148,10 +195,14 @@ $publicHeight: 35px;
}
}
.el-step__main {
width: 200px;
}
.el-step__line {
background-color: rgba(0, 0, 0, 0.15);
margin-right: 30px;
margin-left: 105px;
margin-right: 10px;
margin-left: 135px;
top: 50%;
height: 1px;
}
@ -165,7 +216,7 @@ $publicHeight: 35px;
}
.el-step__title.is-wait {
width: 410%;
width: 100%;
color: #999999;
}

Loading…
Cancel
Save