<template>
  <transition name="el-zoom-in-center">
    <div class="NCC-preview-main user-form">
      <div class="NCC-common-page-header">
        <el-page-header @back="goBack"
          :content="!dataForm.id ?$t(`user.addUser`) : $t(`user.editUser`)" />
        <div class="options">
          <el-button type="primary" :loading="btnLoading" @click="handleConfirm()">
            {{$t('common.confirmButton')}}</el-button>
          <el-button @click="goBack">{{$t('common.cancelButton')}} </el-button>
        </div>
      </div>
      <div class="main" v-loading="formLoading" :element-loading-text="$t('common.loadingText')">
        <el-tabs v-model="userFormTab" class="user-form-tabs" @tab-click="onUserFormTabClick">
          <el-tab-pane label="基本信息" name="info">
        <el-form
          ref="dataForm"
          :model="dataForm"
          :rules="dataRule"
          label-width="120px"
          label-position="right"
          class="user-form-body"
        >
          <!-- 账号与身份 -->
          <el-card class="user-form-card" shadow="never">
            <div slot="header" class="user-form-card__title">账号与身份</div>
            <el-row :gutter="20" class="custom-row">
              <el-col :sm="12" :xs="24">
                <el-form-item label="账户" prop="account">
                  <el-input v-model="dataForm.account" placeholder="账户名称" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="姓名" prop="realName">
                  <el-input v-model="dataForm.realName" placeholder="真实姓名" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="性别" prop="gender">
                  <el-select v-model="dataForm.gender" placeholder="选择性别">
                    <el-option v-for="item in genderTreeData" :key="item.enCode"
                      :label="item.fullName" :value="item.enCode" />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="手机" prop="mobilePhone">
                  <el-input v-model="dataForm.mobilePhone" placeholder="手机号码" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="电子邮箱" prop="email">
                  <el-input v-model="dataForm.email" placeholder="电子邮箱" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="入职时间" prop="entryDate">
                  <el-date-picker
                    v-model="dataForm.entryDate"
                    type="date"
                    placeholder="请选择入职时间"
                    value-format="timestamp"
                    style="width: 100%"
                  />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="状态" prop="enabledMark">
                  <el-switch v-model="dataForm.enabledMark" :active-value="1" :inactive-value="0" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="在职状态" prop="isOnJob">
                  <el-select
                    v-model="dataForm.isOnJob"
                    placeholder="请选择"
                    style="width: 100%"
                    @change="onIsOnJobChange"
                  >
                    <el-option label="在职" :value="1" />
                    <el-option label="离职" :value="0" />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col v-show="dataForm.isOnJob === 0" :sm="12" :xs="24">
                <el-form-item label="离职日期" prop="leaveDate">
                  <el-date-picker
                    v-model="dataForm.leaveDate"
                    type="date"
                    placeholder="请选择离职日期"
                    value-format="timestamp"
                    style="width: 100%"
                  />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="排序" prop="sortCode">
                  <el-input-number :min="0" :max="9999" v-model="dataForm.sortCode"
                    controls-position="right" />
                </el-form-item>
              </el-col>
              <el-col :span="24">
                <el-collapse v-model="avatarCollapse" class="user-form-avatar-collapse">
                  <el-collapse-item name="avatar">
                    <template slot="title">
                      <span class="user-form-avatar-collapse__title">头像（可选）</span>
                      <span class="user-form-avatar-collapse__hint">默认不展示大图；需要更换时再展开上传</span>
                    </template>
                    <el-form-item label="头像" prop="headIcon" class="user-form-avatar-form-item">
                      <el-upload
                        class="avatar-uploader avatar-uploader--compact"
                        :action="define.comUploadUrl+'/userAvatar'"
                        :show-file-list="false"
                        :on-success="handleAvatarSuccess"
                        accept="image/*"
                      >
                        <img v-if="dataForm.headIcon" :src="define.comUrl+dataForm.headIcon" class="avatar avatar--sm">
                        <i v-else class="el-icon-plus avatar-uploader-icon avatar-uploader-icon--sm" />
                      </el-upload>
                    </el-form-item>
                  </el-collapse-item>
                </el-collapse>
              </el-col>
              <el-col :span="24">
                <el-form-item label="备注" prop="description">
                  <el-input v-model="dataForm.description" type="textarea" :rows="4" />
                </el-form-item>
              </el-col>
            </el-row>
          </el-card>

          <!-- 组织与权限 -->
          <el-card class="user-form-card" shadow="never">
            <div slot="header" class="user-form-card__title">组织与权限</div>
            <el-row :gutter="20" class="custom-row">
              <el-col :sm="12" :xs="24">
                <el-form-item label="组织" prop="organizeId">
                  <NCC-TreeSelect v-model="dataForm.organizeId" :options="departmentTreeData"
                    placeholder="选择组织" clearable />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="角色" prop="roleId">
                  <el-select v-model="roleId" multiple placeholder="请选择" @change="roleIdChange"
                    filterable>
                    <el-option-group v-for="group in roleTreeData" :key="group.id"
                      :label="group.fullName+(group.num?'【'+group.num+'】':'')">
                      <el-option v-for="item in group.children" :key="item.id" :label="item.fullName"
                        :value="item.id">
                      </el-option>
                    </el-option-group>
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="直属主管" prop="managerId">
                  <user-select v-model="dataForm.managerId" placeholder="选择直属主管" />
                </el-form-item>
              </el-col>
            </el-row>
          </el-card>

          <!-- 门店与考勤 -->
          <el-card class="user-form-card" shadow="never">
            <div slot="header" class="user-form-card__title">门店与考勤</div>
            <el-alert
              class="user-form-alert"
              type="info"
              :closable="false"
              show-icon
              title="门店用于业务单据默认归属/展示；考勤分组用于考勤规则；二者与「组织」部门(organizeId)含义不同。"
            />
            <el-row :gutter="20" class="custom-row">
              <el-col :sm="12" :xs="24">
                <el-form-item label="门店" prop="mdid">
                  <NCC-TreeSelect v-model="dataForm.mdid" :options="storeTreeData"
                    placeholder="选择门店" clearable />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="考勤分组" prop="attendanceGroupId">
                  <el-select v-model="dataForm.attendanceGroupId" placeholder="选择考勤分组" clearable filterable>
                    <el-option
                      v-for="item in attendanceGroupOptions"
                      :key="item.id"
                      :label="item.fullName"
                      :value="item.id"
                    />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="费用分摊" prop="fyft">
                  <el-select v-model="dataForm.fyft" placeholder="选择费用分摊">
                    <el-option label="是" value="是" />
                    <el-option label="否" value="否" />
                  </el-select>
                </el-form-item>
              </el-col>
            </el-row>
          </el-card>

          <!-- 岗位 -->
          <el-card class="user-form-card" shadow="never">
            <div slot="header" class="user-form-card__title">岗位</div>
            <el-row :gutter="20" class="custom-row">
              <el-col :sm="12" :xs="24">
                <el-form-item label="职位" prop="gw">
                  <el-select v-model="dataForm.gw" placeholder="选择职位" clearable filterable>
                    <el-option
                      v-for="opt in userGwOptions"
                      :key="opt.value"
                      :label="opt.label"
                      :value="opt.value"
                    />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="岗位分类" prop="gwfl">
                  <el-select v-model="dataForm.gwfl" placeholder="选择岗位分类" clearable>
                    <el-option
                      v-for="opt in userGwflOptions"
                      :key="opt.value"
                      :label="opt.label"
                      :value="opt.value"
                    />
                  </el-select>
                </el-form-item>
              </el-col>
            </el-row>
          </el-card>

          <!-- 员工档案 -->
          <el-card class="user-form-card" shadow="never">
            <div slot="header" class="user-form-card__title">员工档案</div>
            <el-row :gutter="20" class="custom-row">
              <el-col :sm="12" :xs="24">
                <el-form-item label="民族" prop="nation">
                  <el-select v-model="dataForm.nation" placeholder="选择民族" filterable>
                    <el-option v-for="item in nationTreeData" :key="item.id" :label="item.fullName"
                      :value="item.id" />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="籍贯" prop="nativePlace">
                  <el-input v-model="dataForm.nativePlace" placeholder="籍贯" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="证件类型" prop="certificatesType">
                  <el-select v-model="dataForm.certificatesType" placeholder="选择证件类型">
                    <el-option v-for="item in certificatesTypeTreeData" :key="item.id"
                      :label="item.fullName" :value="item.id" />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="证件号码" prop="certificatesNumber">
                  <el-input v-model="dataForm.certificatesNumber" placeholder="证件号码" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="文化程度" prop="education">
                  <el-select v-model="dataForm.education" placeholder="选择文化程度">
                    <el-option v-for="item in educationTreeData" :key="item.id" :label="item.fullName"
                      :value="item.id" />
                  </el-select>
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="出生年月" prop="birthday">
                  <el-date-picker v-model="dataForm.birthday" type="date" placeholder="选择出生年月"
                    value-format="timestamp">
                  </el-date-picker>
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="办公电话" prop="telePhone">
                  <el-input v-model="dataForm.telePhone" placeholder="办公电话" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="办公座机" prop="landline">
                  <el-input v-model="dataForm.landline" placeholder="办公座机" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="紧急联系" prop="urgentContacts">
                  <el-input v-model="dataForm.urgentContacts" placeholder="紧急联系人" />
                </el-form-item>
              </el-col>
              <el-col :sm="12" :xs="24">
                <el-form-item label="紧急电话" prop="urgentTelePhone">
                  <el-input v-model="dataForm.urgentTelePhone" placeholder="紧急联系人电话" />
                </el-form-item>
              </el-col>
              <el-col :span="24">
                <el-form-item label="通讯地址" prop="postalAddress">
                  <el-input v-model="dataForm.postalAddress" type="textarea" :rows="4" />
                </el-form-item>
              </el-col>
            </el-row>
          </el-card>
        </el-form>
          </el-tab-pane>
          <el-tab-pane v-if="dataForm.id" label="变更记录" name="audit" lazy>
            <div class="user-audit-toolbar">
              <el-button type="default" size="small" icon="el-icon-refresh" @click="fetchUserAuditLogs">刷新</el-button>
            </div>
            <NCC-table v-loading="auditLoading" :data="auditList" border class="user-audit-table">
              <el-table-column label="" width="44" align="center">
                <template slot-scope="scope">
                  <i class="el-icon-document" :class="auditActionIconClass(scope.row.action)" />
                </template>
              </el-table-column>
              <el-table-column prop="operateTime" label="操作时间" width="168" :show-overflow-tooltip="true" />
              <el-table-column prop="operatorUserName" label="操作人" width="100" :show-overflow-tooltip="true" />
              <el-table-column prop="action" label="动作" width="140" :show-overflow-tooltip="true" />
              <el-table-column prop="fieldLabel" label="字段" width="100" :show-overflow-tooltip="true" />
              <el-table-column prop="oldValue" label="原值" min-width="120" :show-overflow-tooltip="true">
                <template slot-scope="scope">
                  <span>{{ scope.row.oldValue === '' || scope.row.oldValue == null ? '无' : scope.row.oldValue }}</span>
                </template>
              </el-table-column>
              <el-table-column prop="newValue" label="新值" min-width="120" :show-overflow-tooltip="true">
                <template slot-scope="scope">
                  <span>{{ scope.row.newValue === '' || scope.row.newValue == null ? '无' : scope.row.newValue }}</span>
                </template>
              </el-table-column>
              <el-table-column prop="source" label="来源" width="88" :show-overflow-tooltip="true" />
              <el-table-column prop="clientIp" label="IP" width="120" :show-overflow-tooltip="true">
                <template slot-scope="scope">
                  <span>{{ scope.row.clientIp || '无' }}</span>
                </template>
              </el-table-column>
            </NCC-table>
            <pagination
              :total="auditTotal"
              :page.sync="auditParams.currentPage"
              :limit.sync="auditParams.pageSize"
              @pagination="fetchUserAuditLogs"
            />
          </el-tab-pane>
          <el-tab-pane v-if="dataForm.id" label="主档版本" name="profileVersion" lazy>
            <div class="user-audit-toolbar">
              <el-button type="default" size="small" icon="el-icon-refresh" @click="fetchUserProfileVersionLogs">刷新</el-button>
            </div>
            <NCC-table v-loading="profileVersionLoading" :data="profileVersionList" border class="user-audit-table">
              <el-table-column label="" width="44" align="center">
                <template slot-scope="scope">
                  <i class="el-icon-time" :class="profileVersionRowIconClass(scope.row.versionNo)" />
                </template>
              </el-table-column>
              <el-table-column prop="versionNo" label="版本" width="64" :show-overflow-tooltip="true" />
              <el-table-column prop="validFrom" label="生效自" width="168" :show-overflow-tooltip="true" />
              <el-table-column prop="validTo" label="失效于" width="168" :show-overflow-tooltip="true">
                <template slot-scope="scope">
                  <span>{{ scope.row.validTo || '无' }}</span>
                </template>
              </el-table-column>
              <el-table-column prop="mdid" label="门店快照" min-width="100" :show-overflow-tooltip="true">
                <template slot-scope="scope">
                  <span>{{ scope.row.mdid || '无' }}</span>
                </template>
              </el-table-column>
              <el-table-column prop="gw" label="岗位快照" width="100" :show-overflow-tooltip="true">
                <template slot-scope="scope">
                  <span>{{ scope.row.gw || '无' }}</span>
                </template>
              </el-table-column>
              <el-table-column prop="changeTrigger" label="触发" width="160" :show-overflow-tooltip="true" />
              <el-table-column prop="operatorUserName" label="操作人" width="100" :show-overflow-tooltip="true" />
              <el-table-column label="快照" width="100" align="left">
                <template slot-scope="scope">
                  <el-button type="text" size="small" @click="openProfileVersionJsonDialog(scope.row)">查看 JSON</el-button>
                </template>
              </el-table-column>
              <el-table-column label="操作" width="88" align="left">
                <template slot-scope="scope">
                  <el-button type="text" size="small" @click="handleRestoreUserProfileVersion(scope.row)">还原</el-button>
                </template>
              </el-table-column>
            </NCC-table>
            <pagination
              :total="profileVersionTotal"
              :page.sync="profileVersionParams.currentPage"
              :limit.sync="profileVersionParams.pageSize"
              @pagination="fetchUserProfileVersionLogs"
            />
          </el-tab-pane>
        </el-tabs>

        <el-dialog title="主档版本快照" :visible.sync="profileVersionJsonVisible" width="720px" append-to-body
          custom-class="NCC-dialog user-profile-version-json-dialog" lock-scroll>
          <pre class="user-profile-version-json-pre">{{ profileVersionJsonText }}</pre>
          <span slot="footer" class="dialog-footer">
            <el-button @click="profileVersionJsonVisible = false">关 闭</el-button>
          </span>
        </el-dialog>
      </div>
    </div>
  </transition>
