jiangping
2025-06-06 a2299a6d4a6f99e9c11132138f5d3e9ec68f03ea
admin/src/views/workorder/components/detail.vue
@@ -1,14 +1,17 @@
<template>
  <GlobalWindow width="900px" title="工单详情" :visible.sync="visible" :confirm-working="isWorking" @close="close"
    @confirm="confirm">
  <GlobalWindow width="100%" title="工单详情" :withFooter="withFooter" :visible.sync="visible" :confirm-working="isWorking"
    @confirm="confirm" @close="closeView">
    <div class="main">
      <div class="title">
        <span>工单详情</span>
        <div>
          <div class="status primaryColor" v-if="info.dealStatus == 0 || info.dealStatus == null">待指派</div>
          <div class="status" v-if="info.dealStatus == 1">已指派</div>
          <div class="status gray" v-if="info.dealStatus == 2">已处理</div>
        <div class="title_left">
          <span>工单详情</span>
          <div>
            <div class="status primaryColor" v-if="info.dealStatus == 0 || info.dealStatus == null">待指派</div>
            <div class="status green" v-if="info.dealStatus == 1">已指派</div>
            <div class="status gray" v-if="info.dealStatus == 2">已处理</div>
          </div>
        </div>
        <el-button v-if="info.origin === 1 && isShow" @click="openWT">查看问题上报</el-button>
      </div>
      <div class="main_content">
        <div class="list">
@@ -18,25 +21,30 @@
          </div>
          <div class="item">
            <div class="la">对应位置</div>
            <div class="val">{{ info.buildingName }} / {{ info.roomNum || info.floorName }}</div>
            <div class="val">{{ info.projectName }}/{{ info.buildingName }} / {{ info.roomNum || info.floorName }}</div>
          </div>
          <div class="item">
            <div class="la">工单类别</div>
            <div class="la">工单分类</div>
            <div class="val">{{ info.categoryName }}</div>
          </div>
          <div class="item">
            <div class="la">来源</div>
            <div class="val" v-if="info.origin === 0">自建</div>
            <div class="val" v-if="info.origin === 1">问题转工单</div>
          </div>
          <div class="item">
            <div class="la">上报人</div>
            <div class="val">{{ info.creatorName }}</div>
            <div class="val">{{ info.creatorName }}{{ info.creatorCompany ? "-" + info.creatorCompany : '' }}</div>
          </div>
          <div class="item">
            <div class="la">上报人电话</div>
            <div class="val">{{ info.creatorPhone }}</div>
            <div class="val">{{ info.creatorPhone || info.creatorMobile }}</div>
          </div>
          <div class="item">
            <div class="la">上报时间</div>
            <div class="val">{{ info.createDate }}</div>
          </div>
          <div class="item max">
          <div class="item max" v-if="info.areaType == 0">
            <div class="la">上门时间</div>
            <div class="val">{{ info.getDate }}</div>
          </div>
@@ -49,19 +57,29 @@
            <div class="value" v-if="info.fileList == null || !info.fileList.length">无</div>
            <div class="value" v-if="info.fileList != null && info.fileList.length">
              <div v-for="item in info.fileList" :key="item.id" style="display: inline;margin-right: 20px">
                <video v-if="item.fileurlFull && item.fileurlFull.endsWith('.mp4')" ref="videoRef" controls
                  preload="auto" style="width: 80px;height: 80px;object-fit: contain;" :src="item.fileurlFull" />
                <el-image v-else-if="item.fileurlFull" style="width:80px; height: 80px" :src="item.fileurlFull"
                <!-- <video v-if="item.fileurlFull && item.fileurlFull.endsWith('.mp4')" ref="videoRef" controls
                  preload="auto" style="width: 80px;height: 80px;object-fit: contain;" :src="item.fileurlFull" /> -->
                <el-image v-if="item.type == 0" style="width:80px; height: 80px" :src="item.fileurlFull"
                  :preview-src-list="[item.fileurlFull]">
                </el-image>
              </div>
            </div>
          </div>
          <div v-if="info.fileList && info.fileList.length > 0 && info.fileList.filter(i => i.type == 1).length > 0"
            class="item max">
            <div class="la">问题视频</div>
            <div class="value">
              <div v-for="item in info.fileList" :key="item.id" style="display: inline;margin-right: 20px">
                <video v-if="item.type == 1" ref="videoRef" controls preload="auto"
                  style="width: 240px;height: 160px;object-fit: contain;" :src="item.fileurlFull" />
              </div>
            </div>
          </div>
        </div>
        <div class="side">
          <div class="title">工单流转记录员</div>
          <div class="title">工单流转记录</div>
          <div class="flow_list">
            <div class="item" v-for="item,i in info.logList">
            <div class="item" v-for="item, i in info.logList">
              <div class="icon">
                <div class="dian"></div>
                <div v-if="i < info.logList.length - 1" class="line"></div>
