forked from ccsens_fe/tall-mui-3
9 changed files with 594 additions and 31 deletions
@ -0,0 +1,87 @@ |
|||
<template> |
|||
<view class="my-3" v-if="allMembers && allMembers.length"> |
|||
<view class="flex justify-between"> |
|||
<view class="flex flex-wrap text-center items-center"> |
|||
<u-tag |
|||
:type="member.checked ? 'primary' : 'info'" |
|||
:mode="member.checked ? 'dark' : 'light'" |
|||
v-for="(member, index) in topMembers" |
|||
:key="member.memberId" |
|||
class="mb-2 mr-3" |
|||
style="width: 60px" |
|||
:text="member.name" |
|||
:closeable="false" |
|||
@click="tagClick(index, member, 'topMembers')" |
|||
/> |
|||
<span class="ml-2" v-if="!show" @click="show = true">...</span> |
|||
</view> |
|||
</view> |
|||
<!-- 折叠起来的 --> |
|||
<view class="flex flex-wrap text-center items-center" v-if="show"> |
|||
<u-tag |
|||
:type="member.checked ? 'primary' : 'info'" |
|||
:mode="member.checked ? 'dark' : 'light'" |
|||
v-for="(member, index) in bottomMembers" |
|||
:key="member.memberId" |
|||
class="mb-2 mr-3" |
|||
style="width: 60px" |
|||
:text="member.name" |
|||
:closeable="false" |
|||
@click="tagClick(index, member, 'bottomMembers')" |
|||
/> |
|||
<u-icon class="ml-2" name="arrow-up" v-if="show" size="26" @click="show = false"></u-icon> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapState } from 'vuex'; |
|||
|
|||
export default { |
|||
props: { |
|||
checkerList: { |
|||
default: () => [], |
|||
type: Array, |
|||
}, |
|||
}, |
|||
|
|||
data() { |
|||
return { allMembers: [], show: false, topMembers: [], bottomMembers: [] }; |
|||
}, |
|||
|
|||
computed: mapState('role', ['members']), |
|||
|
|||
mounted() { |
|||
if (this.members && this.members.length) { |
|||
this.allMembers = this.members; |
|||
// TODO: 等后台返回默认检查人后修改 |
|||
this.allMembers.forEach(item => { |
|||
item.checked = false; |
|||
}); |
|||
this.topMembers = this.members.slice(0, 3); |
|||
this.bottomMembers = this.members.slice(3); |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
tagClick(index, item, membersType) { |
|||
// 点击选择或取消选择 |
|||
const arr = this.$u.deepClone(this[membersType]); |
|||
arr[index].checked = !arr[index].checked; |
|||
this[membersType] = [...arr]; |
|||
// 将选中的id传给checkerList |
|||
this.$emit('setCheckerList', arr[index].checked, item); |
|||
}, |
|||
|
|||
// 清空所有选中的检查人 |
|||
clearChecked() { |
|||
for (let i = 0; i < this.topMembers.length; i++) { |
|||
this.topMembers[i].checked = false; |
|||
} |
|||
for (let i = 0; i < this.bottomMembers.length; i++) { |
|||
this.bottomMembers[i].checked = false; |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
@ -0,0 +1,149 @@ |
|||
<template> |
|||
<!-- 交付物 --> |
|||
<view class="mt-3"> |
|||
<view v-if="lists && lists.length"> |
|||
<view :key="list.id" v-for="list in lists"> |
|||
<view class="text-gray-400 u-font-12 font-thin leading-none"> |
|||
<span class="mr-2">{{ list.name }}</span> |
|||
<span>{{ $moment(+list.time).format('YYYY-MM-DD HH:mm:ss') }}</span> |
|||
</view> |
|||
<view class="mt-2 py-1 px-2.5 border border-gray-200 rounded flex flex-wrap overflow-hidden break-all" v-if="list.content"> |
|||
<a :href="list.content" class="text-blue-500 u-font-12 font-thin" target="_blank" v-if="CheckUrl(list.content)">{{ |
|||
list.content |
|||
}}</a> |
|||
<span v-else>{{ list.content }}</span> |
|||
</view> |
|||
<view :class="index === 0 ? 'mt-4' : 'mt-3'" v-for="(checker, index) in list.checkerList" :key="index"> |
|||
<view class="flex justify-between leading-none"> |
|||
<view> |
|||
{{ checker.checkerName }} |
|||
<span v-if="checker.isMine">(我)</span> |
|||
</view> |
|||
<view> |
|||
<span class="text-blue-500" v-if="checker.status === 1">通过</span> |
|||
<span class="text-red-500" v-if="checker.status === 2">驳回</span> |
|||
<span class="ml-4" v-if="checker.status !== 0">{{ checker.score }}分</span> |
|||
<span class="text-gray-400" v-if="checker.status === 0 && !checker.isMine">未审核</span> |
|||
<view v-if="checker.status === 0 && checker.isMine"> |
|||
<u-button class="action-btn mr-2" @click="showScore(checker.checkId, 1)" size="mini" shape="circle" type="primary"> |
|||
通过 |
|||
</u-button> |
|||
<u-button class="action-btn" @click="showScore(checker.checkId, 2)" size="mini" shape="circle" type="error">驳回</u-button> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="text-gray-400 text-xs mt-1">{{ checker.remark }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<u-empty icon-size="90" mode="history" text="暂未上传交付物" v-else></u-empty> |
|||
|
|||
<!-- 评分 --> |
|||
<uni-popup :maskClick="false" background-color="#fff" ref="popup" type="bottom"> |
|||
<PDeliverCheck @closeScore="closeScore" @submit="submit"></PDeliverCheck> |
|||
</uni-popup> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex'; |
|||
import UniPopup from '../../components/uni-popup/uni-popup.vue'; |
|||
import PDeliverCheck from '../p-deliver-check/p-deliver-check.vue'; |
|||
|
|||
export default { |
|||
name: 'p-delivery-history', |
|||
props: { task: { type: Object, default: null } }, |
|||
components: { PDeliverCheck, UniPopup }, |
|||
data() { |
|||
return { |
|||
lists: [], |
|||
show: false, |
|||
options: null, |
|||
loading: true, // 是否显示骨架屏组件 |
|||
}; |
|||
}, |
|||
|
|||
computed: mapGetters('project', ['projectId']), |
|||
|
|||
mounted() { |
|||
this.getDeliverOfTask(); |
|||
}, |
|||
|
|||
methods: { |
|||
async getDeliverOfTask() { |
|||
try { |
|||
const { projectId, task } = this; |
|||
const params = { projectId, taskSubId: task.id }; |
|||
const data = await this.$u.api.queryDeliverOfTask(params); |
|||
this.lists = data; |
|||
} catch (error) { |
|||
console.error('p-delivery-history.vue getDeliverOfTask error: ', error); |
|||
this.$t.ui.showToast(error.msg || '提交失败'); |
|||
} |
|||
}, |
|||
|
|||
showScore(checkId, status) { |
|||
// 通过组件定义的ref调用uni-popup方法 ,如果传入参数 ,type 属性将失效 ,仅支持 ['top','left','bottom','right','center'] |
|||
this.$refs.popup.open('bottom'); |
|||
this.options = { checkId, status }; |
|||
}, |
|||
|
|||
closeScore() { |
|||
this.$refs.popup.close('bottom'); |
|||
}, |
|||
|
|||
async submit(remark, score) { |
|||
try { |
|||
await this.checkDeliver(remark, score); |
|||
this.closeScore(); |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 检查交付物 |
|||
* @param {string} checkId 检查记录id |
|||
* @param {string} projectId 项目id |
|||
* @param {string} remark 评论 |
|||
* @param {number} score 分数 |
|||
* @param {number} status 检查状态(1-通过,2-驳回) |
|||
*/ |
|||
async checkDeliver(remark, score) { |
|||
try { |
|||
this.show = true; |
|||
const { projectId, options } = this; |
|||
const { checkId, status } = options; |
|||
const params = { checkId, projectId, status, remark, score }; |
|||
await this.$u.api.checkDeliver(params); |
|||
this.$t.ui.showToast('交付物检查成功'); |
|||
this.options = null; |
|||
this.getDeliverOfTask(); |
|||
} catch (error) { |
|||
console.error('p-delivery-history.vue checkDeliver error: ', error); |
|||
this.$t.ui.showToast('交付物检查失败,请稍后重试'); |
|||
this.options = null; |
|||
} |
|||
}, |
|||
|
|||
// 判断内容是不是链接 |
|||
CheckUrl(url) { |
|||
var reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(.)+$/; |
|||
if (!reg.test(url)) { |
|||
return false; |
|||
} else { |
|||
return true; |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.action-btn { |
|||
padding: 0; |
|||
width: 80rpx; |
|||
height: 40rpx; |
|||
line-height: 40rpx; |
|||
} |
|||
</style> |
@ -0,0 +1,280 @@ |
|||
<template> |
|||
<!-- 上传交付物 --> |
|||
<view class="pt-2 relative"> |
|||
<template v-if="history.length === 0"> |
|||
<u-input |
|||
:auto-height="autoHeight" |
|||
:border="border" |
|||
:height="height" |
|||
:type="type" |
|||
v-model="content" |
|||
placeholder="请输入链接/内容" |
|||
width="100" |
|||
/> |
|||
|
|||
<view class="to-examine mt-2"> |
|||
<view class="examine-title flex justify-between items-center"> |
|||
<view class="flex-shrink-0" style="color: #999">审核人</view> |
|||
<view class="flex items-center justify-end" style="color: #595959; width: calc(100% - 60px)"> |
|||
<text class="examine-people text-right mr-2">{{ examinePerpol }}</text> |
|||
<u-icon name="arrow-down" v-if="!isShowMembers" @click="showMembers"></u-icon> |
|||
<u-icon name="arrow-up" v-else @click="showMembers"></u-icon> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="examine-con" v-if="isShowMembers"> |
|||
<u-checkbox-group @change="checkboxGroupChange"> |
|||
<u-checkbox |
|||
@change="checkboxChange($event, item)" |
|||
v-model="item.checked" |
|||
v-for="(item, index) in list" |
|||
:key="index" |
|||
:name="item.name" |
|||
:data-id="item.id" |
|||
> |
|||
{{ item.name }} |
|||
</u-checkbox> |
|||
</u-checkbox-group> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<template v-else> |
|||
<template v-for="(item, index) in history"> |
|||
<view class="to-examine py-1 flex flex-wrap overflow-hidden break-all" :key="index" v-if="item.content"> |
|||
<a :href="item.content" class="text-blue-500 u-font-12 font-thin" target="_blank" v-if="CheckUrl(item.content)"> |
|||
{{ item.content }} |
|||
</a> |
|||
<span v-else>{{ item.content }}</span> |
|||
</view> |
|||
|
|||
<!-- <template v-if="showHistory"> --> |
|||
<view :class="index === 0 ? 'mt-4' : 'mt-3'" v-for="(checker, index) in item.checkerList" :key="index"> |
|||
<view class="flex justify-between"> |
|||
<view class="leading-none flex items-center"> |
|||
{{ checker.checkerName }} |
|||
<span class="leading-none" v-if="checker.isMine">(我)</span> |
|||
</view> |
|||
<view class="flex items-center"> |
|||
<span class="text-blue-500" v-if="checker.status === 1">通过</span> |
|||
<span class="text-red-500" v-if="checker.status === 2">驳回</span> |
|||
<span class="ml-4" v-if="checker.status !== 0">{{ checker.score }}分</span> |
|||
<span class="text-gray-400 leading-none" v-if="checker.status === 0 && !checker.isMine">未审核</span> |
|||
<view v-if="checker.status === 0 && checker.isMine"> |
|||
<u-button @click="showScore(checker.checkId, 2)" class="mr-3" plain size="mini" type="error">驳回</u-button> |
|||
<u-button @click="showScore(checker.checkId, 1)" plain size="mini" type="primary">通过</u-button> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="text-gray-400 text-xs mt-1">{{ checker.remark }}</view> |
|||
</view> |
|||
<!-- </template> --> |
|||
</template> |
|||
</template> |
|||
|
|||
<!-- 选择检查人 --> |
|||
<!-- <ChooseChecker ref="checker" :checkerList="checkerList" @setCheckerList="setCheckerList"></ChooseChecker> --> |
|||
|
|||
<view class="submit-delivery"> |
|||
<u-button @click="submit" size="mini" type="primary" v-if="currStatus === 0">提交</u-button> |
|||
<template v-if="currStatus === 1"> |
|||
<text class="mr-2">待审核</text> |
|||
<!-- <u-icon @click="changeShowHistory" name="arrow-right" v-if="!showHistory"></u-icon> |
|||
<u-icon @click="changeShowHistory" name="arrow-down" v-else></u-icon> --> |
|||
</template> |
|||
</view> |
|||
|
|||
<!-- <view class="mt-2 flex justify-between"> |
|||
<u-icon @click="changeShowHistory" name="arrow-up" v-if="showHistory"></u-icon> |
|||
<u-icon @click="changeShowHistory" name="arrow-down" v-else></u-icon> |
|||
</view> |
|||
|
|||
<p-delivery-history :task="task" v-if="showHistory" /> --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
// import ChooseChecker from '@/components/ChooseChecker/ChooseChecker.vue'; |
|||
import { mapState, mapGetters } from 'vuex'; |
|||
|
|||
export default { |
|||
name: 'p-upload-deliverable', |
|||
// components: { ChooseChecker }, |
|||
props: { task: { type: Object, default: null } }, |
|||
data() { |
|||
return { |
|||
content: '', |
|||
type: 'textarea', |
|||
border: true, |
|||
height: 40, |
|||
autoHeight: true, |
|||
checkerList: [], |
|||
// showHistory: false, // 展开历史记录 |
|||
list: [], |
|||
examinePerpol: '请选择审核人', |
|||
isShowMembers: false, // 是否显示成员列表 |
|||
currStatus: 0, // 当前状态 |
|||
history: [], |
|||
}; |
|||
}, |
|||
|
|||
computed: { |
|||
...mapState('role', ['members']), |
|||
...mapGetters('project', ['projectId']), |
|||
}, |
|||
|
|||
mounted() { |
|||
if (this.members.length > 0) { |
|||
this.list = []; |
|||
if (this.members.length) { |
|||
this.members.forEach(member => { |
|||
const item = { id: member.memberId, name: member.name, checked: false }; |
|||
this.list.push(item); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
this.getDeliverOfTask(); |
|||
}, |
|||
|
|||
methods: { |
|||
// 选中某个复选框时,由checkbox时触发 |
|||
checkboxChange(e, data) { |
|||
if (e.value) { |
|||
this.checkerList.push(data.id); |
|||
} else { |
|||
const index = this.checkerList.findIndex(checker => checker === data.id); |
|||
this.checkerList.splice(index, 1); |
|||
} |
|||
}, |
|||
|
|||
// 选中任一checkbox时,由checkbox-group触发 |
|||
checkboxGroupChange(e) { |
|||
this.examinePerpol = e.toString(); |
|||
}, |
|||
|
|||
// 是否展开成员面板 |
|||
showMembers() { |
|||
this.isShowMembers = !this.isShowMembers; |
|||
}, |
|||
|
|||
// 设置检查人 |
|||
// setCheckerList(checked, item) { |
|||
// if (checked) { |
|||
// this.checkerList.push(item.memberId); |
|||
// } else { |
|||
// const index = this.checkerList.findIndex(checker => checker === item.memberId); |
|||
// this.checkerList.splice(index, 1); |
|||
// } |
|||
// }, |
|||
|
|||
// 展开合上历史记录 |
|||
// changeShowHistory() { |
|||
// this.showHistory = !this.showHistory; |
|||
// }, |
|||
|
|||
// 提交交付物 |
|||
async submit() { |
|||
try { |
|||
const { content, checkerList, projectId, task } = this; |
|||
if (!this.checkerList.length) { |
|||
this.$t.ui.showToast('请选择检查人'); |
|||
return; |
|||
} |
|||
const params = { content, checkerList, projectId, taskSubId: task.id }; |
|||
await this.$u.api.saveDeliver(params); |
|||
this.$t.ui.showToast('交付物提交成功'); |
|||
this.currStatus = 1; |
|||
this.isShowMembers = false; |
|||
// this.content = ''; |
|||
// this.checkerList = []; |
|||
// this.$refs.checker.clearChecked(); |
|||
} catch (error) { |
|||
console.error('p-upload-deliverable.vue submit error: ', error); |
|||
this.$t.ui.showToast('交付物提交失败,请稍后重试'); |
|||
} |
|||
}, |
|||
|
|||
async getDeliverOfTask() { |
|||
try { |
|||
const { projectId, task } = this; |
|||
const params = { projectId, taskSubId: task.id }; |
|||
const data = await this.$u.api.queryDeliverOfTask(params); |
|||
console.log('1111111', data); |
|||
if (data.length > 0) { |
|||
data.forEach(item => { |
|||
item.checkerList.forEach(v => { |
|||
if (v.status === 0) { |
|||
this.currStatus = 1; |
|||
} |
|||
}); |
|||
}); |
|||
this.history = data; |
|||
} |
|||
} catch (error) { |
|||
console.error('p-delivery-history.vue getDeliverOfTask error: ', error); |
|||
this.$t.ui.showToast(error.msg || '提交失败'); |
|||
} |
|||
}, |
|||
|
|||
// 判断内容是不是链接 |
|||
CheckUrl(url) { |
|||
var reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(.)+$/; |
|||
if (!reg.test(url)) { |
|||
return false; |
|||
} else { |
|||
return true; |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped lang="scss"> |
|||
.to-examine { |
|||
padding-left: 20rpx; |
|||
padding-right: 20rpx; |
|||
border: 2rpx solid #dcdfe6; |
|||
border-radius: 8rpx; |
|||
|
|||
.examine-title { |
|||
height: 60rpx; |
|||
} |
|||
|
|||
.examine-people { |
|||
width: calc(100% - 22px); |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.examine-con { |
|||
margin: 10rpx 0 20rpx; |
|||
} |
|||
} |
|||
|
|||
::v-deep .u-checkbox__label { |
|||
font-size: 24rpx; |
|||
color: #999999; |
|||
} |
|||
|
|||
::v-deep .u-checkbox__icon-wrap { |
|||
width: 20rpx !important; |
|||
height: 20rpx !important; |
|||
border-radius: 50%; |
|||
} |
|||
|
|||
::v-deep .u-checkbox__label { |
|||
margin-left: 16rpx; |
|||
} |
|||
|
|||
::v-deep .u-icon__icon.uicon-checkbox-mark { |
|||
transform: scale(0.5); |
|||
} |
|||
|
|||
.submit-delivery { |
|||
position: absolute; |
|||
right: 0; |
|||
top: -25px; |
|||
} |
|||
</style> |
Loading…
Reference in new issue