<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="IMEI" prop="imei">
        <el-input v-model="queryParams.imei" placeholder="IMEI" clearable @keyup.enter.native="handleQueryDevice" />
      </el-form-item>
      <el-form-item label="型号" prop="deviceType">
        <el-input v-model="queryParams.deviceType" placeholder="设备型号" clearable @keyup.enter.native="handleQueryDevice" />
      </el-form-item>
      <el-form-item label="设备SN" prop="deviceSn">
        <el-input-number
          v-model="queryParams.deviceSn"
          :controls="false"
          :min="0"
          placeholder="设备SN"
          style="width: 160px"
          @keyup.enter.native="handleQueryDevice"
        />
      </el-form-item>
      <el-form-item label="状态" prop="status">
        <el-select v-model="queryParams.status" placeholder="状态" clearable>
          <el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
        </el-select>
      </el-form-item>
      <el-form-item label="生产日期">
        <el-date-picker
          v-model="produceDateRange"
          style="width: 240px"
          value-format="yyyy-MM-dd"
          type="daterange"
          range-separator="-"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
        />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQueryDevice">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQueryDevice">重置</el-button>
      </el-form-item>
    </el-form>

    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAddDevice" v-hasPermi="['tsb:device:add']">新增</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="deviceSingle" @click="handleUpdateDevice()" v-hasPermi="['tsb:device:edit']">修改</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="deviceMultiple" @click="handleDeleteDevice" v-hasPermi="['tsb:device:remove']">删除</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button type="danger" plain icon="el-icon-warning-outline" size="mini" :disabled="deviceMultiple" @click="handleForceDeleteDevice" v-hasPermi="['tsb:device:remove']">强制删除</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="warning"
          plain
          icon="el-icon-download"
          size="mini"
          @click="handleExportDevice"
          v-hasPermi="['tsb:device:export']"
        >导出</el-button>
      </el-col>
      <right-toolbar :showSearch.sync="showSearch" @queryTable="getDeviceList"></right-toolbar>
    </el-row>

    <el-table v-loading="deviceLoading" :data="deviceList" @selection-change="handleDeviceSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="设备序号" align="center" prop="deviceId" width="80" />
      <el-table-column label="设备IMEI" align="center" prop="imei" width="150" show-overflow-tooltip />
      <el-table-column label="设备类型" align="center" prop="deviceType" show-overflow-tooltip />
      <el-table-column label="设备SN码" align="center" prop="deviceSn" />
      <el-table-column label="归属部门" align="center" prop="deptName" show-overflow-tooltip />
      <el-table-column label="生产日期" align="center" prop="deviceProduceDate" width="120">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.deviceProduceDate, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
      <el-table-column label="软件版本" align="center" prop="softwareVersion" width="100" />
      <el-table-column label="状态" align="center" prop="status" width="100">
        <template slot-scope="scope">
          <el-switch
            v-model="scope.row.status"
            active-value="0"
            inactive-value="1"
            @change="handleDeviceStatusChange(scope.row)"
          />
        </template>
      </el-table-column>
      <el-table-column label="最后在线时间" align="center" prop="lastRunTime" width="160">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.lastRunTime) }}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="340">
        <template slot-scope="scope">
          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdateDevice(scope.row)" v-hasPermi="['tsb:device:edit']">修改</el-button>
          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDeleteDevice(scope.row)" v-hasPermi="['tsb:device:remove']">删除</el-button>
          <el-button size="mini" type="text" icon="el-icon-warning-outline" @click="handleForceDeleteDevice(scope.row)" v-hasPermi="['tsb:device:remove']">强制删除</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-user"
            @click="openDeviceBindUser(scope.row)"
            v-hasPermi="['tsb:device:edit']"
          >设备绑定用户</el-button>
        </template>
      </el-table-column>
    </el-table>

    <pagination v-show="deviceTotal > 0" :total="deviceTotal" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getDeviceList" />

    <el-dialog :title="deviceTitle" :visible.sync="deviceOpen" width="560px" append-to-body>
      <el-form ref="deviceForm" :model="deviceForm" :rules="deviceRules" label-width="100px">
        <el-form-item label="IMEI" prop="imei">
          <el-input v-model="deviceForm.imei" placeholder="IMEI" maxlength="32" />
        </el-form-item>
        <el-form-item label="设备型号" prop="deviceType">
          <el-input v-model="deviceForm.deviceType" placeholder="设备型号" maxlength="32" />
        </el-form-item>
        <el-form-item label="设备SN" prop="deviceSn">
          <el-input-number v-model="deviceForm.deviceSn" :controls="false" placeholder="SN" style="width:100%" />
        </el-form-item>
        <el-form-item label="归属部门" prop="deptId">
          <treeselect v-model="deviceForm.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" />
        </el-form-item>
        <el-form-item label="生产日期" prop="deviceProduceDate">
          <el-date-picker
            v-model="deviceForm.deviceProduceDate"
            type="date"
            value-format="yyyy-MM-dd"
            placeholder="选择生产日期"
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item label="软件版本" prop="softwareVersion">
          <el-input v-model="deviceForm.softwareVersion" placeholder="软件版本" maxlength="32" />
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="deviceForm.status">
            <el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="deviceForm.remark" type="textarea" placeholder="备注" />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitDeviceForm">确 定</el-button>
        <el-button @click="deviceOpen = false">取 消</el-button>
      </div>
    </el-dialog>

    <el-dialog title="设备用户绑定" :visible.sync="deviceBindOpen" width="520px" append-to-body @open="onDeviceBindDialogOpen">
      <div v-if="bindScopeDevice" style="margin-bottom: 12px">
        <p><b>设备IMEI：</b>{{ bindScopeDevice.imei }}</p>
        <p><b>设备SN：</b>{{ bindScopeDevice.deviceSn }}</p>
      </div>
      <el-divider content-position="left">当前绑定</el-divider>
      <div v-if="currentDeviceBind" style="margin-bottom: 12px">
        <span>{{ currentDeviceBind.userName }}（{{ currentDeviceBind.nickName || '-' }}）</span>
        <span style="margin-left: 12px; color: #606266">
          绑定时间：{{ currentDeviceBind.bindTime ? parseTime(currentDeviceBind.bindTime) : '—' }}
        </span>
        <el-button
          type="text"
          icon="el-icon-close"
          style="margin-left: 8px"
          @click="handleUnbindCurrentUser"
          v-hasPermi="['tsb:device:edit']"
        >解绑</el-button>
      </div>
      <div v-else style="color: #909399; margin-bottom: 12px">暂无绑定用户</div>
      <el-divider content-position="left">绑定新用户</el-divider>
      <el-form label-width="100px">
        <el-form-item label="选择用户">
          <el-select
            v-model="bindSelectedUserId"
            placeholder="请选择未绑定设备的用户"
            filterable
            clearable
            style="width: 100%"
            :disabled="!!currentDeviceBind"
          >
            <el-option
              v-for="u in unboundUserOptions"
              :key="u.userId"
              :label="u.userName + (u.nickName ? '（' + u.nickName + '）' : '')"
              :value="u.userId"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitDeviceBind" v-hasPermi="['tsb:device:edit']" :disabled="!!currentDeviceBind">确 定绑定</el-button>
        <el-button @click="deviceBindOpen = false">关 闭</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import {
  listTsbDevice,
  getTsbDevice,
  addTsbDevice,
  updateTsbDevice,
  changeTsbDeviceStatus,
  delTsbDevice,
  forceDelTsbDevice,
  listTsbUnboundUsers,
  getTsbBindByDevice,
  bindTsbUserDevice,
  unbindTsbUserDevice
} from '@/api/tsb/device'
import { deptTreeSelect } from '@/api/system/user'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'

