<script lang="ts" setup>
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
import { useUserStore } from '@/store/modules/user'
import * as DeptApi from '@/api/system/dept'
import { IotMaintenancePlanApi } from '@/api/pms/maintenance'
import { dayjs, FormInstance, FormRules } from 'element-plus'
import { IotMaintenanceBomApi } from '@/api/pms/iotmaintenancebom'
import { useTableComponents } from '@/components/ZmTable/useTableComponents'
import { DeviceList, List, Plan, Query } from './types'
import { IotDeviceApi } from '@/api/pms/device'
import MaintenancePlanForm from './maintenance-plan-form.vue'
import maintenanceDeviceList from './maintenance-device-list.vue'
import { useTagsViewStore } from '@/store/modules/tagsView'

const route = useRoute()
const router = useRouter()
const { delView } = useTagsViewStore()
const message = useMessage()
const { t } = useI18n()

const mode = computed(() => {
  if (route.name === 'IotMaintenancePlanDetail') return 'detail'
  if (route.name === 'IotMainPlanEdit') return 'edit'
  return 'create'
})

const isReadonly = computed(() => mode.value === 'detail')

const id = computed(() => route.params.id as string | undefined)

const initQuery = (): Query => ({
  deviceIds: undefined,
  planId: undefined,
  bomFlag: 'b'
})

const queryParams = ref<Query>(initQuery())

const initPlan = (): Plan => ({
  name: '',
  remark: '',
  responsiblePerson: '',
  serialNumber: ''
})

const list = ref<List[]>([])

const { ZmTable, ZmTableColumn } = useTableComponents<List>()

const loading = ref(false)
const panelLoading = ref(false)
const saving = ref(false)
const plan = ref<Plan>(initPlan())
const deviceIds = ref<Set<number>>(new Set())
const originalRowMap = ref(new Map<string, List>())
const attrs = ref(
  new Map<string, { timeAccumulatedAttrs: any[]; mileageAccumulatedAttrs: any[] }>()
)
const planRef = ref<FormInstance>()
const planRules = reactive<FormRules>({
  name: [{ required: true, message: '计划名称不能为空', trigger: ['blur', 'change'] }]
})

const getRowKey = (row: Pick<List, 'deviceId' | 'bomNodeId'>) => `${row.deviceId}-${row.bomNodeId}`

const cloneRow = (row: List): List => ({
  ...row
})

const refreshOriginalRows = () => {
  const currentKeys = new Set(list.value.map(getRowKey))

  list.value.forEach((row) => {
    const key = getRowKey(row)
    originalRowMap.value.set(key, cloneRow(row))
  })

  Array.from(originalRowMap.value.keys()).forEach((key) => {
    if (!currentKeys.has(key)) {
      originalRowMap.value.delete(key)
    }
  })
}

const resetAttrs = (rows: List[]) => {
  attrs.value.clear()
  rows.forEach((row: any) => {
    attrs.value.set(getRowKey(row), {
      timeAccumulatedAttrs: row.timeAccumulatedAttrs || [],
      mileageAccumulatedAttrs: row.mileageAccumulatedAttrs || []
    })
  })
}

const syncListMeta = () => {
  deviceIds.value = new Set(list.value.map((item) => item.deviceId))
  sortList()
}

const resetPageRows = (rows: List[]) => {
  list.value = rows
  resetAttrs(rows)
  refreshOriginalRows()
  syncListMeta()
}

const initPage = async () => {
  panelLoading.value = true

  plan.value = initPlan()
  queryParams.value = initQuery()

  try {
    if (mode.value === 'create') {
      const deptId = useUserStore().getUser.deptId
      const dept = await DeptApi.getDept(deptId)
      plan.value.name = `${dept?.name || ''} - 保养计划`
      plan.value.deptId = deptId

      const { wsCache } = useCache()
      const userInfo = wsCache.get(CACHE_KEY.USER)
      plan.value.responsiblePerson = userInfo.user.id
    } else if (id.value) {
      const res = await IotMaintenancePlanApi.getIotMaintenancePlan(Number(id.value))
      plan.value = res

      queryParams.value.planId = Number(id.value)
      const data = await IotMaintenanceBomApi.getMainPlanBOMs(queryParams.value)
      resetPageRows(data || [])
    }
  } finally {
    panelLoading.value = false
  }
}

