6 changed files with 380 additions and 145 deletions
@ -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> |
@ -1,2 +1,8 @@ |
|||||
// 上传文件的扩展名
|
// 上传文件的扩展名
|
||||
export const UPLOAD_EXTENSION = ['.xls', '.xlsx', '.zip', '.exe', '.pdf', '.doc', '.docx', '.ppt', '.pptx']; |
export const UPLOAD_EXTENSION = ['.xls', '.xlsx', '.zip', '.exe', '.pdf', '.doc', '.docx', '.ppt', '.pptx']; |
||||
|
|
||||
|
// 审核的快捷用语
|
||||
|
export const quickWords = { |
||||
|
RESOLVE: ['加油,再接再厉!', '很棒!', '不错,很详细!', '加油,再接再厉'], // 审核通过常用的审批语
|
||||
|
REJECT: ['不详细', '还有需要改进的地方', '驳回审批1', '驳回审批2'], // 审核驳回常用的审批语
|
||||
|
}; |
||||
|
@ -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> |
Loading…
Reference in new issue