</template>

<script>
/*
 * =============================================================================
 * 用户表单字段说明（BASE_USER / 权限用户）
 * -----------------------------------------------------------------------------
 * organizeId（组织）：行政/权限树中的部门或公司节点，用于组织归属、数据权限等；与门店不是同一概念。
 * mdid（门店）：用户主属/默认门店，常用于业务单据默认归属、列表展示等；月度门店归属等业务口径以 lq_md_target
 *   等表为准（见项目规范），用户上的 mdid 表示默认或主属类用途，勿与 organizeId 混用。
 * roleId（角色）：功能与数据权限角色，多选后以逗号拼接字符串提交。
 * managerId（直属主管）：汇报关系，选人组件存主管用户 id。
 * attendanceGroupId（考勤分组）：考勤规则分组，与组织、门店独立。
 * gw（职位）/ gwfl（岗位分类）：与列表筛选、统计口径（如「科技老师」）一致；选项见 user-gw-options.js。
 * entryDate（入职时间）：必填；请假/年假等流程（如 LeaveApplyService 工龄计算）依赖 BASE_USER.EntryDate。
 *
 * 列表页 getmdname(mdid)：用 getStoreSelector 拉平的 storeOptions，通过 id 匹配 fullName；表单内门店下拉为
 *   同一接口 getStoreSelector 返回的树 storeTreeData（NCC-TreeSelect），展示形态不同、数据源一致。
 * =============================================================================
 */