const sortList = () => {
  list.value = list.value.sort((a, b) => {
    const aCode = a.deviceCode || ''
    const bCode = b.deviceCode || ''
    const aName = a.name || ''
    const bName = b.name || ''

    if (aCode !== bCode) {
      return aCode.localeCompare(bCode)
    }

    return aName.localeCompare(bName)
  })
}

watch(
  () => route.fullPath,
  () => {
    initPage()
  },
  { immediate: true }
)

watch(
  () => list.value.length,
  () => {
    syncListMeta()
  }
)

const runningTimeVisible = computed(() => list.value.some((item) => item.runningTimeRule === 0))
const mileageVisible = computed(() => list.value.some((item) => item.mileageRule === 0))
const naturalDateVisible = computed(() => list.value.some((item) => item.naturalDateRule === 0))

const EMPTY_TEXT = '——'
type DisplayValue = number | string

const isPositiveNumber = (value: unknown): value is number => typeof value === 'number' && value > 0

const toFixedNumber = (value: number, fractionDigits = 2) =>
  parseFloat(value.toFixed(fractionDigits))

const emptyFormatter = (row: List, keys: (keyof List)[], isTime: boolean = false) => {
  const data = [...keys].reverse().find((key) => row[key] !== null && row[key] !== undefined)
  const value = data ? row[data] : EMPTY_TEXT

  return value !== EMPTY_TEXT && isTime ? dayjs(value as number).format('YYYY-MM-DD') : value
}

const positiveField = (row: List, key: keyof List) => {
  const value = row[key]
  return isPositiveNumber(value) ? value : null
}

const positiveDisplayValue = (row: List, keys: (keyof List)[]) => {
  const value = emptyFormatter(row, keys)
  return isPositiveNumber(value) ? value : null
}

const ruleValue = (
  rule: List['runningTimeRule'],
  values: Array<number | null>,
  calculator: (...values: number[]) => DisplayValue
) => {
  const numericValues = values.filter(isPositiveNumber)
  return rule === 0 && numericValues.length === values.length
    ? calculator(...numericValues)
    : EMPTY_TEXT
}

const nextMaintenanceH = (row: List) =>
  ruleValue(
    row.runningTimeRule,
    [positiveField(row, 'lastRunningTime'), positiveField(row, 'nextRunningTime')],
    (last, next) => last + next
  )

const remainH = (row: List) =>
  ruleValue(
    row.runningTimeRule,
    [
      positiveField(row, 'lastRunningTime'),
      positiveField(row, 'nextRunningTime'),
      positiveDisplayValue(row, ['totalRunTime', 'tempTotalRunTime'])
    ],
    (last, next, current) => toFixedNumber(next - (current - last))
  )

const nextMaintenanceKm = (row: List) =>
  ruleValue(
    row.mileageRule,
    [positiveField(row, 'lastRunningKilometers'), positiveField(row, 'nextRunningKilometers')],
    (last, next) => last + next
  )

const remainKm = (row: List) =>
  ruleValue(
    row.mileageRule,
    [
      positiveField(row, 'lastRunningKilometers'),
      positiveField(row, 'nextRunningKilometers'),
      positiveDisplayValue(row, ['totalMileage', 'tempTotalMileage'])
    ],
    (last, next, current) => toFixedNumber(next - (current - last))
  )

const nextNaturalDateValue = (row: List) => {
  if (row.naturalDateRule !== 0 || !row.lastNaturalDate || !row.nextNaturalDate) return null
  return dayjs(row.lastNaturalDate).add(row.nextNaturalDate, 'day')
}

const nextMaintenanceDate = (row: List) =>
  nextNaturalDateValue(row)?.format('YYYY-MM-DD') ?? EMPTY_TEXT

