<template>
  <div class="visit-record-wrapper">
    <div class="search-div">
      <Row type="flex" :gutter="16" class="mb10">
        <Col span="4">
          <span>姓名：</span>
          <Input v-model="filters.name" placeholder="请输入" style="width: 65%" />
        </Col>
        <Col span="4">
          <span>身份证号：</span>
          <Input v-model="filters.card_no" placeholder="请输入" style="width: 55%" />
        </Col>
        <Col span="4">
          <span>选择市：</span>
          <Select v-model="filters.city_id" clearable style="width: 55%" @on-change="handleFilterCascade('city', $event)">
            <Option v-for="c in cityOptions" :key="c.parent_id" :value="c.parent_id">{{ c.name }}</Option>
          </Select>
        </Col>
        <Col span="4">
          <span>选择区：</span>
          <Select v-model="filters.area_id" clearable style="width: 55%" @on-change="handleFilterCascade('area', $event)">
            <Option v-for="c in areaState.areaList" :key="c.parent_id" :value="c.parent_id">{{ c.name }}</Option>
          </Select>
        </Col>
        <Col span="4">
          <span>选择街道：</span>
          <Select v-model="filters.street_id" clearable style="width: 55%" @on-change="handleFilterCascade('street', $event)">
            <Option v-for="c in areaState.streetList" :key="c.parent_id" :value="c.parent_id">{{ c.name }}</Option>
          </Select>
        </Col>
        <Col span="4">
          <span>选择社区：</span>
          <Select v-model="filters.community_id" clearable style="width: 55%">
            <Option v-for="c in areaState.communityList" :key="c.parent_id" :value="c.parent_id">{{ c.name }}</Option>
          </Select>
        </Col>
      </Row>
      <Row type="flex" :gutter="16" class="mb10">
        <Col span="4">
          <span>风险等级：</span>
          <Select v-model="filters.rating_level" clearable style="width: 55%">
            <Option v-for="opt in ratingLevelOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</Option>
          </Select>
        </Col>
        <Col span="4">
          <span>回访状态：</span>
          <Select v-model="filters.visit_status" clearable style="width: 55%">
            <Option v-for="opt in visitStatusOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</Option>
          </Select>
        </Col>
        <Col span="8" class="text-right">
          <Button type="primary" style="margin-right: 10px" @click="handleSearch">搜索</Button>
          <Button type="primary" style="margin-right: 10px" @click="handleReset">重置</Button>
          <Button type="primary" @click="handleBackToStatistics" v-if="this.$route.query.rt">返回重点人员统计</Button>
        </Col>
      </Row>
    </div>
    <Table border :loading="loading" :columns="columns" :data="tableData">
      <template slot="rating_level" slot-scope="{ row }">
        <span>{{ renderRatingLevel(row.rating_level) }}</span>
      </template>
      <template slot="visit_status" slot-scope="{ row }">
        <span>{{ renderVisitStatus(row.visit_status) }}</span>
      </template>
      <template slot="action" slot-scope="{ row }">
        <Button v-if="canShowVisitButton(row)" size="small" type="primary" style="margin-right: 10px" @click="openVisitModal(row)">回访</Button>
        <Button type="primary" size="small" @click="openHistoryModal(row)">回访历史</Button>
      </template>
    </Table>
    <Page
      class="page_style"
      :total="pager.totalRecord"
      :current="pager.pageNo"
      :page-size="pager.pageSize"
      show-total
      show-sizer
      @on-change="pageChange"
      @on-page-size-change="sizeChange"
    />

    <!-- 回访弹窗 -->
    <Modal v-model="visitModal.visible" title="回访" width="800" :mask-closable="false">
      <div v-if="visitModal.loading">
        <Spin fix></Spin>
      </div>
      <div v-else>
        <h4 class="section-title">人员基本信息</h4>
        <Form :label-width="120" inline class="info-form">
          <FormItem label="姓名"><Input :value="visitModal.personInfo.name || '-'" disabled style="width: 220px" /></FormItem>
          <FormItem label="身份证号"><Input :value="visitModal.personInfo.card_no || '-'" disabled style="width: 220px" /></FormItem>
          <FormItem label="联系方式"><Input :value="visitModal.personInfo.phone || '-'" disabled style="width: 220px" /></FormItem>
          <FormItem label="风险等级"><Input :value="renderRatingLevel(visitModal.personInfo.rating_level) || '-'" disabled style="width: 220px" /></FormItem>
          <FormItem label="市（州）"><Input :value="visitModal.personInfo.city_name || '-'" disabled style="width: 220px" /></FormItem>
          <FormItem label="县（市、区）"><Input :value="visitModal.personInfo.area_name || '-'" disabled style="width: 220px" /></FormItem>
          <FormItem label="街道（乡镇）"><Input :value="visitModal.personInfo.street_name || '-'" disabled style="width: 220px" /></FormItem>
          <FormItem label="社区（村）"><Input :value="visitModal.personInfo.community_name || '-'" disabled style="width: 220px" /></FormItem>
        </Form>

        <h4 class="section-title">回访信息</h4>
          <Form ref="visitForm" :model="visitModal.form" :rules="visitModal.rules" :label-width="120">
          <FormItem label="回访时间" prop="visit_time" required>
            <DatePicker
              v-model="visitModal.form.visit_time"
              type="datetime"
              format="yyyy-MM-dd HH:mm:ss"
              placeholder="请选择回访时间"
              style="width: 100%"
            />
          </FormItem>
          <FormItem label="回访记录" prop="visit_record">
            <Input type="textarea" :rows="4" v-model="visitModal.form.visit_record" placeholder="请输入回访记录" />
          </FormItem>
          <FormItem label="上传图片">
              <Upload
                action="#"
                :before-upload="beforeUpload"
                :show-upload-list="false"
              >
                <Button icon="ios-cloud-upload-outline">上传图片</Button>
              </Upload>
            </Upload>
            <!-- <div class="upload-tips">支持多张图片上传，单张图片不超过5MB</div>
            <div v-if="visitModal.form.visit_img_list.length" class="upload-preview">
              <div
                class="demo-upload-list"
                v-for="(item, index) in visitModal.form.visit_img_list"
                :key="item.uid || index"
              >
                <img :src="item.preview || item.url" alt="回访图片" />
                <div class="demo-upload-list-cover">
                  <Icon type="ios-eye-outline" @click.native="handleVisitImagePreview(item)" />
                  <Icon type="ios-trash-outline" @click.native="removeVisitImage(index)" />
                </div>
              </div>
            </div> -->
            <div
              class="demo-upload-list"
              style="display: inline-flex; justify-content: space-around;"
              v-for="(item, index) in visitModal.form.visit_img_list"
              :key="index"
            >
              <span class="hover-effect" @click="checkFile(item,index)">
               图片{{index+1}}-{{item.originalFilename}}
              </span>
              <span style="margin-left: 10px;cursor: pointer;" @click="delFile(item,index)">
                <Icon type="md-close" />
              </span>
            </div>
          </FormItem>
        </Form>
      </div>
      <div slot="footer">
        <Button @click="visitModal.visible=false">取消</Button>
        <Button type="primary" :loading="visitModal.submitting" :disabled="visitModal.loading" @click="submitVisit">保存</Button>
      </div>
    </Modal>

    <!-- 回访历史弹窗 -->
    <VisitHistoryModal
      ref="historyModal"
      :rating_dict_type="currentRatingDictType"
      :key_person_id="historyModal.key_person_id"
    />
    <Modal v-model="visitModal.preview.visible" title="查看图片" width="600">
      <img v-if="visitModal.preview.visible" :src="visitModal.preview.url" alt="预览图片" style="width: 100%" />
    </Modal>
    <CImage ref="cImageRef" />
  </div>
