This commit is contained in:
2026-04-17 14:21:48 +08:00
parent 8ceb928fec
commit 3c3836ae90
5 changed files with 492 additions and 91 deletions
@@ -143,6 +143,7 @@ public interface TrainSignUpActivityService extends BaseService<TrainSignUpActiv
/**
* 保存扫码达标后的动态表单信息。
* 保存时会将同一份动态表单同步到当前活动下已打卡点位对应的报名记录,保证导出和后续展示口径一致。
*
* @param courseId 当前扫码点位所属课程ID
* @param userId 当前登录用户ID
@@ -590,19 +590,8 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
userCourse.setCourseEndTime(activityCourse.getCourseEndTime());
userCourse.setActivityCourseId(activityCourse.getId());
dao().insert(userCourse);
TrainSignUpUser signUpUser = dao().fetch(TrainSignUpUser.class,
Cnd.where("courseId", "=", courseId).and("userId", "=", userId));
if (signUpUser == null) {
signUpUser = new TrainSignUpUser();
signUpUser.setActivityId(activity.getId());
signUpUser.setCourseId(courseId);
signUpUser.setUserId(userId);
signUpUser.setSignUpTime(DateUtil.date());
signUpUser.setState(1);
dao().insert(signUpUser);
}
}
ensureScanCodeSignUpUser(activity.getId(), courseId, userId);
if (userCourse.isAttend()) {
return buildScanCodeResponse(99, "此点位,您已经签到", buildScanCodeData(activity, courseId, userId));
@@ -611,12 +600,15 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
userCourse.setAttend(true);
userCourse.setAttendTime(DateUtil.date());
dao().update(userCourse);
// 新点位签到成功后,如果活动内已经存在已填写的动态表单,则同步覆盖到当前全部已打卡记录。
syncAttendMobileColumnsValue(activity.getId(), userId, getActivityLatestMobileColumnsValue(activity.getId(), userId), false);
return buildScanCodeResponse(0, "签到成功", buildScanCodeData(activity, courseId, userId));
}
/**
* 保存签到达标后的动态表单。
* 仅当活动配置为“系统自动弹出填写信息”且用户已达标时允许保存。
* 保存成功后,会把同一份表单数据同步到当前活动下 isAttend = true 的所有报名记录。
*
* @param courseId 当前扫码点位所属课程ID
* @param userId 当前登录用户ID
@@ -640,22 +632,104 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
throw new IllegalArgumentException("当前活动尚未达标,暂不能填写动态表单");
}
TrainSignUpUser signUpUser = dao().fetch(TrainSignUpUser.class,
Cnd.where("courseId", "=", courseId).and("userId", "=", userId));
if (signUpUser == null) {
throw new IllegalArgumentException("未找到当前报名记录");
}
if (StrUtil.isBlank(mobileColumnsValue)) {
throw new IllegalArgumentException("填写活动报名信息");
throw new IllegalArgumentException("请填写礼品邮递地址");
}
List<NutMap> formData;
try {
formData = Json.fromJsonAsList(NutMap.class, mobileColumnsValue);
} catch (Exception e) {
throw new IllegalArgumentException("活动报名信息格式不正确");
throw new IllegalArgumentException("礼品邮递地址格式不正确");
}
signUpUser.setMobileColumnsValue(formData);
dao().update(signUpUser);
syncAttendMobileColumnsValue(activity.getId(), userId, formData, true);
}
/**
* 确保扫码点位存在对应的报名记录。
* 用户后续继续打卡新点位时,需要有 train_sign_up_user 记录承接同步后的 mobileColumnsValue。
*
* @param activityId 当前活动ID
* @param courseId 当前点位所属课程ID
* @param userId 当前登录用户ID
*/
private void ensureScanCodeSignUpUser(String activityId, String courseId, String userId) {
TrainSignUpUser signUpUser = dao().fetch(TrainSignUpUser.class,
Cnd.where("courseId", "=", courseId).and("userId", "=", userId));
if (signUpUser != null) {
return;
}
signUpUser = new TrainSignUpUser();
signUpUser.setActivityId(activityId);
signUpUser.setCourseId(courseId);
signUpUser.setUserId(userId);
signUpUser.setSignUpTime(DateUtil.date());
signUpUser.setState(1);
dao().insert(signUpUser);
}
/**
* 获取当前活动下用户最近一次已填写的动态表单值。
* 用户后续继续打卡新点位时,使用这份最新数据回填到新产生的已打卡记录。
*
* @param activityId 当前活动ID
* @param userId 当前登录用户ID
* @return 最近一次已保存的动态表单字段和值
*/
private List<NutMap> getActivityLatestMobileColumnsValue(String activityId, String userId) {
List<TrainSignUpUser> signUpUserList = dao().query(TrainSignUpUser.class,
Cnd.where("activityId", "=", activityId)
.and("userId", "=", userId)
.desc("signUpTime"));
for (TrainSignUpUser signUpUser : signUpUserList) {
if (signUpUser.getMobileColumnsValue() != null && !signUpUser.getMobileColumnsValue().isEmpty()) {
return signUpUser.getMobileColumnsValue();
}
}
return new ArrayList<>();
}
/**
* 将同一份动态表单同步覆盖到当前活动下全部已打卡记录。
* 保存表单和后续新增打卡点位都走这套逻辑,保证所有 isAttend = true 的记录保持一致。
*
* @param activityId 当前活动ID
* @param userId 当前登录用户ID
* @param formData 需要同步的动态表单值
* @param throwWhenNoAttendRecord true-无已打卡记录时报错;false-静默跳过
*/
private void syncAttendMobileColumnsValue(String activityId, String userId, List<NutMap> formData, boolean throwWhenNoAttendRecord) {
if (formData == null || formData.isEmpty()) {
return;
}
List<TrainSignUpUserCourse> attendCourseList = dao().query(TrainSignUpUserCourse.class,
Cnd.where("activityId", "=", activityId)
.and("userId", "=", userId)
.and("isAttend", "=", true));
List<String> attendCourseIdList = attendCourseList.stream()
.map(TrainSignUpUserCourse::getCourseId)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.toList());
if (attendCourseIdList.isEmpty()) {
if (throwWhenNoAttendRecord) {
throw new IllegalArgumentException("未找到当前活动已打卡记录");
}
return;
}
List<TrainSignUpUser> signUpUserList = dao().query(TrainSignUpUser.class,
Cnd.where("activityId", "=", activityId)
.and("userId", "=", userId)
.and("courseId", "in", attendCourseIdList));
if (signUpUserList == null || signUpUserList.isEmpty()) {
if (throwWhenNoAttendRecord) {
throw new IllegalArgumentException("未找到当前活动已打卡的报名记录");
}
return;
}
signUpUserList.forEach(item -> {
item.setMobileColumnsValue(Json.fromJsonAsList(NutMap.class, Json.toJson(formData)));
});
dao().update(signUpUserList);
}
/**
@@ -724,7 +798,7 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
private NutMap handleReachTarget(TrainSignUpActivity activity, String userId) {
Integer signHandleType = activity.getSignHandleType() == null ? 3 : activity.getSignHandleType();
if (Integer.valueOf(1).equals(signHandleType)) {
return NutMap.NEW().addv("handleStatus", "PENDING_FORM").addv("handleMsg", "当前活动已达标,请补充活动报名信息");
return NutMap.NEW().addv("handleStatus", "PENDING_FORM").addv("handleMsg", "当前活动已达标,请填写礼品邮递地址");
}
if (Integer.valueOf(2).equals(signHandleType)) {
return buildWelfareSelectResult(activity.getWelfareProjectId(), userId);
@@ -10,59 +10,97 @@
<template v-for="column in dynamicData">
<!-- 文本数值时间 -->
<template v-if="['VARCHAR', 'TEXT', 'INT', 'DATE', 'DATETIME'].includes(column.columnType)">
<van-field
class="field"
v-model="column.columnValue"
:clickable="['SELECT'].includes(column.columnFormType)"
:label="column.columnName"
:name="column.columnCode"
:type="['INT'].includes(column.columnType) ? 'digit' : ''"
:placeholder="(['SELECT'].includes(column.columnFormType) ? '请选择' : '请填写') + column.columnName"
:readonly="['SELECT'].includes(column.columnFormType)"
:rules="[{ required: column.isRequired, message: (['SELECT'].includes(column.columnFormType) ? '请选择' : '请填写') + column.columnName }]"
:required="column.isRequired"
@click="selectFieldClick(column)"
></van-field>
<template v-if="isAddressField(column)">
<van-field
class="field"
:value="getAddressAreaText(column)"
clickable
:label="column.columnName"
:name="column.columnCode + 'Area'"
:placeholder="'请选择' + column.columnName"
readonly
:rules="buildAddressAreaRules(column)"
:required="column.isRequired"
@click="openAddressPicker(column)"
></van-field>
<van-popup
v-model="pickerStates[column.columnCode + 'Picker']"
position="bottom"
get-container="body"
>
<van-area
:area-list="addressAreaList"
:value="getAddressAreaCode(column)"
:title="'选择' + column.columnName"
:area-columns-placeholder="['请选择', '请选择', '请选择']"
@cancel="closeAddressPicker(column)"
@confirm="
(values) => {
addressPickerConfirm(values, column)
}
"
></van-area>
</van-popup>
<van-field
class="field"
v-model="addressStates[column.columnCode].detail"
label="详细地址"
:name="column.columnCode"
placeholder="请填写详细地址"
:rules="buildAddressDetailRules(column)"
:required="column.isRequired"
@input="addressDetailInput(column)"
></van-field>
</template>
<template v-else>
<van-field
class="field"
v-model="column.columnValue"
:clickable="['SELECT'].includes(column.columnFormType)"
:label="column.columnName"
:name="column.columnCode"
:type="['INT'].includes(column.columnType) ? 'digit' : ''"
:placeholder="(['SELECT'].includes(column.columnFormType) ? '请选择' : '请填写') + column.columnName"
:readonly="['SELECT'].includes(column.columnFormType)"
:rules="[{ required: column.isRequired, message: (['SELECT'].includes(column.columnFormType) ? '请选择' : '请填写') + column.columnName }]"
:required="column.isRequired"
@click="selectFieldClick(column)"
></van-field>
<van-popup
v-if="['SELECT'].includes(column.columnFormType)"
v-model="pickerStates[column.columnCode + 'Picker']"
position="bottom"
get-container="body"
>
<template v-if="['DATETIME', 'DATE'].includes(column.columnType)">
<van-datetime-picker
:title="column.columnName"
:type="column.columnType.toLocaleLowerCase()"
show-toolbar
@cancel="
pickerStates[column.columnCode + 'Picker'] = false
column.columnValue = ''
"
@confirm="
(time) => {
dateTimePickerConfirm(time, column)
}
"
/>
</template>
<template v-else>
<van-picker
:columns="column.selectValues"
:title="column.columnName"
show-toolbar
@cancel="
pickerStates[column.columnCode + 'Picker'] = false
column.columnValue = ''
"
@confirm="
(value) => {
ordinaryPickerConfirm(value, column)
}
"
/>
</template>
</van-popup>
<van-popup
v-if="['SELECT'].includes(column.columnFormType)"
v-model="pickerStates[column.columnCode + 'Picker']"
position="bottom"
get-container="body"
>
<template v-if="['DATETIME', 'DATE'].includes(column.columnType)">
<van-datetime-picker
:title="column.columnName"
:type="column.columnType.toLocaleLowerCase()"
show-toolbar
@cancel="dateTimePickerCancel(column)"
@confirm="
(time) => {
dateTimePickerConfirm(time, column)
}
"
/>
</template>
<template v-else>
<van-picker
:columns="column.selectValues"
:title="column.columnName"
show-toolbar
@cancel="ordinaryPickerCancel(column)"
@confirm="
(value) => {
ordinaryPickerConfirm(value, column)
}
"
/>
</template>
</van-popup>
</template>
</template>
<!-- 单选框 -->
<template v-else-if="['BOOLEAN'].includes(column.columnType)"></template>
@@ -110,16 +148,20 @@ module.exports = {
watch: {
dynamicData: {
handler: function (newValue, oldValue) {
this.initAddressStates(newValue)
this.$emit("updateDynamicData", newValue)
},
deep: true
deep: true,
immediate: true
}
},
data() {
return {
//所有的picker状态
pickerStates: {},
fileList: []
fileList: [],
addressStates: {},
addressAreaList: window.trainSignUpAreaList || { province_list: {}, city_list: {}, county_list: {} }
}
},
methods: {
@@ -136,6 +178,270 @@ module.exports = {
},
async onSubmit() {
},
/**
* 初始化地址字段的联动状态。
* 动态表单只保存 columnValue 字符串,这里需要额外拆成省市区和详细地址,方便前端进行地区联动选择。
*
* @param columns 当前动态字段列表
*/
initAddressStates(columns) {
if (!columns || columns.length === 0) {
return
}
columns.forEach((column) => {
if (!this.isAddressField(column)) {
return
}
const existsState = this.addressStates[column.columnCode]
if (existsState && existsState.initializedValue === column.columnValue) {
return
}
const addressState = this.parseAddressValue(column.columnValue)
addressState.initializedValue = column.columnValue || ""
this.$set(this.addressStates, column.columnCode, addressState)
})
},
/**
* 判断当前动态字段是否属于收货地址类字段。
* 目前后台没有独立的地址控件类型,因此这里按字段名称和字段编码做兼容识别。
*
* @param column 动态字段配置
* @return true-按地址控件渲染;false-沿用原有输入方式
*/
isAddressField(column) {
const columnName = (column && column.columnName) ? column.columnName : ""
const columnCode = (column && column.columnCode) ? column.columnCode.toLowerCase() : ""
return ["收货地址", "邮寄地址", "礼品邮递地址", "邮递地址"].some((item) => columnName.indexOf(item) > -1)
|| ["receiveaddress", "mailaddress", "shippingaddress"].some((item) => columnCode.indexOf(item) > -1)
},
/**
* 将已保存的地址字符串拆分为省市区和详细地址。
* 如果旧数据无法可靠拆分,就保留原始值作为兼容显示,避免历史文本地址丢失。
*
* @param addressValue 当前字段已保存的地址字符串
* @return 地址状态对象
*/
parseAddressValue(addressValue) {
const emptyState = {
province: "",
city: "",
county: "",
detail: "",
displayArea: "",
areaCode: "",
legacyValue: addressValue || "",
initializedValue: addressValue || ""
}
if (!addressValue) {
return emptyState
}
const provinceMatch = this.findAreaOption(addressValue, this.addressAreaList.province_list)
if (!provinceMatch) {
return emptyState
}
let remainValue = addressValue.substring(provinceMatch.name.length)
const cityMatch = this.findAreaOption(remainValue, this.addressAreaList.city_list, provinceMatch.code.substring(0, 2))
if (!cityMatch) {
return emptyState
}
remainValue = remainValue.substring(cityMatch.name.length)
const countyMatch = this.findAreaOption(remainValue, this.addressAreaList.county_list, cityMatch.code.substring(0, 4))
if (!countyMatch) {
return {
province: provinceMatch.name,
city: cityMatch.name,
county: "",
detail: remainValue,
displayArea: provinceMatch.name + cityMatch.name,
areaCode: cityMatch.code,
legacyValue: "",
initializedValue: addressValue || ""
}
}
remainValue = remainValue.substring(countyMatch.name.length)
return {
province: provinceMatch.name,
city: cityMatch.name,
county: countyMatch.name,
detail: remainValue,
displayArea: provinceMatch.name + cityMatch.name + countyMatch.name,
areaCode: countyMatch.code,
legacyValue: "",
initializedValue: addressValue || ""
}
},
/**
* 根据地址字符串前缀匹配地区代码和值。
*
* @param addressValue 地址字符串
* @param areaMap 地区编码映射
* @param codePrefix 编码前缀,用于限制省/市/区层级
* @return 匹配到的地区对象
*/
findAreaOption(addressValue, areaMap, codePrefix) {
if (!addressValue || !areaMap) {
return null
}
let match = null
Object.keys(areaMap).forEach((code) => {
if (codePrefix && code.indexOf(codePrefix) !== 0) {
return
}
const name = areaMap[code]
if (addressValue.indexOf(name) !== 0) {
return
}
if (!match || name.length > match.name.length) {
match = {
code: code,
name: name
}
}
})
return match
},
/**
* 获取地址字段当前展示的省市区文本。
*
* @param column 动态字段配置
* @return 省市区展示文本
*/
getAddressAreaText(column) {
const state = this.addressStates[column.columnCode]
if (!state) {
return ""
}
return state.displayArea || state.legacyValue || ""
},
/**
* 获取地区选择器默认定位的地区编码。
*
* @param column 动态字段配置
* @return 地区编码
*/
getAddressAreaCode(column) {
const state = this.addressStates[column.columnCode]
return state ? state.areaCode : ""
},
/**
* 地址地区选择字段校验。
* 已有历史纯文本地址时允许直接通过,避免旧数据因无法拆分省市区而被强制重填。
*
* @param column 动态字段配置
* @return van-field 规则数组
*/
buildAddressAreaRules(column) {
if (!column.isRequired) {
return []
}
return [{
validator: () => {
const state = this.addressStates[column.columnCode]
if (!state) {
return false
}
return !!(state.displayArea || state.legacyValue)
},
message: "请选择" + column.columnName
}]
},
/**
* 地址详细地址字段校验。
* 新填写的数据要求必须包含详细地址,历史纯文本地址继续兼容通过。
*
* @param column 动态字段配置
* @return van-field 规则数组
*/
buildAddressDetailRules(column) {
if (!column.isRequired) {
return []
}
return [{
validator: () => {
const state = this.addressStates[column.columnCode]
if (!state) {
return false
}
return !!(state.detail || state.legacyValue)
},
message: "请填写详细地址"
}]
},
/**
* 打开地址地区选择器。
*
* @param column 动态字段配置
*/
openAddressPicker(column) {
this.$set(this.pickerStates, column.columnCode + "Picker", true)
},
/**
* 关闭地址地区选择器。
*
* @param column 动态字段配置
*/
closeAddressPicker(column) {
this.$set(this.pickerStates, column.columnCode + "Picker", false)
},
/**
* 地址地区确认后同步 columnValue。
*
* @param values van-area 返回的省市区数组
* @param column 动态字段配置
*/
addressPickerConfirm(values, column) {
const validValues = (values || []).filter((item) => item && item.name)
const province = validValues[0] ? validValues[0].name : ""
const city = validValues[1] ? validValues[1].name : ""
const county = validValues[2] ? validValues[2].name : ""
const areaCode = validValues[2] ? validValues[2].code : (validValues[1] ? validValues[1].code : "")
const currentState = this.addressStates[column.columnCode] || {}
this.$set(this.addressStates, column.columnCode, {
province: province,
city: city,
county: county,
detail: currentState.detail || "",
displayArea: province + city + county,
areaCode: areaCode,
legacyValue: "",
initializedValue: currentState.initializedValue || ""
})
this.syncAddressColumnValue(column)
this.closeAddressPicker(column)
},
/**
* 详细地址输入后同步完整地址字符串。
*
* @param column 动态字段配置
*/
addressDetailInput(column) {
const currentState = this.addressStates[column.columnCode] || {}
this.$set(this.addressStates, column.columnCode, {
province: currentState.province || "",
city: currentState.city || "",
county: currentState.county || "",
detail: currentState.detail || "",
displayArea: currentState.displayArea || "",
areaCode: currentState.areaCode || "",
legacyValue: "",
initializedValue: currentState.initializedValue || ""
})
this.syncAddressColumnValue(column)
},
/**
* 将省市区和详细地址重新拼装回 columnValue。
* 后端仍然只接收一个 columnValue 字符串,因此这里保持原有存储结构不变。
*
* @param column 动态字段配置
*/
syncAddressColumnValue(column) {
const state = this.addressStates[column.columnCode]
if (!state) {
return
}
const addressValue = (state.displayArea || "") + (state.detail || "")
this.$set(column, "columnValue", addressValue)
},
selectFieldClick(column) {
this.$set(this.pickerStates, column.columnCode + "Picker", true)
@@ -144,6 +450,15 @@ module.exports = {
// column.selectValues = ['1', '2', '3']
}
},
/**
* 时间picker取消后,清空当前字段值。
*
* @param column 动态字段配置
*/
dateTimePickerCancel(column) {
this.$set(this.pickerStates, column.columnCode + "Picker", false)
this.$set(column, "columnValue", "")
},
/**
* 时间picker确认
* @param time
@@ -151,14 +466,23 @@ module.exports = {
*/
dateTimePickerConfirm(time, column) {
if (column.columnType === "DATE") {
column.columnValue = this.$moment(time).format("YYYY-MM-DD")
this.$set(column, "columnValue", this.$moment(time).format("YYYY-MM-DD"))
} else if (column.columnType === "DATETIME") {
column.columnValue = this.$moment(time).format("YYYY-MM-DD HH:mm:ss")
this.$set(column, "columnValue", this.$moment(time).format("YYYY-MM-DD HH:mm:ss"))
} else {
//预留别的类型
column.columnValue = this.$moment(time).format("YYYY-MM-DD HH:mm:ss")
this.$set(column, "columnValue", this.$moment(time).format("YYYY-MM-DD HH:mm:ss"))
}
this.pickerStates[column.columnCode + "Picker"] = false
this.$set(this.pickerStates, column.columnCode + "Picker", false)
},
/**
* 普通picker取消后,清空当前字段值。
*
* @param column 动态字段配置
*/
ordinaryPickerCancel(column) {
this.$set(this.pickerStates, column.columnCode + "Picker", false)
this.$set(column, "columnValue", "")
},
/**
* 普通picker确认
@@ -166,8 +490,8 @@ module.exports = {
* @param column
*/
ordinaryPickerConfirm(value, column) {
column.columnValue = value
this.pickerStates[column.columnCode + "Picker"] = false
this.$set(column, "columnValue", value)
this.$set(this.pickerStates, column.columnCode + "Picker", false)
},
/**
* 文件读取
@@ -96,9 +96,9 @@ layout("/layouts/platform_h5.html"){
<template v-if="result?.data?.needDynamicForm">
<van-divider></van-divider>
<div class="success_tooltip">当前活动已达标,请补充活动报名信息</div>
<div class="success_tooltip">当前活动已达标,请填写礼品邮递地址</div>
<div style="width: 90%; margin: 12px auto 0">
<van-button block type="primary" @click="openDynamicForm">填写活动报名信息</van-button>
<van-button block type="primary" @click="openDynamicForm">填写礼品邮递地址</van-button>
</div>
</template>
@@ -127,7 +127,7 @@ layout("/layouts/platform_h5.html"){
<div class="weui-msg__title">恭喜您</div>
<div class="weui-msg__msg">
<div>当前活动已达标</div>
<div>活动报名信息补充完成</div>
<div>礼品邮递地址补充完成</div>
</div>
</div>
</div>
@@ -136,11 +136,11 @@ layout("/layouts/platform_h5.html"){
<van-popup class="joinPopup" position="right" v-model:show="dynamicFormPopup">
<van-nav-bar @click-left="dynamicFormPopup = false" left-text="返回" fixed left-arrow placeholder
title="活动报名"></van-nav-bar>
title="填写详细信息"></van-nav-bar>
<div class="join_content">
<van-form @submit="submitDynamicForm" :show-error-message="false">
<div class="van-doc-card-two" style="margin: 0 0 16px 0">
<div class="van-card-header">活动报名信息</div>
<div class="van-card-header">详细信息</div>
<div class="van-card-body">
<train-dynamic-form v-model="dynamicColumnsData" ref="trainDynamicForm"></train-dynamic-form>
</div>
@@ -156,6 +156,7 @@ layout("/layouts/platform_h5.html"){
<script>
<!--#include("/platform/zhghh5/welfare/include/areaList.js"){}#-->
window.trainSignUpAreaList = areaList
const vue = new Vue({
el: "#app",
components: {
@@ -226,7 +227,7 @@ layout("/layouts/platform_h5.html"){
}).then((res) => {
if (res.code === 0) {
this.$set(this.result.data, 'needDynamicForm', false)
this.$set(this.result.data, 'handleMsg', '当前活动已达标,活动报名信息已补充完成')
this.$set(this.result.data, 'handleMsg', '当前活动已达标,礼品邮递地址已补充完成')
this.$set(this, 'dynamicFormPopup', false)
this.$set(this, 'successVisible', true)
} else {
@@ -239,9 +240,6 @@ layout("/layouts/platform_h5.html"){
this.$axios.post('/platform/mobile/train/scanCode/getSignData', {courseId: this.courseId})
.then(res => {
this.$set(this, 'result', res)
if (res.code === 0 && res.data && res.data.needDynamicForm) {
this.openDynamicForm()
}
})
},
},
@@ -359,6 +359,10 @@ layout("/layouts/platform_h5.html"){
</van-popup>
</div>
<script>
<!--#include("/platform/zhghh5/welfare/include/areaList.js"){}#-->
window.trainSignUpAreaList = areaList
</script>
<script src="${base!}/assets/platform/plugins/jr-qrcode/jr-qrcode.js"></script>
<script>
let locations = null