1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import cache from '@/plugins/cache'
import useUserStore from '@/store/modules/user'
 
// 弹窗编辑草稿自动保存/恢复:
// 打开弹窗时注册唯一业务 key,表单有改动时防抖写入 localStorage,
// 关闭/切页/刷新后再次打开同一弹窗时自动恢复未保存的内容;保存成功后草稿清除。
export default {
  data() {
    return {
      draftStates: {}
    }
  },
  created() {
    this.draftBeforeUnload = () => {
      this.draftFlushAll()
    }
    window.addEventListener('beforeunload', this.draftBeforeUnload)
  },
  beforeUnmount() {
    this.draftFlushAll()
    window.removeEventListener('beforeunload', this.draftBeforeUnload)
  },
  methods: {
    // 打开弹窗、表单填好后调用;有未保存草稿则自动恢复
    // bizKey:全局唯一业务名;formField:表单字段名(如 'form');recordId:编辑传记录id、新增传上下文;visibleField:弹窗显隐字段(如 'dialogVisible')
    draftRestore(bizKey, formField, recordId, visibleField) {
      const old = this.draftStates[bizKey]
      if (old) {
        this.draftTeardown(old)
      }
      let uid = ''
      try {
        uid = useUserStore().id || ''
      } catch (e) {
      }
      const rid = (recordId === null || recordId === undefined || recordId === '') ? 'new' : recordId
      const state = {
        key: `limsDraft_${uid}_${bizKey}_${rid}`,
        formField,
        visibleField,
        active: true,
        timer: null,
        baseline: ''
      }
      state.unwatchForm = this.$watch(formField, () => this.draftSchedule(state), { deep: true })
      if (visibleField) {
        state.unwatchVisible = this.$watch(visibleField, (val) => {
          if (!val) {
            this.draftStop(bizKey)
          }
        })
      }
      state.baseline = this.draftSnapshot(state)
      this.draftStates[bizKey] = state
      const raw = cache.local.get(state.key)
      if (raw) {
        try {
          const draft = JSON.parse(raw)
          const target = this[formField]
          if (Array.isArray(target) && Array.isArray(draft)) {
            target.splice(0, target.length, ...draft)
          } else if (target && typeof target === 'object') {
            Object.assign(target, draft)
          } else {
            this[formField] = draft
          }
          this.$message({ type: 'info', message: '已恢复上次未保存的编辑内容' })
        } catch (e) {
          cache.local.remove(state.key)
        }
      }
    },
    draftSnapshot(state) {
      try {
        return JSON.stringify(this[state.formField])
      } catch (e) {
        return ''
      }
    },
    draftSchedule(state) {
      if (!state.active) {
        return
      }
      if (state.timer) {
        clearTimeout(state.timer)
      }
      state.timer = setTimeout(() => {
        state.timer = null
        this.draftWrite(state, true)
      }, 300)
    },
    draftWrite(state, checkVisible) {
      if (!state.active) {
        return
      }
      if (checkVisible && state.visibleField && !this[state.visibleField]) {
        return
      }
      const json = this.draftSnapshot(state)
      if (json === '' || json === state.baseline) {
        cache.local.remove(state.key)
      } else {
        cache.local.set(state.key, json)
      }
    },
    // 用户取消/关闭弹窗时调用(必须在清空表单之前)
    draftStop(bizKey) {
      const state = this.draftStates[bizKey]
      if (!state || !state.active) {
        return
      }
      if (state.timer) {
        clearTimeout(state.timer)
        state.timer = null
      }
      this.draftWrite(state, false)
      this.draftTeardown(state)
    },
    // 保存成功后调用
    draftClear(bizKey) {
      const state = this.draftStates[bizKey]
      if (!state) {
        return
      }
      if (state.timer) {
        clearTimeout(state.timer)
        state.timer = null
      }
      cache.local.remove(state.key)
      this.draftTeardown(state)
    },
    draftTeardown(state) {
      state.active = false
      if (state.unwatchForm) {
        state.unwatchForm()
        state.unwatchForm = null
      }
      if (state.unwatchVisible) {
        state.unwatchVisible()
        state.unwatchVisible = null
      }
    },
    draftFlushAll() {
      Object.keys(this.draftStates).forEach((k) => {
        const state = this.draftStates[k]
        if (state && state.active) {
          if (state.timer) {
            clearTimeout(state.timer)
            state.timer = null
          }
          this.draftWrite(state, true)
          this.draftTeardown(state)
        }
      })
    }
  }
}