@@ -105,6 +105,8 @@ export default { | |||||
} | } | ||||
uni.setStorageSync('folderIds',JSON.stringify(folderIds)); | uni.setStorageSync('folderIds',JSON.stringify(folderIds)); | ||||
return [] | return [] | ||||
case 'upload_old': | |||||
return [] | |||||
case 'guid': | case 'guid': | ||||
return this.GUID('-') | return this.GUID('-') | ||||
@@ -252,6 +254,27 @@ export default { | |||||
} | } | ||||
return uploadUid; | return uploadUid; | ||||
case 'upload_old': | |||||
const valArray = val.map(item=>{ | |||||
return { | |||||
uid:item.uid, | |||||
path:item.path===undefined?item:item.path | |||||
} | |||||
}) | |||||
const uploadUid_ = [] | |||||
for (const { path, uid } of valArray) { | |||||
if (uid) { | |||||
uploadUid_.push(uid) | |||||
continue | |||||
} | |||||
const fileId = await this.HTTP_UPLOAD(path) | |||||
if (fileId) { | |||||
uploadUid_.push(fileId) | |||||
} | |||||
} | |||||
return uploadUid_.join(',') | |||||
default: | default: | ||||
return val || '' | return val || '' | ||||
@@ -347,6 +370,24 @@ export default { | |||||
}) | }) | ||||
} | } | ||||
return fileList | return fileList | ||||
case 'upload_old': | |||||
if (!val) { return [] } | |||||
const uidList_ = val.split(',') | |||||
const fileList_ = [] | |||||
for (const uid of uidList_ || []) { | |||||
const fileInfo = await this.FETCH_FILEINFO(uid) | |||||
if (!fileInfo) { continue } | |||||
const fileType = fileInfo.F_FileType | |||||
const fileSize = fileInfo.F_FileSize | |||||
const fileName = fileInfo.F_FileName | |||||
const path = this.API + 'learun/adms/annexes/wxdown?' + this.URL_QUERY(uid, true) | |||||
fileList_.push({ path, type: fileType, uid, size: fileSize, name:fileName }) | |||||
} | |||||
return fileList_ | |||||
case 'radio': | case 'radio': | ||||
case 'select': | case 'select': | ||||
@@ -1,4 +1,5 @@ | |||||
import wx from '@/common/js/weixin-js-sdk.js'; | import wx from '@/common/js/weixin-js-sdk.js'; | ||||
// 参考文档 https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html | |||||
export default { | export default { | ||||
methods: { | methods: { | ||||
data(){ | data(){ | ||||
@@ -29,7 +30,7 @@ export default { | |||||
}); | }); | ||||
wx.ready(() => { | wx.ready(() => { | ||||
this.wxInit = true | this.wxInit = true | ||||
this.TOAST("wx初始化成功") | |||||
// this.TOAST("wx初始化成功") | |||||
resolve(true) | resolve(true) | ||||
}) | }) | ||||
wx.error(() => { | wx.error(() => { | ||||
@@ -51,7 +52,7 @@ export default { | |||||
} | } | ||||
} | } | ||||
if(!wx.getLocation){ | if(!wx.getLocation){ | ||||
this.TOAST("无效方法") | |||||
this.TOAST("获取定位失败") | |||||
resolve(false) | resolve(false) | ||||
} | } | ||||
wx.getLocation({ | wx.getLocation({ | ||||
@@ -67,7 +68,7 @@ export default { | |||||
}) | }) | ||||
}, | }, | ||||
fail: function(error) { | fail: function(error) { | ||||
this.TOAST("定位失败") | |||||
this.TOAST("获取定位失败!") | |||||
resolve(false) | resolve(false) | ||||
} | } | ||||
}); | }); | ||||
@@ -93,6 +94,7 @@ export default { | |||||
sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有 | sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有 | ||||
success: function(res) { | success: function(res) { | ||||
var localIds = res.localIds;// 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片 | var localIds = res.localIds;// 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片 | ||||
resolve(localIds) | |||||
}, | }, | ||||
fail: function(error) { | fail: function(error) { | ||||
this.TOAST("定位失败") | this.TOAST("定位失败") | ||||
@@ -53,7 +53,10 @@ export default { | |||||
readonly: {}, | readonly: {}, | ||||
value: { default: () => [] }, | value: { default: () => [] }, | ||||
title: {}, | title: {}, | ||||
required: {} | |||||
required: {}, | |||||
accept:{ | |||||
default:()=>['album', 'camera'] | |||||
} | |||||
}, | }, | ||||
methods: { | methods: { | ||||
@@ -104,7 +107,7 @@ export default { | |||||
uni.chooseFile({ | uni.chooseFile({ | ||||
count: Number(this.number), | count: Number(this.number), | ||||
sizeType: ['original', 'compressed'], | sizeType: ['original', 'compressed'], | ||||
sourceType: ['album', 'camera'], | |||||
sourceType: this.accept, | |||||
success: ({ tempFilePaths,tempFiles }) => { | success: ({ tempFilePaths,tempFiles }) => { | ||||
const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | ||||
// tempFilePaths//.map(t => ({ path: t, type: this.getFileExt(t) })) | // tempFilePaths//.map(t => ({ path: t, type: this.getFileExt(t) })) | ||||
@@ -0,0 +1,226 @@ | |||||
<template> | |||||
<view> | |||||
<view class="cu-form-group" style="border-bottom: none; padding-bottom: 0;"> | |||||
<view class="title"> | |||||
<text v-if="required" class="lr-required">*</text> | |||||
{{ title || '' }} | |||||
</view> | |||||
</view> | |||||
<view class="cu-form-group" style="border-top: none;"> | |||||
<view class="grid col-4 grid-square flex-sub"> | |||||
<view v-for="(file, index) in value" :key="index" class="bg-img" style="position: relative;"> | |||||
<!-- :style="{borderColor:file.noUpdated?'#EEE8AA':'#fff'}" --> | |||||
<view v-if="file.noUpdated" class="mask"></view> | |||||
<image | |||||
v-if="isImgFile(file)" | |||||
@click="fileClick(index)" | |||||
:src="file.path?file.path:file" | |||||
:webp="file.type === 'webp'" | |||||
mode="aspectFill" | |||||
></image> | |||||
<view v-else-if="isDocFile(file)" @click="fileClick(index)" class="file-icon solids"> | |||||
<l-icon type="text" /> | |||||
</view> | |||||
<view v-else class="file-icon solids" @click="fileClick(index)"> | |||||
<l-icon type="text" /> | |||||
</view> | |||||
<view v-if="!readonly" @click.stop="delFile(index)" class="cu-tag bg-red" style="height: 24px; width: 24px;"> | |||||
<l-icon type="close" color="white" style="width: 18px; height: 24px; font-size: 24px;" /> | |||||
</view> | |||||
<view class="fileName"> | |||||
<text>{{file.name}}</text> | |||||
</view> | |||||
</view> | |||||
<view v-if="!readonly && value.length < Number(number)" @click="chooseFile" class="solids"> | |||||
<l-icon type="file" /> | |||||
</view> | |||||
</view> | |||||
</view> | |||||
</view> | |||||
</template> | |||||
<script> | |||||
// import uniCopy from '@/common/js/uni-copy.js' | |||||
export default { | |||||
name: 'l-upload-file', | |||||
props: { | |||||
number: { default: 1 }, | |||||
readonly: {}, | |||||
value: { default: () => [] }, | |||||
title: {}, | |||||
required: {}, | |||||
accept:{ | |||||
default:()=>['album', 'camera'] | |||||
} | |||||
}, | |||||
methods: { | |||||
getFileExt(path) { | |||||
return /\.(\w{2,5})$/.exec(path)[1] || null | |||||
}, | |||||
isImgFile(file) { | |||||
const typeString = (file.type || '').toLowerCase() | |||||
return ['jpg','image/jpg','jpeg','image/jpeg', 'png', 'image/png','gif', 'image/gif','bmp', 'image/bmp','webp', 'image/webp','image'].includes(typeString) | |||||
}, | |||||
isDocFile(file) { | |||||
const typeString = (file.type || '').toLowerCase() | |||||
return ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf'].includes(typeString) | |||||
return true | |||||
}, | |||||
async delFile(index) { | |||||
if (!(await this.CONFIRM('删除文件', '确定要删除该文件吗?', true))) { | |||||
return | |||||
} | |||||
const newList = JSON.parse(JSON.stringify(this.value)) | |||||
newList.splice(index, 1) | |||||
this.$emit('input', newList) | |||||
this.$emit('change') | |||||
this.$emit('del') | |||||
}, | |||||
chooseFile() { | |||||
// #ifdef MP-DINGTALK | |||||
// dd.chooseImage({ | |||||
// count: Number(this.number), | |||||
// success: ({ filePaths }) => { | |||||
// if (filePaths) { | |||||
// const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | |||||
// filePaths.map(t => ({ path: t, type: this.getFileExt(t) })) | |||||
// ) | |||||
// this.$emit('input', newList) | |||||
// this.$emit('change', newList) | |||||
// this.$emit('add') | |||||
// } | |||||
// } | |||||
// }) | |||||
// #endif | |||||
// #ifndef MP-DINGTALK | |||||
uni.chooseImage({ | |||||
count: Number(this.number), | |||||
sizeType: ['original', 'compressed'], | |||||
sourceType: this.accept, | |||||
success: ({ tempFilePaths,tempFiles }) => { | |||||
const newList = JSON.parse(JSON.stringify(this.value || [])).concat( | |||||
// tempFilePaths//.map(t => ({ path: t, type: this.getFileExt(t) })) | |||||
tempFilePaths.map((t,i) => ({ path: t, type: tempFiles[i].type, size:tempFiles[i].size, name:tempFiles[i].name, noUpdated:true} )) | |||||
) | |||||
this.$emit('input', newList) | |||||
this.$emit('change', newList) | |||||
this.$emit('add') | |||||
} | |||||
}) | |||||
// #endif | |||||
}, | |||||
async fileClick(index) { | |||||
const { path, type, uid, size = 0 } = this.value[index] | |||||
if (this.isImgFile(this.value[index])) { | |||||
uni.previewImage({ urls: [path], current: path }) | |||||
}else{ | |||||
uni.openDocument({ filePath: this.value[index].path, fileType: type }) | |||||
// uniCopy({ | |||||
// content:this.value[index].path, | |||||
// success:(res)=>{ | |||||
// uni.showToast({ | |||||
// title: "复制链接成功!请在浏览器进行打开~", | |||||
// icon: 'none', | |||||
// duration:3000, | |||||
// }) | |||||
// }, | |||||
// error:(e)=>{ | |||||
// uni.showToast({ | |||||
// title: e, | |||||
// icon: 'none', | |||||
// duration:3000, | |||||
// }) | |||||
// } | |||||
// }) | |||||
} | |||||
// if (this.isImgFile(this.value[index])) { | |||||
// uni.previewImage({ urls: [path], current: path }) | |||||
// } else if (this.isDocFile(this.value[index])) { | |||||
// // #ifndef H5 || MP-DINGTALK | |||||
// if (size >= 50 * 1024 * 1024) { | |||||
// this.TOAST('小程序端无法下载超过50MB的文件,此文件大小为${size}KB,超过限制') | |||||
// return | |||||
// } | |||||
// // #endif | |||||
// // #ifndef MP-DINGTALK | |||||
// const tempFilePath = await this.HTTP_DOWNLOAD(uid) | |||||
// uni.openDocument({ filePath: tempFilePath, fileType: type }) | |||||
// // #endif | |||||
// // #ifdef MP-DINGTALK | |||||
// this.TOAST('钉钉小程序只支持查看图片文件') | |||||
// // #endif | |||||
// } else { | |||||
// // #ifndef MP-DINGTALK | |||||
// this.TOAST('小程序端只支持打开图片和文档(word、pdf等)文件') | |||||
// // #endif | |||||
// // #ifdef MP-DINGTALK | |||||
// this.TOAST('钉钉小程序只支持查看图片文件') | |||||
// // #endif | |||||
// // #ifdef APP-VUE | |||||
// const tempFilePath = await this.HTTP_DOWNLOAD(uid) | |||||
// uni.openDocument({ filePath: tempFilePath, fileType: type }) | |||||
// // #endif | |||||
// // #ifdef H5 | |||||
// await this.HTTP_DOWNLOAD(uid) | |||||
// // #endif | |||||
// } | |||||
}, | |||||
// ClickDownload(url) { | |||||
// var src = url; | |||||
// var iframe = document.createElement('iframe'); | |||||
// iframe.style.display = 'none'; | |||||
// iframe.src = "javascript: '<script>location.href=\"" + src + "\"<\/script>'"; | |||||
// document.getElementsByTagName('body')[0].appendChild(iframe); | |||||
// } | |||||
} | |||||
} | |||||
</script> | |||||
<style lang="less" scoped> | |||||
.file-icon { | |||||
line-height: 100%; | |||||
position: static; | |||||
} | |||||
.fileName{ | |||||
padding: 2px 2px; | |||||
margin-bottom: 2px; | |||||
text-align: center; | |||||
position: absolute; | |||||
bottom: 0px; | |||||
width: 100%; | |||||
background: rgba(0,0,0,0.2); | |||||
color: #fff; | |||||
font-size: 12px; | |||||
text-overflow: ellipsis; | |||||
overflow: hidden; | |||||
white-space: nowrap; | |||||
} | |||||
.mask{ | |||||
position: absolute; | |||||
top: 0;left: 0; | |||||
width: 100%; | |||||
height: 100%; | |||||
// background: rgba(255,252,153,0.2); | |||||
background: rgba(0,0,0,0.7); | |||||
z-index: 100; | |||||
pointer-events: none; | |||||
} | |||||
</style> |
@@ -191,11 +191,7 @@ | |||||
}, | }, | ||||
"domain" : "testapp.bjquanjiang.com", | "domain" : "testapp.bjquanjiang.com", | ||||
"sdkConfigs" : { | "sdkConfigs" : { | ||||
"maps" : { | |||||
"qqmap" : { | |||||
"key" : "EZCBZ-IDUCZ-G3UXY-ZMP3T-5XNQE-AXBZS" | |||||
} | |||||
} | |||||
"maps" : {} | |||||
} | } | ||||
}, | }, | ||||
"mp-qq" : { | "mp-qq" : { | ||||
@@ -407,6 +407,25 @@ | |||||
"navigationBarTitleText": "考勤打卡" | "navigationBarTitleText": "考勤打卡" | ||||
} | } | ||||
}, | }, | ||||
{ | |||||
"path": "pages/AttendanceCard/single", | |||||
"style": { | |||||
"navigationBarTitleText": "外勤打卡" | |||||
} | |||||
}, | |||||
// 学生考勤打卡 | |||||
{ | |||||
"path": "pages/AttendanceCardStudent/list", | |||||
"style": { | |||||
"navigationBarTitleText": "学生考勤打卡" | |||||
} | |||||
}, | |||||
{ | |||||
"path": "pages/AttendanceCardStudent/single", | |||||
"style": { | |||||
"navigationBarTitleText": "学生考勤打卡" | |||||
} | |||||
}, | |||||
//班级自诊打卡 | //班级自诊打卡 | ||||
{ | { | ||||
"path": "pages/EducationalAdministration/Thermography/list", | "path": "pages/EducationalAdministration/Thermography/list", | ||||
@@ -7,7 +7,7 @@ | |||||
上班 {{info.WorkTime}} | 上班 {{info.WorkTime}} | ||||
</view> | </view> | ||||
<view class=""> | <view class=""> | ||||
{{info.UserWorkTime?info.UserWorkTime.substring(8)+' 打卡':'未打卡'}} | |||||
{{info.UserWorkTime?info.UserWorkTime.split(' ')[1]+' 打卡':'未打卡'}} | |||||
</view> | </view> | ||||
</view> | </view> | ||||
<view class=""> | <view class=""> | ||||
@@ -15,7 +15,7 @@ | |||||
下班 {{info.CloseTime}} | 下班 {{info.CloseTime}} | ||||
</view> | </view> | ||||
<view class=""> | <view class=""> | ||||
{{info.UserCloseTime?info.UserCloseTime.substring(8)+' 打卡':'未打卡'}} | |||||
{{info.UserCloseTime?info.UserCloseTime.split(' ')[1]+' 打卡':'未打卡'}} | |||||
</view> | </view> | ||||
</view> | </view> | ||||
</view> | </view> | ||||
@@ -25,7 +25,12 @@ | |||||
<img :class="{gray:info.AttendanceType != 1}" id="attimg" :src="imgsrc" alt="" width="100%"> | <img :class="{gray:info.AttendanceType != 1}" id="attimg" :src="imgsrc" alt="" width="100%"> | ||||
</view> | </view> | ||||
<view class="title"> | <view class="title"> | ||||
{{info.AttendanceTypeString}} | |||||
<text>{{resInfo.AttendanceTypeString}}</text> | |||||
<text>{{postData.AIsOut== 1 ? ' | ' + info.AttendanceTypeString:''}}</text> | |||||
<view style="color: #666;"> | |||||
{{postData.ClockPlace}} | |||||
</view> | |||||
</view> | </view> | ||||
</view> | </view> | ||||
<view class="footer"> | <view class="footer"> | ||||
@@ -73,11 +78,15 @@ | |||||
return { | return { | ||||
// 页面相关参数 | // 页面相关参数 | ||||
info: {}, | info: {}, | ||||
resInfo:{}, | |||||
now: null, | now: null, | ||||
imgsrc: dk, | imgsrc: dk, | ||||
ready: false, | ready: false, | ||||
timer: '', | timer: '', | ||||
timer1:'', | |||||
map: null, | map: null, | ||||
postData: {}, | |||||
isGetingLocal:false, | |||||
} | } | ||||
}, | }, | ||||
@@ -92,9 +101,9 @@ | |||||
this.now = this.getCurrentTime() | this.now = this.getCurrentTime() | ||||
this.timer = setInterval(this.getCurrentTime, 1000) | this.timer = setInterval(this.getCurrentTime, 1000) | ||||
await this.judgeIsDK() | |||||
let res = await this.judgeIsDK() | |||||
this.ready = true | |||||
this.ready = res ? true : false | |||||
this.HIDE_LOADING() | this.HIDE_LOADING() | ||||
}, | }, | ||||
@@ -102,7 +111,11 @@ | |||||
async action(type) { | async action(type) { | ||||
switch (type) { | switch (type) { | ||||
case 'dk': | case 'dk': | ||||
if (this.imgsrc == dkred) { | |||||
if ([5].includes(this.info.AttendanceType)) { | |||||
return | |||||
} | |||||
if ([4].includes(this.info.AttendanceType)) { | |||||
this.NAV_TO(`./single`, this.postData,true) | |||||
return | return | ||||
} | } | ||||
this.LOADING() | this.LOADING() | ||||
@@ -126,7 +139,7 @@ | |||||
async judgeIsDK() { | async judgeIsDK() { | ||||
let success = await this.HTTP_GET('learun/adms/attendance/IsAttendance', {}, '判断当前时间是否可以打卡失败') | let success = await this.HTTP_GET('learun/adms/attendance/IsAttendance', {}, '判断当前时间是否可以打卡失败') | ||||
if (!success) { | if (!success) { | ||||
return | |||||
return false | |||||
} | } | ||||
this.info = success.data | this.info = success.data | ||||
this.imgsrc = dk; | this.imgsrc = dk; | ||||
@@ -138,10 +151,28 @@ | |||||
// this.imgsrc=dkred; | // this.imgsrc=dkred; | ||||
// } | // } | ||||
if (![5].includes(this.info.AttendanceType)) { | if (![5].includes(this.info.AttendanceType)) { | ||||
// 保存原打卡状态,改为外勤 | |||||
this.resInfo = { | |||||
AttendanceType:this.info.AttendanceType, | |||||
AttendanceTypeString:this.info.AttendanceTypeString, | |||||
} | |||||
this.$set(this.info, 'AttendanceType', 4) | |||||
this.$set(this.info, 'AttendanceTypeString', '外勤打卡') | |||||
this.$set(this.postData, 'AIsOut', 1) | |||||
// 获取定位,不是外勤时候改变状态 | |||||
if (!window.BMapGL) await this.loadJScript() | if (!window.BMapGL) await this.loadJScript() | ||||
this.map = new BMapGL.Map('container'); | this.map = new BMapGL.Map('container'); | ||||
await this.isFieldPersonnel() | await this.isFieldPersonnel() | ||||
this.timer1 = setInterval(async ()=>{ | |||||
if(this.isGetingLocal)return | |||||
this.isGetingLocal = true | |||||
await this.isFieldPersonnel() | |||||
// console.log(this.postData) | |||||
this.isGetingLocal = false | |||||
},3000) | |||||
} | } | ||||
return true | |||||
}, | }, | ||||
//返回 | //返回 | ||||
back() { | back() { | ||||
@@ -181,37 +212,71 @@ | |||||
// new BMapGL.Point(116.404, 39.915) | // new BMapGL.Point(116.404, 39.915) | ||||
let myP2 = await this.local(); | let myP2 = await this.local(); | ||||
if (!myP2) { | if (!myP2) { | ||||
this.TOAST('获取定位失败!') | |||||
// this.TOAST('获取定位失败!') | |||||
this.$set(this.info, 'AttendanceType', 4) | |||||
this.$set(this.info, 'AttendanceTypeString', '外勤打卡') | |||||
this.$set(this.postData, 'AIsOut', 1) | |||||
return | return | ||||
} | } | ||||
let distance = this.map.getDistance(myP1, myP2).toFixed(2) | let distance = this.map.getDistance(myP1, myP2).toFixed(2) | ||||
console.log('距离', distance, '打卡坐标:', myP1, '当前坐标:', myP2) | |||||
// alert('距离'+ distance) | |||||
// console.log('距离', distance, '打卡坐标:', myP1, '当前坐标:', myP2) | |||||
if (Number(distance) > Number(this.info.GPSRange)) { | if (Number(distance) > Number(this.info.GPSRange)) { | ||||
this.$set(this.info, 'AttendanceType', 4) | this.$set(this.info, 'AttendanceType', 4) | ||||
this.$set(this.info, 'AttendanceTypeString', '外勤打卡') | this.$set(this.info, 'AttendanceTypeString', '外勤打卡') | ||||
this.$set(this.postData, 'AIsOut', 1) | |||||
} else { | |||||
this.$set(this.info, 'AttendanceType', this.resInfo.AttendanceType) | |||||
this.$set(this.info, 'AttendanceTypeString', this.resInfo.AttendanceTypeString) | |||||
this.$set(this.postData, 'AIsOut', 0) | |||||
} | } | ||||
}, | }, | ||||
// 获取当前位置 | // 获取当前位置 | ||||
local() { | local() { | ||||
return new Promise(async (resolve) => { | return new Promise(async (resolve) => { | ||||
let res = await this.getLocation() | let res = await this.getLocation() | ||||
// let res = { | |||||
// lng: 112.57205562051, | |||||
// lat: 37.742374280962 | |||||
// } | |||||
if (!res) { | if (!res) { | ||||
this.$set(this.postData, 'ALon', '') | |||||
this.$set(this.postData, 'ALat', '') | |||||
this.$set(this.postData, 'ClockPlace', '') | |||||
resolve(false) | resolve(false) | ||||
} | } | ||||
new BMapGL.Convertor().translate([res], 3, 5, data => { | new BMapGL.Convertor().translate([res], 3, 5, data => { | ||||
if(res.status == 0){ | |||||
alert(res.points[0].lng + '' + res.points[0].lat) | |||||
resolve(res.points[0]) | |||||
}else{ | |||||
if (data.status == 0) { | |||||
// alert(data.points[0].lng + '' + data.points[0].lat) | |||||
this.$set(this.postData, 'ALon', data.points[0].lng) | |||||
this.$set(this.postData, 'ALat', data.points[0].lat) | |||||
let geoc = new BMapGL.Geocoder(); | |||||
geoc.getLocation(data.points[0], (rs) => { | |||||
let addComp = rs.addressComponents; | |||||
let address = | |||||
addComp.province + | |||||
addComp.city + | |||||
addComp.district + | |||||
addComp.street + | |||||
addComp.streetNumber | |||||
this.$set(this.postData, 'ClockPlace', address) | |||||
resolve(data.points[0]) | |||||
}); | |||||
} else { | |||||
this.$set(this.postData, 'ALon', '') | |||||
this.$set(this.postData, 'ALat', '') | |||||
this.$set(this.postData, 'ClockPlace', '') | |||||
this.TOAST('获取定位失败!') | |||||
resolve(false) | resolve(false) | ||||
} | } | ||||
}) | }) | ||||
}); | }); | ||||
}, | |||||
} | |||||
}, | }, | ||||
destroyed() { | destroyed() { | ||||
clearInterval(this.timer) | clearInterval(this.timer) | ||||
clearInterval(this.timer1) | |||||
} | } | ||||
} | } | ||||
</script> | </script> | ||||
@@ -0,0 +1,162 @@ | |||||
<template> | |||||
<view class="page"> | |||||
<view v-if="ready"> | |||||
<uploadImage @input="setValue('AttendanceCard.ADPhoto', $event)" :accept="['camera']" :value="getValue('AttendanceCard.ADPhoto')" | |||||
:readonly="!edit" :number="1" title="照片上传" required/> | |||||
<l-textarea @input="setValue('AttendanceCard.ARemark', $event)" :value="getValue('AttendanceCard.ARemark')" | |||||
:readonly="!edit" title="备注" /> | |||||
</view> | |||||
<view v-if="ready" class="bg-white margin-tb padding" style="padding-top: 0; overflow: hidden;"> | |||||
<l-button v-if="edit" @click="action('save')" size="lg" color="green" class="block margin-top" block> | |||||
外勤打卡 | |||||
</l-button> | |||||
</view> | |||||
</view> | |||||
</template> | |||||
<script> | |||||
/* | |||||
* 版 本 Learun-ADMS V7.0.3 力软敏捷开发框架(http://www.learun.cn) | |||||
* Copyright (c) 2013-2020 上海力软信息技术有限公司 | |||||
* 创建人:超级管理员 | |||||
* 日 期:2020-10-21 10:28 | |||||
* 描 述:听课记录 | |||||
*/ | |||||
/** | |||||
* 本段代码由移动端代码生成器输出,移动端须 2.2.0 版本及以上可以使用 | |||||
* 请在移动端 /pages.json 中的 pages 字段中添加一条记录: | |||||
* { "path": "pages/LogisticsManagement/AttendanceCard/single", "style": { "navigationBarTitleText": "表单详情页" } } | |||||
* | |||||
* (navigationBarTitleText 字段为本页面的标题文本,可以修改) | |||||
* (必须自行操作该步骤,力软代码生成器不会自动帮您修改 /pages.json 文件) | |||||
*/ | |||||
import get from 'lodash/get' | |||||
import set from 'lodash/set' | |||||
import moment from 'moment' | |||||
import customPageMixins from '@/common/custompage.js' | |||||
import uploadImage from '@/components/uploadImage.vue' | |||||
export default { | |||||
mixins: [customPageMixins], | |||||
components:{ | |||||
uploadImage | |||||
}, | |||||
data() { | |||||
return { | |||||
// 页面相关参数 | |||||
edit:true, | |||||
mode:null, | |||||
ready: false, | |||||
id:null, | |||||
params:{}, | |||||
// 表单数据 | |||||
current: {}, | |||||
origin: {}, | |||||
// 表单项数据结构 | |||||
scheme: { | |||||
AttendanceCard: { | |||||
ADPhoto: { | |||||
type: 'upload_old', | |||||
title: '图片', | |||||
verify:'NotNull' | |||||
}, | |||||
ARemark: { | |||||
type: 'textarea', | |||||
title: '备注' | |||||
}, | |||||
}, | |||||
}, | |||||
// 数据源 | |||||
dataSource: { | |||||
AttendanceCard: {}, | |||||
} | |||||
} | |||||
}, | |||||
async onLoad({ | |||||
type, | |||||
id | |||||
}) { | |||||
await this.init(type, id) | |||||
}, | |||||
methods: { | |||||
// 页面初始化 | |||||
async init(type, id) { | |||||
this.LOADING('加载数据中...') | |||||
this.params = this.GET_PARAM() | |||||
// 拉取表单数据,同时拉取所有来自数据源的选单数据 | |||||
await Promise.all([ | |||||
() => {} | |||||
]) | |||||
await this.fetchForm() | |||||
this.ready = true | |||||
this.HIDE_LOADING() | |||||
}, | |||||
// 加载表单数据 | |||||
async fetchForm() { | |||||
this.origin = await this.getDefaultForm() | |||||
this.current = this.COPY(this.origin) | |||||
}, | |||||
// 点击 「编辑」、「重置」、「保存」、「删除」 按钮 | |||||
async action(type) { | |||||
switch (type) { | |||||
case 'save': | |||||
const verifyResult = this.verifyForm() | |||||
if (verifyResult.length > 0) { | |||||
this.CONFIRM('表单验证失败', verifyResult.join('\n')) | |||||
return | |||||
} | |||||
if (!(await this.CONFIRM('提交确认', '确定要提交本页表单内容吗?', true))) { | |||||
return | |||||
} | |||||
this.LOADING('正在提交...') | |||||
const postData = await this.getPostData(this.id) | |||||
console.log(postData) | |||||
let strEntity = JSON.parse(postData.strEntity) | |||||
let strEntity_ = {...strEntity,...this.params} | |||||
this.HTTP_POST('learun/adms/attendance/clockin', {strEntity:JSON.stringify(strEntity_)}, '打卡失败').then(success => { | |||||
this.HIDE_LOADING() | |||||
if (!success) { | |||||
this.TOAST('打卡失败') | |||||
return | |||||
} | |||||
this.TOAST('打卡成功', 'success') | |||||
setTimeout(()=>{ | |||||
this.NAV_BACK(2) | |||||
}, 500) | |||||
}) | |||||
break | |||||
default: | |||||
break | |||||
} | |||||
}, | |||||
// 获取表单值 | |||||
getValue(path) { | |||||
return get(this.current, path) | |||||
}, | |||||
// 设置表单值 | |||||
setValue(path, val) { | |||||
set(this.current, path, val) | |||||
}, | |||||
} | |||||
} | |||||
</script> |
@@ -0,0 +1,381 @@ | |||||
<template> | |||||
<view class=""> | |||||
<view v-if="ready" class="contentBox"> | |||||
<view class="rules"> | |||||
<view class=""> | |||||
<view class=""> | |||||
上课 {{info.WorkTime}} | |||||
</view> | |||||
<view class=""> | |||||
{{info.UserWorkTime?info.UserWorkTime.split(' ')[1]+' 打卡':'未打卡'}} | |||||
</view> | |||||
</view> | |||||
<view class=""> | |||||
<view class=""> | |||||
下课 {{info.CloseTime}} | |||||
</view> | |||||
<view class=""> | |||||
{{info.UserCloseTime?info.UserCloseTime.split(' ')[1]+' 打卡':'未打卡'}} | |||||
</view> | |||||
</view> | |||||
</view> | |||||
<view class="content" id="attendContent"> | |||||
<view id="show">{{now}}</view> | |||||
<view class="pen" @click="action('dk')"> | |||||
<img :class="{gray:info.AttendanceType != 1}" id="attimg" :src="imgsrc" alt="" width="100%"> | |||||
</view> | |||||
<view class="title"> | |||||
<text>{{resInfo.AttendanceTypeString}}</text> | |||||
<text>{{postData.AIsOut== 1 ? ' | ' + info.AttendanceTypeString:''}}</text> | |||||
<view style="color: #666;"> | |||||
{{postData.ClockPlace}} | |||||
</view> | |||||
</view> | |||||
</view> | |||||
<view class="footer"> | |||||
<img src="../../common/images/2.png" alt="" width="100%"> | |||||
</view> | |||||
</view> | |||||
<view id='container'></view> | |||||
</view> | |||||
</template> | |||||
<script> | |||||
/* | |||||
* 版 本 Learun-ADMS V7.0.3 力软敏捷开发框架(http://www.learun.cn) | |||||
* Copyright (c) 2013-2020 上海力软信息技术有限公司 | |||||
* 创建人:超级管理员 | |||||
* 日 期:2022-03-10 15:30 | |||||
* 描 述:考勤打卡 | |||||
*/ | |||||
/** | |||||
* 本段代码由移动端代码生成器输出,移动端须 2.2.0 版本及以上可以使用 | |||||
* 请在移动端 /pages.json 中的 pages 字段中添加一条记录: | |||||
* { "path": "pages/AttendanceCard/list", "style": { "navigationBarTitleText": "考勤打卡" } } | |||||
* | |||||
* (navigationBarTitleText 字段为本页面的标题文本,可以修改) | |||||
* (必须自行操作该步骤,力软代码生成器不会自动帮您修改 /pages.json 文件) | |||||
*/ | |||||
import get from 'lodash/get' | |||||
import set from 'lodash/set' | |||||
import moment from 'moment' | |||||
import customPageMixins from '@/common/custompage.js' | |||||
import wxFn from '@/common/wxFn.js' | |||||
//导入图片 | |||||
import dk from '../../common/images/dk.png' | |||||
import dkred from '../../common/images/dkred.png' | |||||
import dkyellow from '../../common/images/dkyellow.png' | |||||
export default { | |||||
mixins: [customPageMixins, wxFn], | |||||
data() { | |||||
return { | |||||
// 页面相关参数 | |||||
info: {}, | |||||
resInfo:{}, | |||||
now: null, | |||||
imgsrc: dk, | |||||
ready: false, | |||||
timer: '', | |||||
timer1:'', | |||||
map: null, | |||||
postData: {}, | |||||
isGetingLocal:false, | |||||
} | |||||
}, | |||||
async onLoad() { | |||||
await this.init() | |||||
}, | |||||
methods: { | |||||
// 页面初始化 | |||||
async init() { | |||||
this.LOADING('加载数据中...') | |||||
this.now = this.getCurrentTime() | |||||
this.timer = setInterval(this.getCurrentTime, 1000) | |||||
let res = await this.judgeIsDK() | |||||
this.ready = res ? true : false | |||||
this.HIDE_LOADING() | |||||
}, | |||||
// 点击 「打卡」按钮 | |||||
async action(type) { | |||||
switch (type) { | |||||
case 'dk': | |||||
if ([5].includes(this.info.AttendanceType)) { | |||||
return | |||||
} | |||||
if ([4].includes(this.info.AttendanceType)) { | |||||
this.NAV_TO(`./single`, this.postData,true) | |||||
return | |||||
} | |||||
this.LOADING() | |||||
this.HTTP_POST('learun/adms/attendance/clockinStudent', {}, '打卡失败').then(success => { | |||||
this.HIDE_LOADING() | |||||
if (!success) { | |||||
this.TOAST('打卡失败') | |||||
return | |||||
} | |||||
this.TOAST('打卡成功', 'success') | |||||
setTimeout(this.back, 500) | |||||
}) | |||||
return | |||||
default: | |||||
break | |||||
} | |||||
}, | |||||
//获取打卡信息 | |||||
async judgeIsDK() { | |||||
let success = await this.HTTP_GET('learun/adms/attendance/IsAttendanceStudent', {}, '判断当前时间是否可以打卡失败') | |||||
if (!success) { | |||||
return false | |||||
} | |||||
this.info = success.data | |||||
this.imgsrc = dk; | |||||
// if ([1].includes(this.info.AttendanceType)) { | |||||
// this.imgsrc=dk; | |||||
// } else if ([2,3].includes(this.info.AttendanceType)) { | |||||
// this.imgsrc=dkyellow; | |||||
// }else { | |||||
// this.imgsrc=dkred; | |||||
// } | |||||
if (![5].includes(this.info.AttendanceType)) { | |||||
// 保存原打卡状态,改为外勤 | |||||
this.resInfo = { | |||||
AttendanceType:this.info.AttendanceType, | |||||
AttendanceTypeString:this.info.AttendanceTypeString, | |||||
} | |||||
this.$set(this.info, 'AttendanceType', 4) | |||||
this.$set(this.info, 'AttendanceTypeString', '外勤打卡') | |||||
this.$set(this.postData, 'AIsOut', 1) | |||||
// 获取定位,不是外勤时候改变状态 | |||||
if (!window.BMapGL) await this.loadJScript() | |||||
this.map = new BMapGL.Map('container'); | |||||
await this.isFieldPersonnel() | |||||
this.timer1 = setInterval(async ()=>{ | |||||
if(this.isGetingLocal)return | |||||
this.isGetingLocal = true | |||||
await this.isFieldPersonnel() | |||||
// console.log(this.postData) | |||||
this.isGetingLocal = false | |||||
},3000) | |||||
} | |||||
return true | |||||
}, | |||||
//返回 | |||||
back() { | |||||
this.NAV_BACK() | |||||
}, | |||||
//获取当前时间 | |||||
getCurrentTime() { | |||||
let nowDate = new Date(); | |||||
let hh = nowDate.getHours(); | |||||
let mf = nowDate.getMinutes() < 10 ? '0' + nowDate.getMinutes() : nowDate.getMinutes(); | |||||
let ss = nowDate.getSeconds() < 10 ? '0' + nowDate.getSeconds() : nowDate.getSeconds(); | |||||
this.now = hh + ':' + mf + ':' + ss; | |||||
}, | |||||
// 判断是否外勤打卡 | |||||
async isFieldPersonnel() { | |||||
let point = new BMapGL.Point(this.info.GPSLon, this.info.GPSLat) | |||||
await this.getDistance(point) | |||||
}, | |||||
//异步加载地图 | |||||
loadJScript() { | |||||
return new Promise((resolve, reject) => { | |||||
window.initMap = function() { | |||||
resolve(BMapGL) | |||||
} | |||||
var script = document.createElement('script'); | |||||
script.type = 'text/javascript'; | |||||
script.src = | |||||
'https://api.map.baidu.com/api?v=1.0&type=webgl&ak=j1TvNK854LRvVuxuAhNNxdhKVB0KbEZD' + | |||||
'&callback=' + 'initMap'; | |||||
script.onerror = reject | |||||
document.head.appendChild(script); | |||||
}) | |||||
}, | |||||
// 计算距离打卡点的距离 | |||||
// 签到状态(1正常打卡,2迟到打卡,3早退打卡,4外勤打卡,5不在考勤时间范围) | |||||
async getDistance(myP1) { | |||||
// new BMapGL.Point(116.404, 39.915) | |||||
let myP2 = await this.local(); | |||||
if (!myP2) { | |||||
// this.TOAST('获取定位失败!') | |||||
this.$set(this.info, 'AttendanceType', 4) | |||||
this.$set(this.info, 'AttendanceTypeString', '外勤打卡') | |||||
this.$set(this.postData, 'AIsOut', 1) | |||||
return | |||||
} | |||||
let distance = this.map.getDistance(myP1, myP2).toFixed(2) | |||||
// alert('距离'+ distance) | |||||
// console.log('距离', distance, '打卡坐标:', myP1, '当前坐标:', myP2) | |||||
if (Number(distance) > Number(this.info.GPSRange)) { | |||||
this.$set(this.info, 'AttendanceType', 4) | |||||
this.$set(this.info, 'AttendanceTypeString', '外勤打卡') | |||||
this.$set(this.postData, 'AIsOut', 1) | |||||
} else { | |||||
this.$set(this.info, 'AttendanceType', this.resInfo.AttendanceType) | |||||
this.$set(this.info, 'AttendanceTypeString', this.resInfo.AttendanceTypeString) | |||||
this.$set(this.postData, 'AIsOut', 0) | |||||
} | |||||
}, | |||||
// 获取当前位置 | |||||
local() { | |||||
return new Promise(async (resolve) => { | |||||
// let res = await this.getLocation() | |||||
let res = { | |||||
lng: 112.57205562051, | |||||
lat: 37.742374280962 | |||||
} | |||||
if (!res) { | |||||
this.$set(this.postData, 'ALon', '') | |||||
this.$set(this.postData, 'ALat', '') | |||||
this.$set(this.postData, 'ClockPlace', '') | |||||
resolve(false) | |||||
} | |||||
new BMapGL.Convertor().translate([res], 3, 5, data => { | |||||
if (data.status == 0) { | |||||
// alert(data.points[0].lng + '' + data.points[0].lat) | |||||
this.$set(this.postData, 'ALon', data.points[0].lng) | |||||
this.$set(this.postData, 'ALat', data.points[0].lat) | |||||
let geoc = new BMapGL.Geocoder(); | |||||
geoc.getLocation(data.points[0], (rs) => { | |||||
let addComp = rs.addressComponents; | |||||
let address = | |||||
addComp.province + | |||||
addComp.city + | |||||
addComp.district + | |||||
addComp.street + | |||||
addComp.streetNumber | |||||
this.$set(this.postData, 'ClockPlace', address) | |||||
resolve(data.points[0]) | |||||
}); | |||||
} else { | |||||
this.$set(this.postData, 'ALon', '') | |||||
this.$set(this.postData, 'ALat', '') | |||||
this.$set(this.postData, 'ClockPlace', '') | |||||
this.TOAST('获取定位失败!') | |||||
resolve(false) | |||||
} | |||||
}) | |||||
}); | |||||
} | |||||
}, | |||||
destroyed() { | |||||
clearInterval(this.timer) | |||||
clearInterval(this.timer1) | |||||
} | |||||
} | |||||
</script> | |||||
<style lang="less"> | |||||
uni-page-body { | |||||
height: 100%; | |||||
width: 100%; | |||||
background-color: #fff; | |||||
} | |||||
.content { | |||||
width: 48%; | |||||
height: 50%; | |||||
position: absolute; | |||||
top: 15%; | |||||
left: 50%; | |||||
transform: translate(-50%, 10%); | |||||
} | |||||
.title { | |||||
font-size: 14px; | |||||
text-align: center; | |||||
color: #333; | |||||
margin-top: 8px; | |||||
} | |||||
.rules { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
color: #666; | |||||
padding: 15px; | |||||
line-height: 24px; | |||||
} | |||||
.rules>* { | |||||
width: 49%; | |||||
background-color: #BDE4FF; | |||||
padding: 8px; | |||||
border-radius: 8px 12px; | |||||
} | |||||
.rules>*>*:first-child { | |||||
color: #333; | |||||
} | |||||
#show { | |||||
text-align: center; | |||||
height: 200rpx; | |||||
font-size: 56rpx; | |||||
} | |||||
.pen { | |||||
// height: 48%; | |||||
border-radius: 50%; | |||||
background-color: #e7f5ff; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
} | |||||
.pen2 { | |||||
width: 91%; | |||||
height: 91%; | |||||
border-radius: 50%; | |||||
background-color: #bde4ff; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
} | |||||
.pen3 { | |||||
width: 84%; | |||||
height: 84%; | |||||
border-radius: 50%; | |||||
background-color: #0c86d8; | |||||
text-align: center; | |||||
font-size: 68rpx; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
color: #ffff; | |||||
} | |||||
.footer { | |||||
width: 100%; | |||||
position: fixed; | |||||
left: 0; | |||||
bottom: 0; | |||||
overflow: hidden; | |||||
} | |||||
.gray { | |||||
-webkit-filter: grayscale(100%); | |||||
-moz-filter: grayscale(100%); | |||||
-ms-filter: grayscale(100%); | |||||
-o-filter: grayscale(100%); | |||||
filter: grayscale(100%); | |||||
filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); | |||||
filter: gray; | |||||
} | |||||
</style> |
@@ -0,0 +1,162 @@ | |||||
<template> | |||||
<view class="page"> | |||||
<view v-if="ready"> | |||||
<uploadImage @input="setValue('AttendanceCard.ADPhoto', $event)" :accept="['camera']" :value="getValue('AttendanceCard.ADPhoto')" | |||||
:readonly="!edit" :number="1" title="照片上传" required/> | |||||
<l-textarea @input="setValue('AttendanceCard.ARemark', $event)" :value="getValue('AttendanceCard.ARemark')" | |||||
:readonly="!edit" title="备注" /> | |||||
</view> | |||||
<view v-if="ready" class="bg-white margin-tb padding" style="padding-top: 0; overflow: hidden;"> | |||||
<l-button v-if="edit" @click="action('save')" size="lg" color="green" class="block margin-top" block> | |||||
外勤打卡 | |||||
</l-button> | |||||
</view> | |||||
</view> | |||||
</template> | |||||
<script> | |||||
/* | |||||
* 版 本 Learun-ADMS V7.0.3 力软敏捷开发框架(http://www.learun.cn) | |||||
* Copyright (c) 2013-2020 上海力软信息技术有限公司 | |||||
* 创建人:超级管理员 | |||||
* 日 期:2020-10-21 10:28 | |||||
* 描 述:听课记录 | |||||
*/ | |||||
/** | |||||
* 本段代码由移动端代码生成器输出,移动端须 2.2.0 版本及以上可以使用 | |||||
* 请在移动端 /pages.json 中的 pages 字段中添加一条记录: | |||||
* { "path": "pages/LogisticsManagement/AttendanceCard/single", "style": { "navigationBarTitleText": "表单详情页" } } | |||||
* | |||||
* (navigationBarTitleText 字段为本页面的标题文本,可以修改) | |||||
* (必须自行操作该步骤,力软代码生成器不会自动帮您修改 /pages.json 文件) | |||||
*/ | |||||
import get from 'lodash/get' | |||||
import set from 'lodash/set' | |||||
import moment from 'moment' | |||||
import customPageMixins from '@/common/custompage.js' | |||||
import uploadImage from '@/components/uploadImage.vue' | |||||
export default { | |||||
mixins: [customPageMixins], | |||||
components:{ | |||||
uploadImage | |||||
}, | |||||
data() { | |||||
return { | |||||
// 页面相关参数 | |||||
edit:true, | |||||
mode:null, | |||||
ready: false, | |||||
id:null, | |||||
params:{}, | |||||
// 表单数据 | |||||
current: {}, | |||||
origin: {}, | |||||
// 表单项数据结构 | |||||
scheme: { | |||||
AttendanceCard: { | |||||
ADPhoto: { | |||||
type: 'upload_old', | |||||
title: '图片', | |||||
verify:'NotNull' | |||||
}, | |||||
ARemark: { | |||||
type: 'textarea', | |||||
title: '备注' | |||||
}, | |||||
}, | |||||
}, | |||||
// 数据源 | |||||
dataSource: { | |||||
AttendanceCard: {}, | |||||
} | |||||
} | |||||
}, | |||||
async onLoad({ | |||||
type, | |||||
id | |||||
}) { | |||||
await this.init(type, id) | |||||
}, | |||||
methods: { | |||||
// 页面初始化 | |||||
async init(type, id) { | |||||
this.LOADING('加载数据中...') | |||||
this.params = this.GET_PARAM() | |||||
// 拉取表单数据,同时拉取所有来自数据源的选单数据 | |||||
await Promise.all([ | |||||
() => {} | |||||
]) | |||||
await this.fetchForm() | |||||
this.ready = true | |||||
this.HIDE_LOADING() | |||||
}, | |||||
// 加载表单数据 | |||||
async fetchForm() { | |||||
this.origin = await this.getDefaultForm() | |||||
this.current = this.COPY(this.origin) | |||||
}, | |||||
// 点击 「编辑」、「重置」、「保存」、「删除」 按钮 | |||||
async action(type) { | |||||
switch (type) { | |||||
case 'save': | |||||
const verifyResult = this.verifyForm() | |||||
if (verifyResult.length > 0) { | |||||
this.CONFIRM('表单验证失败', verifyResult.join('\n')) | |||||
return | |||||
} | |||||
if (!(await this.CONFIRM('提交确认', '确定要提交本页表单内容吗?', true))) { | |||||
return | |||||
} | |||||
this.LOADING('正在提交...') | |||||
const postData = await this.getPostData(this.id) | |||||
console.log(postData) | |||||
let strEntity = JSON.parse(postData.strEntity) | |||||
let strEntity_ = {...strEntity,...this.params} | |||||
this.HTTP_POST('learun/adms/attendance/clockinStudent', {strEntity:JSON.stringify(strEntity_)}, '打卡失败').then(success => { | |||||
this.HIDE_LOADING() | |||||
if (!success) { | |||||
this.TOAST('打卡失败') | |||||
return | |||||
} | |||||
this.TOAST('打卡成功', 'success') | |||||
setTimeout(()=>{ | |||||
this.NAV_BACK(2) | |||||
}, 500) | |||||
}) | |||||
break | |||||
default: | |||||
break | |||||
} | |||||
}, | |||||
// 获取表单值 | |||||
getValue(path) { | |||||
return get(this.current, path) | |||||
}, | |||||
// 设置表单值 | |||||
setValue(path, val) { | |||||
set(this.current, path, val) | |||||
}, | |||||
} | |||||
} | |||||
</script> |