Browse Source

fix(交付物): 重构交付物审核部分,修复审核bug

deliver
wally 4 years ago
parent
commit
5fd88893d0
  1. 3
      CHANGELOG.md
  2. 1
      common/styles/theme/default.scss
  3. 226
      components/zwp-ring-timing/zwp-ring-timing.vue
  4. 6
      config/deliver.js
  5. 85
      plugins/p-deliver-check/check-form-modal.vue
  6. 204
      plugins/p-deliver-check/p-deliver-check.vue

3
CHANGELOG.md

@ -1,4 +1,4 @@
# 1.0.0 (2022-01-22)
# 1.0.0 (2022-01-23)
### 🌟 新功能
范围|描述|commitId
@ -81,6 +81,7 @@
--|--|--
- | deliver检查人重构;更新真实数据的检查人 | [ce808c4](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/ce808c4)
- | project init 重构 | [2457a87](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/2457a87)
- | 交付物代码整理重构 未完 | [d7c6e51](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/d7c6e51)
- | 交付物插件代码审查 | [5f4d47b](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/5f4d47b)
- | 修改插件名的输入框和查看历史记录 | [99fb88e](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/99fb88e)
- | 修改错误单词‘confirmDeleDte’ | [ddbb04c](https://101.201.226.163:50022/TALL/TALL-MUI-4/commits/ddbb04c)

1
common/styles/theme/default.scss

@ -67,7 +67,6 @@
uni-textarea {
width: 596rpx;
padding: 24rpx;
height: 140rpx;
box-sizing: border-box !important;
}

226
components/zwp-ring-timing/zwp-ring-timing.vue

@ -0,0 +1,226 @@
<template>
<view v-if="showViewToken" class="ring-timing" :style="containerStyles">
<!-- #ifndef APP-NVUE -->
<view class="ring-timing-half ring-timing-left" :style="leftStyles" @transitionend="onTimingEnd" />
<view class="ring-timing-half ring-timing-right" :style="rightStyles" />
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view :ref="`leftHalf${showViewToken}`" class="ring-timing-half ring-timing-left" :style="leftStyles" />
<view :ref="`rightHalf${showViewToken}`" class="ring-timing-half ring-timing-right" :style="rightStyles" />
<!-- #endif -->
<view class="ring-timing-center" :style="centerStyles"><slot /></view>
</view>
</template>
<script>
// #ifdef APP-NVUE
const animation = weex.requireModule('animation')
// #endif
/**
* zwp-ring-timing 圆环计时器不使用canvas和定时器仅css
* @property {String} *mode 模式可选值timing定时器chart当作图表用于展示数据图表模式仅限看看真要做图表还是用canvas好
* @property {String} activeColor 进度条走过的颜色
* @property {String} defaultColor 进度条底色
* @property {String} centerBgColor 圆环中间区域的背景色
* @property {Number} radius 圆形半径或整个组件的一半尺寸包含了圆环的宽度
* @property {Number} barWidth 圆环宽度
* @property {Number} startDeg 进度开始的角度
* @property {Number} duration timing模式的定时时间
* @property {Number} value chart模式的值1~100
* @event {Function} timingEnd timing模式下定时完成的回调
*/
export default {
props: {
mode: {
validator: value => ['timing', 'chart'].includes(value),
default: 'timing'
},
activeColor: {
type: String,
default: '#42b983'
},
defaultColor: {
type: String,
default: '#EEEEEE'
},
centerBgColor: {
type: String,
default: '#FFFFFF'
},
radius: {
type: Number,
default: 100
},
barWidth: {
type: Number,
default: 10
},
startDeg: {
type: Number,
default: 0
},
duration: {
type: Number,
default: 1
},
value: Number
},
data() {
return {
isStart: false,
showViewToken: Date.now() // nvue
}
},
computed: {
containerStyles() {
const { radius, startDeg, activeColor } = this
return {
borderRadius: `${radius}rpx`,
height: `${radius * 2}rpx`,
width: `${radius * 2}rpx`,
transform: `rotate(${startDeg}deg)`,
backgroundColor: activeColor
}
},
leftStyles() {
const { mode, radius, defaultColor, isStart, duration, value } = this
return {
height: `${radius * 2}rpx`,
width: `${radius}rpx`,
backgroundColor: defaultColor,
borderTopLeftRadius: `${radius}rpx`,
borderBottomLeftRadius: `${radius}rpx`,
...(mode == 'timing' ? {
// #ifndef APP-NVUE
transitionDuration: `${isStart ? duration : 0}s`,
transform: `rotate(${isStart ? 180 : -180}deg)`
// #endif
} : {
transform: `rotate(${-180 + value * 3.6}deg)`
})
}
},
rightStyles() {
const { mode, radius, activeColor, defaultColor, isStart, duration, value } = this
return {
height: `${radius * 2}rpx`,
width: `${radius}rpx`,
backgroundColor: defaultColor,
borderTopRightRadius: `${radius}rpx`,
borderBottomRightRadius: `${radius}rpx`,
...(mode == 'timing' ? {
// #ifndef APP-NVUE
backgroundColor: isStart ? activeColor : defaultColor,
transitionDelay: `${isStart ? duration / 2 : 0}s`,
transform: `rotate(${isStart ? 0 : -180}deg)`
// #endif
} : {
backgroundColor: value >= 50 ? activeColor : defaultColor,
transform: `rotate(${value >= 50 ? 0 : -180}deg)`,
})
}
},
centerStyles() {
const { radius, centerBgColor, barWidth, startDeg } = this
return {
borderRadius: `${radius - barWidth}rpx`,
height: `${(radius - barWidth) * 2}rpx`,
width: `${(radius - barWidth) * 2}rpx`,
transform: `translate(-50%, -50%) rotate(-${startDeg}deg)`,
backgroundColor: centerBgColor,
left: `${radius}rpx`,
top: `${radius}rpx`
}
}
},
methods: {
// #ifdef APP-NVUE
createAnimation(direction, styles, callback = () => {}) {
let { showViewToken, duration } = this
let isLeft = direction == 'left'
animation.transition(
this.$refs[`${direction}Half${showViewToken}`],
{
styles,
duration: isLeft ? duration * 1000 : 0,
delay: !isLeft ? (duration / 2) * 1000 : 0,
timingFunction: 'linear'
},
callback
)
},
// #endif
start() {
if (this.mode == 'chart') return
// #ifndef APP-NVUE
this.isStart = true
// #endif
// #ifdef APP-NVUE
const { createAnimation, activeColor, onTimingEnd } = this
createAnimation('left', {
transform: 'rotate(180deg)'
}, onTimingEnd)
createAnimation('right', {
backgroundColor: activeColor,
transform: 'rotate(0)'
})
// #endif
},
end() {
if (this.mode == 'chart') return
// #ifndef APP-NVUE
this.isStart = false
// #endif
// #ifdef APP-NVUE
this.showViewToken = 0
this.$nextTick(() => {
this.showViewToken = Date.now()
})
// #endif
},
onTimingEnd() {
this.$emit('timingEnd')
}
}
}
</script>
<style scoped>
.ring-timing {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
position: relative;
}
.ring-timing-half {
flex: 1;
/* #ifndef APP-NVUE */
transition-property: transform, background-color;
transition-timing-function: linear;
/* #endif */
/* #ifdef APP-NVUE */
transform: rotate(-180deg);
/* #endif */
}
.ring-timing-left {
transform-origin: right center;
}
.ring-timing-right {
transform-origin: left center;
}
.ring-timing-center {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
overflow: hidden;
position: absolute;
}
</style>

6
config/deliver.js

@ -1,2 +1,8 @@
// 上传文件的扩展名
export const UPLOAD_EXTENSION = ['.xls', '.xlsx', '.zip', '.exe', '.pdf', '.doc', '.docx', '.ppt', '.pptx'];
// 审核的快捷用语
export const quickWords = {
RESOLVE: ['加油,再接再厉!', '很棒!', '不错,很详细!', '加油,再接再厉'], // 审核通过常用的审批语
REJECT: ['不详细', '还有需要改进的地方', '驳回审批1', '驳回审批2'], // 审核驳回常用的审批语
};

85
plugins/p-deliver-check/check-form-modal.vue

@ -0,0 +1,85 @@
<template>
<!-- 审核通过的modal -->
<u-mask :show="data.mode !== 'HIDE'" @click="handleHide">
<view class="modal-content-wrap" @click.stop>
<!-- 通过modal的标题 -->
<view class="modal-content-head"> {{ data.mode === 'RESOLVE' ? '审核通过' : '审核驳回' }} </view>
<view class="modal-content-body">
<!-- 评分 -->
<view class="flex justify-between mb-4" v-show="data.mode === 'RESOLVE'">
<u-number-box v-model="score" size="30" input-width="50" :max="100" :min="0" :step="1"></u-number-box>
<view class="w-32 pt-4">
<u-slider v-model="score" active-color="#34D399" :max="100" :min="0" :step="1"></u-slider>
</view>
</view>
<u-input v-model="commit" type="textarea" :border="true" :auto-height="true" />
<view class="common-list">
<view v-for="item in words" class="leading-12" @click="commit = item">
{{ item }}
</view>
</view>
</view>
<view class="modal-content-foot">
<view class="cancel" @click="handleHide"> 取消 </view>
<view class="confirm" @click="handleSubmit(data.mode)"> 确定 </view>
</view>
</view>
</u-mask>
</template>
<script setup>
import { ref, computed } from 'vue';
import { useStore } from 'vuex';
import { quickWords } from '@/config/deliver';
const props = defineProps({
data: { type: Object, default: {} },
});
const emits = defineEmits(['hide', 'submit-end']);
const store = useStore();
const words = computed(() => quickWords[props.data.mode]); //
const projectId = computed(() => store.getters['project/projectId']);
const commit = ref(''); //
const score = ref(100); //
/**
* 提交评审信息
* 提交成功后隐藏modal 重置表单控件
* 给父组件信息 更新值
* @param {string} mode 'RESOLVE'|'REJECT'
*/
async function handleSubmit(mode) {
console.log('mode: ', mode);
try {
const deliverRecordId = props.data.deliverRecordId();
const param = {
projectId: projectId.value,
deliverRecordId,
type: mode === 'RESOLVE' ? 1 : 2,
remark: commit.value,
score: mode === 'RESOLVE' ? score.value : '',
};
await uni.$u.api.checkDeliver(param);
handleHide(); // +
uni.$ui.showToast('审核信息提交成功');
//
emits('submit-end', mode);
} catch (error) {
console.error('error: ', error);
uni.$ui.showToast('审核信息提交失败, 请稍后重试');
}
}
//
function handleHide() {
emits('hide');
//
score.value = 100;
commit.value = '';
}
</script>

204
plugins/p-deliver-check/p-deliver-check.vue

@ -1,142 +1,92 @@
<template>
<view class="bg-white rounded-md">
<view class="p-3 flex justify-between" @click="collapsed = !collapsed">
<span class="relative p-1">
<!-- <u-badge :is-dot="true" is-center></u-badge> -->
<view class="bg-white p-3 rounded-md">
<!-- 交付物名称 -->
<view class="flex justify-between" @click="collapsed = !collapsed">
<text>
{{ deliverData ? deliverData.deliverName : '' }}
</span>
</text>
<!-- 展开折叠按钮 -->
<u-icon :name="collapsed ? 'arrow-up' : 'arrow-down'"></u-icon>
</view>
<view class="p-3 pt-0" v-show="collapsed">
<view v-show="collapsed" class="mt-1">
<!-- 提交人和时间信息 -->
<view class="text-gray-400">
<!-- <span class="mr-2" v-if="deliverData && deliverData.submitter">{{ deliverData.submitter }}</span> -->
<span v-if="deliverData && deliverData.submitTime"> {{ dayjs(+deliverData.submitTime).format('MM-DD HH:mm') }}</span>
<view class="text-gray-400 text-xs">
<text class="mr-4" v-if="deliverData && deliverData.submitMemberName">{{ deliverData.submitMemberName }}</text>
<text v-if="deliverData && deliverData.submitTime"> {{ dayjs(+deliverData.submitTime).format('MM-DD HH:mm') }}</text>
</view>
<!-- 提交的链接信息 -->
<view class="w-64 break-all text-blue-400 py-2" v-if="deliverData && deliverData.details && deliverData.details[0]">
<view class="break-all text-blue-400 text-xs" v-if="deliverData && deliverData.details && deliverData.details[0]">
{{ deliverData.details[0] }}
</view>
<!-- 审核人信息 -->
<view class="text-gray-400 flex justify-between">
<span>审核</span>
<span class="text-blue-400" @click="moreRecords">更多记录</span>
<!-- 审核人 标题 -->
<view class="text-gray-400 flex justify-between mt-3">
<text>审核</text>
<text class="text-blue-400 text-sm" @click="moreRecords">更多记录</text>
</view>
<view class="px-2" v-if="deliverData && deliverData.checkerList">
<!-- 审核人 列表 -->
<view v-if="deliverData && deliverData.checkerList">
<!-- 遍历审核人信息 -->
<view class="mt-3 text-sm flex justify-between" v-for="item in deliverData.checkerList">
<view class="mt-2 text-sm flex justify-between" v-for="item in deliverData.checkerList">
<view>
<view>{{ item.checkerName }}</view>
<view class="my-1">{{ item.remark }}</view>
<view class="my-1" v-if="item.checkTime > 0">{{ dayjs(+item.checkTime).format('MM-DD HH:mm') }}</view>
<view class="font-semibold">{{ item.checkerName }}</view>
<view class="text-xs text-gray-400">{{ item.remark }}</view>
<view class="text-xs text-gray-400" v-if="+item.checkTime > 0">{{ dayjs(+item.checkTime).format('MM-DD HH:mm') }}</view>
</view>
<!-- 不是自己 -->
<view v-show="item.isMine !== 1">{{ item.status === null ? '待审核' : item.status === 1 ? '已通过' : '已驳回' }}</view>
<!-- 不是自己 显示审核状态 -->
<view v-show="item.isMine !== 1" class="text-xs">
<text v-if="item.status === 1" class="text-green-600"> 已通过 </text>
<text v-else-if="item.status === 2" class="text-red-600"> 已驳回 </text>
<text v-else class="text-gray-400"> 待审核 </text>
</view>
<!-- 是当前审核人 且未审核状态 -->
<!-- 自己是当前审核人 且未审核状态 -->
<view v-show="item.isMine === 1 && item.status === null">
<u-button size="mini" shape="circle" class="mr-4 h-1-4 leading-1-4" type="primary" @click="approvedModal = true">通过</u-button>
<u-button size="mini" shape="circle" class="h-1-4 leading-1-4" type="error" @click="rebutModal = true">驳回</u-button>
<u-button size="mini" shape="circle" class="mr-4 h-1-4 leading-1-4" type="primary" @click="checkModal.mode = 'RESOLVE'">
通过
</u-button>
<u-button size="mini" shape="circle" class="h-1-4 leading-1-4" type="error" @click="checkModal.mode = 'REJECT'">
驳回
</u-button>
</view>
<!-- 自己是审核人 且审核过 当前审核人的审核状态并展示得分情况 -->
<view v-show="item.isMine === 1 && item.status !== null" class="text-sm">
<view>
{{ item.status == '1' ? '已通过' : '已驳回' }}
</view>
<view v-if="item.score > 0">
<u-circle-progress active-color="#FA8C16" :percent="item.score" width="90" border-width="7" class="mt-2">
<view class="u-progress-content">
<view class="progress-dot text-white text-center">{{ item.score }}</view>
</view>
</u-circle-progress>
<view v-show="item.isMine === 1 && item.status !== null" class="text-xs">
<view class="mb-1">
<text v-if="item.status === 1" class="text-green-600"> 已通过 </text>
<text v-else-if="item.status === 2" class="text-red-600"> 已驳回 </text>
</view>
<zwp-ring-timing mode="chart" :value="item.score" active-color="#F59E0B" radius="30" bar-width="4" v-if="item.score !== null">
<text class="text-yellow-500 font-medium">{{ item.score }}</text>
</zwp-ring-timing>
</view>
</view>
</view>
</view>
<!-- 审核通过的modal -->
<u-mask :show="approvedModal" @click="approvedModal = false">
<view class="modal-content-wrap" @click.stop>
<!-- 通过modal的标题 -->
<view class="modal-content-head"> 审核通过 </view>
<view class="modal-content-body">
<!-- 评分 -->
<view class="flex justify-between mb-4">
<u-number-box v-model="score" size="30" input-width="50" :max="100" :min="0" :step="1"></u-number-box>
<view class="w-32 pt-4">
<u-slider v-model="score" active-color="#34D399" :max="100" :min="0" :step="1"></u-slider>
</view>
</view>
<textarea
class="border-solid border border-gray-300 rounded-md"
placeholder="请输入通过建议"
maxlength="30"
v-model="adviceRef"
></textarea>
<view class="common-list">
<view v-for="item in commonWords" class="leading-12" @click="adviceRef = item">
{{ item }}
</view>
</view>
</view>
<view class="modal-content-foot">
<view class="cancel" @click="approvedModal = false"> 取消 </view>
<view class="confirm" @click="confirmAdvice"> 确定 </view>
</view>
</view>
</u-mask>
<!-- 审批驳回的modal -->
<u-mask :show="rebutModal" @click="rebutModal = false">
<view class="modal-content-wrap" @click.stop>
<!-- 通过modal的标题 -->
<view class="modal-content-head"> 审核驳回 </view>
<view class="modal-content-body">
<textarea
class="border-solid border border-gray-300 rounded-md"
placeholder="请输入通过建议"
maxlength="30"
v-model="rebutRef"
></textarea>
<view class="common-list">
<view v-for="item in rebutWords" class="leading-12" @click="rebutRef = item">
{{ item }}
</view>
</view>
</view>
<view class="modal-content-foot">
<view class="cancel" @click="rebutModal = false"> 取消 </view>
<view class="confirm" @click="confirmReject"> 确定 </view>
</view>
</view>
</u-mask>
<checkFormModal :data="checkModal" @hide="checkModal.mode = 'HIDE'" @submit-end="handleUpdateCheckStatus" />
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { ref, computed, reactive } from 'vue';
import { useStore } from 'vuex';
import dayjs from 'dayjs';
import checkFormModal from './check-form-modal.vue';
const props = defineProps({ task: { type: Object, default: () => {} } });
const store = useStore();
const projectId = computed(() => store.getters['project/projectId']);
const collapsed = ref(false);
const deliverData = ref(null); //
const approvedModal = ref(false); // modal
const rebutModal = ref(false); // modal
const score = ref(100); //
const adviceRef = ref(''); //
const rebutRef = ref(''); //
const commonWords = ['加油,再接再厉!', '很棒!', '不错,很详细!', '加油,再接再厉']; //
const rebutWords = ['不详细', '还有需要改进的地方', '驳回审批1', '驳回审批2']; //
const checkModal = reactive({
mode: 'HIDE', // HIDE-> RESOLVE-> REJECT->
deliverRecordId: () => (deliverData.value ? deliverData.value.deliverRecordId : ''), // id
});
//
(async function getDeliverList() {
@ -148,51 +98,19 @@ const rebutWords = ['不详细', '还有需要改进的地方', '驳回审批1',
}
})();
//
function confirmAdvice() {
// TODO:
// console.log('')
try {
const deliverRecordId = deliverData.value.deliverRecordId;
const param = {
projectId: projectId.value,
deliverRecordId,
type: 1,
remark: adviceRef.value,
score: score.value,
};
console.log(param);
uni.$u.api.checkDeliver(param);
} catch (error) {
console.log('error: ', error);
}
approvedModal.value = false;
}
//
function confirmReject() {
// TODO:
try {
const { deliverRecordId } = store.state.deliver;
const param = {
projectId: projectId.value,
deliverRecordId,
type: 2,
remark: rebutRef.value,
score: '',
};
uni.$u.api.checkDeliver(param);
} catch (error) {
console.log('error: ', error);
}
rebutModal.value = false;
}
//
function moreRecords() {
const { deliverRecordId } = store.state.deliver;
uni.navigateTo({ url: `/pages/checkerList/checkerList?deliverRecordId=${deliverRecordId}` });
}
/**
*
* @param {string} mode RESOLVE|REJECT
*/
function handleUpdateCheckStatus(mode) {
const { checkerList } = deliverData.value;
const target = checkerList.find(item => item.isMine);
target.status = mode === 'RESOLVE' ? 1 : 2;
}
</script>
<style scoped lang="scss"></style>

Loading…
Cancel
Save