@@ -70,12 +88,15 @@
                <div class="name">{{ item.title }}</div>
                <div class="time">操作时间:{{ item.createDate }}</div>
                <div class="creator">操作人:{{ item.param1 }}</div>
                <div class="creator" v-if="item.param2">指派给:{{ item.param2 }}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="title">工单处理</div>
      <div class="title"
        v-if="info.dealStatus == 2 || info.dealStatus == 0 || (info.dealStatus == 1 && info.dealUserId === userInfo.id)">
        {{ info.dealStatus == 0 || info.dealStatus == 1 ? '工单处理' : '处理结果' }}</div>
      <el-form :model="param" ref="form" :rules="rules">
        <template v-if="info.dealStatus == 0 || info.dealStatus == null">
          <el-form-item label="处理方式" prop="dealType">
@@ -98,13 +119,13 @@
            <el-date-picker type="datetime" class="w400" v-model="param.getDate" format="yyyy-MM-dd HH:mm"
              value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择"></el-date-picker>
          </el-form-item>
          <el-form-item label="回复内容" prop="dealInfo">
          <el-form-item label="处理说明" prop="dealInfo">
            <el-input type="textarea" class="w400" :rows="4" v-model="param.dealInfo" placeholder="请填写说明"></el-input>
          </el-form-item>
          <el-form-item label="现场图片">
            <div class="file_list">
              <el-upload class="avatar-uploader" :data="uploadData" multiple :limit="6" :auto-upload="true"
                :action="uploadImgUrl" :show-file-list="false" :on-success="uploadAvatarSuccess" :on-error="uploadError"
              <el-upload class="avatar-uploader" :data="uploadData" :auto-upload="true" :action="uploadImgUrl"
                :show-file-list="false" :on-success="uploadAvatarSuccess" :on-error="uploadError"
                :before-upload="beforeUpload">
                <div class="upload_wrap">
                  <i class="el-icon-plus avatar-uploader-icon"></i>
@@ -123,14 +144,18 @@
        <template v-if="info.dealStatus == 2">
          <div class="list">
            <div class="item item2">
              <div class="la">处理时间:</div>
              <div class="val">{{ info.getDate }}</div>
              <div class="la">{{ info.dispatchUserId ? '处理人' : '回复人' }}:</div>
              <div class="val">{{ info.dealUserName }}{{ info.dealUserCompany ? '-' + info.dealUserCompany : '' }}</div>
            </div>
            <div class="item item2">
              <div class="la">处理备注:</div>
              <div class="la">{{ info.dispatchUserId ? '处理时间' : '回复时间' }}:</div>
              <div class="val">{{ info.dealDate || info.getDate }}</div>
            </div>
            <div class="item item2">
              <div class="la">{{ info.dispatchUserId ? '处理说明' : '回复内容' }}:</div>
              <div class="val">{{ info.dealInfo }}</div>
            </div>
            <div class="item item2">
            <div v-if="info.dealFileList != null && info.dealFileList.length" class="item item2">
              <div class="la">现场照片:</div>
              <div class="value" v-if="info.dealFileList == null || !info.dealFileList.length">无</div>
              <div class="value" v-if="info.dealFileList != null && info.dealFileList.length">
@@ -146,6 +171,8 @@
          </div>
        </template>
      </el-form>
      <!--  问题上报详情  -->
      <ProblemReportingDetails ref="problem_Reporting_Details" @close="closeDetails" />
    </div>
  </GlobalWindow>
