|
@@ -33,6 +33,13 @@
|
33
|
33
|
placeholder="选择日期时间"
|
34
|
34
|
/>
|
35
|
35
|
</el-form-item>
|
|
36
|
+ <el-form-item label-width="0">
|
|
37
|
+ <img
|
|
38
|
+ style="width: 100px; height: 100px"
|
|
39
|
+ :src="imgURL"
|
|
40
|
+ fit="fill"
|
|
41
|
+ >
|
|
42
|
+ </el-form-item>
|
36
|
43
|
<el-form-item label-width="0">
|
37
|
44
|
<el-button
|
38
|
45
|
type="primary"
|
|
@@ -101,6 +108,7 @@ export default {
|
101
|
108
|
startTime: [{ required: true, message: '请输入签到开始时间', trigger: 'blur' }],
|
102
|
109
|
endTime: [{ required: true, message: '请输入签到结束时间', trigger: 'blur' }]
|
103
|
110
|
},
|
|
111
|
+
|
104
|
112
|
allClassList: [],
|
105
|
113
|
classList: [],
|
106
|
114
|
isIndeterminateClass: false,
|
|
@@ -110,29 +118,48 @@ export default {
|
110
|
118
|
termList: [],
|
111
|
119
|
isIndeterminateTerm: false,
|
112
|
120
|
checkAllTerm: false,
|
113
|
|
- checkedTerms: []
|
|
121
|
+ checkedTerms: [],
|
|
122
|
+
|
|
123
|
+ imgURL: undefined,
|
|
124
|
+ oldclassList: [],
|
|
125
|
+ oldclassIdList: [],
|
|
126
|
+ lastTimeClassList: []
|
114
|
127
|
}
|
115
|
128
|
},
|
116
|
129
|
watch: {
|
117
|
|
- checkedTerms() {
|
118
|
|
- if (this.checkedTerms.length > 0) {
|
119
|
|
- const finalArr = this.allClassList.filter((item) => this.checkedTerms.includes(item.termId))
|
120
|
|
- this.classList = finalArr
|
121
|
|
- const finalArr2 = finalArr.filter((item) => this.checkedClasss.includes(item.classId))
|
122
|
|
- this.checkedClasss = []
|
123
|
|
- finalArr2.map(item => {
|
124
|
|
- this.checkedClasss.push(item.classId)
|
125
|
|
- })
|
126
|
|
- } else {
|
127
|
|
- this.classList = []
|
128
|
|
- this.checkedClasss = []
|
129
|
|
- }
|
|
130
|
+ checkedTerms: {
|
|
131
|
+ handler() {
|
|
132
|
+ if (this.checkedTerms.length === 0) {
|
|
133
|
+ this.isIndeterminateTerm = false
|
|
134
|
+ this.checkAllTerm = false
|
|
135
|
+ this.classList = []
|
|
136
|
+ this.checkedClasss = []
|
|
137
|
+ } else if (this.checkedTerms.length > 0) {
|
|
138
|
+ if (this.checkedTerms.length === this.termList.length) {
|
|
139
|
+ this.checkAllTerm = true
|
|
140
|
+ } else this.isIndeterminateTerm = true
|
|
141
|
+ const finalArr = this.allClassList.filter((item) => this.checkedTerms.includes(item.termId))
|
|
142
|
+ this.classList = finalArr
|
|
143
|
+ const finalArr2 = finalArr.filter((item) => this.checkedClasss.includes(item.classId))
|
|
144
|
+ this.checkedClasss = []
|
|
145
|
+ finalArr2.map(item => {
|
|
146
|
+ this.checkedClasss.push(item.classId)
|
|
147
|
+ })
|
|
148
|
+ }
|
|
149
|
+ this.lastTimeClassList = this.checkedClasss
|
|
150
|
+ },
|
|
151
|
+ immediate: true
|
130
|
152
|
},
|
131
|
|
- checkedClasss() {
|
132
|
|
- if (this.checkedClasss.length === 0) {
|
133
|
|
- this.isIndeterminateClass = false
|
134
|
|
- this.checkAllClass = false
|
135
|
|
- }
|
|
153
|
+ checkedClasss: {
|
|
154
|
+ handler() {
|
|
155
|
+ if (this.checkedClasss.length === 0) {
|
|
156
|
+ this.isIndeterminateClass = false
|
|
157
|
+ this.checkAllClass = false
|
|
158
|
+ } else if (this.checkedClasss.length === this.classList.length) {
|
|
159
|
+ this.checkAllClass = true
|
|
160
|
+ } else this.isIndeterminateClass = true
|
|
161
|
+ },
|
|
162
|
+ immediate: true
|
136
|
163
|
}
|
137
|
164
|
},
|
138
|
165
|
mounted() {
|
|
@@ -149,16 +176,20 @@ export default {
|
149
|
176
|
})
|
150
|
177
|
getSchoolClassList().then((res) => {
|
151
|
178
|
this.allClassList = res.data.records
|
|
179
|
+ getSignClassList(this.signId).then(res => {
|
|
180
|
+ this.oldclassList = res.data
|
|
181
|
+ if (this.oldclassList) {
|
|
182
|
+ this.oldclassList.map(item => {
|
|
183
|
+ if (this.checkedTerms.indexOf(item.termId) === -1) {
|
|
184
|
+ this.checkedTerms.push(item.termId)
|
|
185
|
+ }
|
|
186
|
+ this.checkedClasss.push(item.classId)
|
|
187
|
+ })
|
|
188
|
+ this.oldclassIdList = this.checkedClasss
|
|
189
|
+ }
|
|
190
|
+ })
|
152
|
191
|
})
|
153
|
|
- getSignClassList(this.signId).then(res => {
|
154
|
|
- var thisList = res.data
|
155
|
|
- if (thisList) {
|
156
|
|
- thisList.map(item => {
|
157
|
|
- this.checkedClasss.push(item.classId)
|
158
|
|
- this.checkedTerms.push(item.termId)
|
159
|
|
- })
|
160
|
|
- }
|
161
|
|
- })
|
|
192
|
+ this.toUrl()
|
162
|
193
|
},
|
163
|
194
|
methods: {
|
164
|
195
|
// 学期
|
|
@@ -185,6 +216,23 @@ export default {
|
185
|
216
|
this.isIndeterminateClass = false
|
186
|
217
|
},
|
187
|
218
|
handleCheckedClasssChange(value) {
|
|
219
|
+ if (this.lastTimeClassList.length > this.checkedClasss.length) {
|
|
220
|
+ this.lastTimeClassList.map(item => {
|
|
221
|
+ // 当上一次班级数组中的一项在现在班级选中数组中不显示说明当前项就是取消的哪一项 然后判断是否是上次保存过的签到班级
|
|
222
|
+ if (this.checkedClasss.indexOf(item) === -1 && this.oldclassIdList.indexOf(item) !== -1) {
|
|
223
|
+ this.checkedClasss.push(item)
|
|
224
|
+ this.$confirm('此操作将使该班级无法签到是否继续?', '提示', {
|
|
225
|
+ confirmButtonText: '删除',
|
|
226
|
+ cancelButtonText: '取消',
|
|
227
|
+ type: 'warning'
|
|
228
|
+ }).then(() => {
|
|
229
|
+ this.checkedClasss.pop()
|
|
230
|
+ }).catch(() => { })
|
|
231
|
+ }
|
|
232
|
+ })
|
|
233
|
+ }
|
|
234
|
+ // 将当前选中班级放在数组中记录一下
|
|
235
|
+ this.lastTimeClassList = this.checkedClasss
|
188
|
236
|
const checkedCount = value.length
|
189
|
237
|
this.checkAllClass = checkedCount === this.classList.length
|
190
|
238
|
this.isIndeterminateClass = checkedCount > 0 && checkedCount < this.classList.length
|
|
@@ -192,12 +240,20 @@ export default {
|
192
|
240
|
// 修改签到池
|
193
|
241
|
editSignClass() {
|
194
|
242
|
var submitList = []
|
195
|
|
- var serialNo = 0
|
196
|
243
|
this.classList.map((item, index) => {
|
197
|
244
|
if (this.checkedClasss.indexOf(item.classId) !== -1) {
|
198
|
|
- submitList.push({ classId: item.classId, termId: item.termId, signId: this.signId, serialNo: serialNo++ })
|
|
245
|
+ submitList.push({ classId: item.classId, termId: item.termId, signId: this.signId })
|
199
|
246
|
}
|
200
|
247
|
})
|
|
248
|
+ if (this.oldclassList.length > 0) {
|
|
249
|
+ this.oldclassList.map(item => {
|
|
250
|
+ submitList.map((item2, index) => {
|
|
251
|
+ if (item2.classId === item.classId) {
|
|
252
|
+ submitList[index].serialNo = item.serialNo
|
|
253
|
+ }
|
|
254
|
+ })
|
|
255
|
+ })
|
|
256
|
+ }
|
201
|
257
|
saveSignClass(submitList, this.signId).then(() => {
|
202
|
258
|
this.$message('签到池修改成功')
|
203
|
259
|
})
|
|
@@ -236,20 +292,25 @@ export default {
|
236
|
292
|
text: 'http://192.168.89.76:8080/signIn?signId=' + val
|
237
|
293
|
})
|
238
|
294
|
},
|
239
|
|
- // 下载二维码
|
240
|
|
- downloadQrcode() {
|
|
295
|
+ // canvans转base64 很消耗内存所以把转换后的结果imgURL拿出来
|
|
296
|
+ toUrl() {
|
241
|
297
|
document.getElementById('qrcode').innerHTML = ''
|
242
|
298
|
this.qrcode(this.signId) // 下载之前首先要有二维码
|
243
|
299
|
// 先找到canvas节点下的二维码图片
|
244
|
300
|
const myCanvas = document.getElementById('qrcode').getElementsByTagName('canvas')
|
|
301
|
+ // 设置a的href属性将canvas变成png格式
|
|
302
|
+ this.imgURL = myCanvas[0].toDataURL('image/jpg')
|
|
303
|
+ },
|
|
304
|
+ // 下载二维码 把base64转为blob并且下载
|
|
305
|
+ downloadQrcode() {
|
245
|
306
|
const img = document.getElementById('qrcode').getElementsByTagName('img')
|
246
|
307
|
// 创建一个a节点
|
247
|
308
|
const a = document.createElement('a')
|
248
|
|
- // 设置a的href属性将canvas变成png格式
|
249
|
|
- const imgURL = myCanvas[0].toDataURL('image/jpg')
|
|
309
|
+ // 获得浏览器用户代理
|
250
|
310
|
const ua = navigator.userAgent
|
251
|
|
- if (ua.indexOf('Trident') !== -1 && ua.indexOf('Windows') !== -1) { // IE内核 并且 windows系统 情况下 才执行;
|
252
|
|
- var bstr = atob(imgURL.split(',')[1])
|
|
311
|
+ if (ua.indexOf('Trident') !== -1 && ua.indexOf('Windows') !== -1) { // IE内核 并且 windows系统 情况下 才执行
|
|
312
|
+ // canvas转base64 后生成的数据是由 图片格式+逗号+真正的base64码组成的
|
|
313
|
+ var bstr = atob(this.imgURL.split(',')[1])
|
253
|
314
|
var n = bstr.length
|
254
|
315
|
var u8arr = new Uint8Array(n)
|
255
|
316
|
while (n--) {
|
|
@@ -258,14 +319,15 @@ export default {
|
258
|
319
|
var blob = new Blob([u8arr])
|
259
|
320
|
window.navigator.msSaveOrOpenBlob(blob, this.signForm.name + '.png')
|
260
|
321
|
} else if (ua.indexOf('Firefox') > -1) { // 火狐兼容下载
|
261
|
|
- const blob = this.base64ToBlob(imgURL) // new Blob([content]);
|
|
322
|
+ const blob = this.base64ToBlob(this.imgURL) // new Blob([content]);
|
262
|
323
|
const evt = document.createEvent('HTMLEvents')
|
263
|
324
|
evt.initEvent('click', true, true)// initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
|
264
|
325
|
a.download = this.signForm.name + '.png'// 下载图片名称,如果填内容识别不到,下载为未知文件,所以我这里就不填为空
|
|
326
|
+ // 讲blob数据转换成url
|
265
|
327
|
a.href = URL.createObjectURL(blob)
|
266
|
328
|
a.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }))// 兼容火狐
|
267
|
329
|
} else { // 谷歌兼容下载
|
268
|
|
- img.src = imgURL
|
|
330
|
+ img.src = this.imgURL
|
269
|
331
|
a.href = img.src
|
270
|
332
|
// 设置下载文件的名字
|
271
|
333
|
a.download = this.signForm.name + '.png'
|
|
@@ -275,14 +337,20 @@ export default {
|
275
|
337
|
},
|
276
|
338
|
// base64转blob
|
277
|
339
|
base64ToBlob(code) {
|
|
340
|
+ // this.imgURl打印出来可以看到等于data:image/png;base64,+base64码
|
278
|
341
|
const parts = code.split(';base64,')
|
|
342
|
+ // 截取后pasts[0]等于data:image/png parts[1]就是base64吗 (至于为什么我们上面写image/jpg 现在变成png我也不知道哈哈哈哈哈)
|
279
|
343
|
const contentType = parts[0].split(':')[1]
|
|
344
|
+ // 用:分隔contentType 等于image/png
|
280
|
345
|
const raw = window.atob(parts[1])
|
|
346
|
+ // 获取解码后的长度
|
281
|
347
|
const rawLength = raw.length
|
282
|
348
|
const uInt8Array = new Uint8Array(rawLength)
|
283
|
349
|
for (let i = 0; i < rawLength; ++i) {
|
|
350
|
+ // 循环 把每位都转为相对应的unicode码
|
284
|
351
|
uInt8Array[i] = raw.charCodeAt(i)
|
285
|
352
|
}
|
|
353
|
+ // Blob储存二进制的
|
286
|
354
|
return new Blob([uInt8Array], { type: contentType })
|
287
|
355
|
}
|
288
|
356
|
}
|