digital-agriculture-app/pages/farm/detail/taskManageDetail.vue
2025-04-16 02:11:26 +01:00

651 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="task">
<u-alert class="margin-bottom-20" type = "warning" description = "此页面数据项设置之后自动更新" :show-icon="true" :closable="true"></u-alert>
<view class="baseInfo">
<!-- 任务基本信息 -->
<view class="title">
<text class="taskName">{{baseInfo.taskName}}</text>
<u-tag @click="showPicker1=true" plain color="#fff" :text="baseInfo.status | transformStatusToText(typeList)" size="mini" :bgColor="baseInfo.status | transformTagColor()" :borderColor="baseInfo.status | transformTagColor()" ></u-tag>
</view>
<view class="content">
<u-row class="item">
<u-col span="6">
<view class="item">地块名称{{baseInfo.landName?baseInfo.landName:"--"}}</view>
</u-col>
<u-col span="6">
<view class="item">批次名称{{baseInfo.batchName}}</view>
</u-col>
</u-row>
<u-row class="item">
<u-col span="6">
<view class="item">开始时间{{baseInfo.planStart}}</view>
</u-col>
<u-col span="6">
<view class="item">结束时间{{baseInfo.planFinish}}</view>
</u-col>
</u-row>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 任务状态 -->
<view class="taskStatus" @click="showPicker1=true">
<view class="label">
<u-icon name="hourglass-half-fill" size="20" color="#2b7"></u-icon>
<text>任务状态</text>
</view>
<view class="status">
<text>{{baseInfo.status | transformStatusToText(typeList)}}</text>
<u-icon name="arrow-right"></u-icon>
</view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 任务实际实际时间-->
<view class="actualTime" >
<view class="label">
<u-icon name="calendar-fill" size="20" color="#2b7"></u-icon>
<text>任务实际开始结束时间</text>
</view>
<view class="content">
<u-tag plain color="#2b7" borderColor="#2b7" @click="showDate1=true" :text="`开始时间:${baseInfo.actualStart?baseInfo.actualStart:'未设置'}`"></u-tag>
<u-tag plain color="#2b7" borderColor="#2b7" @click="showDate2=true" :text="`结束时间:${baseInfo.actualFinish?baseInfo.actualFinish:'未设置'}`"></u-tag>
</view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 责任人 -->
<view class="header" @click="showPicker2=true">
<view class="label">
<u-icon name="account-fill" size="20" color="#2b7"></u-icon>
<text>责任人</text>
</view>
<view class="name">
<u-avatar class="avatar" :text="baseInfo.taskHead | transformHeadFirstName(employeeList)" size="24" fontSize="12" bgColor="#2b7"></u-avatar>
<u-icon name="arrow-right"></u-icon>
</view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 任务内容 -->
<view class="taskdetail">
<view class="label">
<u-icon name="file-text-fill" size="20" color="#2b7"></u-icon>
<text>任务内容</text>
</view>
<u-textarea class="margin-top-20" v-model="baseInfo.remark" placeholder="请输入内容" @blur="changeBaseInfo" height="200rpx"></u-textarea>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 参与人 -->
<view class="participants" @click="selectEmployee">
<view class="label">
<u-icon name="plus-people-fill" size="20" color="#2b7"></u-icon>
<text>参与人</text>
</view>
<view class="member">
<scroll-view :scroll-x="true" style="display: flex;">
<view class="memberList">
<u-avatar class="avatar" bgColor="#2b7" size="24" fontSize="12" v-for="(item,index) in taskEmployeeList"
:key="index" :text="item.employeeName.slice(0,1)"></u-avatar>
</view>
</scroll-view>
<u-icon name="arrow-right" ></u-icon>
</view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 人工工时 -->
<view class="workHours" @click="jump('employeeWorkHours')">
<view class="label">
<u-icon name="man-add-fill" size="25" color="#2b7"></u-icon>
<text>人工工时</text>
<text class="margin-left-20 font-weight-bold">{{workHour}}小时</text>
</view>
<view class="content">工时详情<u-icon name="arrow-right" class="margin-left-20"></u-icon></view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 机械工时 -->
<view class="workHours" @click="jump('machineWorkHours')">
<view class="label">
<u-icon name="car-fill" size="25" color="#2b7"></u-icon>
<text>机械工时</text>
<text class="margin-left-20 font-weight-bold">{{machineryHour}}小时</text>
</view>
<view class="content">工时详情<u-icon name="arrow-right" class="margin-left-20"></u-icon></view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 农资用量 -->
<view class="consume" @click="jump('materialUsedCount')">
<view class="label">
<view class="flex">
<u-icon name="bag-fill" size="20" color="#2b7"></u-icon>
<text>农资用量</text>
</view>
<u-icon name="arrow-right" class="margin-left-20"></u-icon>
</view>
<view class="content">
<!-- 微信小程序,开发工具图表会显示最上层,但是真机没有问题,无需在意 -->
<qiun-data-charts :canvas2d="true" canvasId="BleFwOHudClAKDffjpTSNNSnIWLnNHPM" type="column" :opts="opts" :chartData="chartData" :tooltipShow="false" :ontouch="true"/>
</view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 图片 -->
<view class="image">
<view class="label">
<u-icon name="camera-fill" size="20" color="#2b7"></u-icon>
<text>图片</text>
</view>
<view class="content">
<image-upload v-model="baseInfo.taskImages" :maxSize="2"></image-upload>
</view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 视频 -->
<view class="video">
<view class="label">
<u-icon name="play-right-fill" size="20" color="#2b7"></u-icon>
<text>视频</text>
</view>
<view class="content">
<video-upload v-model="baseInfo.taskVideos" :maxCount="2" :maxSize="5"></video-upload>
</view>
</view>
<u-gap height="10" bgColor="#eee"></u-gap>
<!-- 日志 -->
<view class="log">
<view class="label" @click="logVisiable=!logVisiable">
<view class="flex">
<u-icon name="info-circle-fill" size="20" color="#2b7"></u-icon>
<text>任务日志</text>
</view>
<u-icon :name="!logVisiable?'arrow-down':'arrow-up'"></u-icon>
</view>
<view class="content" v-if="logVisiable">
<view v-for="item in logList" :key="item.operId">
<text style="color: #2b7">{{item.createTime}}</text> <text style="color: #ffba00;">{{item.operName}}</text>{{item.operDes}}
</view>
</view>
</view>
</view>
<!-- 兼容ios微信浏览器的margin-bottom无效的情况 -->
<view class="height-30"></view>
<!-- 任务状态和负责人选择控件 -->
<u-picker :show="showPicker1" :columns="[typeList]" keyName='dictLabel' @confirm="confirmPicker($event,1)" @cancel="showPicker1=false"></u-picker>
<u-picker :show="showPicker2" :columns="[employeeList]" keyName='employeeName' @confirm="confirmPicker($event,2)" @cancel="showPicker2=false"></u-picker>
<!-- 时间选择控件 -->
<u-datetime-picker :show="showDate1" @cancel="showDate1=false" v-model="todayDate" mode="date" @confirm="confirmDatePicker($event,1)"></u-datetime-picker>
<u-datetime-picker :show="showDate2" @cancel="showDate2=false" v-model="todayDate" mode="date" @confirm="confirmDatePicker($event,2)"></u-datetime-picker>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
export default {
data() {
return {
//任务ID
taskId:null,
//任务信息
baseInfo:{},
//任务状态列表
typeList:[],
//参与任务雇员列表
taskEmployeeList:[],
//雇员列表
employeeList:[],
showPicker1:false,
showPicker2:false,
showDate1:false,
showDate2:false,
//设置日期选择控件定位到当天
todayDate: Number(new Date()),
//是否监听图片的第一次值的变化
isWatchPicChanges:false,
//是否监听视频的第一次值的变化
isWatchVideoChanges:false,
//任务日志列表
logList:[],
//人工工时统计
workHour:0,
//机械工时统计
machineryHour:0,
//农资统计图标数据
chartData: {},
//图标配置数据项
opts: {
color: ["#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
padding: [15,15,0,5],
touchMoveLimit: 24,
enableScroll: true,
legend: {
show:false
},
xAxis: {
disableGrid: true,
scrollShow: true,
itemCount: 4,
},
yAxis: {},
extra: {
column: {
type: "group",
width: 10,
activeBgColor: "#000000",
activeBgOpacity: 0.08,
linearType: "custom",
barBorderCircle: true,
}
}
},
//控制日志的折叠参数
logVisiable:false
}
},
onLoad(option) {
this.taskId = option?.taskId;
this.getData();
},
async onPullDownRefresh() {
//this.getData()等所有的promise resolve了之后才resolve
await this.getData();
uni.stopPullDownRefresh();
},
onShow() {
this.getData();
},
watch:{
//监听上传图片触发保存
"baseInfo.taskImages":{
handler(val){
if(this.isWatchPicChanges){
this.changeBaseInfo("taskImages",val)
}
this.isWatchPicChanges=true
}
},
//监听上传视频触发保存
"baseInfo.taskVideos":{
handler(val){
if(this.isWatchVideoChanges){
this.changeBaseInfo("taskVideos",val)
}
this.isWatchVideoChanges=true
}
}
},
filters:{
//将任务状态值翻译成名称
transformStatusToText(val,typeList){
let name="--"
typeList.forEach((item,index)=>{
if(item.dictValue==val){
name = item.dictLabel
}
})
return name
},
//将任务状态值翻译成任务Tag的颜色
transformTagColor(val){
let color = ""
if(val==0){
color="#dadada"
}else if(val==1){
color="#fc842d"
}else if(val==2){
color="#ead900"
}else if(val==3){
color="#2b7"
}else{
color="#636363"
}
return color;
},
//将任务负责人ID翻译成姓
transformHeadFirstName(val,employeeList){
let firstName=""
employeeList.forEach((item,index)=>{
if(item.employeeId==val){
firstName = item.employeeName
}
})
firstName=firstName[0]
return firstName
}
},
methods:{
//统一调用查询数据接口
getData(){
Promise.all([
//获取任务详情
this.getTask(),
//查询参与任务的雇员
this.getTaskEmployeeList(),
//查询任务日志
this.getTaskLogList(),
//统计人工工时
this.getCostEmployeeListToCountHours(),
//统计机械工时
this.getCostMachineListToCountHours(),
//农资用量
this.loadMaterialMap(),
//获取字典
this.getDic(),
//查询雇员列表
this.getEmployeeList()
])
},
//根据任务ID查询任务详情
async getTask(){
const {data} = await uni.$u.http.get("/agriculture/batchTask/"+this.taskId)
this.baseInfo = data;
},
//根据任务ID查看任务雇员
async getTaskEmployeeList(){
const {rows} = await uni.$u.http.get('/agriculture/taskEmployee/list?taskId='+this.taskId);
this.taskEmployeeList=rows
},
//根据任务ID查询任务日志
async getTaskLogList(){
const {rows} = await uni.$u.http.get('/agriculture/log/list?taskId='+this.taskId)
this.logList=rows;
},
//根据任务ID加载农资用量图标
async loadMaterialMap(){
const {data} = await uni.$u.http.get('/agriculture/costMaterial/selectMaterialGroupByMaterialName/'+this.taskId);
let chartData = {
categories: data.map(item=>item.materialName),
series: [
{
name: "农资用量",
data: data.map(item=>item.num)
}
]
};
this.chartData = JSON.parse(JSON.stringify(chartData));
},
//根据任务ID查询人工工时列表然后统计总工时
async getCostEmployeeListToCountHours(){
const {rows} = await uni.$u.http.get('/agriculture/costEmployee/list?taskId='+this.taskId)
//先清空
this.workHour=0;
rows.forEach(item=>{
this.workHour+=item.workingHours;
})
},
//根据任务ID查询机械工时列表然后统计总工时
async getCostMachineListToCountHours(){
const {rows} = await uni.$u.http.get('/agriculture/costMachine/list?taskId='+this.taskId)
//先清空
this.machineryHour=0;
rows.forEach(item=>{
this.machineryHour+=item.workingHours
})
},
//获取字典
async getDic(){
const {data} = await uni.$u.http.get('/system/dict/data/type/agriculture_batch_task_status')
this.typeList=data
},
//查询雇员列表
async getEmployeeList(){
const {rows} = await uni.$u.http.get('/agriculture/employee/list')
this.employeeList=rows;
},
//保存任务修改数据
changeBaseInfo(key,value){
let query={
...this.baseInfo
}
if(key&&value){
query[key]=value
}
uni.$u.http.put('/agriculture/batchTask',query).then(res=>{
this.baseInfo[key]=value
this.$refs.uToast.show({
type: 'success',
message: "修改成功",
duration:'500'
})
})
},
//状态选择和责任人选择控件的确认事件
confirmPicker(data,type){
if(type==1){
this.changeBaseInfo('status',data.value[0].dictValue)
this.showPicker1=false
}else if(type==2){
this.changeBaseInfo('taskHead',data.value[0].employeeId)
this.showPicker2=false
}
},
//日期选择控件确认事件
confirmDatePicker(data,type){
if(type==1){
this.changeBaseInfo('actualStart',uni.$u.timeFormat(data.value, 'yyyy-mm-dd'))
this.showDate1=false
}else if(type==2){
this.changeBaseInfo('actualFinish',uni.$u.timeFormat(data.value, 'yyyy-mm-dd'))
this.showDate2=false
}
},
//处理参与人员选择
selectEmployee(){
uni.$u.route({
url: 'pages/farm/detail/employee',
params: {
taskId: this.baseInfo.taskId
}
})
},
//页面跳转
jump(pageName){
console.log(this.taskId)
uni.$u.route({
url: 'pages/farm/detail/'+pageName,
params: {
taskId:this.taskId
}
})
}
}
}
</script>
<style lang="scss">
.task{
// padding:0 10rpx;
background-color: #eee;
.baseInfo{
background: #fff;
.title{
box-sizing: border-box;
display: flex;
padding:0 20rpx;
height:80rpx;
display: flex;
align-items: center;
justify-content: space-between;
.taskName{
font-size: 40rpx;
font-weight: bold;
}
}
.content{
box-sizing: border-box;
.item{
font-size: 25rpx;
padding:10rpx;
}
}
.taskdetail{
padding: 20rpx;
box-sizing: border-box;
.label{
display: flex;
}
}
.taskStatus{
padding: 20rpx;
box-sizing: border-box;
height: 120rpx;
display: flex;
justify-content: space-between;
align-items: center;
.label{
display: flex;
width: 30%;
}
.status{
max-width: 70%;
display: flex;
text{
margin-right: 20rpx;
font-color:#eee;
font-size:25rpx;
}
}
}
.actualTime{
padding: 20rpx 20rpx 0;
box-sizing: border-box;
.label{
display: flex;
}
.content{
display: flex;
padding:20rpx 0;
justify-content: space-between;
view{
flex:0 0 auto;//不放大也不缩写
}
}
}
.header{
padding: 20rpx;
box-sizing: border-box;
height: 120rpx;
display: flex;
justify-content: space-between;
align-items: center;
.label{
display: flex;
width: 30%;
}
.name{
max-width: 70%;
display: flex;
.avatar{
margin-right: 20rpx;
}
}
}
.participants{
padding: 20rpx;
box-sizing: border-box;
height: 120rpx;
display: flex;
justify-content: space-between;
align-items: center;
.label{
width: 30%;
display: flex;
}
.member{
max-width: 70%;
display: flex;
.memberList{
display: flex;
.avatar{
margin-right: 20rpx;
}
}
}
}
.workHours{
padding: 20rpx;
box-sizing: border-box;
height: 120rpx;
display: flex;
justify-content: space-between;
align-items: center;
.label{
width: 50%;
display: flex;
}
.content{
display:flex;
font-size: 25rpx;
}
}
.consume{
width: 100%;
box-sizing: border-box;
.label{
padding:20rpx;
display: flex;
justify-content: space-between;
}
.content{
height: 300rpx;
box-sizing: border-box;
padding:0 20rpx 20rpx;
}
}
.image{
width: 100%;
box-sizing: border-box;
.label{
padding:20rpx;
display:flex;
}
.content{
box-sizing: border-box;
padding:0 20rpx 0rpx;
}
}
.video{
width: 100%;
box-sizing: border-box;
.label{
padding:20rpx;
display: flex;
}
.content{
box-sizing: border-box;
padding:0 20rpx 20rpx;
}
}
.log{
width: 100%;
box-sizing: border-box;
.label{
padding:20rpx;
display: flex;
justify-content: space-between;
}
.content{
box-sizing: border-box;
padding:0 20rpx 20rpx;
font-size:24rpx;
view{
line-height: 40rpx;
}
}
}
}
}
</style>