RepairOrderView.vue 9.05 KB
<template>
  <div class="repair-container">
    <el-card shadow="never" class="search-card">
      <el-form :inline="true" :model="searchForm" size="small">
        <el-form-item label="工单状态">
          <el-select v-model="searchForm.status" placeholder="全部状态" clearable @change="handleSearch">
            <el-option label="待接单" value="PENDING" />
            <el-option label="维修中" value="REPAIRING" />
            <el-option label="已完成" value="COMPLETED" />
            <el-option label="已取消" value="CANCELLED" />
          </el-select>
        </el-form-item>
        <el-form-item label="维修人员">
          <el-select v-model="searchForm.repairerId" placeholder="全部" filterable clearable>
            <el-option v-for="user in engineerList" :key="user.user_id"
                       :label="user.name" :value="user.user_id" />
          </el-select>
        </el-form-item>
        <el-form-item label="时间范围">
          <el-date-picker v-model="dateRange" type="datetimerange"
                          range-separator="至" start-placeholder="开始" end-placeholder="结束"
                          format="yyyy-MM-dd HH:mm:ss" value-format="yyyy-MM-dd HH:mm:ss" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch" icon="el-icon-search">查询</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card shadow="never">
      <div slot="header"><span>工单列表(共 {{ pagination.total }} 条)</span></div>
      <el-table :data="tableData" border stripe size="small" v-loading="loading">
        <el-table-column prop="title" label="工单标题" min-width="180" />
        <el-table-column prop="submitter_name" label="提交人" width="100" />
        <el-table-column prop="repair_location" label="报修位置" min-width="180" />
        <el-table-column prop="repairer_name" label="维修人" width="100" />
        <el-table-column prop="status" label="状态" width="100">
          <template slot-scope="scope">
            <el-tag :type="statusTagType(scope.row.status)" size="small">
              {{ statusLabel(scope.row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="create_time" label="创建时间" width="180" />
        <el-table-column label="操作" width="180" fixed="right">
          <template slot-scope="scope">
            <el-button type="text" size="small" @click="showDetail(scope.row)">详情</el-button>
            <el-button v-if="scope.row.status === 'PENDING'"
                       type="text" size="small" @click="handleAssign(scope.row)">分配</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        style="margin-top: 16px; text-align: right;"
        @size-change="handleSizeChange" @current-change="handlePageChange"
        :current-page="pagination.page" :page-sizes="[10, 20, 50, 100]"
        :page-size="pagination.row" :total="pagination.total"
        layout="total, sizes, prev, pager, next, jumper" />
    </el-card>

    <!-- 工单详情对话框 -->
    <el-dialog title="工单详情" :visible.sync="detailVisible" width="600px">
      <el-descriptions :column="2" border size="small" v-if="currentOrder">
        <el-descriptions-item label="工单标题">{{ currentOrder.title }}</el-descriptions-item>
        <el-descriptions-item label="状态">
          <el-tag :type="statusTagType(currentOrder.status)" size="small">
            {{ statusLabel(currentOrder.status) }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="提交人">{{ currentOrder.submitter_name }}</el-descriptions-item>
        <el-descriptions-item label="维修人">{{ currentOrder.repairer_name || '未分配' }}</el-descriptions-item>
        <el-descriptions-item label="报修位置">{{ currentOrder.repair_location }}</el-descriptions-item>
        <el-descriptions-item label="坐标">{{ currentOrder.longitude }}, {{ currentOrder.latitude }}</el-descriptions-item>
        <el-descriptions-item label="问题描述" :span="2">{{ currentOrder.description }}</el-descriptions-item>
        <el-descriptions-item label="报修图片" :span="2">
          <template v-if="parseImages(currentOrder.images).length">
            <el-image v-for="(url, i) in parseImages(currentOrder.images)" :key="i"
                      :src="url" style="width: 80px; height: 80px; margin-right: 8px;"
                      :preview-src-list="parseImages(currentOrder.images)" fit="cover" />
          </template>
          <span v-else>无</span>
        </el-descriptions-item>
        <el-descriptions-item label="维修结果" :span="2">{{ currentOrder.repair_result || '暂无' }}</el-descriptions-item>
        <el-descriptions-item label="结果图片" :span="2">
          <template v-if="parseImages(currentOrder.result_images).length">
            <el-image v-for="(url, i) in parseImages(currentOrder.result_images)" :key="i"
                      :src="url" style="width: 80px; height: 80px; margin-right: 8px;"
                      :preview-src-list="parseImages(currentOrder.result_images)" fit="cover" />
          </template>
          <span v-else>无</span>
        </el-descriptions-item>
        <el-descriptions-item label="创建时间">{{ currentOrder.create_time }}</el-descriptions-item>
        <el-descriptions-item label="完成时间">{{ currentOrder.complete_time || '未完成' }}</el-descriptions-item>
      </el-descriptions>
    </el-dialog>

    <!-- 分配维修人员对话框 -->
    <el-dialog title="分配维修人员" :visible.sync="assignVisible" width="400px">
      <el-select v-model="assignForm.repairerId" placeholder="选择维修人员" style="width: 100%">
        <el-option v-for="user in engineerList" :key="user.user_id"
                   :label="user.name" :value="user.user_id" />
      </el-select>
      <span slot="footer">
        <el-button @click="assignVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmAssign">确认分配</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { queryRepairOrders, updateRepairStatus } from '@/api/property/propertyApi'
import { queryPropertyUsers } from '@/api/property/propertyApi'

export default {
  name: 'RepairOrderView',
  data() {
    return {
      searchForm: { status: '', repairerId: '' },
      dateRange: [],
      engineerList: [],
      tableData: [],
      loading: false,
      pagination: { page: 1, row: 20, total: 0 },
      detailVisible: false,
      currentOrder: null,
      assignVisible: false,
      assignForm: { orderId: '', repairerId: '' }
    }
  },
  mounted() { this.loadEngineers(); this.handleSearch() },
  methods: {
    statusLabel(s) {
      const map = { PENDING: '待接单', REPAIRING: '维修中', COMPLETED: '已完成', CANCELLED: '已取消' }
      return map[s] || s
    },
    statusTagType(s) {
      const map = { PENDING: 'warning', REPAIRING: 'primary', COMPLETED: 'success', CANCELLED: 'info' }
      return map[s] || 'info'
    },
    async loadEngineers() {
      try {
        const res = await queryPropertyUsers({ workType: 'ENGINEERING', page: 1, row: 200 })
        this.engineerList = res.data && res.data.data || []
      } catch (e) { console.error(e) }
    },
    async handleSearch() {
      this.loading = true
      try {
        const params = { page: this.pagination.page, row: this.pagination.row, ...this.searchForm }
        Object.keys(params).forEach(k => { if (!params[k]) delete params[k] })
        if (this.dateRange && this.dateRange.length === 2) {
          params.startTime = this.dateRange[0]
          params.endTime = this.dateRange[1]
        }
        const res = await queryRepairOrders(params)
        this.tableData = res.data && res.data.data || []
        this.pagination.total = res.data && res.data.total || 0
      } catch (e) {
        this.$message.error('查询失败')
      } finally { this.loading = false }
    },
    /** 解析JSON数组格式的图片URL */
    parseImages(images) {
      if (!images) return []
      try { return JSON.parse(images) } catch (e) { return [] }
    },
    showDetail(row) { this.currentOrder = row; this.detailVisible = true },
    handleAssign(row) {
      this.assignForm.orderId = row.id
      this.assignForm.repairerId = row.repairer_id || ''
      this.assignVisible = true
    },
    async confirmAssign() {
      if (!this.assignForm.repairerId) { this.$message.warning('请选择维修人员'); return }
      try {
        await updateRepairStatus({
          id: this.assignForm.orderId,
          status: 'REPAIRING',
          repairerId: this.assignForm.repairerId
        })
        this.$message.success('分配成功')
        this.assignVisible = false
        this.handleSearch()
      } catch (e) { this.$message.error('分配失败') }
    },
    handleSizeChange(val) { this.pagination.row = val; this.handleSearch() },
    handlePageChange(val) { this.pagination.page = val; this.handleSearch() }
  }
}
</script>

<style scoped>
.repair-container { padding: 16px; }
.search-card { margin-bottom: 16px; }
</style>