const remainDay = (row: List) =>
  isPositiveNumber(row.nextNaturalDate)
    ? (nextNaturalDateValue(row)?.diff(dayjs(), 'day') ?? EMPTY_TEXT)
    : EMPTY_TEXT

const hasEnabledRule = (row: List) =>
  row.runningTimeRule === 0 || row.mileageRule === 0 || row.naturalDateRule === 0

const requiresTimeAccumulatedAttr = (row: List) => {
  const rowAttrs = attrs.value.get(getRowKey(row))
  return (
    row.runningTimeRule === 0 &&
    (rowAttrs?.timeAccumulatedAttrs.length ?? 0) > 0 &&
    (row.totalRunTime == null || isNaN(row.totalRunTime))
  )
}

const requiresMileageAccumulatedAttr = (row: List) => {
  const rowAttrs = attrs.value.get(getRowKey(row))
  return (
    row.mileageRule === 0 &&
    (rowAttrs?.mileageAccumulatedAttrs.length ?? 0) > 0 &&
    (row.totalMileage == null || isNaN(row.totalMileage))
  )
}

const checkRowFilled = (row: List) => {
  if (!hasEnabledRule(row)) return false

  const runningTimeFilled =
    row.runningTimeRule !== 0 ||
    (isPositiveNumber(row.lastRunningTime) &&
      isPositiveNumber(row.nextRunningTime) &&
      isPositiveNumber(row.timePeriodLead) &&
      (!requiresTimeAccumulatedAttr(row) || !!row.code))

  const mileageFilled =
    row.mileageRule !== 0 ||
    (isPositiveNumber(row.lastRunningKilometers) &&
      isPositiveNumber(row.nextRunningKilometers) &&
      isPositiveNumber(row.kiloCycleLead) &&
      (!requiresMileageAccumulatedAttr(row) || !!row.type))

  const naturalDateFilled =
    row.naturalDateRule !== 0 ||
    (!!row.lastNaturalDate &&
      isPositiveNumber(row.nextNaturalDate) &&
      isPositiveNumber(row.naturalDatePeriodLead))

  return runningTimeFilled && mileageFilled && naturalDateFilled
}

const remainValueMap = {
  remainH,
  remainKmometers: remainKm,
  remainDay
}
type RemainColumnProp = keyof typeof remainValueMap

const isNegativeValue = (value: DisplayValue) => typeof value === 'number' && value < 0

const isRemainColumnProp = (property?: string): property is RemainColumnProp =>
  !!property && property in remainValueMap

const cellClassName = ({
  row,
  column
}: {
  row: List
  column: { type?: string; property?: string }
}) => {
  if (column.type === 'index' && checkRowFilled(row)) return 'all-filled'

  const getRemainValue = isRemainColumnProp(column.property)
    ? remainValueMap[column.property]
    : undefined
  return getRemainValue && isNegativeValue(getRemainValue(row)) ? 'negative-remain-value' : ''
}

const getRowDisplayName = (row: List) => `${row.deviceCode || '-'}-${row.name || '-'}`

const validateTableData = () => {
  if (list.value.length === 0) {
    message.error('请至少添加一条设备保养明细')
    return false
  }

  for (const [index, row] of list.value.entries()) {
    const rowNumber = index + 1
    const rowName = getRowDisplayName(row)

    if (!hasEnabledRule(row)) {
      message.error(`第 ${rowNumber} 行（${rowName}）：保养项至少设置1个保养规则`)
      return false
    }

    if (row.runningTimeRule === 0) {
      if (
        !isPositiveNumber(row.lastRunningTime) ||
        !isPositiveNumber(row.nextRunningTime) ||
        !isPositiveNumber(row.timePeriodLead)
      ) {
        message.error(`第 ${rowNumber} 行（${rowName}）：请完整配置运行时长规则`)
        return false
      }

      if (requiresTimeAccumulatedAttr(row) && !row.code) {
        message.error(`第 ${rowNumber} 行（${rowName}）：请选择累计运行时长参数`)
        return false
      }
    }

    if (row.mileageRule === 0) {
      if (
        !isPositiveNumber(row.lastRunningKilometers) ||
        !isPositiveNumber(row.nextRunningKilometers) ||
        !isPositiveNumber(row.kiloCycleLead)
      ) {
        message.error(`第 ${rowNumber} 行（${rowName}）：请完整配置运行里程规则`)
        return false
      }

      if (requiresMileageAccumulatedAttr(row) && !row.type) {
        message.error(`第 ${rowNumber} 行（${rowName}）：请选择累计运行公里数参数`)
        return false
      }
    }

    if (
      row.naturalDateRule === 0 &&
      (!row.lastNaturalDate ||
        !isPositiveNumber(row.nextNaturalDate) ||
        !isPositiveNumber(row.naturalDatePeriodLead))
    ) {
      message.error(`第 ${rowNumber} 行（${rowName}）：请完整配置自然日期规则`)
      return false
    }
  }

  return true
}