</template>
@@ -153,18 +180,24 @@
<script>
import GlobalWindow from '@/components/common/GlobalWindow'
import BaseOpera from '@/components/base/BaseOpera'
// import ProblemReportingDetails from './problemReportingDetails'
// import ProblemReportingDetails from '@/views/workorder/components/problemReportingDetails'
import { detailById, dispatchOrder, dealOrder } from '@/api/workorder/ywWorkorder'
import { getByWorkorderId } from '@/api/ywProblem'
import { getUserList } from '@/api/system/user'
import { Message, Loading } from 'element-ui'
import { mapState } from 'vuex'
import dayjs from 'dayjs'
export default {
  name: 'detail',
  components: {
    GlobalWindow
    GlobalWindow,
    ProblemReportingDetails: () => import('./problemReportingDetails')
  },
  extends: BaseOpera,
  data() {
    return {
      id: '',
      visible: false,
      param: {
        dealType: 0
      },
@@ -178,19 +211,51 @@
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/uploadBatch',
      dealFileList: [],
      uploadData: {
        folder: 'HIDDEN_DANGER_FILE'
        folder: 'YW_WORKORDER_FILE'
      },
      isShow: true,
      test: false
    }
  },
  computed: {
    userInfo() {
      return this.$store.state.userInfo
    },
    withFooter() {
      if (this.info) {
        return this.info.dealStatus === 0 || (this.info.dealStatus === 1 && (this.userInfo.id === this.info.dealUserId));
      } else {
        return false;
      }
    }
  },
  created() {
    this.getStaff()
  },
  methods: {
    closeDetails() {
      console.log('1')
      this.test = false
    },
    closeView() {
      this.$emit('close')
      this.visible = false
    },
    open (title, target, show) {
      this.title = title
      this.isShow = show
      this.id = target.workorderId
      this.getDetail()
    },
    openWT() {
      getByWorkorderId(this.id)
        .then(res => {
          this.test = true
          this.$nextTick(() => {
            this.$refs.problem_Reporting_Details.open('问题上报详情', res, false)
          })
        })
    },
    confirm() {
      this.$refs['form'].validate((valid) => {
        if (valid) {
@@ -217,6 +282,10 @@
      const { id } = this
      detailById(id).then(res => {
        this.info = res
        if (this.info.dealStatus == 1) {
          this.$set(this.param, 'getDate', dayjs().format('YYYY-MM-DD HH:mm:ss'))
        }
        this.visible = true
      })
    },
    getStaff() {
@@ -287,32 +356,41 @@
  padding-top: 20px;
  .title {
    font-weight: 500;
    font-size: 18px;
    color: $primary-color;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    .status {
      padding: 0 6px;
      height: 22px;
      line-height: 22px;
      border-radius: 2px;
      border: 1px solid #00BA92;
      color: #00BA92;
      font-weight: 400;
      font-size: 12px;
      margin-left: 10px;
    }
    .primaryColor {
      border: 1px solid $primary-color;
    }
    .gray {
      color: gray;
      border: 1px solid gray;
    justify-content: space-between;
    .title_left {
      display: flex;
      align-items: center;
      font-weight: 500;
      font-size: 18px;
      color: $primary-color;
      .status {
        padding: 0 12px;
        height: 24px;
        line-height: 24px;
        border-radius: 2px;
        border: 1px solid #00BA92;
        color: #00BA92;
        font-weight: 400;
        font-size: 12px;
        margin-left: 10px;
      }
      .primaryColor {
        border: 1px solid rgba(63, 126, 239, .2);
        background-color: rgba(63, 126, 239, .2);
      }
      .green {
        background-color: rgba(83, 183, 148, .2);
        border: 1px solid rgba(83, 183, 148, .2);
      }
      .gray {
        color: #333333;
        background-color: rgba(128, 128, 128, .2);
        border: 1px solid rgba(128, 128, 128, .2);
      }
    }
  }
@@ -326,11 +404,11 @@
    .item {
      width: 33.3%;
      margin-bottom: 12px;
      margin-bottom: 14px;
      .la {
        color: #7f7f7f;
        margin-top: 2px;
        margin-bottom: 6px;
      }
    }
@@ -338,44 +416,58 @@
      width: 100%;
      display: flex;
      align-items: center;
      .la {
        margin-bottom: 0;
        width: 72px;
      }
    }
    .max {
      width: 100%;
    }
  }
  .main_content{
  .main_content {
    display: flex;
    .side{
      width: 240px;
      .title{
    .side {
      width: 370px;
      .title {
        font-size: 14px;
      }
      .flow_list{
        .item{
      .flow_list {
        .item {
          display: flex;
          .icon{
          .icon {
            width: 28px;
            display: flex;
            flex-direction: column;
            align-items: center;
            .dian{
            .dian {
              width: 12px;
              height: 12px;
              border-radius: 50%;
              background-color: #e89e42;
            }
            .line{
            .line {
              width: 1px;
              height: 100%;
              background-color: #e89e42;
            }
          }
          .content{
          .content {
            font-size: 12px;
            color: #999999;
            padding-bottom: 12px;
            .name{
            .name {
              font-size: 13px;
              color: #333333;
            }