export default {
  name: 'TsbDevice',
  dicts: ['sys_normal_disable'],
  components: { Treeselect },
  data() {
    return {
      showSearch: true,
      deviceLoading: true,
      deviceList: [],
      deviceIds: [],
      deviceSingle: true,
      deviceMultiple: true,
      deviceTotal: 0,
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        imei: undefined,
        deviceType: undefined,
        deviceSn: undefined,
        status: undefined
      },
      produceDateRange: [],
      deviceOpen: false,
      deviceTitle: '',
      deviceForm: {},
      deptOptions: undefined,
      enabledDeptOptions: undefined,
      deviceRules: {
        deviceSn: [
          {
            required: true,
            validator: (rule, value, callback) => {
              if (value === null || value === undefined || value === '') {
                callback(new Error('设备SN不能为空'))
              } else {
                callback()
              }
            },
            trigger: ['blur', 'change']
          }
        ],
        imei: [
          { required: true, message: '设备IMEI不能为空', trigger: 'blur' },
          { max: 32, message: 'IMEI长度不能超过32个字符', trigger: 'blur' }
        ],
        deviceType: [
          { required: true, message: '设备型号不能为空', trigger: 'blur' },
          { max: 32, message: '设备型号长度不能超过32个字符', trigger: 'blur' }
        ],
        deptId: [{ required: true, message: '归属部门不能为空', trigger: 'change' }],
        deviceProduceDate: [{ required: true, message: '生产日期不能为空', trigger: 'change' }],
        status: [{ required: true, message: '状态不能为空', trigger: 'change' }]
      },
      deviceBindOpen: false,
      bindScopeDevice: null,
      currentDeviceBind: null,
      unboundUserOptions: [],
      bindSelectedUserId: undefined
    }
  },
  created() {
    this.getDeviceList()
    this.getDeptTree()
  },
  methods: {
    getDeptTree() {
      deptTreeSelect().then(response => {
        this.deptOptions = response.data
        this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
      })
    },
    filterDisabledDept(deptList) {
      return deptList.filter(dept => {
        if (dept.disabled) {
          return false
        }
        if (dept.children && dept.children.length) {
          dept.children = this.filterDisabledDept(dept.children)
        }
        return true
      })
    },
    getDeviceList() {
      this.deviceLoading = true
      listTsbDevice(this.addDateRange(this.queryParams, this.produceDateRange, 'ProduceDate')).then(response => {
        this.deviceList = response.rows
        this.deviceTotal = response.total
        this.deviceLoading = false
      })
    },
    handleQueryDevice() {
      this.queryParams.pageNum = 1
      this.getDeviceList()
    },
    resetQueryDevice() {
      this.produceDateRange = []
      this.resetForm('queryForm')
      this.handleQueryDevice()
    },
    /** 导出设备列表（与当前查询条件、生产日期区间一致） */
    handleExportDevice() {
      this.download(
        'tsb/device/export',
        this.addDateRange({ ...this.queryParams }, this.produceDateRange, 'ProduceDate'),
        `tsb_device_${new Date().getTime()}.xlsx`
      )
    },
    handleDeviceSelectionChange(selection) {
      this.deviceIds = selection.map(item => item.deviceId)
      this.deviceSingle = selection.length !== 1
      this.deviceMultiple = !selection.length
    },
    handleAddDevice() {
      this.resetDeviceForm()
      this.deviceOpen = true
      this.deviceTitle = '新增设备'
    },
    handleUpdateDevice(row) {
      const deviceId = row && row.deviceId ? row.deviceId : this.deviceIds[0]
      this.resetDeviceForm()
      getTsbDevice(deviceId).then(response => {
        this.deviceForm = response.data
        this.deviceOpen = true
        this.deviceTitle = '修改设备'
      })
    },
    submitDeviceForm() {
      this.$refs['deviceForm'].validate(valid => {
        if (!valid) return
        if (this.deviceForm.deviceId != null) {
          updateTsbDevice(this.deviceForm).then(() => {
            this.$modal.msgSuccess('修改成功')
            this.deviceOpen = false
            this.getDeviceList()
          })
        } else {
          addTsbDevice(this.deviceForm).then(() => {
            this.$modal.msgSuccess('新增成功')
            this.deviceOpen = false
            this.getDeviceList()
          })
        }
      })
    },
    /** 删除确认文案：以设备 SN 为准，无 SN 时用设备 ID */
    deviceSnDeleteLabel(row) {
      if (row && row.deviceId != null) {
        if (row.deviceSn != null && row.deviceSn !== '') {
          return String(row.deviceSn)
        }
        return 'ID:' + row.deviceId
      }
      if (!this.deviceIds || this.deviceIds.length === 0) {
        return ''
      }
      return this.deviceIds.map(id => {
        const d = this.deviceList.find(x => x.deviceId === id)
        if (d && d.deviceSn != null && d.deviceSn !== '') {
          return String(d.deviceSn)
        }
        return 'ID:' + id
      }).join('、')
    },
    extractErrorMessage(err) {
      if (typeof err === 'string') {
        return err
      }
      if (err && err.message) {
        return err.message
      }
      return ''
    },
    /** 普通 remove 因绑定失败时的后端提示 */
    isBindUserBlockDeleteError(msg) {
      return typeof msg === 'string' && msg.indexOf('已绑定用户') !== -1 && msg.indexOf('请先解绑') !== -1
    },
    handleDeleteDevice(row) {
      const ids = row && row.deviceId ? row.deviceId : this.deviceIds
      const snLabel = this.deviceSnDeleteLabel(row)
      this.$modal.confirm('是否确认删除设备SN为"' + snLabel + '"的数据项？').then(() => {
        return delTsbDevice(ids)
      }).then(() => {
        this.getDeviceList()
        this.$modal.msgSuccess('删除成功')
      }).catch(err => {
        const msg = this.extractErrorMessage(err)
        if (this.isBindUserBlockDeleteError(msg)) {
          this.$modal.confirm('该设备已绑定用户。是否改为强制删除（将自动解除绑定并删除设备）？').then(() => {
            return forceDelTsbDevice(ids)
          }).then(() => {
            this.getDeviceList()
            this.$modal.msgSuccess('强制删除成功')
          }).catch(() => {})
        }
      })
    },
    handleForceDeleteDevice(row) {
      const ids = row && row.deviceId ? row.deviceId : this.deviceIds
      const snLabel = this.deviceSnDeleteLabel(row)
      this.$modal.confirm(
        '强制删除将解除这些设备与用户的绑定关系，并删除设备。是否确认强制删除设备SN为"' + snLabel + '"？'
      ).then(() => {
        return forceDelTsbDevice(ids)
      }).then(() => {
        this.getDeviceList()
        this.$modal.msgSuccess('强制删除成功')
      }).catch(() => {})
    },
    handleDeviceStatusChange(row) {
      const text = row.status === '0' ? '启用' : '停用'
      const snLabel = this.deviceSnDeleteLabel(row)
      this.$modal.confirm('确认要"' + text + '""' + snLabel + '"设备吗？').then(() => {
        return changeTsbDeviceStatus(row.deviceId, row.status)
      }).then(() => {
        this.$modal.msgSuccess(text + '成功')
      }).catch(() => {
        row.status = row.status === '0' ? '1' : '0'
      })
    },
    resetDeviceForm() {
      this.deviceForm = {
        deviceId: undefined,
        imei: undefined,
        deviceType: undefined,
        deviceSn: undefined,
        deptId: undefined,
        deviceProduceDate: undefined,
        softwareVersion: undefined,
        status: '0',
        remark: undefined
      }
      this.resetForm('deviceForm')
    },
    openDeviceBindUser(row) {
      this.bindScopeDevice = row
      this.bindSelectedUserId = undefined
      this.currentDeviceBind = null
      this.unboundUserOptions = []
      this.deviceBindOpen = true
    },
    onDeviceBindDialogOpen() {
      this.refreshDeviceBindDialog()
    },
    refreshDeviceBindDialog() {
      if (!this.bindScopeDevice) {
        return
      }
      const deviceId = this.bindScopeDevice.deviceId
      Promise.all([
        getTsbBindByDevice(deviceId),
        listTsbUnboundUsers()
      ]).then(([bindRes, usersRes]) => {
        this.currentDeviceBind = bindRes.data || null
        this.unboundUserOptions = usersRes.data || []
      })
    },
    submitDeviceBind() {
      if (!this.bindScopeDevice) {
        return
      }
      if (this.currentDeviceBind) {
        this.$modal.msgWarning('请先解绑当前用户后再绑定')
        return
      }
      if (this.bindSelectedUserId == null) {
        this.$modal.msgWarning('请选择用户')
        return
      }
      bindTsbUserDevice(
        this.bindSelectedUserId,
        this.bindScopeDevice.deviceId
      ).then(() => {
        this.$modal.msgSuccess('绑定成功')
        this.bindSelectedUserId = undefined
        this.refreshDeviceBindDialog()
      })
    },
    handleUnbindCurrentUser() {
      if (!this.currentDeviceBind) {
        return
      }
      this.$modal.confirm('是否确认解绑该用户与当前设备？').then(() => {
        return unbindTsbUserDevice(
          this.currentDeviceBind.userId,
          this.bindScopeDevice.deviceId
        )
      }).then(() => {
        this.$modal.msgSuccess('解绑成功')
        this.refreshDeviceBindDialog()
      }).catch(() => {})
    }
  }
}
</script>