const close = () => {
  delView(unref(router.currentRoute))
  router.push({ name: 'IotMaintenancePlan', params: {} })
}

const savePlan = async () => {
  if (isReadonly.value) return
  if (!planRef.value) return

  try {
    await planRef.value.validate()
  } catch {
    return
  }

  if (!validateTableData()) return

  saving.value = true
  try {
    const data = {
      mainPlan: plan.value,
      mainPlanBom: list.value
    }

    if (mode.value === 'create') {
      await IotMaintenancePlanApi.createIotMaintenancePlan(data)
      message.success(t('common.createSuccess'))
    } else {
      await IotMaintenancePlanApi.updatePlan(data)
      message.success(t('common.updateSuccess'))
    }

    close()
  } finally {
    saving.value = false
  }
}

type RuleType = 'runningTime' | 'mileage' | 'naturalDate'
type RuleField =
  | 'tempTotalRunTime'
  | 'lastRunningTime'
  | 'nextRunningTime'
  | 'timePeriodLead'
  | 'tempTotalMileage'
  | 'lastRunningKilometers'
  | 'nextRunningKilometers'
  | 'kiloCycleLead'
  | 'lastNaturalDate'
  | 'nextNaturalDate'
  | 'naturalDatePeriodLead'
  | 'code'
  | 'type'

const ruleFieldMap: Record<RuleType, RuleField[]> = {
  runningTime: ['lastRunningTime', 'nextRunningTime', 'timePeriodLead', 'code', 'tempTotalRunTime'],
  mileage: [
    'lastRunningKilometers',
    'nextRunningKilometers',
    'kiloCycleLead',
    'type',
    'tempTotalMileage'
  ],
  naturalDate: ['lastNaturalDate', 'nextNaturalDate', 'naturalDatePeriodLead']
}

const clearRuleFields = (row: List, fields: RuleField[]) => {
  fields.forEach((field) => {
    row[field] = null
  })
}

const restoreRuleFields = (row: List, fields: RuleField[]) => {
  const originalRow = originalRowMap.value.get(getRowKey(row))
  if (!originalRow) return

  fields.forEach((field) => {
    row[field] = originalRow[field] as any
  })
}

const handleRuleChange = (row: List, ruleType: RuleType, value: unknown) => {
  const fields = ruleFieldMap[ruleType]

  if (value === 1) {
    clearRuleFields(row, fields)
    return
  }

  restoreRuleFields(row, fields)
}

const deviceList = ref()

const onDeviceSelect = () => {
  if (isReadonly.value) return
  deviceList.value.open()
}