</template>

<script>
import { selectCityList } from '@/api/contradiction'
import { getDictList } from '@/api/common'
import { uploadFile } from '@/api/contradiction.js'
import {
  findVisitRecordList,
  getPersonInfoForVisit,
  saveVisitRecord,
  selectCurrentUserInfo,
  getVisitButtonPower
} from '@/api/key-person'
import axios from 'axios'
import VisitHistoryModal from './components/VisitHistoryModal.vue'
import CImage from '_c/c-image/index.vue'

const createVisitForm = () => ({
  key_person_id: '',
  key_person_visit_id: '',
  rating_dict_type: '',
  sys_type_office_label: '',
  sys_type_office_value: '',
  plan_name: '',
  plan_type: '',
  rating_type: '',
  visit_time: null,
  visit_record: '',
  visit_img_list: []
})

// 身份证号统一转码（移除空白并大写），避免查询条件失效
const normalizeCardNo = (val) => {
  if (!val) return ''
  const cleaned = String(val).replace(/\s+/g, '').trim()
  if (!cleaned) return ''
  return cleaned.toUpperCase()
}
export default {
  name: 'key-person-visit-record-index',
  components: {
    VisitHistoryModal, CImage
  },
  props: {
    // 重点人员类别（rating_dict_type），对应sys_type
    category: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      filters: {
        name: '',
        card_no: '',
        city_id: '',
        area_id: '',
        street_id: '',
        community_id: '',
        rating_level: '',
        visit_status: ''
      },
      cityOptions: [],
      areaState: {
        areaList: [],
        streetList: [],
        communityList: []
      },
      ratingLevelOptions: [],
      visitStatusOptions: [],
      loading: false,
      tableData: [],
      columns: [
        { type: 'index', title: '序号', width: 60, align: 'center' },
        { title: '市（州）', key: 'city_name', align: 'center' },
        { title: '县（市、区）', key: 'area_name', align: 'center' },
        { title: '街道（乡镇）', key: 'street_name', align: 'center' },
        { title: '社区（村）', key: 'community_name', align: 'center' },
        { title: '姓名', key: 'name', align: 'center' },
        { title: '身份证号', key: 'card_no', align: 'center' },
        { title: '联系方式', key: 'phone', align: 'center' },
        { title: '风险等级', key: 'rating_level', align: 'center', slot: 'rating_level' },
        { title: '回访状态', key: 'visit_status', align: 'center', slot: 'visit_status' },
        { title: '操作', key: 'action', align: 'center', width: 180, slot: 'action' }
      ],
      pager: {
        pageNo: 1,
        pageSize: 10,
        totalRecord: 0
      },
      visitModal: {
        visible: false,
        loading: false,
        submitting: false,
        personInfo: {},
        form: createVisitForm(),
        rules: {
          visit_time: [{ required: true, type: 'date', message: '请选择回访时间', trigger: 'change' }],
          visit_record: [
            {
              trigger: ['blur', 'change'],
              validator: (rule, value, callback) => {
                const text = (value || '').trim()
                const hasImages = Array.isArray(this.visitModal.form.visit_img_list) && this.visitModal.form.visit_img_list.length > 0
                if (text || hasImages) {
                  callback()
                } else {
                  callback(new Error('请填写回访记录或上传图片，至少一项'))
                }
              }
            }
          ]
        },
        preview: {
          visible: false,
          url: ''
        }
      },
      historyModal: {
        key_person_id: ''
      },
      currentRatingDictType: '',
      visitButtonPower: {},
      severUserInfo: {},
      suffixList: ['jpg', 'jpeg', 'png'],
      urlList: []
    }
  },
  created () {
    // 从路由参数中读取 visit_status，用于自动设置回访状态筛选
    const routeQuery = this.$route.query || {}
    if (routeQuery.visit_status) {
      this.filters.visit_status = routeQuery.visit_status
    }
    // 获取用户信息
    this.severUserInfo = this.$store.state.user.otherUserInfo || {}
    this.init()
  },
  methods: {
    async init () {
      await this.loadCityOptions()
      await this.loadDicts()
      await this.fetchVisitButtonPower()
      this.loadList()
    },
    async loadCityOptions () {
      try {
        const res = await selectCityList({})// { parent_id: '0' }
        if (res.data && res.data.errcode === 0) {
          this.cityOptions = res.data.data || []
        }
      } catch (e) {
        console.error('加载城市列表失败', e)
      }
    },
    async loadDicts () {
      // 加载风险等级字典
      try {
        const res = await getDictList({ type: 'rating_level' })
        if (res && res.data && res.data.errcode === 0) {
          const results = res.data.data && res.data.data.results ? res.data.data.results : []
          this.ratingLevelOptions = results.map(it => ({
            label: it.label || it.name,
            value: it.value || it.dictValue
          }))
        }
      } catch (e) {
        console.error('加载风险等级字典失败', e)
      }
      // 加载回访状态字典
      try {
        const res = await getDictList({ type: 'visit_status' })
        if (res && res.data && res.data.errcode === 0) {
          const results = res.data.data && res.data.data.results ? res.data.data.results : []
          this.visitStatusOptions = results.map(it => ({
            label: it.label || it.name,
            value: it.value || it.dictValue
          }))
        }
      } catch (e) {
        console.error('加载回访状态字典失败', e)
      }
    },
    handleFilterCascade (level, value) {
      if (level === 'city') {
        this.filters.city_id = value
        this.filters.area_id = ''
        this.filters.street_id = ''
        this.filters.community_id = ''
        this.areaState.areaList = []
        this.areaState.streetList = []
        this.areaState.communityList = []
        if (!value) return
        selectCityList({ parent_id: value }).then(res => {
          if (res.data && res.data.errcode === 0) {
            this.areaState.areaList = res.data.data || []
          }
        })
      } else if (level === 'area') {
        this.filters.area_id = value
        this.filters.street_id = ''
        this.filters.community_id = ''
        this.areaState.streetList = []
        this.areaState.communityList = []
        if (!value) return
        selectCityList({ parent_id: value }).then(res => {
          if (res.data && res.data.errcode === 0) {
            this.areaState.streetList = res.data.data || []
          }
        })
      } else if (level === 'street') {
        this.filters.street_id = value
        this.filters.community_id = ''
        this.areaState.communityList = []
        if (!value) return
        selectCityList({ parent_id: value }).then(res => {
          if (res.data && res.data.errcode === 0) {
            this.areaState.communityList = res.data.data || []
          }
        })
      }
    },
    handleSearch () {
      this.pager.pageNo = 1
      this.loadList()
    },
    handleReset () {
      this.filters = {
        name: '',
        card_no: '',
        city_id: '',
        area_id: '',
        street_id: '',
        community_id: '',
        rating_level: '',
        visit_status: ''
      }
      this.areaState = {
        areaList: [],
        streetList: [],
        communityList: []
      }
      this.pager.pageNo = 1
      this.loadList()
    },
    handleBackToStatistics () {
      this.$router.push({
        path: '/keyPerson/statistics'
      })
    },
    async fetchVisitButtonPower () {
      const payload = {}
      try {
        const ret = await getVisitButtonPower(payload)
        if (ret && ret.data && ret.data.errcode === 0) {
          this.visitButtonPower = ret.data.data || {}
        } else {
          this.visitButtonPower = {}
        }
      } catch (e) {
        console.error('获取回访按钮权限失败', e)
        this.visitButtonPower = {}
      }
    },
    canShowVisitButton (row) {
      const isAdmin = (this.severUserInfo.loginName === 'admin')
      const power = this.visitButtonPower || {}

      // 优先使用 sys_type，如果没有则使用 rating_dict_type 或 category
      const type = String(row.sys_type || row.rating_dict_type || this.category || '')

      if (isAdmin) return true
      if (type === '2') return !!power['rucs_visit']
      if (type === '3') return !!power['psmd_visit']
      if (type === '6') return !!power['km_visit']
      return false
    },
    async loadList () {
      this.loading = true
      try {
        // 调用 selectCurrentUserInfo 来重置用户信息并自动填充 area_id
        // 这个 API 后端会调用 DataScopeUtil.resetUser()，根据 company_grade 和 area_id 联合确定匹配哪个字段
        let userInfoParams = {}
        try {
          const userInfoRes = await selectCurrentUserInfo({})
          if (userInfoRes && userInfoRes.data && userInfoRes.data.errcode === 0) {
            userInfoParams = userInfoRes.data.data || {}
          }
        } catch (e) {
          console.error('获取用户信息失败', e)
          // 即使获取用户信息失败，也继续执行查询
        }
        const normalizedCardNo = normalizeCardNo(this.filters.card_no)
        const params = {
          ...this.filters,
          card_no: normalizedCardNo,
          cardNo: normalizedCardNo,
          pageNo: this.pager.pageNo,
          pageSize: this.pager.pageSize,
          // 将重置后的用户信息合并到参数中
          ...userInfoParams
        }
        // 如果传入了category（重点人员类别），则转换为sys_type传给后端
        if (this.category) {
          params.sys_type = this.category
        }
        const res = await findVisitRecordList(params)
        if (res && res.data && res.data.errcode === 0) {
          const page = res.data.data || { results: [], totalRecord: 0 }
          this.tableData = page.results || []
          this.pager.totalRecord = page.totalRecord || 0
        } else {
          this.$Message.error((res.data && res.data.errmsg) || '查询失败')
          this.tableData = []
          this.pager.totalRecord = 0
        }
      } catch (e) {
        console.error('查询列表失败', e)
        this.$Message.error('查询列表失败')
        this.tableData = []
        this.pager.totalRecord = 0
      } finally {
        this.loading = false
      }
    },
    pageChange (pageNo) {
      this.pager.pageNo = pageNo
      this.loadList()
    },
    sizeChange (pageSize) {
      this.pager.pageSize = pageSize
      this.pager.pageNo = 1
      this.loadList()
    },
    renderRatingLevel (val) {
      if (!val) return '-'
      const found = this.ratingLevelOptions.find(it => it.value === val)
      return found ? found.label : val
    },
    renderVisitStatus (val) {
      if (val === null || val === undefined || val === '') return '-'
      const s = String(val)
      const found = this.visitStatusOptions.find(it => it.value === s)
      return found ? found.label : (s === '0' ? '无待访' : s === '1' ? '正常待访' : s === '2' ? '临期待访' : s === '3' ? '超期待访' : s)
    },
    async openVisitModal (row) {
      this.visitModal.visible = true
      this.visitModal.loading = true
      const nextForm = createVisitForm()
      nextForm.key_person_id = row.person_id
      nextForm.key_person_visit_id = row.key_person_visit_id || row.visit_plan_id || ''
      nextForm.rating_dict_type = row.rating_dict_type
      nextForm.sys_type_office_label = row.sys_type_office_label || ''
      nextForm.sys_type_office_value = row.sys_type_office_value || ''
      nextForm.plan_name = row.plan_name || ''
      nextForm.plan_type = row.plan_type || ''
      nextForm.rating_type = row.plan_rating_type || row.rating_level || ''
      nextForm.visit_time = new Date()
      this.$set(this.visitModal, 'form', nextForm)
      this.currentRatingDictType = row.rating_dict_type || ''
      try {
        const visitParams = { person_id: row.person_id, rating_dict_type: row.rating_dict_type }
        // 如果传入了category（重点人员类别），则转换为sys_type传给后端
        if (this.category) {
          visitParams.sys_type = this.category
        } else if (row.sys_type) {
          // 如果row中有sys_type，也传入
          visitParams.sys_type = row.sys_type
        }
        const res = await getPersonInfoForVisit(visitParams)
        if (res && res.data && res.data.errcode === 0) {
          this.visitModal.personInfo = res.data.data || {}
        } else {
          this.$Message.error((res.data && res.data.errmsg) || '获取人员信息失败')
        }
      } catch (e) {
        console.error('获取人员信息失败', e)
        this.$Message.error('获取人员信息失败')
      } finally {
        this.visitModal.loading = false
        this.$nextTick(this.clearVisitFormValidate)
      }
    },
    // beforeUpload (file) {
    //   const allowedTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/bmp', 'image/gif', 'image/webp']
    //   const isValidType = allowedTypes.includes(file.type) || file.type.startsWith('image/')
    //   const isLt5M = file.size / 1024 / 1024 < 5
    //   if (!isValidType) {
    //     this.$Message.error('请上传图片格式')
    //     return false
    //   }
    //   if (!isLt5M) {
    //     this.$Message.error('图片大小不能超过5MB！')
    //     return false
    //   }
    //   const tempItem = {
    //     uid: `${Date.now()}_${Math.random().toString(16).slice(2)}`,
    //     name: file.name,
    //     status: 'uploading',
    //     preview: '',
    //     url: ''
    //   }
    //   this.visitModal.form.visit_img_list.push(tempItem)
    //   const reader = new FileReader()
    //   reader.onload = (e) => {
    //     this.$set(tempItem, 'preview', e.target.result)
    //   }
    //   reader.readAsDataURL(file)
    //   this.uploadFile(file, tempItem)
    //   return false
    // },
    // async uploadFile (file, targetItem) {
    //   const formData = new FormData()
    //   formData.append('file', file)
    //   try {
    //     const res = await uploadPic(formData)
    //     if (res && res.data && res.data.errcode === 0) {
    //       const url = this.extractUploadUrl(res.data)
    //       if (url) {
    //         if (targetItem) {
    //           this.$set(targetItem, 'url', url)
    //           this.$set(targetItem, 'status', 'finished')
    //         } else {
    //           this.visitModal.form.visit_img_list.push({
    //             name: file.name,
    //             url: url,
    //             status: 'finished'
    //           })
    //         }
    //         this.$Message.success('上传成功')
    //         this.revalidateVisitRecordField()
    //       }
    //     } else {
    //       this.$Message.error((res && res.data && res.data.errmsg) || '上传失败')
    //       this.removeVisitImageByItem(targetItem)
    //     }
    //   } catch (e) {
    //     console.error('上传失败', e)
    //     this.$Message.error('上传失败')
    //     this.removeVisitImageByItem(targetItem)
    //   }
    // },
    // removeVisitImage (index) {
    //   if (index < 0) return
    //   this.visitModal.form.visit_img_list.splice(index, 1)
    //   this.revalidateVisitRecordField()
    // },
    // removeVisitImageByItem (item) {
    //   if (!item) return
    //   const idx = this.visitModal.form.visit_img_list.indexOf(item)
    //   if (idx > -1) {
    //     this.visitModal.form.visit_img_list.splice(idx, 1)
    //   }
    //   this.revalidateVisitRecordField()
    // },
    // handleVisitImagePreview (item) {
    //   if (!item) return
    //   const url = item.url || item.preview
    //   if (!url) return
    //   this.visitModal.preview.url = url
    //   this.visitModal.preview.visible = true
    // },
    getImgUrl (uuid, suffix, fileInfo) {
      let that = this
      axios({
        method: 'get',
        responseType: 'arraybuffer',
        url:
          '/api/ac/jilinsscgsdp/uploadService/getObsObject?uuid=' +
          uuid +
          '&&suffix=' +
          suffix
      }).then(function (res) {
        // 构建完整的附件对象，包含所有必要信息
        let fileObj = {
          uuid: fileInfo.uuid,
          suffix: suffix,
          originalFilename: fileInfo.original_name
        }
        if (that.suffixList.includes(suffix)) {
          const base64String = btoa(
            new Uint8Array(res.data).reduce(
              (data, byte) => data + String.fromCharCode(byte),
              ''
            )
          )
          fileObj.url = 'data:image/png;base64,' + base64String
        } else {
          fileObj.url = res.data
        }
        that.visitModal.form.visit_img_list.push(fileObj)
        // 调用下载方法，把后端传过来的流传给fileDownload方法
        // this.fileDownload(res.data, fileName)
      })
    },
    checkFile (item, index) {
      console.log('item, index>>', item, index)
      // window.open
      if (this.suffixList.includes(item.suffix)) {
        this.$refs.cImageRef.init({ src: item.url })
      } else {
        window.open(item.url, '_blank')
      }
      console.log(item, index)
    },
    delFile (item, index) {
      this.urlList.splice(index, 1)
      this.visitModal.form.visit_img_list.splice(index, 1)
      console.log(item, index)
    },
    // 上传图片前转base64
    beforeUpload (file) {
      const fileType = file.name.split('.').pop()
      const fileTypes = this.suffixList
      if (!fileTypes.includes(fileType)) {
        this.$Message.error({
          content: `请上传${fileTypes.join('、')}格式的文件`,
          duration: 5
        })
        return
      }
      const reader = new FileReader()
      reader.readAsDataURL(file)
      reader.onload = (e) => {
        // 初始时先保存文件名，上传成功后再更新为服务器返回的文件名
        this.visitModal.form.visit_img_list.push({
          url: e.target.result,
          originalFilename: file.name,
          suffix: file.name.split('.').pop()
        })
      }
      let formdata = new FormData()
      formdata.append('file', file)
      formdata.append('fileName', file.name)
      formdata.append('json', JSON.stringify({ business_type: 'jlEvent' }))
      console.log(formdata, 'formdata')
      uploadFile(formdata).then((res) => {
        let len = this.visitModal.form.visit_img_list.length
        // 使用 $set 确保 Vue 响应式更新
        this.$set(this.visitModal.form.visit_img_list[len - 1], 'uuid', res.data.data.uuid)
        this.$set(this.visitModal.form.visit_img_list[len - 1], 'suffix', res.data.data.suffix)
        this.$set(this.visitModal.form.visit_img_list[len - 1], 'originalFilename', res.data.data.originalFilename)
        this.urlList.push(res.data.data)
        // setTimeout(this.msg, 3000)
      })
      console.log(this.visitModal.form.visit_img_list, 'this.visitModal.form.visit_img_list')
    },
    async submitVisit () {
      const formRef = this.$refs.visitForm
      if (!formRef) {
        this.$Message.warning('表单尚未加载完成，请稍后再试')
        return
      }
      formRef.validate(async (valid) => {
        console.log('submitVisit', valid)
        if (!valid) {
          return false
        }
        const visitTimeStr = this.normalizeVisitTimeValue(this.visitModal.form.visit_time)
        if (!visitTimeStr) {
          this.$Message.error('请选择有效的回访时间')
          return false
        }
        const visitRecord = (this.visitModal.form.visit_record || '').trim()
        const hasVisitImages = this.visitModal.form.visit_img_list.length > 0
        if (!visitRecord && !hasVisitImages) {
          this.$Message.error('请填写回访记录或上传图片，至少一项')
          return false
        }
        if (visitRecord) {
          this.visitModal.form.visit_record = visitRecord
        }
        this.visitModal.submitting = true
        try {
          let imgs = this.visitModal.form.visit_img_list.map(img => ({
            uuid: img.uuid,
            originalFilename: img.originalFilename,
            suffix: img.suffix
          }))
          const visitImg = JSON.stringify(imgs)
          const params = {
            key_person_id: this.visitModal.form.key_person_id,
            key_person_visit_id: this.visitModal.form.key_person_visit_id,
            rating_dict_type: this.visitModal.form.rating_dict_type,
            sys_type_office_label: this.visitModal.form.sys_type_office_label,
            sys_type_office_value: this.visitModal.form.sys_type_office_value,
            plan_name: this.visitModal.form.plan_name,
            plan_type: this.visitModal.form.plan_type,
            rating_type: this.visitModal.form.rating_type,
            visit_time: visitTimeStr,
            visit_record: this.visitModal.form.visit_record,
            visit_img: visitImg
          }
          const res = await saveVisitRecord(params)
          if (res && res.data && res.data.errcode === 0) {
            this.$Message.success('保存成功')
            this.visitModal.visible = false
            this.loadList()
          } else {
            this.$Message.error((res.data && res.data.errmsg) || '保存失败')
          }
        } catch (e) {
          console.error('保存回访记录失败', e)
          this.$Message.error('保存回访记录失败')
        } finally {
          this.visitModal.submitting = false
        }
      })
    },
    openHistoryModal (row) {
      this.historyModal.key_person_id = row.person_id
      this.currentRatingDictType = row.rating_dict_type || ''
      // 等待 props 更新到子组件后再打开弹窗，避免首次点击时 key_person_id 还是旧值
      this.$nextTick(() => {
        if (this.$refs.historyModal && typeof this.$refs.historyModal.open === 'function') {
          this.$refs.historyModal.open()
        }
      })
    },
    formatDateTime (date) {
      if (!date) return ''
      const d = date instanceof Date ? new Date(date.getTime()) : new Date(date)
      if (Number.isNaN(d.getTime())) return String(date)
      return this.formatDateSegments(d)
    },
    formatDateSegments (d) {
      const y = d.getFullYear()
      const mm = String(d.getMonth() + 1).padStart(2, '0')
      const dd = String(d.getDate()).padStart(2, '0')
      const HH = String(d.getHours()).padStart(2, '0')
      const MM = String(d.getMinutes()).padStart(2, '0')
      const SS = String(d.getSeconds()).padStart(2, '0')
      return `${y}-${mm}-${dd} ${HH}:${MM}:${SS}`
    },
    clearVisitFormValidate () {
      const visitFormRef = this.$refs.visitForm
      if (!visitFormRef) return
      if (typeof visitFormRef.clearValidate === 'function') {
        visitFormRef.clearValidate()
        return
      }
      if (visitFormRef.fields && Array.isArray(visitFormRef.fields)) {
        visitFormRef.fields.forEach(field => {
          if (!field) return
          field.validateState = ''
          field.validateMessage = ''
        })
      }
    },
    normalizeVisitTimeValue (value) {
      if (!value && value !== 0) return ''
      if (value instanceof Date) {
        return Number.isNaN(value.getTime()) ? '' : this.formatDateSegments(value)
      }
      if (typeof value === 'number' && !Number.isNaN(value)) {
        const fromNumber = new Date(value)
        return Number.isNaN(fromNumber.getTime()) ? '' : this.formatDateSegments(fromNumber)
      }
      if (typeof value === 'string') {
        const trimmed = value.trim()
        if (!trimmed) return ''
        const direct = new Date(trimmed)
        if (!Number.isNaN(direct.getTime())) return this.formatDateSegments(direct)
        const withSlash = new Date(trimmed.replace(/-/g, '/'))
        if (!Number.isNaN(withSlash.getTime())) return this.formatDateSegments(withSlash)
        const match = trimmed.match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?$/)
        if (match) {
          const [, y, m, d, hh = '00', mm = '00', ss = '00'] = match
          return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
        }
        return ''
      }
      if (value && typeof value === 'object' && typeof value.valueOf === 'function') {
        const timestamp = value.valueOf()
        if (!Number.isNaN(timestamp)) {
          const fromValue = new Date(timestamp)
          return Number.isNaN(fromValue.getTime()) ? '' : this.formatDateSegments(fromValue)
        }
      }
      return ''
    },
    extractUploadUrl (responseData) {
      if (!responseData) return ''
      if (typeof responseData === 'string') return responseData
      const data = responseData.data || {}
      return data.url || data.fileUrl || data.file_url || responseData.url || ''
    },
    revalidateVisitRecordField () {
      const formRef = this.$refs.visitForm
      if (formRef && typeof formRef.validateField === 'function') {
        formRef.validateField('visit_record')
      }
    }
  }
}
</script>

