This commit is contained in:
@jyuhsin
2025-11-07 11:56:13 +08:00
parent 90026a54a3
commit ae86803b17
17 changed files with 381 additions and 159 deletions
@@ -0,0 +1,91 @@
// =============== 坐标系工具 ===============
const PI = 3.1415926535897932384626
const a = 6378245.0 //卫星椭球坐标投影到平面地图坐标系的投影因子。
const ee = 0.00669342162296594323 //椭球的偏心率。
const coordinateUtil = {
// 判断是否在中国范围(仅中国加密)
outOfChina(lon, lat) {
if (lon < 72.004 || lon > 137.8347) {
return true;
}
if (lat < 0.8293 || lat > 55.8271) {
return true;
}
return false;
},
// 基础偏移计算
transformLat(lng, lat) {
let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng))
ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0
ret += ((20.0 * Math.sin(lat * PI) + 40.0 * Math.sin((lat / 3.0) * PI)) * 2.0) / 3.0
ret += ((160.0 * Math.sin((lat / 12.0) * PI) + 320 * Math.sin((lat * PI) / 30.0)) * 2.0) / 3.0
return ret
},
transformLng(lng, lat) {
let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng))
ret += ((20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0) / 3.0
ret += ((20.0 * Math.sin(lng * PI) + 40.0 * Math.sin((lng / 3.0) * PI)) * 2.0) / 3.0
ret += ((150.0 * Math.sin((lng / 12.0) * PI) + 300.0 * Math.sin((lng / 30.0) * PI)) * 2.0) / 3.0
return ret
},
// WGS-84 → GCJ-02(用于地图展示)
wgs84ToGcj02(lng, lat) {
let dlat = this.transformLat(lng - 105.0, lat - 35.0);
let dlng = this.transformLng(lng - 105.0, lat - 35.0);
let radlat = (lat / 180.0) * PI;
let magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
let sqrtmagic = Math.sqrt(magic);
dlat =
(dlat * 180.0) /
(((a * (1 - ee)) / (magic * sqrtmagic)) * PI);
dlng =
(dlng * 180.0) / ((a / sqrtmagic) * Math.cos(radlat) * PI);
let mglat = lat + dlat;
let mglng = lng + dlng;
return [mglat, mglng];
},
// GCJ-02 → WGS-84(用于存储签到点)
gcj02ToWgs84(lng, lat) {
const originalLngSign = Math.sign(lng);
const originalLatSign = Math.sign(lat);
lat = Math.abs(lat);
lng = Math.abs(lng);
let dlat = this.transformLat(lng - 105.0, lat - 35.0)
let dlng = this.transformLng(lng - 105.0, lat - 35.0)
let radlat = lat / 180.0 * PI
let magic = Math.sin(radlat)
magic = 1 - ee * magic * magic
let sqrtmagic = Math.sqrt(magic)
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI)
let mglat = lat + dlat
let mglng = lng + dlng
let lngs = lng * 2 - mglng
let lats = lat * 2 - mglat
let finalLng = originalLngSign * lngs;
let finalLat = originalLatSign * lats;
return [finalLat, finalLng];
},
// 计算两点间距离(米),输入 WGS-84 坐标
getDistance(lat1, lng1, lat2, lng2) {
const R = 6371000; // 地球半径(米)
const φ1 = lat1 * Math.PI / 180;
const φ2 = lat2 * Math.PI / 180;
const Δφ = (lat2 - lat1) * Math.PI / 180;
const Δλ = (lng2 - lng1) * Math.PI / 180;
const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
},
};
@@ -55,6 +55,7 @@
<script src="${base!}/components/plugins/sysDict/DictData.js"></script>
<script src="${base!}/assets/platform/js/util/commonUtil.js"></script>
<script src="${base!}/assets/platform/js/util/coordinateUtil.js"></script>
<script src="${base!}/assets/platform/js/main.js"></script>
<script src="${base!}/assets/platform/js/mixin/styleMixin.js"></script>
<script src="${base!}/assets/platform/js/tool/businessTool.js"></script>
@@ -375,6 +376,7 @@
Vue.prototype.$moment = moment
Vue.prototype.$businessTool = businessTool
Vue.prototype.$commonUtil = commonUtil
Vue.prototype.$coordinateUtil = coordinateUtil
Vue.prototype.$auth = commonUtil.authService()
Vue.prototype.$axios = commonUtil.axiosService()
Vue.prototype.$downLoad = commonUtil.downLoadService.bind(commonUtil)
@@ -11,7 +11,6 @@
<link rel="stylesheet" href="${base!}/assets/platform/css/root.css" />
<link rel="stylesheet" href="${base!}/assets/platform/fonts/themify-icons.css" />
<link rel="stylesheet" href="${base!}/assets/platform/fonts/font-awesome.min.css" />
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/qweather-icons@1.3.0/font/qweather-icons.css">-->
<!-- import Vue before Element -->
<script src="${base!}/assets/platform/plugins/vue/vue.js"></script>
@@ -72,7 +71,7 @@
<script src="https://vxeui.com/umd/xe-utils@3.5.30/dist/xe-utils.umd.min.js"></script>
<script src="https://vxeui.com/umd/vxe-pc-ui@3.1.25/lib/index.umd.min.js"></script>
<script src="https://vxeui.com/umd/vxe-table@3.9.0/lib/index.umd.min.js"></script>
l
l
<!-- 引入 form-create 和 designer -->
<script src="${base!}/assets/platform/plugins/form-create/form-create.min.js"></script>
<script src="${base!}/assets/platform/plugins/form-create/index.umd.js"></script>
@@ -85,6 +84,7 @@ l
<script src="${base!}/components/plugins/sysDict/DictData.js"></script>
<script src="${base!}/assets/platform/js/util/commonUtil.js"></script>
<script src="${base!}/assets/platform/js/util/coordinateUtil.js"></script>
<script src="${base!}/assets/platform/js/main.js"></script>
<script src="${base!}/assets/platform/js/mixin/initTableMixins.js"></script>
<script src="${base!}/assets/platform/js/mixin/styleMixin.js"></script>
@@ -98,7 +98,7 @@ l
src="https://webapi.amap.com/maps?v=2.0&key=b4fa2e2bc10a725ab007b98a3aa447cc&plugin=AMap.PolyEditor,AMap.Geolocation"
></script>-->
<!-- <script src="https://map.qq.com/api/gljs?v=2.exp&key=MLLBZ-GQECI-ASXG7-5GNOZ-XW2OF-H5BVH"></script>-->
<script src="https://map.qq.com/api/gljs?v=2.exp&key=MLLBZ-GQECI-ASXG7-5GNOZ-XW2OF-H5BVH"></script>
<script type="text/javascript">
window._AMapSecurityConfig = {
@@ -327,6 +327,7 @@ l
Vue.prototype.$moment = moment
Vue.prototype.$businessTool = businessTool
Vue.prototype.$commonUtil = commonUtil
Vue.prototype.$coordinateUtil = coordinateUtil
Vue.prototype.$auth = commonUtil.authService()
Vue.prototype.$axios = commonUtil.axiosService()
Vue.prototype.$downLoad = commonUtil.downLoadService
@@ -703,7 +704,7 @@ l
})
}
// 页面加载时设置active状态和页脚显示
// 页面加载时设置active状态和页脚显示
setActiveNavItem()
toggleFooter()
@@ -179,10 +179,10 @@ const customForm = {
<el-dialog :close-on-click-modal="false" :visible.sync="mapDialog" title="位置信息" :append-to-body="true">
<map-container v-if="mapDialog"
:radius="formData.courseList[moreInfoIndex].radius"
:radius="formData.courseList[moreInfoIndex].radius ? Number(formData.courseList[moreInfoIndex].radius) : 100"
:position.sync="formData.courseList[mapIndex].courseLocationCoordinates"></map-container>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="mapDialog = false">确 定</el-button>
<el-button type="primary" @click="onMap">确 定</el-button>
</span>
</el-dialog>
@@ -221,6 +221,13 @@ const customForm = {
this.unionList = await this.$businessTool.listUnion()
this.moreInfoDrawer = true
},
onMap() {
const posi = this.formData.courseList[this.mapIndex].courseLocationCoordinates
if(posi && posi.length > 1) {
this.formData.courseList[this.mapIndex].transPosition = this.$coordinateUtil.gcj02ToWgs84(posi[1], posi[0])
}
this.mapDialog = false
}
},
created() {
if(!this.formData.courseList) {
@@ -23,14 +23,14 @@ const info = {
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="签到情况" v-if="clickRow.isMobileSign === true && Object.keys(userSignInfo).length > 0">
<el-tabs style="height: 600px" tab-position="left" class="mt20">
<el-tab-pane v-for="(item, key) in userSignInfo" :key="key">
<el-tab-pane label="签到情况" v-if="clickRow.isMobileSign === true && timeList.length > 0">
<el-tabs style="height: 660px" tab-position="left" class="mt20" @tab-click="tabClick">
<el-tab-pane v-for="item,index in timeList" :key="index">
<span slot="label">
<i class="el-icon-date"></i>
{{key}}
{{item.courseStartTime + ' 至 ' + item.courseEndTime}}
</span>
<el-table :data="item" style="max-height: 600px; overflow-y: auto">
<el-table :data="signUserList" style="max-height: 600px; overflow-y: auto">
<el-table-column label="姓名" prop="username"></el-table-column>
<el-table-column label="工号" prop="loginname"></el-table-column>
<el-table-column label="是否签到" prop="isAttend">
@@ -45,7 +45,14 @@ const info = {
</template>
</el-table-column>
<el-table-column label="签到时间" prop="attendTime"></el-table-column>
<el-table-column label="操作" prop="attendTime">
<template v-slot="{ row }">
<el-button v-if="row.isAttend" @click="onSign(row)" size="mini" type="danger">设置未签到</el-button>
<el-button v-if="!row.isAttend" @click="onSign(row)" size="mini" type="primary">设置签到</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-tab-pane>
</el-tabs>
</el-tab-pane>
@@ -53,6 +60,7 @@ const info = {
</div>
`,
dicts: ["TRAIN_SIGNUP_TYPE"],
mixins: [initTableMixins],
data() {
return {
registerUserTableData: [],
@@ -74,23 +82,77 @@ const info = {
{label: '报名时间', prop: 'signUpTime'},
{label: '报名状态', prop: 'state'},
],
userSignInfo: {},
clickRow: {}
clickRow: {},
timeList: [],
signUserList: [],
timeId: '',
pageForm: {},
}
},
methods: {
async onOpen(row) {
this.clickRow = row
const resp_register = await this.$axios.post(loc() + "/registerUserList", {courseId: row.id})
this.registerUserTableData = resp_register.data
const resp_signInfo = await this.$axios.post(loc() + "/getSignInfo", {courseId: row.id})
this.userSignInfo = resp_signInfo.data
const resp_columnInfo = await $.get(loc() + '/getTaleColumnInfo', {courseId: row.id})
if (resp_columnInfo.data) {
this.registerUserTableColumns = []
this.registerUserTableColumns = this.cloneTableColumns.concat(resp_columnInfo.data)
await this.registerUserList()
await this.selectTimes()
await this.getTaleColumnInfo()
},
async doSearch() {
this.pageForm.pageNumber = 1
await this.selectSignUsers(this.timeId)
},
async pageNumberChange(val) {
this.pageForm.pageNumber = val
await this.selectSignUsers(this.timeId)
},
async pageSizeChange(val) {
this.pageForm.pageSize = val
await this.selectSignUsers(this.timeId)
},
onSign(row) {
this.$confirm("您确定要设置吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/platform/trainSignUp/statistics/adjustSign", { id: row.id }).then(async (res) => {
if (res.code === 0) {
this.$message.success(res.msg)
await this.selectSignUsers(this.timeId)
}
})
})
},
async tabClick(val) {
await this.selectSignUsers(this.timeList[val.index].id)
},
async registerUserList() {
const res = await this.$axios.post(loc() + "/registerUserList", { courseId: this.clickRow.id })
this.registerUserTableData = res.data
},
async selectTimes() {
const res = await this.$axios.post(loc() + "/selectTimes", { courseId: this.clickRow.id })
this.timeList = res.data
if(this.timeList.length > 0) {
await this.selectSignUsers(this.timeList[0].id)
}
}
},
async selectSignUsers(timeId) {
this.timeId = timeId
this.$set(this.pageForm, 'courseId', this.clickRow.id)
this.$set(this.pageForm, 'timeId', timeId)
const res = await this.$axios.post(loc() + "/getSignInfo", this.pageForm)
if (res.code === 0) {
this.signUserList = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
},
async getTaleColumnInfo() {
const res = await $.get(loc() + '/getTaleColumnInfo', { courseId: this.clickRow.id })
if (res.data) {
this.registerUserTableColumns = []
this.registerUserTableColumns = this.cloneTableColumns.concat(res.data)
}
},
},
style: /*language=CSS*/ `
@@ -89,72 +89,51 @@ layout("/layouts/platform_h5.html"){
}],
});
},
getLocation(callback) {
if (typeof callback !== 'function') {
callback = () => {};
}
if (!navigator.geolocation) {
this.$toast('当前浏览器不支持定位功能');
callback(null);
return;
}
const loading = vant.Toast.loading({
message: "获取定位中...",
forbidClick: false,
loadingType: "spinner",
duration: 0,
})
navigator.geolocation.getCurrentPosition(
(position) => {
callback({
lat: position.coords.latitude,
lng: position.coords.longitude
});
loading.close()
},
(error) => {
let msg = '定位失败,请稍后重试';
switch (error.code) {
case error.PERMISSION_DENIED:
msg = '请允许浏览器获取位置信息';
break;
case error.POSITION_UNAVAILABLE:
msg = '无法获取当前位置';
break;
case error.TIMEOUT:
msg = '定位超时,请重试';
break;
}
this.$toast(msg);
callback(null);
loading.close()
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000
getUserLocation() {
return new Promise((resolve) => {
if (!navigator.geolocation) {
vant.Toast('浏览器不支持定位');
return resolve(null);
}
);
const loading = vant.Toast.loading({ message: '定位中...', duration: 0 });
navigator.geolocation.getCurrentPosition(
(pos) => {
loading.close();
resolve({
lat: pos.coords.latitude,
lng: pos.coords.longitude
});
if (this.markerLayer) {
this.markerLayer.remove(["current"])
}
const transPosi = this.$coordinateUtil.wgs84ToGcj02(pos.coords.longitude, pos.coords.latitude)
console.log(transPosi)
const center = new TMap.LatLng(transPosi[0], transPosi[1])
this.createMarker(center, 'current', 'current')
},
(err) => {
console.log(err)
loading.close();
vant.Toast('定位失败,请重试');
resolve(null);
},
{ enableHighAccuracy: true, timeout: 3000 }
);
});
},
async fetchCourse() {
const res = await this.$axios.post('/platform/trainSignUp/mine/fetchCourse', {courseId: this.courseId})
this.row = res.data
},
onSign() {
if(this.markerLayer) {
this.markerLayer.remove(["current"])
async onSign() {
const coords = await this.getUserLocation()
if (coords) {
this.res = await this.$axios.post('/platform/trainSignUp/mine/drivingScan', {
courseId: this.row.id,
lat: coords.lat,
lng: coords.lng
})
}
this.getLocation(async (coords) => {
if (coords) {
const center = new TMap.LatLng(coords.lat, coords.lng)
this.createMarker(center, 'current', 'current')
this.res = await this.$axios.post('/platform/trainSignUp/mine/drivingScan', {
courseId: this.row.id,
lat: coords.lat,
lng: coords.lng
})
}
})
}
},
async created() {