const deviceChoose = async (rows: DeviceList[]) => {
  const selectIds = rows.map((item) => item.id)
  const params = {
    deviceIds: selectIds.join(','),
    bomFlag: 'b'
  }
  try {
    const res = await IotDeviceApi.deviceAssociateBomList(params)

    if (res.length === 0) {
      message.error('选择的设备不存在待保养BOM项')
    }

    if (!Array.isArray(res)) return

    const existingKeys = new Set(list.value.map((item) => `${item.deviceId}-${item.bomNodeId}`))

    const items = res
      .filter((item) => !existingKeys.has(`${item.id}-${item.bomNodeId}`))
      .map<List>((item) => {
        const row: List = {
          deviceId: item.id,
          bomNodeId: item.bomNodeId,
          deviceCode: item.deviceCode,
          deviceName: item.deviceName,
          name: item.name,
          runningTimeRule: 1,
          mileageRule: 1,
          naturalDateRule: 1,
          totalRunTime: item.totalRunTime,
          tempTotalRunTime: null,
          totalMileage: item.totalMileage,
          tempTotalMileage: null,
          lastMaintenanceDate: null,
          lastRunningTime: null,
          nextRunningTime: null,
          lastRunningKilometers: null,
          nextRunningKilometers: null,
          lastNaturalDate: null,
          nextNaturalDate: null,
          kiloCycleLead: null,
          timePeriodLead: null,
          naturalDatePeriodLead: null,
          code: null,
          type: null
        }

        attrs.value.set(getRowKey(row), {
          timeAccumulatedAttrs: item.timeAccumulatedAttrs || [],
          mileageAccumulatedAttrs: item.mileageAccumulatedAttrs || []
        })

        return row
      })

    list.value.push(...items)
    refreshOriginalRows()
    syncListMeta()
  } catch (error) {
    message.error('获取设备关联保养BOM项失败')
  }
}

const handleDelete = (str: string) => {
  list.value = list.value.filter((item) => `${item.deviceId}-${item.bomNodeId}` !== str)
}

const planForm = ref()

const editPlan = (row: List) => {
  if (row.runningTimeRule !== 0 && row.mileageRule !== 0 && row.naturalDateRule !== 0) {
    message.error('请先设置保养规则')
    return
  }

  const rowAttrs = attrs.value.get(getRowKey(row))
  planForm.value?.open({
    row,
    readonly: isReadonly.value,
    timeAccumulatedAttrs: rowAttrs?.timeAccumulatedAttrs || [],
    mileageAccumulatedAttrs: rowAttrs?.mileageAccumulatedAttrs || []
  })
}
</script>

