# Conflicts:
#	src/main/resources/views/platform/zhgh/activity/trainSignUp/manage/basicForm.js
This commit is contained in:
2025-10-31 11:09:16 +08:00
35 changed files with 700 additions and 140 deletions
@@ -80,6 +80,7 @@
src="https://webapi.amap.com/maps?v=2.0&key=57f0d098ba1b881ecc436c4cfd23bbbf&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>
Vue.config.devtools = true
@@ -31,9 +31,9 @@
<link rel="stylesheet" href="${base!}/assets/platform/css/common.css" />
<!-- import Jquery -->
<script src="${base!}/assets/platform/plugins/jquery/jquery-high.min.js"></script>
<script src="${base!}/assets/platform/plugins/jquery/jquery.js"></script>
<!-- pjax是异步加载html片段的工具,模拟前端路由机制 -->
<script src="${base!}/assets/platform/plugins/pjax/jquery.pjax-high.min.js"></script>
<script src="${base!}/assets/platform/plugins/pjax/jquery.pjax.js"></script>
<!-- nprogress 配合pjax使用 -->
<link rel="stylesheet" href="${base!}/assets/platform/plugins/nprogress/nprogress.css" />
<script src="${base!}/assets/platform/plugins/nprogress/nprogress.js"></script>
@@ -92,28 +92,13 @@ l
<script src="${base!}/assets/platform/js/util/autoShowError.js"></script>
<script src="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.min.js"></script>
<script>
// 安全地冻结 Object.prototype(跳过不可配置属性)
(function () {
const badKeys = ['constructor', 'prototype'];
for (const key of badKeys) {
if (key in Object.prototype) {
try {
delete Object.prototype[key];
} catch (e) {
// 忽略无法删除的属性(如 __proto__ 在现代浏览器中不可删除)
}
}
}
<!--<script
type="text/javascript"
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>
// 冻结 Object.prototype(如果可能)
try {
Object.freeze(Object.prototype);
} catch (e) {
// 忽略错误(某些环境可能不允许)
}
})();
</script>
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: "4fa1e1aeabba7eb9518129cf57ab17c1"
@@ -71,22 +71,21 @@ layout("/layouts/platform.html"){
<el-table-column prop="loginname" label="工号" width="100" fixed="left"></el-table-column>
<el-table-column prop="username" label="姓名" fixed="left" width="120" show-overflow-tooltip></el-table-column>
<el-table-column prop="sex" label="性别" sortable></el-table-column>
<!-- <el-table-column prop="mobile" label="手机号" width="120"></el-table-column>-->
<el-table-column prop="mobile" label="手机号" width="120"></el-table-column>
<el-table-column prop="birthday" label="生日" sortable width="120">
<template slot-scope="{row}">{{$moment(row.birthday).format('YYYY-MM-DD')}}</template>
</el-table-column>
<el-table-column prop="userState" label="在职状态" sortable width="120"></el-table-column>
<el-table-column prop="arrivalAtSchoolDate" label="来校时间" sortable width="120"></el-table-column>
<el-table-column prop="preparedBy" label="编制类别" sortable width="120"></el-table-column>
<el-table-column prop="postDoctoralJoinDate" label="进站时间" sortable width="120"></el-table-column>
<el-table-column prop="personType" label="教职工类别" sortable width="120"></el-table-column>
<el-table-column prop="comeSchoolDate" label="来校年月" sortable width="120"></el-table-column>
<el-table-column prop="technicalTitle" label="技术职称" sortable width="120"></el-table-column>
<el-table-column prop="position" label="干部职务" sortable width="120" show-overflow-tooltip></el-table-column>
<el-table-column prop="education" label="学历" show-overflow-tooltip sortable width="120"></el-table-column>
<el-table-column prop="academicDegree" label="学位" show-overflow-tooltip sortable width="120"></el-table-column>
<el-table-column prop="unitName" label="单位" show-overflow-tooltip sortable width="120"></el-table-column>
<el-table-column prop="unitId" label="单位编码" sortable width="120"></el-table-column>
<el-table-column prop="nationality" label="国籍" sortable></el-table-column>
<el-table-column prop="political" label="政治面貌" sortable></el-table-column>
<el-table-column prop="nation" label="民族" sortable></el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
@@ -92,7 +92,7 @@
<!-- import axios -->
<script src="${base!}/assets/platform/plugins/axios/axios.js"></script>
<!-- import Jquery -->
<script src="${base!}/assets/platform/plugins/jquery/jquery-high.min.js"></script>
<script src="${base!}/assets/platform/plugins/jquery/jquery.js"></script>
<!-- import SM2 -->
<script src="${base!}/assets/platform/plugins/sm-crypto/sm2.js"></script>
<!-- import commonUtil -->
@@ -31,11 +31,11 @@ const courseList = {
<el-col class="query-content">
<el-tag
:effect="pageForm.assortTypes.includes(item) ? 'dark' : 'plain'"
:key="item"
:key="index"
:type="item"
@click="tagClick('assortTypes', item)"
style="margin-right: 10px; cursor: pointer"
v-for="item in assortList"
v-for="item,index in assortList"
>
{{ item }}
</el-tag>
@@ -31,11 +31,11 @@ const courseList = {
<el-col class="query-content">
<el-tag
:effect="pageForm.assortTypes.includes(item) ? 'dark' : 'plain'"
:key="item"
:key="index"
:type="item"
@click="tagClick('assortTypes', item)"
style="margin-right: 10px; cursor: pointer"
v-for="item in assortList"
v-for="item,index in assortList"
>
{{ item }}
</el-tag>
@@ -67,7 +67,7 @@ const basicForm = {
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" >
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item label="面向对象" prop="joinCnd">
<div style="display: flex; justify-content: space-between">
@@ -101,31 +101,19 @@ const basicForm = {
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item prop="hostUnitIds" label="主办单位">
<el-select v-model="formData.hostUnitIds" clearable filterable multiple
placeholder="请选择主办单位"
style="width: 100%">
<el-option
v-for="item in unitOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
<el-form-item label="主办单位" prop="hostUnits">
<el-select multiple filterable placeholder="请选择主办单位" style="width: 100%" v-model="formData.hostUnits">
<el-option :label="item.name" :value="item.id" :key="item.id" v-for="item in undertakeOptions"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="undertakeUnitIds" label="承办单位">
<el-select v-model="formData.undertakeUnitIds" clearable filterable multiple
placeholder="请选择承办单位"
style="width: 100%">
<el-option
v-for="item in unitOptions"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
<el-form-item label="协办单位" prop="helpUnits">
<el-select multiple filterable placeholder="请选择协办单位" style="width: 100%" v-model="formData.helpUnits">
<el-option :label="item.name" :value="item.id" :key="item.id" v-for="item in undertakeOptions"></el-option>
</el-select>
</el-form-item>
</el-col>
@@ -346,7 +334,9 @@ const basicForm = {
},
restrictLimit: 1,
limitNum: 1,
typeLimits: []
typeLimits: [],
hostUnits: [],
helpUnits: [],
},
historicalActList: [],
trainTypeList: [],
@@ -359,9 +349,7 @@ const basicForm = {
},
campusList: [],
courseTypeList: [],
unitOptions: [],
clubOptions: [],
undertakeOptions: [],
}
},
components: {
@@ -568,8 +556,8 @@ const basicForm = {
}
cloneData.typeLimits = JSON.stringify(this.formData.typeLimits)
cloneData.courseList = JSON.stringify(cloneData.courseList)
cloneData.undertakeUnitIds = JSON.stringify(cloneData.undertakeUnitIds)
cloneData.hostUnitIds = JSON.stringify(cloneData.hostUnitIds)
cloneData.hostUnits = JSON.stringify(cloneData.hostUnits)
cloneData.helpUnits = JSON.stringify(cloneData.helpUnits)
const confirm = await this.$confirm("您确定要" + type + "吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
@@ -599,22 +587,16 @@ const basicForm = {
}
}
},
async getClubsByRole() {
const resp = await this.$axios.post("/platform/club/examine/apply/getClubsByRole")
return resp.data
},
async initData(row) {
this.activityGroupList = await this.getActivityGroup()
this.historicalActList = await this.getHistoricalActList()
this.courseTypeList = await this.getAllType()
await this.selectUnionAndClub()
await this.init(row)
this.clubOptions = await this.getClubsByRole()
this.clubOptions.map((v) => {
v.name = v.clubName
})
const units = await this.$businessTool.listUnit()
this.unitOptions = this.clubOptions.concat(units)
},
async selectUnionAndClub() {
const resp = await this.$axios.post("/platform/trainSignUp/manage/selectUnionAndClub")
this.undertakeOptions = resp.data
},
},
watch: {
@@ -75,11 +75,32 @@ const customForm = {
</el-col>
</el-row>
<el-row v-if="formData.courseList[moreInfoIndex].isMobileSign === true" :gutter="50" type="flex">
<el-col :span="4">
<span>签到时间误差</span>
</el-col>
<el-col :span="20">
<el-input placeholder="请输入签到时间误差" v-model="formData.courseList[moreInfoIndex].signUnit" type="number">
<template slot="append">分钟</template>
</el-input>
</el-col>
</el-row>
<el-row v-if="formData.courseList[moreInfoIndex].isMobileSign === true" :gutter="50" type="flex">
<el-col :span="4">
<span>签到半径</span>
</el-col>
<el-col :span="20">
<el-input placeholder="请输入签到半径" v-model="formData.courseList[moreInfoIndex].radius" type="number">
<template slot="append">米</template>
</el-input>
</el-col>
</el-row>
<el-row
v-if="formData.courseList[moreInfoIndex].isMobileSign === true
&& formData.courseList[moreInfoIndex].signType == 3"
:gutter="50"
type="flex"
v-if="formData.courseList[moreInfoIndex].isMobileSign === true"
:gutter="50"
type="flex"
>
<el-col :span="4">
<span>地点坐标</span>
@@ -157,7 +178,9 @@ const customForm = {
</el-drawer>
<el-dialog :close-on-click-modal="false" :visible.sync="mapDialog" title="位置信息" :append-to-body="true">
<map-container v-if="mapDialog" :position.sync="formData.courseList[mapIndex].courseLocationCoordinates"></map-container>
<map-container v-if="mapDialog"
:radius="formData.courseList[moreInfoIndex].radius"
:position.sync="formData.courseList[mapIndex].courseLocationCoordinates"></map-container>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="mapDialog = false">确 定</el-button>
</span>
@@ -181,7 +204,7 @@ const customForm = {
},
components: {
"union-form": unionForm,
"map-container": httpVueLoader("/components/plugins/mapContainer/MapContainer.vue?v=1.0.1")
"map-container": httpVueLoader("/components/plugins/mapContainer/TMap.vue?v=1.0.6")
},
methods: {
openMap(index) {
@@ -66,14 +66,14 @@ const makeQrcode = {
this.courseDialog = true
},
makeCourseCode(row) {
const url = '/platform/trainSignUp/mine/drivingScan'
const url = '${AppDomain!}/platform/trainSignUp/mine/drivingScan'
const data = url + '?courseId=' + row.id
console.log(data)
const content = jrQrcode.getQrBase64(data)
let image = new Image()
image.src = content
let viewer = new Viewer(image, {
zIndex: 99999999,
zIndex: 999999,
})
viewer.show()
},
@@ -115,9 +115,11 @@ layout("/layouts/platform.html"){
}
},
activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.TRAIN_SIGNUP_TYPE.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
this.$nextTick(() => {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.TRAIN_SIGNUP_TYPE?.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
})
},
exportSignUser() {
this.$downLoad(loc() + "/exportSignUser", { activityId: this.pageForm.activityId })
@@ -105,9 +105,11 @@ layout("/layouts/platform.html"){
},
methods: {
activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.TRAIN_SIGNUP_TYPE.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
this.$nextTick(() => {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.TRAIN_SIGNUP_TYPE?.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
})
},
async yearChange() {
this.pageForm.activityId = null
@@ -108,8 +108,8 @@ layout("/layouts/platform.html"){
{ label: "姓名", prop: "username" },
{ label: "工号", prop: "loginname" },
{ label: "联系方式", prop: "mobile" },
{ label: "单位", prop: "unitname", sortable: true },
{ label: "分工会", prop: "unionname", sortable: true },
{ label: "单位", prop: "unitName", sortable: true },
{ label: "分工会", prop: "unionName", sortable: true },
{ label: "课程", prop: "courseNames", sortable: true },
{ label: "缺席次数", prop: "absentCount" },
{ label: "是否黑名单", prop: "isDisabled", sortable: true }
@@ -192,12 +192,14 @@ layout("/layouts/platform.html"){
this.$downLoad(url, param)
},
async activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.TRAIN_SIGNUP_TYPE.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
const resp = await this.$axios.post(loc() + "/getCourseByActivityId", { activityId: val })
this.courseList = resp.data
this.pageForm.courseId = ""
this.$nextTick(async () => {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.TRAIN_SIGNUP_TYPE?.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
const resp = await this.$axios.post(loc() + "/getCourseByActivityId", { activityId: val })
this.courseList = resp.data
this.pageForm.courseId = ""
})
},
async handleUser(userId) {
const resp = await $.post(loc() + "/doHandleUser", { userId })
@@ -57,8 +57,7 @@ const CLUB_MANAGER_TEMPLATE = {
<el-button type="primary" @click="managePerson.push({})" size="mini">增加</el-button>
</template>
<template slot-scope="scope">
<el-button :disabled="scope.row.roleCode === 'CLUB_PRESIDENT'
|| scope.row.roleCode === 'CLUB_SECRETARY'"
<el-button
@click="deleteRow(scope.row, scope.$index)"
size="mini" type="danger">删除
</el-button>
@@ -101,7 +101,7 @@ layout("/layouts/platform.html"){
async doHandle(type) {
let formData = {}
try {
let hz = this.$refs.clubManagerRef.managePerson.filter((o) => o.roleCode === CLUB_ROLE_CONSTANT.CLUB_PRESIDENT)
/*let hz = this.$refs.clubManagerRef.managePerson.filter((o) => o.roleCode === CLUB_ROLE_CONSTANT.CLUB_PRESIDENT)
if (hz.length !== 1) {
this.$message.warning({ title: "警告", message: "会长需要1人" })
return
@@ -110,14 +110,14 @@ layout("/layouts/platform.html"){
if (msz.length !== 1) {
this.$message.warning({ title: "警告", message: "秘书长需要1人" })
return
}
}*/
formData.sponsor = this.$refs.clubSponsorRef.sponsorData
.filter((o) => o.userId !== "" && o.userId !== undefined)
.map((o) => o.userId)
if (['onFinishTask', 'onSubmit'].includes(type) && formData.sponsor && formData.sponsor.length < 3) {
/*if (['onFinishTask', 'onSubmit'].includes(type) && formData.sponsor && formData.sponsor.length < 3) {
this.$message.warning({ title: "警告", message: "发起人要求不少于3人" })
return
}
}*/
let manageValid = false
for (const item of this.$refs.clubManagerRef.managePerson) {
if (!item.userId) {
@@ -125,10 +125,10 @@ layout("/layouts/platform.html"){
break
}
}
if (['onFinishTask', 'onSubmit'].includes(type) && (this.$refs.clubManagerRef.managePerson.length === 0 || manageValid)) {
/*if (['onFinishTask', 'onSubmit'].includes(type) && (this.$refs.clubManagerRef.managePerson.length === 0 || manageValid)) {
this.$message.warning({ title: "警告", message: "请填写理事机构信息" })
return
}
}*/
const cloneData = clone(this.$refs.clubFormRef.formData)
let array = []
if (formData.sponsor) {
@@ -31,11 +31,11 @@ const courseList = {
<el-col class="query-content">
<el-tag
:effect="pageForm.assortTypes.includes(item) ? 'dark' : 'plain'"
:key="item"
:key="index"
:type="item"
@click="tagClick('assortTypes', item)"
style="margin-right: 10px; cursor: pointer"
v-for="item in assortList"
v-for="item,index in assortList"
>
{{ item }}
</el-tag>
@@ -32,7 +32,7 @@ layout("/layouts/platform_h5.html"){
<van-tabs v-if="assortList.length > 0" type="card" color="#1867B0"
style="margin-top: 10px" @click="tabClick">
<van-tab v-for="item in assortList" :name="item" :title="item">
<van-tab v-for="item,index in assortList" :name="item" :title="item" :key="index">
</van-tab>
</van-tabs>
@@ -4,6 +4,7 @@ const times = {
`
<div>
<van-action-sheet v-model="visible" title="时间段" cancel-text="取消">
<div id="mapContainer" v-if="row?.isMobileSign === true && row?.signType === 3" style="width: 100%; height: 250px"></div>
<button v-for="(item,index) in row?.courseTimes" type="button" class="van-action-sheet__item">
<div style="display: flex; justify-content: space-between; align-items: center">
<div>
@@ -44,6 +45,10 @@ const times = {
selectCourseTime: {},
signVisible: false,
markerLayer: null,
map: null,
circle: null,
}
},
components: {
@@ -56,22 +61,140 @@ const times = {
onOpen(row) {
this.row = row
this.visible = true
this.$nextTick(() => {
if(this.row.signType === 3) {
if(this.map) this.map.destroy()
this.initMap()
this.getLocation((coords) => {
if (coords) {
const center = new TMap.LatLng(coords.lat, coords.lng)
this.markerLayer.remove(["current"])
this.createMarker(center, 'current', 'current')
}
})
}
})
},
onSign(courseTime) {
async onSign(courseTime) {
this.selectCourseTime = courseTime
if(this.row.signType === 1) {
if (this.row.signType === 1) {
this.signVisible = true
this.$nextTick(() => {
this.$refs.scanCodeRef.init()
})
}
if(this.row.signType === 2) {
if (this.row.signType === 2) {
this.makeCode()
}
if(this.row.signType === 3) {
this.$toast('此签到模式正在升级中')
if (this.row.signType === 3) {
this.getLocation((coords) => {
if (coords) {
this.$axios.post('/platform/trainSignUp/mine/positionSign', {
timeId: courseTime.id,
courseId: this.row.id,
lat: coords.lat,
lng: coords.lng
}).then(res => {
if (res.code === 0) {
this.$toast('签到成功')
this.visible = false
} else {
this.$toast(res.msg)
this.markerLayer.remove(["current"])
this.getLocation((coords) => {
if (coords) {
const center = new TMap.LatLng(coords.lat, coords.lng)
this.createMarker(center, 'current', 'current')
}
})
}
})
}
})
}
},
getLocation(callback) {
if (typeof callback !== 'function') {
callback = () => {};
}
if (!navigator.geolocation) {
this.$toast('当前浏览器不支持定位功能');
callback(null);
return;
}
navigator.geolocation.getCurrentPosition(
(position) => {
callback({
lat: position.coords.latitude,
lng: position.coords.longitude
});
},
(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);
},
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000
}
);
},
initMap() {
if(!this.row.courseLocationCoordinates) {
this.$toast('未设置签到点')
return
}
const posi = JSON.parse(this.row.courseLocationCoordinates)
const center = new TMap.LatLng(posi[0], posi[1])
this.map = new TMap.Map('mapContainer', {
resizeEnable: true,
zoom: 16,
center: center
})
this.markerLayer = new TMap.MultiMarker({
map: this.map,
styles: {
"current": new TMap.MarkerStyle({
"src": "https://mapapi.qq.com/web/bundles/lbs-home/prod/assets/markerActive-NhH9NoBV.png",
"width": 40, // 点标记样式宽度(像素)
})
},
geometries: []
})
this.createMarker(center)
this.createCircle(center)
},
createMarker(position, styleId = 'marker', id = 'marker_' + Date.now()) {
this.markerLayer.add([
{
id: id,
position: position,
styleId: styleId
}
]);
},
createCircle(position) {
this.circle = new TMap.MultiCircle({
map: this.map,
geometries: [{
center: position,
radius: this.row.radius || 100,
}],
});
},
makeCode() {
const url = '/platform/trainSignUp/mine/passiveScan'
const data = url + '?id=' + this.selectCourseTime.id
@@ -26,7 +26,7 @@ layout("/layouts/platform_h5.html"){
<van-tabs v-if="assortList.length > 0" type="card" color="#1867B0"
style="margin-top: 10px" @click="tabClick">
<van-tab v-for="item in assortList" :name="item" :title="item">
<van-tab v-for="item,index in assortList" :name="item" :title="item" :key="index">
</van-tab>
</van-tabs>
@@ -26,7 +26,7 @@ layout("/layouts/platform_h5.html"){
<van-tabs v-if="assortList.length > 0" type="card" color="#1867B0"
style="margin-top: 10px" @click="tabClick">
<van-tab v-for="item in assortList" :name="item" :title="item">
<van-tab v-for="item,index in assortList" :name="item" :title="item" :key="index">
</van-tab>
</van-tabs>