<style scoped>
.visit-record-wrapper {
  padding: 16px;
}
.search-div {
  border: 1px solid #dce1e7;
  padding: 15px;
  margin-bottom: 15px;
  background-color: #f8fbff;
}
.mb10 {
  margin-bottom: 10px;
}
.text-right {
  text-align: right;
}
.page_style {
  margin-top: 16px;
  text-align: right;
}
.section-title {
  margin: 16px 0 12px 0;
  font-weight: 600;
  font-size: 14px;
  color: #333;
}
.info-form {
  margin-bottom: 16px;
}
.upload-tips {
  color: #999;
  font-size: 12px;
  margin-top: 8px;
}
.upload-preview {
  display: flex;
  flex-wrap: wrap;
  margin-top: 12px;
}
/* .demo-upload-list {
  width: 104px;
  height: 104px;
  border: 1px solid #e8eaec;
  border-radius: 4px;
  margin-right: 12px;
  margin-bottom: 12px;
  position: relative;
  overflow: hidden;
  background-color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.demo-upload-list img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.demo-upload-list-cover {
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.2s ease;
}
.demo-upload-list:hover .demo-upload-list-cover {
  opacity: 1;
}
.demo-upload-list-cover i {
  color: #fff;
  font-size: 20px;
  margin: 0 8px;
  cursor: pointer;
} */
.hover-effect {
  cursor: pointer; /* 小手效果 */
  transition: all 0.3s ease; /* 添加过渡效果使变化更平滑 */
}

.hover-effect:hover {
  color: #1890ff; /* 文字变蓝色 */
  background-color: #e6f7ff; /* 背景变浅蓝色 */
  border-color: #1890ff; /* 边框变蓝色 */
}
</style>