<template>
  <div
    v-loading="panelLoading"
    class="flex flex-col gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]">
    <section class="panel">
      <div class="plan-info-accent"></div>
      <el-form
        :model="plan"
        size="default"
        :rules="planRules"
        label-width="88px"
        class="plan-info-form"
        ref="planRef">
        <el-row :gutter="24">
          <el-col :xs="24" :md="13">
            <el-form-item :label="t('main.planName')" prop="name">
              <el-input v-model="plan.name" :disabled="isReadonly" clearable />
            </el-form-item>
          </el-col>
          <el-col :xs="24" :md="11">
            <el-form-item :label="t('main.planCode')" prop="serialNumber">
              <el-input v-model="plan.serialNumber" disabled />
            </el-form-item>
          </el-col>
          <el-col :span="24" class="mt-2">
            <el-form-item :label="t('iotMaintain.remark')" prop="remark">
              <el-input
                v-model="plan.remark"
                type="textarea"
                :rows="3"
                :placeholder="t('iotMaintain.remarkHolder')"
                :disabled="isReadonly"
                resize="none"
                show-word-limit
                maxlength="300" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </section>
    <section class="panel content-panel flex-1!">
      <div v-if="!isReadonly" class="operation">
        <el-button size="default" type="success" @click="onDeviceSelect">
          <Icon icon="ep:plus" class="mr-5px" />{{ t('operationFill.add') }}
        </el-button>
      </div>
      <div class="table">
        <el-auto-resizer class="absolute">
          <template #default="{ width, height }">
            <ZmTable
              :data="list"
              :loading="loading"
              :width="width"
              :height="height"
              :highlight-current-row="false"
              :cell-class-name="cellClassName">
              <ZmTableColumn
                type="index"
                :label="t('iotDevice.serial')"
                fixed="left"
                hide-in-column-settings />
              <ZmTableColumn
                :min-width="120"
                prop="deviceCode"
                :label="t('iotMaintain.deviceCode')" />
              <ZmTableColumn
                :min-width="240"
                prop="deviceName"
                :label="t('iotMaintain.deviceName')" />
              <ZmTableColumn :min-width="240" prop="name" :label="t('bomList.bomNode')" />
              <ZmTableColumn prop="runningTimeRule" width="66" :label="t('main.runTime')">
                <template #default="{ row }">
                  <el-switch
                    v-model="row.runningTimeRule"
                    :active-value="0"
                    :inactive-value="1"
                    :disabled="isReadonly"
                    @change="(value) => handleRuleChange(row, 'runningTime', value)" />
                </template>
              </ZmTableColumn>
              <ZmTableColumn prop="mileageRule" width="66" :label="t('main.mileage')">
                <template #default="{ row }">
                  <el-switch
                    v-model="row.mileageRule"
                    :active-value="0"
                    :inactive-value="1"
                    :disabled="isReadonly"
                    @change="(value) => handleRuleChange(row, 'mileage', value)" />
                </template>
              </ZmTableColumn>
              <ZmTableColumn prop="naturalDateRule" width="66" :label="t('main.date')">
                <template #default="{ row }">
                  <el-switch
                    v-model="row.naturalDateRule"
                    :active-value="0"
                    :inactive-value="1"
                    :disabled="isReadonly"
                    @change="(value) => handleRuleChange(row, 'naturalDate', value)" />
                </template>
              </ZmTableColumn>
              <ZmTableColumn
                prop="totalRunTime"
                :label="t('operationFillForm.sumTime')"
                width="108"
                :real-value="(row) => emptyFormatter(row, ['totalRunTime', 'tempTotalRunTime'])"
                cover-formatter />
              <ZmTableColumn
                prop="totalMileage"
                :label="t('operationFillForm.sumKil')"
                width="128"
                :real-value="(row) => emptyFormatter(row, ['totalMileage', 'tempTotalMileage'])"
                cover-formatter />
              <ZmTableColumn
                prop="lastMaintenanceDate"
                :label="t('mainPlan.lastMaintenanceDate')"
                width="90"
                :real-value="(row) => emptyFormatter(row, ['lastMaintenanceDate'], true)"
                cover-formatter />

              <ZmTableColumn
                :visible="runningTimeVisible"
                column-key="time-group"
                label="保养时长"
                is-parent>
                <ZmTableColumn
                  prop="lastRunningTime"
                  :label="t('mainPlan.lastMaintenanceOperationTime')"
                  :real-value="(row) => emptyFormatter(row, ['lastRunningTime'])"
                  cover-formatter />
                <ZmTableColumn
                  prop="nextMaintenanceH"
                  :label="t('mainPlan.nextMaintenanceH')"
                  :real-value="nextMaintenanceH"
                  cover-formatter />
                <ZmTableColumn
                  prop="remainH"
                  :label="t('mainPlan.remainH')"
                  :real-value="remainH"
                  cover-formatter />
              </ZmTableColumn>
              <ZmTableColumn
                :visible="mileageVisible"
                column-key="mileage-group"
                label="保养里程"
                is-parent>
                <ZmTableColumn
                  prop="lastRunningKilometers"
                  :label="t('mainPlan.lastMaintenanceMileage')"
                  :real-value="(row) => emptyFormatter(row, ['lastRunningKilometers'])"
                  cover-formatter />
                <ZmTableColumn
                  prop="nextRunningKilometers"
                  :label="t('mainPlan.nextMaintenanceKm')"
                  :real-value="nextMaintenanceKm"
                  cover-formatter />
                <ZmTableColumn
                  prop="remainKmometers"
                  :label="t('mainPlan.remainKm')"
                  :real-value="remainKm"
                  cover-formatter />
              </ZmTableColumn>
              <ZmTableColumn
                :visible="naturalDateVisible"
                column-key="date-group"
                label="保养日期"
                is-parent>
                <ZmTableColumn
                  prop="lastNaturalDate"
                  :label="t('mainPlan.lastMaintenanceNaturalDate')"
                  :real-value="(row) => emptyFormatter(row, ['lastNaturalDate'], true)"
                  cover-formatter />
                <ZmTableColumn
                  prop="nextMaintenanceDate"
                  :label="t('mainPlan.nextMaintDate')"
                  :real-value="nextMaintenanceDate"
                  cover-formatter />
                <ZmTableColumn
                  prop="remainDay"
                  :label="t('mainPlan.remainDay')"
                  :real-value="remainDay"
                  cover-formatter />
              </ZmTableColumn>
              <ZmTableColumn
                column-key="operation"
                :label="t('operationFill.operation')"
                :width="140"
                fixed="right">
                <template #default="{ row }">
                  <el-button size="default" link type="primary" @click="editPlan(row)">
                    <div class="i-lucide:edit-3 mr-1 translate-y-1px"></div>
                    {{ isReadonly ? t('form.set') : t('modelTemplate.update') }}
                  </el-button>
                  <el-button
                    size="default"
                    v-if="!isReadonly"
                    link
                    type="danger"
                    @click="handleDelete(`${row.deviceId}-${row.bomNodeId}`)">
                    <div class="i-lucide:x mr-1 translate-y-1px"></div>
                    {{ t('modelTemplate.delete') }}
                  </el-button>
                </template>
              </ZmTableColumn>
            </ZmTable>
          </template>
        </el-auto-resizer>
      </div>
    </section>
    <section class="panel footer-panel">
      <el-button @click="close">{{ t('iotMaintain.cancel') }}</el-button>
      <el-button v-if="!isReadonly" type="primary" :loading="saving" @click="savePlan">{{
        t('iotMaintain.save')
      }}</el-button>
    </section>
  </div>
  <maintenance-device-list ref="deviceList" @choose="deviceChoose" />
  <maintenance-plan-form ref="planForm" @saved="refreshOriginalRows" />
