commit
This commit is contained in:
+15
-9
@@ -59,17 +59,11 @@ public class QsvActivityController {
|
||||
//保存问卷基础信息
|
||||
@At
|
||||
@SaCheckPermission("qsv.activity")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("保存问卷基础信息")
|
||||
@SLog(type = "qsv.activity", tag = "保存问卷基础信息", msg = "保存问卷基础信息")
|
||||
public Result save(QsvActivity qsvActivity) {
|
||||
if (qsvActivity.getCategory().equals("QUIZ")) {
|
||||
if (qsvActivity.getMode().equals("SCHEDULED")) {
|
||||
qsvActivity.setRepeatMode("DAILY");
|
||||
} else if (qsvActivity.getMode().equals("REGULAR")) {
|
||||
qsvActivity.setRepeatMode("TOTAL");
|
||||
}
|
||||
}
|
||||
dao.insertOrUpdate(qsvActivity);
|
||||
qsvActivityService.saveActivity(qsvActivity);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@@ -83,13 +77,25 @@ public class QsvActivityController {
|
||||
// 删除问卷
|
||||
@At
|
||||
@SaCheckPermission("qsv.activity")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("删除问卷")
|
||||
@SLog(type = "qsv.activity", tag = "删除问卷", msg = "删除问卷")
|
||||
public Result delete(@Valid String id) {
|
||||
dao.delete(QsvActivity.class, id);
|
||||
qsvActivityService.deleteActivity(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
// 更新活动开启状态
|
||||
@At
|
||||
@SaCheckPermission("qsv.activity")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("更新活动开启状态")
|
||||
@SLog(type = "qsv.activity", tag = "更新活动开启状态", msg = "更新活动开启状态")
|
||||
public Result updateEnabled(@Valid String id, Boolean enabled) {
|
||||
qsvActivityService.updateEnabled(id, enabled);
|
||||
return Result.success(enabled ? "开启成功" : "关闭成功");
|
||||
}
|
||||
|
||||
|
||||
// 保存问卷题目
|
||||
@At
|
||||
|
||||
@@ -36,6 +36,7 @@ public class H5QsvController {
|
||||
public Result pageData(@Valid PageForm pageForm, @Valid String category) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("category", "=", category);
|
||||
cnd.and(Cnd.exps("enabled", "=", true).or("enabled", "is", null));
|
||||
cnd.desc("startTime");
|
||||
Pagination pagination = qsvActivityService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||
return Result.success(pagination);
|
||||
|
||||
+34
@@ -46,6 +46,10 @@ public class H5QsvSurveyController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result subjects(String activityId) {
|
||||
QsvActivity activity = dao.fetch(QsvActivity.class, activityId);
|
||||
Result activityStatusResult = checkActivityStatus(activity);
|
||||
if (activityStatusResult != null) {
|
||||
return activityStatusResult;
|
||||
}
|
||||
|
||||
int count = dao.count(ActivityUserScope.class, Cnd.where("groupId", "=", activity.getGroupId())
|
||||
.and("userId", "=", SecurityUtil.getUserId()));
|
||||
@@ -82,6 +86,30 @@ public class H5QsvSurveyController {
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验调查活动是否处于可答题状态。activity 为空表示活动不存在;
|
||||
* enabled 为 false 表示活动已关闭,当前时间早于 startTime 表示未开始,当前时间晚于 endTime 表示已结束。
|
||||
*
|
||||
* @param activity 当前调查活动,包含开启状态、开始时间和结束时间
|
||||
* @return 状态或时间不允许答题时返回错误结果,允许答题时返回 null
|
||||
*/
|
||||
private Result checkActivityStatus(QsvActivity activity) {
|
||||
if (activity == null) {
|
||||
return Result.error("调查不存在");
|
||||
}
|
||||
if (Boolean.FALSE.equals(activity.getEnabled())) {
|
||||
return Result.error("活动已关闭,暂不能参与");
|
||||
}
|
||||
Date now = new Date();
|
||||
if (activity.getStartTime() != null && activity.getStartTime().after(now)) {
|
||||
return Result.error("调查尚未开始,请在开始后再参与");
|
||||
}
|
||||
if (activity.getEndTime() != null && activity.getEndTime().before(now)) {
|
||||
return Result.error("调查已结束");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步问卷当前题目到未完成答题记录。后台新增题目后,已进入过问卷的用户记录里没有新题ID,
|
||||
* 这里补齐 subjectIds 和 extJson,保证手机端能拿到最新题目并正常提交答案。
|
||||
@@ -133,6 +161,12 @@ public class H5QsvSurveyController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result submitAnswer(@Valid @Param("answer") QsvAnswerParam qsvAnswerParam) {
|
||||
QsvActivity activity = dao.fetch(QsvActivity.class, qsvAnswerParam.getActivityId());
|
||||
Result activityStatusResult = checkActivityStatus(activity);
|
||||
if (activityStatusResult != null) {
|
||||
return activityStatusResult;
|
||||
}
|
||||
|
||||
QsvUserAnswerRecord answerRecord = dao.fetch(QsvUserAnswerRecord.class, qsvAnswerParam.getAnswerRecordId());
|
||||
JSONObject extJson = answerRecord.getExtJson();
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.budwk.app.zhgh.dayofficework.qsv.models;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.sys.services.SysHomeConvert;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
@@ -14,7 +16,7 @@ import java.util.Date;
|
||||
@Table("qsv_activity")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("问卷调查投票活动表")
|
||||
public class QsvActivity extends BaseModel implements Serializable {
|
||||
public class QsvActivity extends BaseModel implements Serializable, SysHomeConvert {
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@@ -46,6 +48,12 @@ public class QsvActivity extends BaseModel implements Serializable {
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date endTime;
|
||||
|
||||
@Column
|
||||
@Comment("是否开启")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default("1")
|
||||
private Boolean enabled;
|
||||
|
||||
@Column
|
||||
@Comment("活动分组ID")
|
||||
@ColDefine(type = ColType.INT)
|
||||
@@ -107,4 +115,35 @@ public class QsvActivity extends BaseModel implements Serializable {
|
||||
@Comment("封面图片")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
private String cover;
|
||||
|
||||
@Override
|
||||
public Sys_home_activity covertToSysHomeActivity() {
|
||||
Sys_home_activity sysHomeActivity = new Sys_home_activity();
|
||||
sysHomeActivity.setId(this.getId());
|
||||
sysHomeActivity.setName(this.getTitle());
|
||||
sysHomeActivity.setCover(this.getCover());
|
||||
sysHomeActivity.setContent(this.getDescription());
|
||||
sysHomeActivity.setUrl("/platform/qsv/activity");
|
||||
sysHomeActivity.setH5Url(getH5Url());
|
||||
sysHomeActivity.setStartDate(this.getStartTime());
|
||||
sysHomeActivity.setEndDate(this.getEndTime());
|
||||
sysHomeActivity.setAllowUserGroupId(this.getGroupId());
|
||||
sysHomeActivity.setEnable(!Boolean.FALSE.equals(this.getEnabled()));
|
||||
sysHomeActivity.setClassPath(this.getClass().getPackageName() + this.getClass().getName());
|
||||
return sysHomeActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据活动类型生成移动端首页跳转地址。
|
||||
* QUIZ 跳转答题页,SURVEY 跳转调查页,VOTE 预留投票页地址,返回值为移动端路由字符串。
|
||||
*/
|
||||
private String getH5Url() {
|
||||
if ("SURVEY".equals(this.getCategory())) {
|
||||
return "/platform/h5/qsv/survey?id=" + this.getId();
|
||||
}
|
||||
if ("VOTE".equals(this.getCategory())) {
|
||||
return "/platform/h5/qsv/vote?id=" + this.getId();
|
||||
}
|
||||
return "/platform/h5/qsv/quiz?id=" + this.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,10 @@ import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvActivity;
|
||||
|
||||
public interface QsvActivityService extends BaseService<QsvActivity> {
|
||||
|
||||
void saveActivity(QsvActivity qsvActivity);
|
||||
|
||||
void deleteActivity(String id);
|
||||
|
||||
void updateEnabled(String id, Boolean enabled);
|
||||
}
|
||||
|
||||
+53
@@ -1,9 +1,13 @@
|
||||
package com.budwk.app.zhgh.dayofficework.qsv.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.models.QsvActivity;
|
||||
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvActivityService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
@@ -12,4 +16,53 @@ public class QsvActivityServiceImpl extends BaseServiceImpl<QsvActivity> impleme
|
||||
public QsvActivityServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void saveActivity(QsvActivity qsvActivity) {
|
||||
fillQuizRepeatMode(qsvActivity);
|
||||
dao().insertOrUpdate(qsvActivity);
|
||||
syncHomeActivity(qsvActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void deleteActivity(String id) {
|
||||
dao().delete(QsvActivity.class, id);
|
||||
dao().delete(Sys_home_activity.class, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void updateEnabled(String id, Boolean enabled) {
|
||||
QsvActivity activity = dao().fetch(QsvActivity.class, id);
|
||||
if (activity == null) {
|
||||
return;
|
||||
}
|
||||
activity.setEnabled(enabled);
|
||||
dao().update(activity);
|
||||
syncHomeActivity(activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 答题活动的重复模式由出题模式决定。定时定题按天统计,常规模式按活动总次数统计。
|
||||
*/
|
||||
private void fillQuizRepeatMode(QsvActivity qsvActivity) {
|
||||
if (!"QUIZ".equals(qsvActivity.getCategory())) {
|
||||
return;
|
||||
}
|
||||
if ("SCHEDULED".equals(qsvActivity.getMode())) {
|
||||
qsvActivity.setRepeatMode("DAILY");
|
||||
} else if ("REGULAR".equals(qsvActivity.getMode())) {
|
||||
qsvActivity.setRepeatMode("TOTAL");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步移动端首页活动。问卷活动保存或启停后,都以活动自身 enabled、时间、人员范围生成首页记录。
|
||||
*/
|
||||
private void syncHomeActivity(QsvActivity activity) {
|
||||
Sys_home_activity sysHomeActivity = activity.covertToSysHomeActivity();
|
||||
dao().insertOrUpdate(sysHomeActivity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,17 @@ const basicForm = {
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="封面" prop="cover">
|
||||
<file-upload
|
||||
:upload_number="1"
|
||||
:value.sync="formData.cover"
|
||||
accept=".jpg,.jpeg,.png"
|
||||
upload_mode="image"
|
||||
upload_result_category="interval"
|
||||
upload_result_type="url"
|
||||
></file-upload>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="formData.category==='QUIZ'">
|
||||
<el-form-item label="出题模式" prop="mode">
|
||||
<span slot="label">
|
||||
@@ -171,17 +182,6 @@ const basicForm = {
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!-- <el-form-item label="封面" prop="cover">-->
|
||||
<!-- <file-upload-->
|
||||
<!-- :upload_number="1"-->
|
||||
<!-- :value.sync="formData.cover"-->
|
||||
<!-- accept=".jpg,.jpeg,.png"-->
|
||||
<!-- complete_result-->
|
||||
<!-- upload_mode="image"-->
|
||||
<!-- upload_result_category="interval"-->
|
||||
<!-- ></file-upload>-->
|
||||
<!-- </el-form-item>-->
|
||||
|
||||
</template>
|
||||
</el-form>
|
||||
</div>
|
||||
@@ -204,7 +204,8 @@ const basicForm = {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
formData: {
|
||||
category: ''
|
||||
category: '',
|
||||
cover: ''
|
||||
},
|
||||
formRules: {
|
||||
category: [{ required: true, message: "请选择类型", trigger: "change" }],
|
||||
@@ -228,7 +229,9 @@ const basicForm = {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.formData = {}
|
||||
this.formData = {
|
||||
cover: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
onSubmit() {
|
||||
|
||||
@@ -31,11 +31,27 @@ layout("/layouts/platform.html"){
|
||||
</el-table-column>
|
||||
<el-table-column label="开始时间" prop="startTime" sortable></el-table-column>
|
||||
<el-table-column label="结束时间" prop="endTime" sortable></el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="450px">
|
||||
<el-table-column label="状态" width="100">
|
||||
<template scope="{row}">
|
||||
<el-tag v-if="row.enabled !== false" type="success">开启</el-tag>
|
||||
<el-tag v-else type="info">关闭</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="520px">
|
||||
<template scope="{row}">
|
||||
<el-button size="mini" type="primary" @click="openQrCode(row)">二维码</el-button>
|
||||
<el-button size="mini" type="primary" @click="openEdit(row)">编辑</el-button>
|
||||
<el-button size="mini" type="primary" @click="openSubject(row.id)">题目设置</el-button>
|
||||
<el-button
|
||||
v-if="row.enabled === false"
|
||||
size="mini"
|
||||
type="success"
|
||||
@click="updateEnabled(row, true)">开启</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
size="mini"
|
||||
type="warning"
|
||||
@click="updateEnabled(row, false)">关闭</el-button>
|
||||
<el-button size="mini" type="danger" @click="onDelete(row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -94,6 +110,26 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
|
||||
// 开启或关闭活动,关闭后移动端首页不展示,直达手机端问卷也不能答题
|
||||
updateEnabled(row, enabled) {
|
||||
const actionText = enabled ? "开启" : "关闭"
|
||||
this.$confirm("您确认" + actionText + "该活动吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
$.post("/platform/qsv/activity/updateEnabled", {
|
||||
id: row.id,
|
||||
enabled
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 删除
|
||||
onDelete(id) {
|
||||
this.$confirm("您确认删除吗, 是否继续?", "提示", {
|
||||
|
||||
@@ -12,19 +12,18 @@ const subjectForm = {
|
||||
<transition-group>
|
||||
<div v-for="(subject, subjectIndex) in subjects" :key="subject.id" class="subject-item">
|
||||
<div class="subject-header">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<div class="subject-title-row">
|
||||
<i class="el-icon-rank drag-handler"></i>
|
||||
<span style="font-weight: bold; margin-right: 10px;">第 {{subjectIndex + 1}} 题</span>
|
||||
<el-input
|
||||
class="subject-title-input"
|
||||
v-model="subject.title"
|
||||
placeholder="请输入题目"
|
||||
style="flex: 1">
|
||||
placeholder="请输入题目">
|
||||
</el-input>
|
||||
<el-button
|
||||
class="subject-visible-btn"
|
||||
type="primary"
|
||||
icon="el-icon-setting"
|
||||
size="mini"
|
||||
style="margin-left: 8px;"
|
||||
@click="openSubjectVisibleSetting(subjectIndex, subject)">
|
||||
隐显逻辑
|
||||
</el-button>
|
||||
@@ -663,6 +662,21 @@ const subjectForm = {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/deep/ .subject-title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/deep/ .subject-title-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/deep/ .subject-visible-btn {
|
||||
height: 40px;
|
||||
margin-left: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/deep/ .subject-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -101,6 +101,12 @@ layout("/layouts/platform_h5.html"){
|
||||
resize: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.required-star {
|
||||
color: #ee0a24;
|
||||
margin-left: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
@@ -109,7 +115,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<h2 class="title">{{ activity.title }}</h2>
|
||||
<div v-if="!isFinished">
|
||||
<div v-for="(subject, index) in visibleSubjects" :key="subject.id" class="subject">
|
||||
<p>{{index+1}}、{{ subject.title }}</p>
|
||||
<p>{{index+1}}、{{ subject.title }}<span class="required-star">*</span></p>
|
||||
<div class="tag">
|
||||
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
|
||||
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
|
||||
|
||||
Reference in New Issue
Block a user