Browse Source

feat: 交付物2

text-draggable
xuesinan 4 years ago
parent
commit
22fb409623
  1. 2
      src/components/tall/center/Index.vue
  2. 346
      src/plugins/p-deliver-second/p-deliver-check-second.vue
  3. 121
      src/plugins/p-deliver-second/p-deliver-second-detail.vue
  4. 4
      src/plugins/p-deliver-second/p-deliver-upload-second.vue

2
src/components/tall/center/Index.vue

@ -36,9 +36,11 @@ const tasksHeight = ref(null); // 定期任务高度
watch(globals, () => {
nextTick(() => {
setTimeout(() => {
clientHeight.value = `${document.documentElement.clientHeight}`; //
globalHeight.value = globalRef.value.$el.clientHeight;
tasksHeight.value = clientHeight.value - 48 - 44 - 36 - globalHeight.value;
}, 30);
});
});
</script>

346
src/plugins/p-deliver-second/p-deliver-check-second.vue

@ -1,122 +1,326 @@
<template>
<div>
<!-- 审核标题 -->
<div class="flex justify-between items-center" @click="collapsed = !collapsed">
<div class="flex justify-between items-center">
<div>{{ deliverData ? deliverData.deliverName : '' }}审核状态</div>
<DownOutlined v-if="!collapsed" />
<UpOutlined v-else />
</div>
<!-- 审核结果 -->
<div v-show="collapsed">
<div>
<!-- 提交人和时间 -->
<div class="my-2 flex justify-between items-center">
<div class="text-gray-400 text-xs">
<span class="mr-4" v-if="deliverData.submitMemberName">{{ deliverData.submitMemberName }}</span>
<span v-if="deliverData.submitTime"> {{ dayjs(+deliverData.submitTime).format('MM-DD HH:mm') }}</span>
</div>
<span class="text-blue-400 text-xs text-right" @click="openDeliverHistory">历史交付物</span>
</div>
<div @click="openLink" class="break-all text-blue-400 text-xs my-1" v-if="deliverData.details && deliverData.details[0]">
<div
@click="openLink"
class="break-all text-blue-400 text-xs my-1 cursor-pointer"
v-if="deliverData.details && deliverData.details[0]"
>
{{ deliverData.details[0] }}
</div>
<!-- 审核人 标题 -->
<div class="text-gray-400 flex justify-between mt-3">
<span>审核</span>
<span class="text-blue-400 text-xs" @click="openMoreRecords">更多审核记录</span>
</div>
<!-- 审核人 列表 -->
<div v-if="deliverData.checkerList">
<div class="mt-2 text-sm flex justify-between" v-for="(item, index) in deliverData.checkerList" :key="index">
<div v-for="(item, index) in deliverData.checkerList" :key="index">
<template v-if="item.isMine === 1">
<div class="mt-2 text-sm flex justify-between" v-show="item.status > 0 && isRepeatCheck === 0">
<div>
<div class="font-semibold">{{ item.checkerName }}</div>
<div class="text-xs text-gray-400">{{ item.remark }}</div>
<div class="text-xs text-gray-400" v-if="+item.checkTime > 0">{{ dayjs(+item.checkTime).format('MM-DD HH:mm') }}</div>
</div>
<!-- 不是自己 显示审核状态 -->
<div v-show="item.isMine !== 1" class="text-xs">
<span v-if="item.status === 1" class="text-green-600"> 已通过 </span>
<span v-else-if="item.status === 2" class="text-red-600"> 已驳回 </span>
<span v-else class="text-gray-400"> 待审核 </span>
<div class="time-box" v-if="item.checkDuration">
<div class="relative">
<div class="initial-duration bg-yellow-400" :style="{ width: item.initialPercent + '%' }"></div>
<div class="absolute duration-value">默认值{{ deliverData.initialDuration / 3600000 }}小时</div>
</div>
<div class="relative">
<div class="duration bg-blue-400" :style="{ width: item.currPercent + '%' }"></div>
<div class="absolute duration-value">工作量时长{{ deliverData.duration / 3600000 }}小时</div>
</div>
<div class="relative">
<div class="check-duration bg-green-400" :style="{ width: item.checkPercent + '%' }"></div>
<div class="absolute duration-value">确认工作{{ item.checkDuration / 3600000 }}小时</div>
</div>
</div>
<!-- 自己是当前审核人 且未审核状态 -->
<div v-show="item.isMine === 1 && (item.status === null || item.status === 0)">
<a-button size="small" shape="round" class="mr-4 h-1-4 leading-1-4" type="primary" @click="checkModal.mode = 'RESOLVE'">
通过
<!-- 自己是审核人 且审核过 当前审核人的审核状态并展示得分情况 -->
<div class="text-xs">
<div class="mb-1">
<div v-if="item.status === 1" class="text-green-600">已通过</div>
<div v-else-if="item.status === 2" class="text-red-600">已驳回</div>
</div>
<div class="text-yellow-500 font-medium text-base">{{ item.score }}</div>
<!-- <view class="text-blue-500" @click="repeatCheck(1)">重新审核</view> -->
</div>
</div>
<div v-if="item.status === null || item.status === 0 || isRepeatCheck === 1">
<!-- <view v-if="isRepeatCheck === 1" class="text-blue-500 text-right" @click="repeatCheck(0)">取消重新审核</view> -->
<div class="mt-3 pb-2" style="border-bottom: 1px solid #d1d5db">
<div class="flex justify-between">
<div class="mr-1 text-sm flex items-center">
<div class="mr-2">确认工作</div>
<div class="flex flex-wrap">
<a-button
:type="checkedIndex === 0 ? 'primary' : 'default'"
size="small"
class="my-1 ml-0 mr-2"
@click="handleSelectTime(0)"
>
半小时
</a-button>
<a-button
:type="checkedIndex === 1 ? 'primary' : 'default'"
size="small"
class="my-1 ml-0 mr-2"
@click="handleSelectTime(1)"
>
1小时
</a-button>
<a-button size="small" shape="round" class="h-1-4 leading-1-4" type="primary" danger @click="checkModal.mode = 'REJECT'">
驳回
<a-button
:type="checkedIndex === 2 ? 'primary' : 'default'"
size="small"
class="my-1 ml-0 mr-2"
@click="handleSelectTime(2)"
>
2小时
</a-button>
</div>
</div>
<!-- 自己是审核人 且审核过 当前审核人的审核状态并展示得分情况 -->
<div v-show="item.isMine === 1 && item.status > 0" class="text-xs">
<div class="mb-1">
<span v-if="item.status === 1" class="text-green-600"> 已通过 </span>
<span v-else-if="item.status === 2" class="text-red-600"> 已驳回 </span>
<!-- 时长 -->
<div class="flex items-center justify-end flex-1 text-sm">
<a-input
v-model="checkDuration"
type="text"
placeholder="工作量时长"
class="input"
style="text-align: right; width: 120px"
></a-input>
小时
</div>
</div>
</div>
<div class="mt-3 flex justify-between items-center">
<div>交付物质量</div>
<a-progress v-if="item.score" type="circle" :percent="item.score" strokeColor="#FA8C16" :width="40" :strokeWidth="10">
<template #format="percent">
<span
class="inline-block text-center text-white text-sm rounded-full"
style="background: #fa8c16; width: 24px; height: 24px; line-height: 24px"
<div class="flex justify-end items-center">
<a-input-number v-model:value="score" :max="100" :min="0" :step="1"> </a-input-number>
<div class="w-64 ml-3">
<a-progress :percent="score" />
</div>
</div>
</div>
<div class="mt-3 relative">
<a-textarea style="height: 80px" v-model:value="commit" placeholder="鼓励一下小伙伴" />
<div
class="absolute border border-solid border-gray-300 rounded-md text-center text-base cursor-pointer word-btn"
@click="showWords = !showWords"
>
{{ percent }}
</span>
</div>
</div>
<div class="common-list" v-if="showWords">
<div v-for="(item, index) in words" :key="index" class="px-2 leading-12 word-item" @click="commit = item">
{{ item }}
</div>
</div>
<div class="mt-4 flex justify-center items-center">
<a-button class="mx-4" type="primary" @click="handleSubmit(1)"> 通过 </a-button>
<a-button class="mx-4" type="primary" danger @click="handleSubmit(2)"> 驳回 </a-button>
</div>
</div>
</template>
</a-progress>
</div>
<div v-for="(item, index) in deliverData.checkerList" :key="index">
<!-- 不是我 -->
<template v-if="item.isMine !== 1">
<div class="mt-2 text-sm flex justify-between">
<div>
<div class="font-semibold">{{ item.checkerName }}</div>
<div class="text-xs text-gray-400">{{ item.remark }}</div>
<div class="text-xs text-gray-400" v-if="+item.checkTime > 0">{{ dayjs(+item.checkTime).format('MM-DD HH:mm') }}</div>
</div>
<div class="time-box" v-if="item.checkDuration">
<div class="relative">
<div class="initial-duration bg-yellow-400" :style="{ width: item.initialPercent + '%' }"></div>
<div class="absolute duration-value">默认值{{ deliverData.initialDuration / 3600000 }}小时</div>
</div>
<div class="relative">
<div class="duration bg-blue-400" :style="{ width: item.currPercent + '%' }"></div>
<span class="absolute duration-value">工作量时长{{ deliverData.duration / 3600000 }}小时</span>
</div>
<div class="relative">
<div class="check-duration bg-green-400" :style="{ width: item.checkPercent + '%' }"></div>
<span class="absolute duration-value">确认工作{{ item.checkDuration / 3600000 }}小时</span>
</div>
</div>
<!-- <checkFormModal :data="checkModal" @hide="checkModal.mode = 'HIDE'" @submit-end="$emit('check-success')" /> -->
<!-- 不是自己 显示审核状态 -->
<div class="text-xs">
<span v-if="item.status === 1" class="text-green-600"> 已通过 </span>
<span v-else-if="item.status === 2" class="text-red-600"> 已驳回 </span>
<span v-else class="text-gray-400"> 待审核 </span>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, inject, defineEmits } from 'vue';
import { ref, computed, watch, defineProps, defineEmits } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import { message } from 'ant-design-vue';
import { checkDeliver } from 'apis';
import { DownOutlined, UpOutlined } from '@ant-design/icons-vue';
// import checkFormModal from './check-form-modal.vue';
import { quickWords } from '@/utils/deliver';
const props = defineProps({
deliverData: { type: Object, default: () => {} },
task: { type: Object, default: () => {} },
});
const store = useStore();
const deliverData = inject('deliver');
const collapsed = ref(false); // /
defineEmits(['check-success']);
const deliverData = computed(() => props.deliverData);
const projectId = computed(() => store.getters['project/projectId']);
const sessionProjectId = sessionStorage.getItem('projectId');
const roleId = computed(() => store.state.role.roleId);
const isRepeatCheck = ref(0); //
const words = computed(() => quickWords.RESOLVE); //
const checkDuration = ref(2); //
const checkedIndex = ref(2); //
const score = ref(100); //
const commit = ref(''); //
const showWords = ref(false); //
const maxDuration = ref(null);
const emits = defineEmits(['check-success']);
if (Object.keys(props.deliverData).length) {
checkDuration.value = Number(props.deliverData.duration) / 3600000; //
checkedIndex.value = checkDuration.value === 0.5 ? 0 : checkDuration.value === 1 ? 1 : checkDuration.value === 2 ? 2 : -1;
handleDataRender(props.deliverData);
}
watch(deliverData, () => {
checkDuration.value = Number(deliverData.value.duration) / 3600000; //
checkedIndex.value = checkDuration.value === 0.5 ? 0 : checkDuration.value === 1 ? 1 : checkDuration.value === 2 ? 2 : -1;
handleDataRender(deliverData.value);
});
//
async function handleDataRender(data) {
maxDuration.value =
deliverData.value.initialDuration > deliverData.value.duration ? deliverData.value.initialDuration : deliverData.value.duration;
data.checkerList.forEach(item => {
if (item.checkDuration) {
maxDuration.value = maxDuration.value > item.checkDuration ? maxDuration.value : item.checkDuration;
if (maxDuration.value === deliverData.value.initialDuration) {
item.initialPercent = 100;
item.currPercent = Math.floor((deliverData.value.duration / deliverData.value.initialDuration) * 100);
item.checkPercent = Math.floor((item.checkDuration / deliverData.value.initialDuration) * 100);
} else if (maxDuration.value === deliverData.value.duration) {
item.currPercent = 100;
item.initialPercent = Math.floor((deliverData.value.initialDuration / deliverData.value.duration) * 100);
item.checkPercent = Math.floor((item.checkDuration / deliverData.value.duration) * 100);
} else if (maxDuration.value === item.checkDuration) {
item.checkPercent = 100;
item.initialPercent = Math.floor((deliverData.value.initialDuration / item.checkDuration) * 100);
item.currPercent = Math.floor((deliverData.value.duration / item.checkDuration) * 100);
}
}
});
return data;
}
//
function openLink() {
window.open(deliverData.details[0], '_blank');
window.open(props.deliverData.details[0], '_blank');
}
const checkModal = reactive({
mode: 'HIDE', // HIDE-> RESOLVE-> REJECT->
deliverRecordId: () => (deliverData.value ? deliverData.value.deliverRecordId : ''), // id
});
//
function handleSelectTime(data) {
checkedIndex.value = data;
checkDuration.value = data === 0 ? 0.5 : data === 1 ? 1 : 2;
}
/**
* 提交评审信息
* 提交成功后隐藏modal 重置表单控件
* 给父组件信息 更新值
* @param {string} mode 'RESOLVE'|'REJECT'
*/
async function handleSubmit(mode) {
try {
const { url } = store.state.projects.project;
const deliverRecordId = props.deliverData ? props.deliverData.deliverRecordId : '';
const param = {
param: {
projectId: projectId.value || sessionProjectId,
roleId: roleId.value,
deliverRecordId,
type: mode === 'RESOLVE' ? 1 : 2,
remark: commit.value,
score: score.value,
checkDuration: checkDuration.value * 3600000,
msgId: props.task.msgId,
},
};
await checkDeliver(param, url);
handleHide(); // +
message.info('审核信息提交成功');
//
emits('submit-end', param);
} catch (error) {
console.error('error: ', error);
message.info('审核信息提交失败, 请稍后重试');
}
}
//
function openDeliverHistory() {
const { deliverId } = deliverData.value;
store.commit('task/setDeliverId', deliverId); // id
store.commit('task/setTaskDetailUrl', ''); //
store.commit('task/setTaskDetailShow', 'deliverHistory'); //
//
function handleHide() {
score.value = 100;
commit.value = '';
}
//
function openMoreRecords() {
const { deliverRecordId } = deliverData.value;
store.commit('task/setDeliverRecordId', deliverRecordId); // id
store.commit('task/setTaskDetailUrl', ''); //
store.commit('task/setTaskDetailShow', 'auditRecords'); //
//
function repeatCheck(data) {
isRepeatCheck.value = data;
}
</script>
@ -125,4 +329,34 @@ function openMoreRecords() {
width: 40px !important;
height: 40px !important;
}
.word-btn {
right: 10px;
bottom: 10px;
width: 30px;
height: 30px;
line-height: 28px;
}
.word-item {
border-bottom: 1px solid #e5e7eb;
}
.time-box {
width: 120px;
}
.time-box view {
height: 15px;
border-radius: 2px;
margin: 2px 0;
}
.time-box .duration-value {
height: 15px;
line-height: 15px;
font-size: 12px;
top: 0;
left: 0;
}
</style>

121
src/plugins/p-deliver-second/p-deliver-second-detail.vue

@ -38,12 +38,71 @@
<div class="px-3">
<p-deliver-check-second
class="p-3 bg-white rounded-md"
v-if="deliverData"
:deliverData="deliverData"
:task="task"
@submit-end="getDeliverData"
></p-deliver-check-second>
</div>
<!-- 历史记录 -->
<div class="p-3 text-base scroll-2">历史记录</div>
<div class="px-3" v-if="listRef && listRef.length">
<div class="bg-white mb-3 rounded-md p-3 text-gray-400" v-for="(item, index) in listRef" :key="index">
<!-- 插件名称和提交时间显示 -->
<div class="flex justify-between mb-2">
<div class="text-gray-800">{{ deliverName }}</div>
<div class="ml-1 text-xs w-24 text-right">{{ dayjs(+item.submitTime).format('MM-DD HH:mm') }}</div>
</div>
<!-- 提交的链接 -->
<div @click="openLink" class="break-all text-blue-400 text-xs my-1 cursor-pointer" v-if="item.details && item.details[0]">
{{ item.details[0] }}
</div>
<!-- 该插件物的审核人 -->
<div class="mb-1 mt-3">审核人</div>
<div class="flex justify-between mb-2" v-for="(checkItem, checkIndex) in item.checkerList" :key="checkIndex">
<div>
<div class="mb-1 text-gray-800 font-semibold">
{{ checkItem.checkerName }}
</div>
<div class="mb-1 text-xs">
{{ checkItem.remark }}
</div>
<div class="mb-1 text-xs" v-if="+checkItem.checkTime > 0">
{{ dayjs(+checkItem.checkTime).format('MM-DD HH:mm') }}
</div>
</div>
<div class="time-box" v-if="checkItem.checkDuration">
<div class="relative">
<div class="initial-duration bg-yellow-400" :style="{ width: checkItem.initialPercent + '%' }"></div>
<span class="absolute duration-value">默认值{{ initialDuration / 3600000 }}小时</span>
</div>
<div class="relative">
<div class="duration bg-blue-400" :style="{ width: checkItem.currPercent + '%' }"></div>
<span class="absolute duration-value">工作量时长{{ item.duration / 3600000 }}小时</span>
</div>
<div class="relative">
<div class="check-duration bg-green-400" :style="{ width: checkItem.checkPercent + '%' }"></div>
<span class="absolute duration-value">确认工作{{ checkItem.checkDuration / 3600000 }}小时</span>
</div>
</div>
<div class="text-center text-xs">
<div v-if="checkItem.status == null" class="text-gray-400">待审核</div>
<div v-else-if="checkItem.status === 1">
<div class="text-green-600 mb-1">已通过</div>
<div class="text-yellow-500 font-medium text-base">{{ checkItem.score }}</div>
</div>
<div class="text-red-600" v-else>已驳回</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
@ -51,7 +110,7 @@
<script setup>
import { useStore } from 'vuex';
import { ref, onMounted, computed, watch, provide } from 'vue';
import { getDeliverByTaskId } from 'apis';
import { getDeliverByTaskId, getDeliverHistory } from 'apis';
import { message } from 'ant-design-vue';
import pDeliverUploadSecond from '@/plugins/p-deliver-second/p-deliver-upload-second.vue';
import pDeliverCheckSecond from '@/plugins/p-deliver-second/p-deliver-check-second.vue';
@ -77,6 +136,10 @@ const current = ref(0); // 当前点击的按钮
const deliverData = ref(null); //
const task = ref(null); //
const deliverName = ref(null);
const listRef = ref([]); //
const initialDuration = ref(null); //
const maxDuration = ref(null);
//
if (sessionDetailParams && !detailParams.value) {
@ -101,6 +164,7 @@ watch(detailParams, () => {
onMounted(() => {
document.getElementById('deliverCon').addEventListener('scroll', handleScroll, true);
getDeliverData();
});
//
@ -120,6 +184,26 @@ function handleScroll(e) {
console.log('scrollTop', scrollTop);
}
// id
async function getHistory() {
try {
const { url } = store.state.projects.project;
const param = { param: { deliverId: detailParams.value.deliver.deliverId } };
const data = await getDeliverHistory(param, url);
deliverName.value = data.deliverName;
initialDuration.value = data.initialDuration;
listRef.value = data.deliverRecordList;
listRef.value.forEach(item => {
handleDataRender(item);
});
} catch (error) {
console.log('error: ', error);
message.info('获取交付物历史失败');
}
}
// id
async function getDeliverData() {
try {
@ -133,12 +217,45 @@ async function getDeliverData() {
message.info(error);
}
}
//
async function handleDataRender(data) {
maxDuration.value =
deliverData.value.initialDuration > deliverData.value.duration ? deliverData.value.initialDuration : deliverData.value.duration;
data.checkerList.forEach(item => {
if (item.checkDuration) {
maxDuration.value = maxDuration.value > item.checkDuration ? maxDuration.value : item.checkDuration;
if (maxDuration.value === deliverData.value.initialDuration) {
item.initialPercent = 100;
item.currPercent = Math.floor((deliverData.value.duration / deliverData.value.initialDuration) * 100);
item.checkPercent = Math.floor((item.checkDuration / deliverData.value.initialDuration) * 100);
} else if (maxDuration.value === deliverData.value.duration) {
item.currPercent = 100;
item.initialPercent = Math.floor((deliverData.value.initialDuration / deliverData.value.duration) * 100);
item.checkPercent = Math.floor((item.checkDuration / deliverData.value.duration) * 100);
} else if (maxDuration.value === item.checkDuration) {
item.checkPercent = 100;
item.initialPercent = Math.floor((deliverData.value.initialDuration / item.checkDuration) * 100);
item.currPercent = Math.floor((deliverData.value.duration / item.checkDuration) * 100);
}
}
});
return data;
}
//
function openLink() {
window.open(deliverData.value.details[0], '_blank');
}
</script>
<style scoped>
.tab-box {
height: 44px;
z-index: 999;
z-index: 8;
}
.tab-box .tab-item {

4
src/plugins/p-deliver-second/p-deliver-upload-second.vue

@ -96,8 +96,8 @@ const roleId = computed(() => store.state.role.roleId);
const deliverInject = inject('deliver'); //
const taskInject = inject('task'); //
const deliver = computed(() => (Object.keys(props.deliverData).length ? props.deliverData : deliverInject.value));
const task = computed(() => (Object.keys(props.task).length ? props.task : taskInject));
const deliver = computed(() => (props.deliverData && Object.keys(props.deliverData).length ? props.deliverData : deliverInject.value));
const task = computed(() => (props.task && Object.keys(props.task).length ? props.task : taskInject));
const linkValue = ref(''); //
const duration = ref(2); //

Loading…
Cancel
Save