</template>

<style scoped>
.panel {
  position: relative;
  flex: 0 0 auto;
  padding: 18px 20px 8px;
  overflow: hidden;
  background: var(--el-bg-color);
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 8px;
  box-shadow: 0 1px 3px rgb(0 0 0 / 4%);
}

.plan-info-accent {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  height: 3px;
  background: linear-gradient(
    90deg,
    var(--el-color-primary),
    var(--el-color-success),
    var(--el-color-warning)
  );
}

.plan-info-form {
  width: 100%;
}

.plan-info-form :deep(.el-form-item) {
  margin-bottom: 14px;
}

.plan-info-form :deep(.el-form-item__label) {
  height: 32px;
  font-size: 13px;
  line-height: 32px;
  color: var(--el-text-color-regular);
}

.plan-info-form :deep(.el-input__wrapper),
.plan-info-form :deep(.el-textarea__inner) {
  border-radius: 6px;
  box-shadow: 0 0 0 1px var(--el-border-color-light) inset;
}

.plan-info-form :deep(.el-input__wrapper:hover),
.plan-info-form :deep(.el-textarea__inner:hover) {
  box-shadow: 0 0 0 1px var(--el-border-color) inset;
}

.plan-info-form :deep(.el-input.is-disabled .el-input__wrapper) {
  background-color: var(--el-fill-color-lighter);
}

.plan-info-form :deep(.el-textarea__inner) {
  min-height: 76px !important;
  padding-top: 8px;
  line-height: 1.6;
}

.content-panel {
  display: flex;
  min-height: 0;
  flex-direction: column;
}

.operation {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: flex-end;
  padding-bottom: 12px;
}

.table {
  position: relative;
  min-height: 0;
  flex: 1 1 auto;
}

.footer-panel {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 12px 20px;
}

:deep(.zm-table .all-filled) {
  background-color: #67c23a !important;
}

:deep(.zm-table .all-filled .cell) {
  color: #fff;
}

:deep(.zm-table .negative-remain-value .cell) {
  color: var(--el-color-danger);
}

@media (width <= 768px) {
  .panel {
    padding: 16px 14px 4px;
  }
}
</style>