import { getDepartmentSelector } from '@/api/permission/department'
import { getRoleSelector } from '@/api/permission/role'
import { createUser, updateUser, getUserInfo } from '@/api/permission/user'
import { getUserProfileAuditLogs } from '@/api/extend/userProfileAudit'
import { getUserProfileVersionLogs, restoreUserProfileVersion } from '@/api/extend/userProfileVersion'
import { getStoreSelector } from '@/api/extend/store'
import { getAttendanceGroupSelector } from '@/api/extend/attendanceSetting'
import { USER_GW_OPTIONS, USER_GWFL_OPTIONS } from './user-gw-options'

export default {
  data() {
    return {
      visible: false,
      btnLoading: false,
      userFormTab: 'info',
      auditLoading: false,
      auditList: [],
      auditTotal: 0,
      auditParams: {
        currentPage: 1,
        pageSize: 20
      },
      profileVersionLoading: false,
      profileVersionList: [],
      profileVersionTotal: 0,
      profileVersionParams: {
        currentPage: 1,
        pageSize: 20
      },
      profileVersionJsonVisible: false,
      profileVersionJsonText: '',
      userGwOptions: USER_GW_OPTIONS,
      userGwflOptions: USER_GWFL_OPTIONS,
      dataForm: {
        id: '',
        sortCode: 0,
        enabledMark: 1,
        isOnJob: 1,
        account: '',
        realName: '',
        organizeId: '',
        managerId: '',
        positionId: '',
        roleId: '',
        description: '',
        headIcon: '',
        gender: null,
        nationId: '',
        nativePlace: '',
        entryDate: null,
        leaveDate: null,
        certificatesType: '',
        certificatesNumber: '',
        education: '',
        birthday: null,
        telePhone: '',
        landline: '',
        mobilePhone: '',
        email: '',
        urgentContacts: '',
        urgentTelePhone: '',
        postalAddress: '',
        mdid: '',
        attendanceGroupId: '',
        fyft: '否',
        gwfl: '',
        gw: ''
      },
      roleId: [],
      departmentTreeData: [],
      roleTreeData: [],
      genderTreeData: [],
      nationTreeData: [],
      educationTreeData: [],
      certificatesTypeTreeData: [],
      storeTreeData: [],
      attendanceGroupOptions: [],
      /** 头像区默认折叠，避免占满首屏 */
      avatarCollapse: [],
      formLoading: false,
      genderProps: {
        value: 'enCode',
        label: 'fullName'
      },
      dataRule: {
        account: [
          { required: true, message: '请输入账户名称', trigger: 'blur' },
          { validator: this.formValidate('userAccount', '账户名称只能是数字英文'), trigger: 'blur' },
          { max: 50, message: '账户名称最多为50个字符！', trigger: 'blur' }
        ],
        realName: [
          { required: true, message: '请输入真实姓名', trigger: 'blur' },
          { validator: this.formValidate('fullName', '真实姓名不能含有特殊符号'), trigger: 'blur' },
          { max: 50, message: '真实姓名最多为50个字符！', trigger: 'blur' }
        ],
        gender: [
          { required: true, message: '请选择性别', trigger: 'change' }
        ],
        organizeId: [
          { required: true, message: '请选择组织', trigger: 'change' }
        ],
        entryDate: [
          { required: true, message: '请选择入职时间', trigger: 'change' },
          {
            validator: (rule, value, callback) => {
              if (value === null || value === undefined || value === '') {
                callback(new Error('请选择入职时间'))
                return
              }
              if (typeof value === 'number' && value > 0) {
                callback()
                return
              }
              const t = new Date(value).getTime()
              if (!Number.isNaN(t)) {
                callback()
                return
              }
              callback(new Error('请选择有效的入职时间'))
            },
            trigger: 'change'
          }
        ],
        leaveDate: [
          {
            validator: (rule, value, callback) => {
              if (this.dataForm.isOnJob !== 0 && this.dataForm.isOnJob !== '0') {
                callback()
                return
              }
              if (value === null || value === undefined || value === '') {
                callback(new Error('离职状态请填写离职日期'))
                return
              }
              if (typeof value === 'number' && value > 0) {
                callback()
                return
              }
              const t = new Date(value).getTime()
              if (!Number.isNaN(t)) {
                callback()
                return
              }
              callback(new Error('请选择有效的离职日期'))
            },
            trigger: 'change'
          }
        ]
      }
    }
  },
  methods: {
    onIsOnJobChange(val) {
      if (val === 1 || val === '1') {
        this.dataForm.leaveDate = null
      }
      this.$nextTick(() => {
        if (this.$refs.dataForm) {
          this.$refs.dataForm.validateField('leaveDate')
        }
      })
    },
    auditActionIconClass(action) {
      const a = (action || '').toUpperCase()
      if (a.includes('PASSWORD') || a.includes('密码')) return 'user-audit-icon user-audit-icon--danger'
      if (a.includes('DELETE') || a.includes('删除')) return 'user-audit-icon user-audit-icon--warning'
      if (a.includes('SELF')) return 'user-audit-icon user-audit-icon--success'
      return 'user-audit-icon user-audit-icon--primary'
    },
    onUserFormTabClick(tab) {
      if (tab.name === 'audit' && this.dataForm.id) {
        this.fetchUserAuditLogs()
      }
      if (tab.name === 'profileVersion' && this.dataForm.id) {
        this.fetchUserProfileVersionLogs()
      }
    },
    fetchUserAuditLogs() {
      if (!this.dataForm.id) return
      this.auditLoading = true
      getUserProfileAuditLogs({
        targetUserId: this.dataForm.id,
        currentPage: this.auditParams.currentPage,
        pageSize: this.auditParams.pageSize
      }).then(res => {
        const rawList = (res.data && res.data.list) || []
        // 后端 Newtonsoft DefaultContractResolver 输出 PascalCase，表格需统一为 camelCase
        this.auditList = rawList.map(r => this.normalizeUserProfileAuditRow(r))
        this.auditTotal = (res.data.pagination && res.data.pagination.total) || 0
      }).catch(() => {
        this.auditList = []
        this.auditTotal = 0
      }).finally(() => {
        this.auditLoading = false
      })
    },
    /** 用户主档审计行：兼容 API 返回 PascalCase */
    profileVersionRowIconClass(versionNo) {
      const n = Number(versionNo) || 0
      const m = n % 3
      if (m === 0) return 'user-audit-icon user-audit-icon--primary'
      if (m === 1) return 'user-audit-icon user-audit-icon--success'
      return 'user-audit-icon user-audit-icon--muted'
    },
    fetchUserProfileVersionLogs() {
      if (!this.dataForm.id) return
      this.profileVersionLoading = true
      getUserProfileVersionLogs({
        targetUserId: this.dataForm.id,
        currentPage: this.profileVersionParams.currentPage,
        pageSize: this.profileVersionParams.pageSize
      }).then(res => {
        const rawList = (res.data && res.data.list) || []
        this.profileVersionList = rawList.map(r => this.normalizeUserProfileVersionRow(r))
        this.profileVersionTotal = (res.data.pagination && res.data.pagination.total) || 0
      }).catch(() => {
        this.profileVersionList = []
        this.profileVersionTotal = 0
      }).finally(() => {
        this.profileVersionLoading = false
      })
    },
    /** 用户主档版本行：兼容 API 返回 PascalCase */
    normalizeUserProfileVersionRow(row) {
      if (!row) return row
      const pick = (a, b) => (a !== undefined && a !== null ? a : b)
      return {
        id: pick(row.id, row.Id),
        targetUserId: pick(row.targetUserId, row.TargetUserId),
        versionNo: pick(row.versionNo, row.VersionNo),
        validFrom: pick(row.validFrom, row.ValidFrom),
        validTo: pick(row.validTo, row.ValidTo),
        operatorUserId: pick(row.operatorUserId, row.OperatorUserId),
        operatorUserName: pick(row.operatorUserName, row.OperatorUserName),
        changeTrigger: pick(row.changeTrigger, row.ChangeTrigger),
        mdid: pick(row.mdid, row.Mdid),
        gw: pick(row.gw, row.Gw),
        organizeId: pick(row.organizeId, row.OrganizeId),
        fullSnapshotJson: pick(row.fullSnapshotJson, row.FullSnapshotJson)
      }
    },
    openProfileVersionJsonDialog(row) {
      const r = this.normalizeUserProfileVersionRow(row)
      let text = ''
      try {
        const full = r.fullSnapshotJson ? JSON.parse(r.fullSnapshotJson) : null
        text = JSON.stringify(full, null, 2)
      } catch (e) {
        text = r.fullSnapshotJson || '无'
      }
      this.profileVersionJsonText = text || '无'
      this.profileVersionJsonVisible = true
    },
    handleRestoreUserProfileVersion(row) {
      const r = this.normalizeUserProfileVersionRow(row)
      const versionId = r && r.id
      if (!versionId) {
        this.$message.error('缺少版本主键，请刷新版本列表后重试')
        return
      }
      this.$confirm('确定将当前用户主档还原为该版本快照吗？未保存的编辑将丢失，并会新增一条版本记录；登录密码不会被改回历史。', '还原确认', {
        type: 'warning',
        confirmButtonText: '确定还原',
        cancelButtonText: '取消'
      }).then(() => {
        return restoreUserProfileVersion({ versionId })
      }).then(() => {
        this.$message.success('已还原')
        this.fetchUserProfileVersionLogs()
        if (this.dataForm.id) {
          return getUserInfo(this.dataForm.id)
        }
        return Promise.resolve(null)
      }).then(res => {
        if (res && res.data) {
          this.dataForm = this.normalizeUserFormPayload(res.data)
          if (this.dataForm.roleId) this.roleId = this.dataForm.roleId.split(',')
        }
      }).catch(err => {
        if (err === 'cancel' || err === 'close') return
      })
    },
    /** 用户详情：兼容 API 返回 camelCase / PascalCase，并补全在职状态默认值 */
    normalizeUserFormPayload(raw) {
      if (!raw) return raw
      const pick = (a, b) => (a !== undefined && a !== null ? a : b)
      const v = pick(raw.isOnJob, raw.IsOnJob)
      const isOnJob = v !== undefined && v !== null ? Number(v) : 1
      const leaveDate = pick(raw.leaveDate, raw.LeaveDate)
      return { ...raw, isOnJob, leaveDate: leaveDate != null ? leaveDate : null }
    },
    normalizeUserProfileAuditRow(row) {
      if (!row) return row
      const pick = (a, b) => (a !== undefined && a !== null ? a : b)
      return {
        id: pick(row.id, row.Id),
        targetUserId: pick(row.targetUserId, row.TargetUserId),
        operatorUserId: pick(row.operatorUserId, row.OperatorUserId),
        operatorUserName: pick(row.operatorUserName, row.OperatorUserName),
        operateTime: pick(row.operateTime, row.OperateTime),
        action: pick(row.action, row.Action),
        batchId: pick(row.batchId, row.BatchId),
        fieldKey: pick(row.fieldKey, row.FieldKey),
        fieldLabel: pick(row.fieldLabel, row.FieldLabel),
        oldValue: pick(row.oldValue, row.OldValue),
        newValue: pick(row.newValue, row.NewValue),
        source: pick(row.source, row.Source),
        clientIp: pick(row.clientIp, row.ClientIp),
        userAgent: pick(row.userAgent, row.UserAgent),
        remark: pick(row.remark, row.Remark)
      }
    },
    init(id, organizeId) {
      this.visible = true
      this.userFormTab = 'info'
      this.auditParams.currentPage = 1
      this.auditList = []
      this.auditTotal = 0
      this.profileVersionParams.currentPage = 1
      this.profileVersionList = []
      this.profileVersionTotal = 0
      this.dataForm.id = id || ''
      this.roleId = []
      this.$nextTick(() => {
        this.$refs['dataForm'].resetFields()

        // 获取公司+部门
        getDepartmentSelector().then(res => {
          this.departmentTreeData = res.data.list
        })


        // 获取角色
        getRoleSelector().then(res => {
          this.roleTreeData = res.data.list
        })

        // 获取民族
        this.$store.dispatch('base/getDictionaryData', { sort: 'Nation' }).then(res => {
          this.nationTreeData = res
        })

        // 获取学历
        this.$store.dispatch('base/getDictionaryData', { sort: 'Education' }).then(res => {
          this.educationTreeData = res
        })

        // 获取证件类型
        this.$store.dispatch('base/getDictionaryData', { sort: 'certificateType' }).then(res => {
          this.certificatesTypeTreeData = res
        })

        // 获取性别
        this.$store.dispatch('base/getDictionaryData', { sort: 'sex' }).then(res => {
          this.genderTreeData = res
        })

        // 获取门店数据
        getStoreSelector().then(res => {
          this.storeTreeData = res.data.list
        }).catch(() => {
          this.storeTreeData = []
        })

        getAttendanceGroupSelector().then(res => {
          this.attendanceGroupOptions = res.data.list || []
        }).catch(() => {
          this.attendanceGroupOptions = []
        })

        if (this.dataForm.id) {
          this.formLoading = true
          getUserInfo(this.dataForm.id).then(res => {
            this.dataForm = this.normalizeUserFormPayload(res.data)
            if (this.dataForm.roleId) this.roleId = this.dataForm.roleId.split(',')
            this.formLoading = false
          }).catch(() => this.formLoading = false)
        } else {
          this.dataForm.organizeId = organizeId
        }
      })
    },
    goBack() {
      this.$emit('close')
    },
    roleIdChange() {
      this.dataForm.roleId = this.roleId.toString()
    },
    handleAvatarSuccess(res) {
      if (res.code === 200 && res.data && res.data.url) {
        this.dataForm.headIcon = res.data.url
      } else {
        this.$message.error('头像上传失败');
      }
    },
    handleConfirm() {
      this.roleIdChange()
      this.$refs['dataForm'].validate((valid) => {
        if (valid) {
          this.btnLoading = true
          const formMethod = this.dataForm.id ? updateUser : createUser
          formMethod(this.dataForm).then(res => {
            this.$message({
              message: res.msg,
              type: 'success',
              duration: 1500,
              onClose: () => {
                this.visible = false
                this.btnLoading = false
                this.$emit('close', true)
              }
            })
          }).catch(() => {
            this.btnLoading = false
          })
        }
      })
    }
  }
}
</script>
<style lang="scss" scoped>
.user-form {
  .main {
    padding: 10px 30px 0;
  }

  .user-form-body {
    padding-bottom: 24px;
  }

  .user-form-card {
    margin-bottom: 16px;
    border-radius: 12px;

    ::v-deep .el-card__header {
      padding: 12px 16px;
      border-bottom: 1px solid #ebeef5;
    }

    ::v-deep .el-card__body {
      padding: 16px;
    }
  }

  .user-form-card__title {
    font-weight: 600;
    font-size: 15px;
    color: #303133;
  }

  .user-form-alert {
    margin-bottom: 16px;

    ::v-deep .el-alert__title {
      font-size: 13px;
      line-height: 1.5;
    }
  }

  ::v-deep .el-select,
  ::v-deep .el-date-editor {
    width: 100%;
  }

  ::v-deep .avatar-uploader {
    .el-upload {
      border: 1px dashed #dcdfe6;
      border-radius: 6px;
      cursor: pointer;
      position: relative;
      overflow: hidden;
    }

    .el-upload:hover {
      border-color: #409eff;
    }
  }

  .user-form-avatar-collapse {
    border: none;

    ::v-deep .el-collapse-item__header {
      height: auto;
      line-height: 1.5;
      padding: 8px 0;
      font-weight: normal;
      border-bottom: none;
    }

    ::v-deep .el-collapse-item__wrap {
      border-bottom: none;
    }

    ::v-deep .el-collapse-item__content {
      padding-bottom: 8px;
    }
  }

  .user-form-avatar-collapse__title {
    font-weight: 600;
    color: #303133;
    margin-right: 8px;
  }

  .user-form-avatar-collapse__hint {
    font-size: 12px;
    color: #909399;
    font-weight: normal;
  }

  .user-form-avatar-form-item {
    margin-bottom: 0;
  }

  .avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 130px;
    height: 130px;
    line-height: 130px;
    text-align: center;
  }

  .avatar-uploader-icon--sm {
    width: 88px;
    height: 88px;
    line-height: 88px;
    font-size: 22px;
  }

  .avatar {
    width: 130px;
    height: 130px;
    display: block;
  }

  .avatar--sm {
    width: 88px;
    height: 88px;
    object-fit: cover;
    border-radius: 6px;
  }

  ::v-deep .avatar-uploader--compact .el-upload {
    border-radius: 8px;
  }

  .user-form-tabs {
    ::v-deep .el-tabs__content {
      padding-top: 8px;
    }
  }

  .user-audit-toolbar {
    text-align: left;
    margin-bottom: 10px;
  }

  .user-audit-table {
    width: 100%;
  }

  .user-audit-icon {
    font-size: 16px;
  }

  .user-audit-icon--primary {
    color: #409eff;
  }

  .user-audit-icon--success {
    color: #67c23a;
  }

  .user-audit-icon--warning {
    color: #e6a23c;
  }

  .user-audit-icon--danger {
    color: #f56c6c;
  }

  .user-audit-icon--muted {
    color: #909399;
  }
}
</style>
<style lang="scss">
/* append-to-body 弹窗脱离 scoped，单独写 */
.user-profile-version-json-dialog .user-profile-version-json-pre {
  max-height: 480px;
  overflow: auto;
  margin: 0;
  padding: 12px;
  font-size: 12px;
  line-height: 1.45;
  background: #f5f7fa;
  border-radius: 8px;
  white-space: pre-wrap;
  word-break: break-all;
}
</style>
