Browse Source

人员档案增加暂存逻辑

cyy 1 week ago
parent
commit
46c40eacf6

+ 12 - 2
src/components/ibps-selector/dialog.vue

@@ -2,7 +2,7 @@
   <el-dialog
     v-if="dialogVisible"
     ref="dialog"
-    :show-close="showClose"
+    :show-close="showCloseVisible"
     :close-on-click-modal="closeOnClickModal"
     :close-on-press-escape="closeOnPressEscape"
     :visible.sync="dialogVisible"
@@ -148,7 +148,8 @@ export default {
   },
   data() {
     return {
-      dialogVisible: this.visible
+      dialogVisible: this.visible,
+      showCloseVisible: this.showClose
     }
   },
   computed: {
@@ -225,9 +226,18 @@ export default {
         this.dialogVisible = this.visible
       },
       immediate: true
+    },
+    showClose: {
+      handler(val) {
+        this.showCloseVisible = val
+      },
+      immediate: true
     }
   },
   methods: {
+    setShowClose(value) {
+      this.showCloseVisible = value
+    },
     handleLabel(data) {
       const config = this.labelKey
       if (data[this.labelKey + '_label_value']) {

+ 5 - 1
src/views/component/personnelFile/components/gzjlTag.vue

@@ -451,7 +451,11 @@ export default {
       )
     },
     submitForm(formName, val) {
-      // console.log('33333333333333333333')
+      if (this.btnType === 'temporaryStorage') {
+        this.$emit('changeBaseData', val, 'gzjl')
+        this.$emit('changeButtonShow', this.$parent.$parent.$parent.btnShow)
+        return
+      }
       this.$refs[formName].validate((valid) => {
         if (valid) {
           this.$emit('changeBaseData', val, 'gzjl')

+ 39 - 32
src/views/component/personnelFile/components/jbqkTag.vue

@@ -208,17 +208,19 @@
               />
             </el-form-item>
           </div>
-        </div>  
+        </div>
       </div>
-      <div class="rowSty"> 
+      <div class="rowSty">
         <div class="colSty">
           <div class="grid-content bg-purple">本岗位任职时间</div>
         </div>
         <div class="colSty">
           <div v-if="judgeTag()" class="grid-content bg-purple-light">
-            <div >
+            <div>
               {{
-                nowData.hasOwnProperty('renZhiShiJian') > 0 ? nowData.renZhiShiJian : '/'
+                nowData.hasOwnProperty('renZhiShiJian') > 0
+                  ? nowData.renZhiShiJian
+                  : '/'
               }}
             </div>
           </div>
@@ -232,7 +234,7 @@
               />
             </el-form-item>
           </div>
-        </div>  
+        </div>
         <div class="colSty">
           <div class="grid-content bg-purple">职务</div>
         </div>
@@ -434,7 +436,7 @@
           <div class="grid-content bg-purple-light">
             <el-form-item prop="sheBao">
               <ibps-attachment
-                v-model="nowData.fujIan"
+                v-model="nowData.fuJian"
                 :download="true"
                 multiple
                 accept="*"
@@ -511,25 +513,25 @@ export default {
   watch: {
     // 监听入职日期变化
     // 'nowData.ruZhiShiJian': {
-      // handler(newVal) {
-        // if (newVal) {
-          // this.calculateWorkYears(newVal, 'benZhuanYeGong')
-        // } else {
-          // this.nowData.benZhuanYeGong = 0
-        // }
-      // },
-      // immediate: true
+    // handler(newVal) {
+    // if (newVal) {
+    // this.calculateWorkYears(newVal, 'benZhuanYeGong')
+    // } else {
+    // this.nowData.benZhuanYeGong = 0
+    // }
+    // },
+    // immediate: true
     // },
     // 监听入职日期变化
     // 'nowData.canJiaGongZuo': {
-      // handler(newVal) {
-        // if (newVal) {
-          // this.calculateWorkYears(newVal, 'gongZuoNianXia')
-        // } else {
-          // this.nowData.gongZuoNianXia = 0
-        // }
-      // },
-      // immediate: true
+    // handler(newVal) {
+    // if (newVal) {
+    // this.calculateWorkYears(newVal, 'gongZuoNianXia')
+    // } else {
+    // this.nowData.gongZuoNianXia = 0
+    // }
+    // },
+    // immediate: true
     // },
     //监听身份证变化
     'nowData.shenFenZhengHao': {
@@ -568,10 +570,10 @@ export default {
           }, 0)
         }
         // if(this.nowData.ruZhiShiJian){
-          // this.calculateWorkYears(this.nowData.ruZhiShiJian, 'benZhuanYeGong')
+        // this.calculateWorkYears(this.nowData.ruZhiShiJian, 'benZhuanYeGong')
         // }
         // if(this.nowData.canJiaGongZuo){
-          // this.calculateWorkYears(this.nowData.canJiaGongZuo, 'gongZuoNianXia')
+        // this.calculateWorkYears(this.nowData.canJiaGongZuo, 'gongZuoNianXia')
         // }
       },
       deep: true,
@@ -599,19 +601,19 @@ export default {
     // calculateWorkYears(entryDate, type) {
     //  const startDate = new Date(entryDate)
     //  const now = new Date()
-    //  
+    //
     //  let years = now.getFullYear() - startDate.getFullYear()
     //  const monthDiff = now.getMonth() - startDate.getMonth()
-    //  
+    //
     //  if (monthDiff < 0 || (monthDiff === 0 && now.getDate() < startDate.getDate())) {
-      //  years--
+    //  years--
     //  }
     //  console.log('calculateWorkYears', years)
-      // if(type == 'benZhuanYeGong'){
-        // this.$set(this.nowData, 'benZhuanYeGong', years > 0 ? years : '0')
-      // }else{
-        // this.$set(this.nowData, 'gongZuoNianXia', years > 0 ? years : '0')
-      // }
+    // if(type == 'benZhuanYeGong'){
+    // this.$set(this.nowData, 'benZhuanYeGong', years > 0 ? years : '0')
+    // }else{
+    // this.$set(this.nowData, 'gongZuoNianXia', years > 0 ? years : '0')
+    // }
     // },
     judgeTag() {
       // return this.planeData.length>0&& this.btnShow === true && this.buttonType!==1 ? true : false
@@ -622,6 +624,11 @@ export default {
       )
     },
     submitForm(formName, val) {
+      if (this.btnType === 'temporaryStorage') {
+        this.$emit('changeBaseData', val, 'ryjbqk')
+        this.$emit('changeButtonShow', this.$parent.$parent.$parent.btnShow)
+        return
+      }
       this.$refs[formName].validate((valid) => {
         if (valid) {
           this.$emit('changeBaseData', val, 'ryjbqk')

+ 5 - 0
src/views/component/personnelFile/components/jyjlTag.vue

@@ -413,6 +413,11 @@ export default {
       )
     },
     submitForm(formName, val) {
+      if (this.btnType === 'temporaryStorage') {
+        this.$emit('changeBaseData', val, 'jyjl')
+        this.$emit('changeButtonShow', this.$parent.$parent.$parent.btnShow)
+        return
+      }
       this.$refs[formName].validate((valid) => {
         if (valid) {
           this.$emit('changeBaseData', val, 'jyjl')

+ 35 - 11
src/views/component/personnelFile/components/personnelInfo.vue

@@ -15,9 +15,7 @@
           fit="fit"
           @error="errorHandler"
         >
-          <img
-            src="../../../../../public/images/common/default_user_image.jpg"
-          />
+          <img src="/images/common/default_user_image.jpg" />
         </el-avatar>
       </div>
       <div class="contentSty">
@@ -59,7 +57,6 @@
               >流程图</el-button
             >
             <!-- <el-button type="primary" icon="el-icon-picture" @click="changeButton('flowChart')">流程图</el-button> -->
-            <!-- <el-button v-if="buttonType===0&&buttonShow===false" type="primary" icon="ibps-icon-save" @click="changeButton('temporaryStorage')">暂存</el-button> -->
             <el-button
               v-if="buttonType === 0 && buttonShow === false"
               type="primary"
@@ -89,12 +86,35 @@
               >退回</el-button
             >
             <el-button
-              v-if="buttonType === 0 && buttonShow === true"
+              v-if="
+                buttonType === 0 &&
+                buttonShow === true &&
+                type !== 'dialog' &&
+                hasDraftData
+              "
+              type="primary"
+              icon="el-icon-edit-outline"
+              @click="changeButtonShow(false, 'continueEdit')"
+              >继续编辑</el-button
+            >
+            <el-button
+              v-if="
+                buttonType === 0 &&
+                buttonShow === true &&
+                (type === 'dialog' || !hasDraftData)
+              "
               type="primary"
               icon="el-icon-edit-outline"
               @click="changeButtonShow(false, 'edit')"
               >编辑</el-button
             >
+            <el-button
+              v-if="buttonType === 0 && buttonShow === false"
+              type="primary"
+              icon="ibps-icon-save"
+              @click="changeButton('temporaryStorage')"
+              >暂存</el-button
+            >
             <el-button
               v-if="buttonType === 0 && buttonShow === false"
               type="warning"
@@ -304,6 +324,10 @@ export default {
     btnType: {
       type: String,
       default: ''
+    },
+    hasDraftData: {
+      type: Boolean,
+      default: false
     }
   },
   data() {
@@ -321,8 +345,8 @@ export default {
   },
   watch: {
     personInfoData: {
-      handler: function (val, oldVal) {
-        if (Object.keys(val).length > 0) {
+      handler: function (val) {
+        if (val && typeof val === 'object' && Object.keys(val).length > 0) {
           // eslint-disable-next-line no-undef
           this.submitperInfoData = structuredClone(val)
         }
@@ -383,8 +407,8 @@ export default {
                 obj.activeName = 'ryjbqk'
                 obj.activeNameTab = 'ryjbqk'
               }
-              this.$emit('changeBtnShow', val)
-              this.changeButton(name)
+              this.$emit('changeBtnShow', val, name === 'continueEdit')
+              this.changeButton(name === 'continueEdit' ? 'edit' : name)
             }
           })
       } else {
@@ -395,8 +419,8 @@ export default {
         if (typeof obj !== 'undefined') {
           obj.activeName = 'ryjbqk'
         }
-        this.$emit('changeBtnShow', val)
-        this.changeButton(name)
+        this.$emit('changeBtnShow', val, name === 'continueEdit')
+        this.changeButton(name === 'continueEdit' ? 'edit' : name)
       }
     },
     changeButton(val) {

+ 5 - 0
src/views/component/personnelFile/components/zsbTag.vue

@@ -410,6 +410,11 @@ export default {
       )
     },
     submitForm(formName, val) {
+      if (this.btnType === 'temporaryStorage') {
+        this.$emit('changeBaseData', val, 'zsb')
+        this.$emit('changeButtonShow', this.$parent.$parent.$parent.btnShow)
+        return
+      }
       this.$refs[formName].validate((valid) => {
         if (valid) {
           this.$emit('changeBaseData', val, 'zsb')

+ 779 - 0
src/views/component/personnelFile/constants/draftSql.js

@@ -0,0 +1,779 @@
+/**
+ * 人员档案暂存查询 key 及对应 SQL
+ * 需在后台通用查询脚本中配置相同 key
+ */
+export const draftQueryKeys = {
+  main: 'getRydaZcxxbByRenYuan',
+  jbqk: 'getRydaJbqkzcByParentId',
+  jyjl: 'getRydaJyjlzcByParentId',
+  gzjl: 'getRydaGzjlzcByParentId',
+  zsb: 'getRydaZsbzcByParentId'
+}
+
+export const draftQuerySql = {
+  // params: [renYuan, zhuangTai]
+  [draftQueryKeys.main]:
+    'SELECT * FROM t_rydazcxxb WHERE renYuan = ? AND zhuangTai = ? ORDER BY create_time_ DESC LIMIT 1',
+  // params: [parentId]
+  [draftQueryKeys.jbqk]: 'SELECT * FROM t_jbqkxxzc WHERE parentId = ?',
+  [draftQueryKeys.jyjl]:
+    'SELECT * FROM t_jyjlzc WHERE parentId = ? ORDER BY create_time_ ASC',
+  [draftQueryKeys.gzjl]:
+    'SELECT * FROM t_gzjlzc WHERE parentId = ? ORDER BY create_time_ ASC',
+  [draftQueryKeys.zsb]:
+    'SELECT * FROM t_zsbzc WHERE parentId = ? ORDER BY create_time_ ASC'
+}
+
+export const draftChildQueryKeys = {
+  t_jbqkxxzc: draftQueryKeys.jbqk,
+  t_jyjlzc: draftQueryKeys.jyjl,
+  t_gzjlzc: draftQueryKeys.gzjl,
+  t_zsbzc: draftQueryKeys.zsb
+}
+
+/** 暂存表单 formKey */
+export const draftFormKey = 'rydazcljgxbdqddmsy'
+
+/** 暂存表单 boCode */
+export const draftBoCode = 'rydazcxxb'
+
+/**
+ * 查询结果下划线字段 → 代码驼峰字段
+ * (与 BO / 数据库列名一致)
+ */
+export const draftSnakeToCamelMap = {
+  zhuang_tai_: 'zhuangTai',
+  ren_yuan_: 'renYuan',
+  parent_id_: 'parentId',
+  shi_fou_guo_shen_: 'shiFouGuoShen',
+  di_dian_: 'diDian',
+  bian_zhi_ren_: 'bianZhiRen',
+  bian_zhi_bu_men_: 'bianZhiBuMen',
+  bian_zhi_shi_jian_: 'bianZhiShiJian',
+  kuai_zhao_: 'kuaiZhao',
+  jian_dang_ri_qi_: 'jianDangRiQi',
+  nian_ling_: 'nianLing',
+  chu_sheng_ri_qi_: 'chuShengRiQi',
+  zui_gao_xue_li_x_: 'zuiGaoXueLiX',
+  yuan_bi_ye_yuan_x: 'yuanBiYeYuanXi',
+  yuan_bi_ye_yuan_xi_: 'yuanBiYeYuanXi',
+  xian_cong_shi_zhu: 'xianCongShiZhua',
+  xian_cong_shi_zhua_: 'xianCongShiZhua',
+  can_jia_gong_zuo: 'canJiaGongZuo',
+  can_jia_gong_zuo_: 'canJiaGongZuo',
+  ru_zhi_shi_jian_: 'ruZhiShiJian',
+  ren_zhi_shi_jian_: 'renZhiShiJian',
+  xing_zheng_zhi_wu: 'xingZhengZhiWu',
+  xing_zheng_zhi_wu_: 'xingZhengZhiWu',
+  zhi_cheng_deng_ji: 'zhiChengDengJi',
+  zhi_cheng_deng_ji_: 'zhiChengDengJi',
+  zhi_cheng_: 'zhiCheng',
+  shen_fen_zheng_ha: 'shenFenZhengHao',
+  shen_fen_zheng_hao_: 'shenFenZhengHao',
+  ren_yuan_lei_xing: 'renYuanLeiXing',
+  ren_yuan_lei_xing_: 'renYuanLeiXing',
+  bao_mi_xie_yi_: 'baoMiXieYi',
+  qian_zi_tu_wen_: 'qianZiTuWen',
+  cheng_nuo_han_: 'chengNuoHan',
+  she_bao_: 'sheBao',
+  fu_jian_: 'fuJian',
+  kai_shi_shi_jian_: 'kaiShiShiJian',
+  jie_shu_shi_jian_: 'jieShuShiJian',
+  xue_xiao_: 'xueXiao',
+  zhuan_ye_: 'zhuanYe',
+  xue_li_xue_wei_: 'xueLiXueWei',
+  li_zhi_shi_jian_: 'liZhiShiJian',
+  dan_wei_ming_chen: 'danWeiMingCheng',
+  dan_wei_ming_cheng_: 'danWeiMingCheng',
+  zhi_wei_: 'zhiWei',
+  bu_men_: 'buMen',
+  gong_zuo_nei_rong: 'gongZuoNeiRong',
+  gong_zuo_nei_rong_: 'gongZuoNeiRong',
+  zheng_shu_ming_c_: 'zhengShuMingC',
+  zheng_jian_hao_: 'zhengJianHao',
+  fa_zheng_dan_wei_: 'faZhengDanWei',
+  fa_zheng_shi_jian: 'faZhengShiJian',
+  fa_zheng_shi_jian_: 'faZhengShiJian',
+  dang_an_bao_cun_: 'dangAnBaoCun',
+  huo_jiang_zheng_s: 'huoJiangZhengS',
+  huo_jiang_zheng_s_: 'huoJiangZhengS'
+}
+
+/** 日期类字段(el-date-picker 需要 yyyy-MM-dd 字符串) */
+const draftDateFields = [
+  'bianZhiShiJian',
+  'jianDangRiQi',
+  'chuShengRiQi',
+  'canJiaGongZuo',
+  'ruZhiShiJian',
+  'renZhiShiJian',
+  'kaiShiShiJian',
+  'jieShuShiJian',
+  'liZhiShiJian',
+  'faZhengShiJian'
+]
+
+function toYmd(date) {
+  const y = date.getFullYear()
+  const m = String(date.getMonth() + 1).padStart(2, '0')
+  const d = String(date.getDate()).padStart(2, '0')
+  return `${y}-${m}-${d}`
+}
+
+/** 将时间戳 / Date 等非字符串日期转为 yyyy-MM-dd */
+function formatDraftDateValue(value) {
+  if (value === undefined || value === null || value === '') {
+    return value === null ? '' : value
+  }
+  if (typeof value === 'string') {
+    const trimmed = value.trim()
+    if (!trimmed) {
+      return ''
+    }
+    if (/^\d{4}-\d{2}-\d{2}/.test(trimmed)) {
+      return trimmed.substring(0, 10)
+    }
+    if (/^\d{10,13}$/.test(trimmed)) {
+      return formatDraftDateValue(Number(trimmed))
+    }
+    const parsed = new Date(trimmed)
+    if (!isNaN(parsed.getTime()) && trimmed.length >= 8) {
+      return toYmd(parsed)
+    }
+    return trimmed
+  }
+  if (typeof value === 'number' && !Number.isNaN(value)) {
+    let parsed
+    if (value > 1e11) {
+      parsed = new Date(value)
+    } else if (value > 1e9) {
+      parsed = new Date(value * 1000)
+    }
+    if (parsed && !isNaN(parsed.getTime())) {
+      return toYmd(parsed)
+    }
+    return String(value)
+  }
+  if (value instanceof Date && !isNaN(value.getTime())) {
+    return toYmd(value)
+  }
+  return ''
+}
+
+function normalizeDraftDateFields(result = {}) {
+  draftDateFields.forEach((camelKey) => {
+    const snakeKeys = Object.keys(draftSnakeToCamelMap).filter(
+      (k) => draftSnakeToCamelMap[k] === camelKey
+    )
+    ;[camelKey, ...snakeKeys].forEach((key) => {
+      if (
+        result[key] !== undefined &&
+        result[key] !== null &&
+        result[key] !== ''
+      ) {
+        result[key] = formatDraftDateValue(result[key])
+      }
+    })
+    if (result[camelKey] && snakeKeys.length) {
+      snakeKeys.forEach((snakeKey) => {
+        result[snakeKey] = result[camelKey]
+      })
+    }
+  })
+  if (
+    result.nian_ling_ !== undefined &&
+    result.nian_ling_ !== null &&
+    result.nian_ling_ !== ''
+  ) {
+    const age = Number(result.nian_ling_)
+    if (!Number.isNaN(age)) {
+      result.nianLing = age
+    }
+  } else if (
+    result.nianLing !== undefined &&
+    result.nianLing !== null &&
+    result.nianLing !== ''
+  ) {
+    const age = Number(result.nianLing)
+    if (!Number.isNaN(age)) {
+      result.nianLing = age
+    }
+  }
+  return result
+}
+
+/** 将 query 返回的单行数据转为驼峰字段名 */
+export function normalizeDraftQueryRow(row = {}) {
+  if (!row || typeof row !== 'object') {
+    return row
+  }
+  const result = { ...row }
+  Object.keys(draftSnakeToCamelMap).forEach((snakeKey) => {
+    const camelKey = draftSnakeToCamelMap[snakeKey]
+    if (
+      result[snakeKey] !== undefined &&
+      result[snakeKey] !== null &&
+      (result[camelKey] === undefined || result[camelKey] === null || result[camelKey] === '')
+    ) {
+      result[camelKey] = result[snakeKey]
+    }
+  })
+  if (result.id_ !== undefined && (result.id === undefined || result.id === '')) {
+    result.id = result.id_
+  }
+  if (
+    result.parent_id_ !== undefined &&
+    (result.parentId === undefined || result.parentId === '')
+  ) {
+    result.parentId = result.parent_id_
+  }
+  return normalizeDraftDateFields(result)
+}
+
+/** 将 query 返回的多行数据转为驼峰字段名 */
+export function normalizeDraftQueryRows(rows = []) {
+  return (rows || []).map((row) => normalizeDraftQueryRow(row))
+}
+
+function normalizeGzjlRowForPage(row = {}) {
+  const normalized = { ...row }
+  if (
+    normalized.danWeiMingCheng !== undefined &&
+    normalized.danWeiMingCheng !== null &&
+    normalized.danWeiMingCheng !== ''
+  ) {
+    normalized.danWeiMingChen =
+      normalized.danWeiMingChen || normalized.danWeiMingCheng
+  } else if (
+    normalized.danWeiMingChen !== undefined &&
+    normalized.danWeiMingChen !== null &&
+    normalized.danWeiMingChen !== ''
+  ) {
+    normalized.danWeiMingCheng =
+      normalized.danWeiMingCheng || normalized.danWeiMingChen
+  }
+  return normalized
+}
+
+function hasDraftValue(val) {
+  return val !== undefined && val !== null && val !== ''
+}
+
+function formatDraftFieldValue(camelKey, val) {
+  if (!hasDraftValue(val)) {
+    return ''
+  }
+  return draftDateFields.includes(camelKey) ? formatDraftDateValue(val) : val
+}
+
+/**
+ * 读取 VO 字段值:优先同名属性,其次别名/下划线对应关系
+ */
+function getDraftFieldValue(source = {}, camelKey) {
+  if (hasDraftValue(source[camelKey])) {
+    return formatDraftFieldValue(camelKey, source[camelKey])
+  }
+  const aliases = draftFieldAliasMap[camelKey] || []
+  for (const alias of aliases) {
+    if (hasDraftValue(source[alias])) {
+      return formatDraftFieldValue(camelKey, source[alias])
+    }
+  }
+  const snakeKeys = Object.keys(draftSnakeToCamelMap).filter(
+    (k) => draftSnakeToCamelMap[k] === camelKey
+  )
+  for (const snakeKey of snakeKeys) {
+    if (hasDraftValue(source[snakeKey])) {
+      return formatDraftFieldValue(camelKey, source[snakeKey])
+    }
+  }
+  return ''
+}
+
+function getDraftFieldValueFromSources(sources = [], camelKey) {
+  for (const source of sources) {
+    const val = getDraftFieldValue(source || {}, camelKey)
+    if (val !== '') {
+      return val
+    }
+  }
+  return ''
+}
+
+const draftCommonChildFields = [
+  'id',
+  'parentId',
+  'shiFouGuoShen',
+  'diDian',
+  'bianZhiRen',
+  'bianZhiBuMen',
+  'bianZhiShiJian',
+  'kuaiZhao'
+]
+
+const draftJbqkFields = [
+  'jianDangRiQi',
+  'nianLing',
+  'chuShengRiQi',
+  'zuiGaoXueLiX',
+  'yuanBiYeYuanXi',
+  'xianCongShiZhua',
+  'canJiaGongZuo',
+  'ruZhiShiJian',
+  'renZhiShiJian',
+  'xingZhengZhiWu',
+  'zhiChengDengJi',
+  'zhiCheng',
+  'shenFenZhengHao',
+  'renYuanLeiXing',
+  'baoMiXieYi',
+  'qianZiTuWen',
+  'chengNuoHan',
+  'sheBao',
+  'fuJian'
+]
+
+const draftJyjlFields = [
+  'kaiShiShiJian',
+  'jieShuShiJian',
+  'xueXiao',
+  'zhuanYe',
+  'xueLiXueWei',
+  'fuJian'
+]
+
+const draftGzjlFields = [
+  'ruZhiShiJian',
+  'liZhiShiJian',
+  'danWeiMingCheng',
+  'zhiWei',
+  'buMen',
+  'gongZuoNeiRong'
+]
+
+const draftZsbFields = [
+  'zhengShuMingC',
+  'zhengJianHao',
+  'faZhengDanWei',
+  'faZhengShiJian',
+  'dangAnBaoCun',
+  'huoJiangZhengS'
+]
+
+function pickFields(source = {}, fields = []) {
+  const result = {}
+  fields.forEach((key) => {
+    result[key] = getDraftFieldValue(source, key)
+  })
+  return result
+}
+
+function toPlainObject(value) {
+  if (value === undefined || value === null) {
+    return value
+  }
+  try {
+    return JSON.parse(JSON.stringify(value))
+  } catch (error) {
+    return { ...value }
+  }
+}
+
+function toDraftVoString(val) {
+  if (val === undefined || val === null) {
+    return ''
+  }
+  return String(val)
+}
+
+function flattenFirstRowFields(rows = [], fields = []) {
+  const result = {}
+  fields.forEach((key) => {
+    result[key] = rows.length ? toDraftVoString(rows[0][key]) : ''
+  })
+  return result
+}
+
+function buildDraftChildVoRow(
+  item = {},
+  parentId,
+  mainMeta,
+  businessFields,
+  index,
+  isNewDraft = false
+) {
+  const source = toPlainObject(item)
+  const normalized = normalizeDraftQueryRow(source)
+  const row = {}
+  draftCommonChildFields.forEach((key) => {
+    if (key === 'parentId') {
+      row.parentId = toDraftVoString(
+        parentId ||
+          (isNewDraft ? '' : getDraftFieldValue(normalized, 'parentId')) ||
+          ''
+      )
+      return
+    }
+    if (key === 'id') {
+      row.id = toDraftVoString(
+        isNewDraft ? '' : getDraftFieldValue(normalized, 'id')
+      )
+      return
+    }
+    const selfVal = getDraftFieldValue(normalized, key)
+    row[key] = toDraftVoString(
+      selfVal !== '' ? selfVal : getDraftFieldValue(mainMeta, key) || ''
+    )
+  })
+  businessFields.forEach((key) => {
+    row[key] = toDraftVoString(getDraftFieldValue(normalized, key))
+  })
+  row.$index = index
+  return row
+}
+
+function mapDraftChildRow(
+  item = {},
+  parentId,
+  mainMeta,
+  fields,
+  index = 0,
+  isNewDraft = false
+) {
+  return buildDraftChildVoRow(
+    item,
+    parentId,
+    mainMeta,
+    fields,
+    index,
+    isNewDraft
+  )
+}
+
+function normalizeJbqkRow(row = {}) {
+  const normalized = { ...row }
+  if (normalized.fuJian !== undefined && normalized.fuJian !== '') {
+    normalized.fujIan = normalized.fuJian
+  } else if (normalized.fujIan !== undefined && normalized.fujIan !== '') {
+    normalized.fuJian = normalized.fujIan
+  }
+  return normalized
+}
+
+export { normalizeJbqkRow }
+
+function hasDraftFieldValues(row = {}, fields = []) {
+  return fields.some(
+    (key) => row[key] !== undefined && row[key] !== null && row[key] !== ''
+  )
+}
+
+/**
+ * 将 VO / 暂存表查询结果转为页面 personInfoData 子表结构
+ */
+export function parseDraftVoToPageData(voData = {}) {
+  const normalizedVo = normalizeDraftQueryRow(voData)
+  let jbqkList = (voData.jbqkxxzc || []).map((row) =>
+    normalizeJbqkRow(normalizeDraftQueryRow(row))
+  )
+  let jyjlList = (voData.jyjlzc || []).map((row) => normalizeDraftQueryRow(row))
+  let gzjlList = (voData.gzjlzc || []).map((row) =>
+    normalizeGzjlRowForPage(normalizeDraftQueryRow(row))
+  )
+  let zsbList = (voData.zsbzc || []).map((row) => normalizeDraftQueryRow(row))
+
+  if (!jbqkList.length || !hasDraftFieldValues(jbqkList[0], draftJbqkFields)) {
+    const fromRoot = normalizeJbqkRow({
+      ...(jbqkList[0] || {}),
+      ...pickFields(normalizedVo, draftJbqkFields),
+      parentId:
+        jbqkList[0]?.parentId || normalizedVo.id || normalizedVo.id_ || ''
+    })
+    if (hasDraftFieldValues(fromRoot, draftJbqkFields)) {
+      jbqkList = [fromRoot]
+    }
+  }
+  if (!jyjlList.length || !hasDraftFieldValues(jyjlList[0], draftJyjlFields)) {
+    const fromRoot = {
+      ...(jyjlList[0] || {}),
+      ...pickFields(normalizedVo, draftJyjlFields),
+      parentId:
+        jyjlList[0]?.parentId || normalizedVo.id || normalizedVo.id_ || ''
+    }
+    if (hasDraftFieldValues(fromRoot, draftJyjlFields)) {
+      jyjlList = [fromRoot]
+    }
+  }
+  if (!gzjlList.length || !hasDraftFieldValues(gzjlList[0], draftGzjlFields)) {
+    const fromRoot = normalizeGzjlRowForPage({
+      ...(gzjlList[0] || {}),
+      ...pickFields(normalizedVo, draftGzjlFields),
+      parentId:
+        gzjlList[0]?.parentId || normalizedVo.id || normalizedVo.id_ || ''
+    })
+    if (hasDraftFieldValues(fromRoot, draftGzjlFields)) {
+      gzjlList = [fromRoot]
+    }
+  }
+  if (!zsbList.length || !hasDraftFieldValues(zsbList[0], draftZsbFields)) {
+    const fromRoot = {
+      ...(zsbList[0] || {}),
+      ...pickFields(normalizedVo, draftZsbFields),
+      parentId:
+        zsbList[0]?.parentId || normalizedVo.id || normalizedVo.id_ || ''
+    }
+    if (hasDraftFieldValues(fromRoot, draftZsbFields)) {
+      zsbList = [fromRoot]
+    }
+  }
+
+  return {
+    ryjbqkInfoPoList: jbqkList,
+    educationInfoPoList: jyjlList,
+    workInfoPoList: gzjlList,
+    certificateInfoPoList: zsbList
+  }
+}
+
+/**
+ * VO 字段 → 页面别名字段(同名优先,此处为次级对应关系)
+ */
+export const draftFieldAliasMap = {
+  fuJian: ['fujIan'],
+  danWeiMingCheng: ['danWeiMingChen']
+}
+
+/**
+ * 页面 personInfoData 子表 → VO 子表字段名
+ */
+export const pageToDraftChildMap = {
+  ryjbqkInfoPoList: 'jbqkxxzc',
+  educationInfoPoList: 'jyjlzc',
+  workInfoPoList: 'gzjlzc',
+  certificateInfoPoList: 'zsbzc'
+}
+
+const draftPersonHeaderFields = [
+  'name',
+  'jianDingZiGeZ',
+  'gender',
+  'mobile',
+  'email',
+  'photo',
+  'status'
+]
+
+function buildPersonHeaderSnapshot(data = {}) {
+  const snapshot = {}
+  draftPersonHeaderFields.forEach((key) => {
+    const val = data[key]
+    if (val !== undefined && val !== null && val !== '') {
+      snapshot[key] = val
+    }
+  })
+  if (!Object.keys(snapshot).length) {
+    return data.kuaiZhao || ''
+  }
+  try {
+    return JSON.stringify(snapshot)
+  } catch (error) {
+    return data.kuaiZhao || ''
+  }
+}
+
+export function parsePersonHeaderSnapshot(kuaiZhao = '') {
+  if (!kuaiZhao || typeof kuaiZhao !== 'string') {
+    return {}
+  }
+  const trimmed = kuaiZhao.trim()
+  if (!trimmed.startsWith('{')) {
+    return {}
+  }
+  try {
+    const parsed = JSON.parse(trimmed)
+    return parsed && typeof parsed === 'object' ? parsed : {}
+  } catch (error) {
+    return {}
+  }
+}
+
+/**
+ * 将页面 personInfoData 转为 saveFormData/vo 所需 data 结构
+ */
+export function buildDraftVoData(data = {}, options = {}) {
+  return buildDraftFormData({
+    ...options,
+    personInfoData: data
+  })
+}
+
+/**
+ * 组装 saveFormData/vo 的 data 字段
+ * 结构:
+ * {
+ *   id, shiFouGuoShen, diDian, bianZhiRen, bianZhiBuMen, bianZhiShiJian, kuaiZhao, zhuangTai, renYuan,
+ *   jbqkxxzc: [...], jyjlzc: [...], gzjlzc: [...], zsbzc: [...],
+ *   ...jbqk/jyjl/gzjl/zsb 首行字段平铺
+ * }
+ */
+export function buildDraftFormData({
+  draftMainId = '',
+  renYuan = '',
+  personInfoData = {},
+  userId = '',
+  zhuangTai = '已暂存'
+}) {
+  const safePersonInfoData =
+    personInfoData && typeof personInfoData === 'object' ? personInfoData : {}
+  const jbqkSrc = safePersonInfoData.ryjbqkInfoPoList?.[0] || {}
+  const jyjlSrc = safePersonInfoData.educationInfoPoList || []
+  const gzjlSrc = safePersonInfoData.workInfoPoList || []
+  const zsbSrc = safePersonInfoData.certificateInfoPoList || []
+  const parentId = draftMainId || ''
+  const isNewDraft = !parentId
+
+  const mainMeta = {
+    shiFouGuoShen: getDraftFieldValueFromSources(
+      [jbqkSrc, safePersonInfoData],
+      'shiFouGuoShen'
+    ),
+    diDian: getDraftFieldValueFromSources(
+      [safePersonInfoData, jbqkSrc],
+      'diDian'
+    ),
+    bianZhiRen:
+      getDraftFieldValueFromSources(
+        [safePersonInfoData, jbqkSrc],
+        'bianZhiRen'
+      ) ||
+      userId ||
+      '',
+    bianZhiBuMen: getDraftFieldValueFromSources(
+      [safePersonInfoData, jbqkSrc],
+      'bianZhiBuMen'
+    ),
+    bianZhiShiJian: getDraftFieldValueFromSources(
+      [safePersonInfoData, jbqkSrc],
+      'bianZhiShiJian'
+    ),
+    kuaiZhao: getDraftFieldValueFromSources(
+      [safePersonInfoData, jbqkSrc],
+      'kuaiZhao'
+    )
+  }
+
+  const jbqkxxzc = safePersonInfoData.ryjbqkInfoPoList?.length
+    ? [
+        buildDraftChildVoRow(
+          jbqkSrc,
+          parentId,
+          mainMeta,
+          draftJbqkFields,
+          0,
+          isNewDraft
+        )
+      ]
+    : []
+  const jyjlzc = jyjlSrc.map((item, index) =>
+    buildDraftChildVoRow(
+      item,
+      parentId,
+      mainMeta,
+      draftJyjlFields,
+      index,
+      isNewDraft
+    )
+  )
+  const gzjlzc = gzjlSrc.map((item, index) =>
+    buildDraftChildVoRow(
+      item,
+      parentId,
+      mainMeta,
+      draftGzjlFields,
+      index,
+      isNewDraft
+    )
+  )
+  const zsbzc = zsbSrc.map((item, index) =>
+    buildDraftChildVoRow(
+      item,
+      parentId,
+      mainMeta,
+      draftZsbFields,
+      index,
+      isNewDraft
+    )
+  )
+
+  return {
+    id: toDraftVoString(parentId),
+    shiFouGuoShen: toDraftVoString(mainMeta.shiFouGuoShen),
+    diDian: toDraftVoString(mainMeta.diDian),
+    bianZhiRen: toDraftVoString(mainMeta.bianZhiRen),
+    bianZhiBuMen: toDraftVoString(mainMeta.bianZhiBuMen),
+    bianZhiShiJian: toDraftVoString(mainMeta.bianZhiShiJian),
+    kuaiZhao: toDraftVoString(mainMeta.kuaiZhao),
+    zhuangTai: toDraftVoString(zhuangTai),
+    renYuan: toDraftVoString(renYuan),
+    jbqkxxzc,
+    jyjlzc,
+    gzjlzc,
+    zsbzc,
+    ...flattenFirstRowFields(jbqkxxzc, draftJbqkFields),
+    ...flattenFirstRowFields(jyjlzc, draftJyjlFields),
+    ...flattenFirstRowFields(gzjlzc, draftGzjlFields),
+    ...flattenFirstRowFields(zsbzc, draftZsbFields)
+  }
+}
+
+/** 暂存相关表名 */
+export const draftTableNames = {
+  main: 't_rydazcxxb',
+  jbqk: 't_jbqkxxzc',
+  jyjl: 't_jyjlzc',
+  gzjl: 't_gzjlzc',
+  zsb: 't_zsbzc'
+}
+
+/**
+ * 构建提交后更新暂存主表状态的 update 参数
+ */
+export function buildDraftSubmittedUpdateParams(
+  parentId = '',
+  zhuangTai = '已提交'
+) {
+  if (!parentId) {
+    return []
+  }
+  return [
+    {
+      tableName: draftTableNames.main,
+      updList: [
+        {
+          where: { id_: parentId },
+          param: { zhuang_tai_: zhuangTai }
+        }
+      ]
+    }
+  ]
+}
+
+export default {
+  draftQueryKeys,
+  draftQuerySql,
+  draftChildQueryKeys,
+  draftTableNames,
+  draftFormKey,
+  draftBoCode,
+  pageToDraftChildMap,
+  draftFieldAliasMap,
+  buildDraftVoData,
+  buildDraftFormData,
+  buildDraftSubmittedUpdateParams,
+  parseDraftVoToPageData,
+  parsePersonHeaderSnapshot,
+  normalizeJbqkRow,
+  draftSnakeToCamelMap,
+  normalizeDraftQueryRow,
+  normalizeDraftQueryRows
+}

+ 354 - 49
src/views/component/personnelFile/index.vue

@@ -27,8 +27,8 @@
             stauts === '已退回'
               ? seal.sealNo
               : stauts === '待审核'
-                ? seal.sealPing
-                : seal.sealSuc
+              ? seal.sealPing
+              : seal.sealSuc
           "
         />
         <personnel-info
@@ -39,6 +39,7 @@
           :type="type"
           :btn-show="btnShow"
           :btn-type="btnType"
+          :has-draft-data="hasDraftData"
           :person-info-data="personInfoData"
           @showTF="showTF"
           @changeBtn="changeBtn"
@@ -71,8 +72,8 @@
             stauts === '已退回'
               ? seal.sealNo
               : stauts === '待审核'
-                ? seal.sealPing
-                : seal.sealSuc
+              ? seal.sealPing
+              : seal.sealSuc
           "
         />
         <personnel-info
@@ -82,6 +83,7 @@
           "
           :btn-show="btnShow"
           :btn-type="btnType"
+          :has-draft-data="hasDraftData"
           :person-info-data="personInfoData"
           @showTF="showTF"
           @changeBtn="changeBtn"
@@ -117,6 +119,17 @@ import { getInfo, setInfo } from '@/api/platform/personFile/base'
 import { get } from '@/api/platform/personFile/unidirectionalCorrelation'
 import { startFlow } from '@/api/platform/bpmn/bpmInst'
 import { agree, reject } from '@/api/platform/bpmn/bpmTask'
+import { saveFormData } from '@/api/platform/data/dataTemplate'
+import {
+  buildDraftSubmittedUpdateParams,
+  buildDraftVoData,
+  draftBoCode,
+  draftFormKey,
+  draftQueryKeys,
+  normalizeJbqkRow,
+  parseDraftVoToPageData,
+  parsePersonHeaderSnapshot
+} from './constants/draftSql'
 
 export default {
   components: {
@@ -166,7 +179,12 @@ export default {
       seal,
       stauts: '',
       tipsControls: false,
-      processKey: setting?.system?.isJYB ? 'Process_0v35zf8' : 'Process_08xwabfNEW'
+      processKey: setting?.system?.isJYB
+        ? 'Process_0v35zf8'
+        : 'Process_08xwabfNEW',
+      draftMainId: '',
+      hasDraftData: false,
+      originalPersonInfoData: null
     }
   },
   watch: {
@@ -191,7 +209,7 @@ export default {
     }
   },
   created() {
-    this.$parent.$parent.showClose = false
+    this.hideParentDialogClose()
     if (this.$attrs.params) {
       const { taskId, instanceId } = this.$attrs.params || {}
       if (!taskId && !instanceId) {
@@ -219,24 +237,27 @@ export default {
     }
   },
   methods: {
+    hideParentDialogClose() {
+      let parent = this.$parent
+      while (parent) {
+        if (typeof parent.setShowClose === 'function') {
+          parent.setShowClose(false)
+          return
+        }
+        parent = parent.$parent
+      }
+    },
     init(val) {
-
       getInfo({ id: val }).then((res) => {
-        this.personInfoData = res.data
+        const data = res?.data && typeof res.data === 'object' ? res.data : {}
+        this.personInfoData = data
+        this.ensurePersonInfoLists(this.personInfoData)
+        // eslint-disable-next-line no-undef
+        this.originalPersonInfoData = structuredClone(this.personInfoData)
+        this.setBaseDataFromPersonInfo(this.personInfoData)
         this.stauts =
-          this.personInfoData.ryjbqkInfoPoList.length > 0
-            ? this.personInfoData.ryjbqkInfoPoList[0].shiFouGuoShen
-            : ''
-
-        // 保存基本数据
-        simulated.baseDataObj.ryjbqk.data = res.data.ryjbqkInfoPoList[0]
-        this.$set(this.baseData, 'ryjbqk', simulated.baseDataObj.ryjbqk)
-        simulated.baseDataObj.jyjl.data = res.data.educationInfoPoList
-        this.$set(this.baseData, 'jyjl', simulated.baseDataObj.jyjl)
-        simulated.baseDataObj.gzjl.data = res.data.workInfoPoList
-        this.$set(this.baseData, 'gzjl', simulated.baseDataObj.gzjl)
-        simulated.baseDataObj.zsb.data = res.data.certificateInfoPoList
-        this.$set(this.baseData, 'zsb', simulated.baseDataObj.zsb)
+          this.personInfoData.ryjbqkInfoPoList?.[0]?.shiFouGuoShen || ''
+        this.checkDraftData(val)
       })
       // const sql1 = `select * from t_rydatablpzb where xian_shi_yin_cang = 'Y'`
       this.$common
@@ -293,7 +314,13 @@ export default {
         this.tabChangeSetData(this.userId, this.activeName, page)
       }
     },
-    changeBtnShow(val) {
+    changeBtnShow(val, loadDraft = false) {
+      if (val === false && loadDraft && this.hasDraftData) {
+        this.loadDraftContent(this.getDraftRenYuan()).finally(() => {
+          this.btnShow = false
+        })
+        return
+      }
       this.btnShow = val
     },
     getChangeBaseData(val, name) {
@@ -302,22 +329,27 @@ export default {
         (this.btnType === 'save' ||
           this.btnType === 'agree' ||
           this.btnType === 'submit' ||
-          this.btnType === 'sendBack') &&
+          this.btnType === 'sendBack' ||
+          this.btnType === 'temporaryStorage') &&
         this.tipsControls === false &&
-        this.checkData(this.personInfoData)
+        (this.btnType === 'temporaryStorage' ||
+          this.checkData(this.personInfoData))
       ) {
+        this.ensurePersonInfoLists(this.personInfoData)
         switch (name) {
           case 'ryjbqk':
             // eslint-disable-next-line no-undef
             this.personInfoData.ryjbqkInfoPoList[0] = structuredClone(val)
-            this.personInfoData.ryjbqkInfoPoList[0].shiFouGuoShen =
-              this.btnType === 'submit' ||
-              (this.btnType === 'agree' &&
-                this.$attrs.params.attrs.flow * 1 === 4)
-                ? '待审核'
-                : this.btnType === 'sendBack'
+            if (this.btnType !== 'temporaryStorage') {
+              this.personInfoData.ryjbqkInfoPoList[0].shiFouGuoShen =
+                this.btnType === 'submit' ||
+                (this.btnType === 'agree' &&
+                  this.$attrs.params.attrs.flow * 1 === 4)
+                  ? '待审核'
+                  : this.btnType === 'sendBack'
                   ? '已退回'
                   : '已完成'
+            }
             this.infoNumArr.push(1)
             break
           case 'zsb':
@@ -341,18 +373,23 @@ export default {
         if (this.infoNumArr.length === 4) {
           if (this.btnType === 'submit') {
             startFlow({
-              defId: this.processKey == 'Process_0v35zf8' ? '1453020655493578752' : '1315609540510613504',
+              defId:
+                this.processKey == 'Process_0v35zf8'
+                  ? '1453020655493578752'
+                  : '1315609540510613504',
               version: '0',
               data: simulated.data
             }).then((res) => {
-              this.$alert(`启动成功!`, '提示', {
-                confirmButtonText: '确定',
-                callback: (action) => {
-                  this.$children[0].buttonShow = true
-                  this.infoNumArr = []
+              this.updateDraftSubmitted(this.personInfoData).finally(() => {
+                this.$alert(`启动成功!`, '提示', {
+                  confirmButtonText: '确定',
+                  callback: (action) => {
+                    this.$children[0].buttonShow = true
+                    this.infoNumArr = []
 
-                  this.saveData(this.personInfoData, 'Refresh')
-                }
+                    this.saveData(this.personInfoData, 'Refresh')
+                  }
+                })
               })
             })
           } else if (this.btnType === 'agree') {
@@ -392,6 +429,8 @@ export default {
             })
           } else if (this.btnType === '') {
             console.log('重置')
+          } else if (this.btnType === 'temporaryStorage') {
+            this.saveDraftData(this.personInfoData)
           } else if (this.btnType === 'save') {
             this.personInfoData.shouQuanQianZ = this.userId
             this.personInfoData.updateTime = this.$common.getDateNow(19)
@@ -449,7 +488,6 @@ export default {
     },
     saveData(val, r) {
       setInfo(val).then((res) => {
-
         this.showTF(false)
         if (r === 'Refresh') {
           location.reload()
@@ -457,9 +495,40 @@ export default {
       })
     },
     changeBtn(val, data) {
+      if (
+        val === 'save' ||
+        val === 'agree' ||
+        val === 'submit' ||
+        val === 'sendBack' ||
+        val === 'temporaryStorage'
+      ) {
+        this.infoNumArr = []
+      }
       this.btnType = val
-      if (Object.keys(data).length > 0) {
-        this.personInfoData = data
+      if (data && typeof data === 'object' && Object.keys(data).length > 0) {
+        if (!this.personInfoData || typeof this.personInfoData !== 'object') {
+          this.personInfoData = {}
+        }
+        const listKeys = [
+          'ryjbqkInfoPoList',
+          'educationInfoPoList',
+          'workInfoPoList',
+          'certificateInfoPoList'
+        ]
+        const preservedLists = {}
+        listKeys.forEach((key) => {
+          preservedLists[key] = this.personInfoData[key]
+        })
+        Object.assign(this.personInfoData, data)
+        listKeys.forEach((key) => {
+          if (
+            !Array.isArray(this.personInfoData[key]) ||
+            !this.personInfoData[key].length
+          ) {
+            this.personInfoData[key] = preservedLists[key] || []
+          }
+        })
+        this.ensurePersonInfoLists(this.personInfoData)
       }
       if (
         (this.btnType === 'save' ||
@@ -502,6 +571,246 @@ export default {
         }
       })
     },
+    getDraftRenYuan() {
+      return this.type === 'dialog' ? this.personID : this.userId
+    },
+    ensurePersonInfoLists(data = this.personInfoData) {
+      if (!data || typeof data !== 'object') {
+        return
+      }
+      if (
+        !Array.isArray(data.ryjbqkInfoPoList) ||
+        !data.ryjbqkInfoPoList.length
+      ) {
+        this.$set(data, 'ryjbqkInfoPoList', [{}])
+      }
+      if (!Array.isArray(data.educationInfoPoList)) {
+        this.$set(data, 'educationInfoPoList', [])
+      }
+      if (!Array.isArray(data.workInfoPoList)) {
+        this.$set(data, 'workInfoPoList', [])
+      }
+      if (!Array.isArray(data.certificateInfoPoList)) {
+        this.$set(data, 'certificateInfoPoList', [])
+      }
+    },
+    setBaseDataFromPersonInfo(data) {
+      if (!data || typeof data !== 'object') {
+        return
+      }
+      simulated.baseDataObj.ryjbqk.data = data.ryjbqkInfoPoList?.[0] || {}
+
+      this.$set(this.baseData, 'ryjbqk', simulated.baseDataObj.ryjbqk)
+      simulated.baseDataObj.jyjl.data = data.educationInfoPoList || []
+      this.$set(this.baseData, 'jyjl', simulated.baseDataObj.jyjl)
+      simulated.baseDataObj.gzjl.data = data.workInfoPoList || []
+      this.$set(this.baseData, 'gzjl', simulated.baseDataObj.gzjl)
+      simulated.baseDataObj.zsb.data = data.certificateInfoPoList || []
+      this.$set(this.baseData, 'zsb', simulated.baseDataObj.zsb)
+    },
+    restoreOriginalPersonInfo() {
+      if (
+        !this.originalPersonInfoData ||
+        !Object.keys(this.originalPersonInfoData).length
+      ) {
+        return
+      }
+      // eslint-disable-next-line no-undef
+      this.personInfoData = structuredClone(this.originalPersonInfoData)
+      this.ensurePersonInfoLists(this.personInfoData)
+      this.setBaseDataFromPersonInfo(this.personInfoData)
+    },
+    checkDraftData(renYuan) {
+      return this.$common
+        .request('query', {
+          key: draftQueryKeys.main,
+          params: [renYuan, '已暂存']
+        })
+        .then((r) => {
+          const rows = r?.variables?.data || []
+          this.hasDraftData = rows.length > 0
+          if (rows.length > 0) {
+            this.draftMainId = rows[0].id_ || rows[0].id || ''
+          } else {
+            this.draftMainId = ''
+          }
+          return this.hasDraftData
+        })
+        .catch(() => {
+          this.hasDraftData = false
+          this.draftMainId = ''
+          return false
+        })
+    },
+    applyDraftData(voData) {
+      if (!this.personInfoData || typeof this.personInfoData !== 'object') {
+        this.personInfoData = {}
+      }
+      this.ensurePersonInfoLists(this.personInfoData)
+      const draftData = parseDraftVoToPageData(voData)
+      const headerSnapshot = parsePersonHeaderSnapshot(
+        voData.kuaiZhao || voData.kuai_zhao_ || ''
+      )
+      Object.assign(this.personInfoData, headerSnapshot)
+      if (draftData.ryjbqkInfoPoList?.length) {
+        this.personInfoData.ryjbqkInfoPoList = draftData.ryjbqkInfoPoList
+      }
+      if (draftData.educationInfoPoList?.length) {
+        this.personInfoData.educationInfoPoList = draftData.educationInfoPoList
+      }
+      if (draftData.workInfoPoList?.length) {
+        this.personInfoData.workInfoPoList = draftData.workInfoPoList
+      }
+      if (draftData.certificateInfoPoList?.length) {
+        this.personInfoData.certificateInfoPoList =
+          draftData.certificateInfoPoList
+      }
+      this.setBaseDataFromPersonInfo(this.personInfoData)
+    },
+    loadDraftContent(renYuan) {
+      return this.$common
+        .request('query', {
+          key: draftQueryKeys.main,
+          params: [renYuan, '已暂存']
+        })
+        .then((r) => {
+          const rows = r?.variables?.data || []
+          if (!rows.length) {
+            this.hasDraftData = false
+            this.draftMainId = ''
+            return
+          }
+          this.hasDraftData = true
+          const mainRow = rows[0]
+          this.draftMainId = mainRow.id_ || mainRow.id || ''
+          const parentId = this.draftMainId
+          if (!parentId) {
+            return
+          }
+          return Promise.all([
+            this.$common.request('query', {
+              key: draftQueryKeys.jbqk,
+              params: [parentId]
+            }),
+            this.$common.request('query', {
+              key: draftQueryKeys.jyjl,
+              params: [parentId]
+            }),
+            this.$common.request('query', {
+              key: draftQueryKeys.gzjl,
+              params: [parentId]
+            }),
+            this.$common.request('query', {
+              key: draftQueryKeys.zsb,
+              params: [parentId]
+            })
+          ]).then(([jbqkRes, jyjlRes, gzjlRes, zsbRes]) => {
+            this.applyDraftData({
+              ...mainRow,
+              jbqkxxzc: jbqkRes?.variables?.data || [],
+              jyjlzc: jyjlRes?.variables?.data || [],
+              gzjlzc: gzjlRes?.variables?.data || [],
+              zsbzc: zsbRes?.variables?.data || []
+            })
+          })
+        })
+    },
+    loadDraftData(renYuan) {
+      return this.loadDraftContent(renYuan)
+    },
+    saveDraftData(data) {
+      const sourceData = data || this.personInfoData
+      if (!sourceData || typeof sourceData !== 'object') {
+        this.$message.warning('暂存数据为空')
+        this.infoNumArr = []
+        return
+      }
+      const renYuan = this.getDraftRenYuan()
+      const doSave = () => {
+        const voData = buildDraftVoData(sourceData, {
+          draftMainId: this.draftMainId,
+          renYuan,
+          userId: this.userId
+        })
+        saveFormData({
+          boCode: draftBoCode,
+          version: '0',
+          formKey: draftFormKey,
+          pk: this.draftMainId || '',
+          data: JSON.stringify(this.$common.replaceNullWithEmpty(voData))
+        }).then((res) => {
+          const savedId =
+            res?.data?.id || res?.variables?.id || this.draftMainId || ''
+          if (savedId) {
+            this.draftMainId = savedId
+          }
+          this.hasDraftData = true
+          this.infoNumArr = []
+          this.restoreOriginalPersonInfo()
+          this.btnShow = true
+          this.btnType = ''
+          this.$message.success('暂存成功!')
+        })
+      }
+      if (this.draftMainId) {
+        doSave()
+        return
+      }
+      this.$common
+        .request('query', {
+          key: draftQueryKeys.main,
+          params: [renYuan, '已暂存']
+        })
+        .then((r) => {
+          const rows = r?.variables?.data || []
+          if (rows.length > 0) {
+            this.draftMainId = rows[0].id_ || rows[0].id || ''
+          }
+          doSave()
+        })
+        .catch(() => {
+          doSave()
+        })
+    },
+    updateDraftSubmitted(data) {
+      const renYuan = this.getDraftRenYuan()
+      const runUpdate = () => {
+        if (!this.draftMainId) {
+          return Promise.resolve()
+        }
+        const updateParamsList = buildDraftSubmittedUpdateParams(
+          this.draftMainId,
+          '已提交'
+        )
+        if (!updateParamsList.length) {
+          return Promise.resolve()
+        }
+        return Promise.all(
+          updateParamsList.map((params) =>
+            this.$common.request('update', params)
+          )
+        ).then(() => {
+          this.hasDraftData = false
+          this.draftMainId = ''
+        })
+      }
+      if (this.draftMainId) {
+        return runUpdate()
+      }
+      return this.$common
+        .request('query', {
+          key: draftQueryKeys.main,
+          params: [renYuan, '已暂存']
+        })
+        .then((r) => {
+          const rows = r?.variables?.data || []
+          if (rows.length > 0) {
+            this.draftMainId = rows[0].id_ || rows[0].id || ''
+          }
+          return runUpdate()
+        })
+        .catch(() => runUpdate())
+    },
     saveOperate() {
       // const sql = `select b.id_,b.name_ from ibps_bpm_inst a join ibps_bpm_tasks b on b.PROC_DEF_KEY_ = a.PROC_DEF_KEY_ where b.PROC_DEF_KEY_ = '${this.processKey}' and a.CREATE_BY_ = '${this.personID}'`
       this.$common
@@ -564,10 +873,8 @@ export default {
     // padding-top: 1%;
     .perInfo {
       // margin-top: 2%;
-      box-shadow:
-        0 -2px 12px 0 rgba(0, 0, 0, 0.04),
-        2px 0px 12px 0 rgba(0, 0, 0, 0.04),
-        -2px 0px 12px 0 rgba(0, 0, 0, 0.04);
+      box-shadow: 0 -2px 12px 0 rgba(0, 0, 0, 0.04),
+        2px 0px 12px 0 rgba(0, 0, 0, 0.04), -2px 0px 12px 0 rgba(0, 0, 0, 0.04);
     }
   }
 }
@@ -583,10 +890,8 @@ export default {
     align-items: center;
     .perInfo {
       // margin-top: 2%;
-      box-shadow:
-        0 -2px 12px 0 rgba(0, 0, 0, 0.04),
-        2px 0px 12px 0 rgba(0, 0, 0, 0.04),
-        -2px 0px 12px 0 rgba(0, 0, 0, 0.04);
+      box-shadow: 0 -2px 12px 0 rgba(0, 0, 0, 0.04),
+        2px 0px 12px 0 rgba(0, 0, 0, 0.04), -2px 0px 12px 0 rgba(0, 0, 0, 0.04);
       border-radius: 4px 4px 0 0;
     }
   }