diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/satisfactionEvaluate/TheRapyRecuperationSatisfactionEvaluateController.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/satisfactionEvaluate/TheRapyRecuperationSatisfactionEvaluateController.java new file mode 100644 index 0000000..b14d399 --- /dev/null +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/controller/satisfactionEvaluate/TheRapyRecuperationSatisfactionEvaluateController.java @@ -0,0 +1,186 @@ +package io.v.nutz.zhgh.therapyRecuperation.controller.satisfactionEvaluate; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; +import cn.wizzer.framework.base.Result; +import io.v.nutz.base.query.PageForm; +import io.v.nutz.sys.models.Sys_user; +import io.v.nutz.web.commons.utils.ShiroUtil; +import io.v.nutz.zhgh.therapyRecuperation.model.*; +import io.v.nutz.zhgh.therapyRecuperation.service.TheRapyRecuperationEnrollService; +import org.apache.shiro.authz.annotation.RequiresAuthentication; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +import java.util.Date; +import java.util.List; +import java.util.Objects; + +@IocBean +@At("/platform/theRapyRecuperation/satisfactionEvaluate") +@Ok("json:full") +public class TheRapyRecuperationSatisfactionEvaluateController { + + @Inject + private Dao dao; + @Inject + private TheRapyRecuperationEnrollService enrollService; + + + @At("") + @Ok("beetl:/platform/theRapyRecuperation/satisfactionEvaluate/index.html") + @RequiresPermissions("theRapyRecuperation.satisfactionEvaluate") + public void index() { + + } + + @At + @RequiresPermissions("theRapyRecuperation.satisfactionEvaluate") + public Result pageData(PageForm pageForm) { + + return Result.success(); + } + + + /** + * 查询线路 + * @param year + * @return + */ + @At + @RequiresPermissions("theRapyRecuperation.satisfactionEvaluate") + public Result listLines(Integer year) { + Sql sql = Sqls.create(""" + SELECT + t2.id, + t2.lineName + FROM + `the_rapy_recuperation_line_union_select` t1 + LEFT JOIN the_rapy_recuperation_line t2 ON t2.id = t1.lineId + WHERE + YEAR(selectTime) = @year + GROUP BY + t1.id + """); + sql.setParam("year", year); + List list = enrollService.listMap(sql); + return Result.success(list); + } + + + /** + * 查询线路的出行时间会有多条 + * @param lineId + * @param year + * @return + */ + @At + @RequiresPermissions("theRapyRecuperation.satisfactionEvaluate") + public Result listTimeByLineId(String lineId, Integer year) { + Sql sql = Sqls.create(""" + SELECT + concat(DATE_FORMAT(playStartTime, '%Y-%m-%d'), '至', DATE_FORMAT(playEndTime, '%Y-%m-%d')) AS label + FROM + `the_rapy_recuperation_line_union_select` + WHERE + lineId = @lineId + AND YEAR(selectTime) = @year + ORDER BY + playStartTime ASC + """); + sql.setParam("lineId",lineId); + sql.setParam("year", year); + List list = enrollService.listMap(sql); + return Result.success(list); + } + + + /** + * 提交评价 + */ + @At + @RequiresAuthentication + public Result submit(TheRapyRecuperationSatisfactionEvaluate satisfactionEvaluate) { + satisfactionEvaluate.setEvaluateDate(new Date()); + dao.insertOrUpdate(satisfactionEvaluate); + return Result.success(); + } + + /** + * 查看详情 + */ + @At + @RequiresAuthentication + public Result detail() { + + return Result.success(); + } + + + /** + * 基础信息 旅行社、时间等等 + * + * @param enrollId 报名id + * @return + */ + @At + @RequiresAuthentication + public Result basicInfo(String enrollId) { + NutMap result = new NutMap(); + + TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, enrollId); + + result.put("enrollId", enroll.getId()); + result.put("userName", enroll.getUserName()); + result.put("loginName", enroll.getLoginName()); + result.put("mobile", ((Sys_user) Objects.requireNonNull(ShiroUtil.getPrincipal())).getMobile()); + + + if (StrUtil.isNotBlank(enroll.getTakePartInLineId())) { + // 参加的线路 + TheRapyRecuperationLineUnionSelect selectLine = dao.fetch(TheRapyRecuperationLineUnionSelect.class, enroll.getTakePartInLineId()); + TheRapyRecuperationLine line = dao.fetch(TheRapyRecuperationLine.class, selectLine.getLineId()); + TheRapyRecuperationTravelAgency travelAgency = dao.fetch(TheRapyRecuperationTravelAgency.class, line.getTravelAgencyId()); + int teaNum = dao.count(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", enroll.getTakePartInLineId())); + + result.put("teaNum", teaNum); + result.put("selectLineId", selectLine.getId()); + result.put("lineId", line.getId()); + result.put("lineName", line.getLineName()); + result.put("travelAgencyPlace", line.getTravelAgencyPlace()); + result.put("travelAgencyName", travelAgency.getTravelAgencyName()); + result.put("playStartTime", selectLine.getPlayStartTime()); + result.put("playEndTime", selectLine.getPlayEndTime()); + } else if (StrUtil.isNotBlank(enroll.getTakePartInBaseManagementId())) { + // 参加的酒店 + TheRapyRecuperationBaseManagement hotel = dao.fetch(TheRapyRecuperationBaseManagement.class, enroll.getTakePartInBaseManagementId()); + TheRapyRecuperationTravelAgency travelAgency = dao.fetch(TheRapyRecuperationTravelAgency.class, hotel.getTravelAgencyId()); + int teaNum = dao.count(TheRapyRecuperationEnroll.class, Cnd.where("takePartInBaseManagementId", "=", enroll.getTakePartInBaseManagementId())); + + result.put("teaNum", teaNum); + result.put("hotelId", hotel.getId()); + result.put("travelAgencyName", travelAgency.getTravelAgencyName()); + result.put("playStartTime", hotel.getActivityStartTime()); + result.put("playEndTime", hotel.getActivityEndTime()); + } + + TheRapyRecuperationSatisfactionEvaluate evaluate = dao.fetch(TheRapyRecuperationSatisfactionEvaluate.class, Cnd.where("enrollId", "=", enrollId) + .and("loginName", "=", ShiroUtil.getPlatformLoginname())); + + if (evaluate != null) { + result.putAll(BeanUtil.beanToMap(evaluate)); + } + + return Result.success(result); + } + + +} diff --git a/src/main/java/io/v/nutz/zhgh/therapyRecuperation/model/TheRapyRecuperationSatisfactionEvaluate.java b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/model/TheRapyRecuperationSatisfactionEvaluate.java new file mode 100644 index 0000000..3e8ee90 --- /dev/null +++ b/src/main/java/io/v/nutz/zhgh/therapyRecuperation/model/TheRapyRecuperationSatisfactionEvaluate.java @@ -0,0 +1,98 @@ +package io.v.nutz.zhgh.therapyRecuperation.model; + +import cn.wizzer.framework.base.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.Date; + +@EqualsAndHashCode(callSuper = true) +@Table +@Data +public class TheRapyRecuperationSatisfactionEvaluate extends BaseModel { + + @Name + @Column + @Comment("ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(uu32 = true) + private String id; + + @Column + @Comment("报名id") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String enrollId; + + @Column + @Comment("参加线路id") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String selectLineId; + + @Column + @Comment("线路id") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String lineId; + + @Column + @Comment("参加酒店id") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String hotelId; + + @Column + @Comment("姓名") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String userName; + + @Column + @Comment("工号") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String loginName; + + @Column + @Comment("住宿条件得分") + @ColDefine(type = ColType.INT) + private Integer accommodationScore; + + @Column + @Comment("餐饮条件得分") + @ColDefine(type = ColType.INT) + private Integer cateringScore; + + @Column + @Comment("行程景点安排得分") + @ColDefine(type = ColType.INT) + private Integer travelScore; + + @Column + @Comment("导游服务得分") + @ColDefine(type = ColType.INT) + private Integer guideScore; + + @Column + @Comment("安全措施得分") + @ColDefine(type = ColType.INT) + private Integer safetyScore; + + @Column + @Comment("总体评价及建议") + @ColDefine(type = ColType.VARCHAR, width = 1000) + private String evaluateText; + + @Column + @Comment("评价时间") + @ColDefine(type = ColType.DATETIME) + private Date evaluateDate; + + @Column + @Comment("联系电话") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String mobile; + + @Column + @Comment("签名") + @ColDefine(type = ColType.TEXT) + private String signature; + +} diff --git a/src/main/resources/static/components/sign/mobileSign.vue b/src/main/resources/static/components/sign/mobileSign.vue index dd20536..806628f 100644 --- a/src/main/resources/static/components/sign/mobileSign.vue +++ b/src/main/resources/static/components/sign/mobileSign.vue @@ -1,45 +1,82 @@ - diff --git a/src/main/resources/views/mobile/therapyRecuperation/SatisfactionEvaluate.js b/src/main/resources/views/mobile/therapyRecuperation/SatisfactionEvaluate.js new file mode 100644 index 0000000..f989ba6 --- /dev/null +++ b/src/main/resources/views/mobile/therapyRecuperation/SatisfactionEvaluate.js @@ -0,0 +1,589 @@ +const SatisfactionEvaluate = { + template: /*language=HTML*/ ` +
+
+ 满意度调查 + × +
+
+
+

疗休养满意度评价表

+ +
+
疗休养服务单位:
+
{{formData.travelAgencyName}}
+
+ +
+
疗休养地点:
+
{{formData.travelAgencyPlace}}
+
+ +
+
教职工人数:
+
{{formData.teaNum}}
+
+ +
+
疗休养时间:
+
+ {{moment(formData.playStartTime).format('YYYY年MM月DD日')}} + 至 + {{moment(formData.playEndTime).format('MM月DD日')}} +
+
+ +
+
评分项目及分值(100分)
+
满意度评价(请您在认为的选项后空格内评分)
+ + + + + + + + + + + + + + + + + + + + + + + +
评分项目较好一般分数
{{item.title}}({{item.maxScore}}分) + {{option.range}} + + +
合计得分{{totalScore}}
+
+ +
+
对本次疗休养的整体评价及建议
+ +
+ +
+
+
本人姓名:
+
+ +
+
+ +
+
联系电话:
+
+ +
+
+ +
+
签名:
+
+ +
+
+ +
+ +
+
注:
+
1. 请在相应栏目中写上具体分数并合计得分。
+
2. 得分90分(含)以上为满意,80分(含)-90分为合格,80分以下为不合格。
+
3. 此表须由每团70%及以上的教职工(含领队)填写。
+
+ +
+ +
+
+
+
+ `, + data() { + return { + show: false, + enrollId: null, + formData: {}, + evaluationItems: [ + { + title: "住宿条件", + maxScore: 20, + field: "accommodationScore", + options: [ + { label: "好", range: "20-18" }, + { label: "较好", range: "17-16" }, + { label: "一般", range: "15-12" }, + { label: "差", range: "<12" }, + ], + }, + { + title: "餐饮状况", + maxScore: 20, + field: "cateringScore", + options: [ + { label: "好", range: "20-18" }, + { label: "较好", range: "17-16" }, + { label: "一般", range: "15-12" }, + { label: "差", range: "<12" }, + ], + }, + { + title: "行程景点安排", + maxScore: 30, + field: "travelScore", + options: [ + { label: "好", range: "30-25" }, + { label: "较好", range: "24-20" }, + { label: "一般", range: "19-15" }, + { label: "差", range: "<15" }, + ], + }, + { + title: "车辆状况和司机服务", + maxScore: 10, + field: "guideScore", + options: [ + { label: "好", range: "10-9" }, + { label: "较好", range: "8-7" }, + { label: "一般", range: "6-5" }, + { label: "差", range: "<5" }, + ], + }, + { + title: "导游服务", + maxScore: 10, + field: "guideScore", + options: [ + { label: "好", range: "10-9" }, + { label: "较好", range: "8-7" }, + { label: "一般", range: "6-5" }, + { label: "差", range: "<5" }, + ], + }, + { + title: "安全措施", + maxScore: 10, + field: "safetyScore", + options: [ + { label: "好", range: "10-9" }, + { label: "较好", range: "8-7" }, + { label: "一般", range: "6-5" }, + { label: "差", range: "<5" }, + ], + }, + ], + evaluationItemsType2: [ + { + title: "住宿条件", + maxScore: 30, + field: "accommodationScore", + options: [ + { label: "好", range: "30-25" }, + { label: "较好", range: "24-20" }, + { label: "一般", range: "19-15" }, + { label: "差", range: "<15" }, + ], + }, + { + title: "餐饮状况", + maxScore: 30, + field: "cateringScore", + options: [ + { label: "好", range: "30-25" }, + { label: "较好", range: "24-20" }, + { label: "一般", range: "19-15" }, + { label: "差", range: "<15" }, + ], + }, + { + title: "行程景点安排", + maxScore: 30, + field: "travelScore", + options: [ + { label: "好", range: "30-25" }, + { label: "较好", range: "24-20" }, + { label: "一般", range: "19-15" }, + { label: "差", range: "<15" }, + ], + }, + { + title: "安全措施", + maxScore: 10, + field: "safetyScore", + options: [ + { label: "好", range: "10-9" }, + { label: "较好", range: "8-7" }, + { label: "一般", range: "6-5" }, + { label: "差", range: "<5" }, + ], + }, + ], + }; + }, + computed: { + totalScore() { + return this.currentEvaluationItems.reduce((sum, item) => { + return sum + (Number(this.formData[item.field]) || 0); + }, 0); + }, + currentEvaluationItems() { + return this.formData.type === 1 + ? this.evaluationItems + : this.evaluationItemsType2; + }, + }, + methods: { + onOpen(id) { + this.enrollId = id; + this.getBasicInfo(); + this.show = true; + }, + selectOption(itemIndex, optionIndex) { + const item = this.currentEvaluationItems[itemIndex]; + const range = item.options[optionIndex].range; + if (range.includes("-")) { + const highScore = Number(range.split("-")[0]); + this.formData[item.field] = highScore; + } else if (range.includes("<")) { + const threshold = Number(range.replace("<", "")); + this.formData[item.field] = threshold - 1; + } + }, + onSubmit() { + this.$dialog + .confirm({ + title: "提示", + message: "您确定提交吗?", + }) + .then(() => { + $.post( + "/platform/theRapyRecuperation/satisfactionEvaluate/submit", + this.formData, + ).then((res) => { + if (res.code === 0) { + this.$toast.success("提交成功"); + // this.show = false; + this.$emit("refresh"); + } else { + this.$toast(res.msg); + } + }); + }); + }, + getScoreLevel(score, item) { + if (!score && score !== 0) return -1; + + const options = item.options; + // 从最低分的选项开始判断 + for (let i = options.length - 1; i >= 0; i--) { + const range = options[i].range; + if (range.includes("<")) { + const threshold = Number(range.replace("<", "")); + if (score < threshold) { + return i; + } + } else if (range.includes("-")) { + const [max, min] = range.split("-").map(Number); + if (score >= min && score <= max) { + return i; + } + } + } + return -1; + }, + validateScore(event, item) { + const value = Number(event.target.value); + if (isNaN(value)) { + this.formData[item.field] = 0; + return; + } + + // 限制基本范围 0 到最大分值 + if (value > item.maxScore) { + this.formData[item.field] = item.maxScore; + return; + } else if (value < 0) { + this.formData[item.field] = 0; + return; + } + + // 根据分值自动选中对应等级 + let selectedLevel = this.getScoreLevel(value, item); + if (selectedLevel === -1) { + // 如果没有找到对应等级,调整到最近的合法范围 + const options = item.options; + for (let i = options.length - 1; i >= 0; i--) { + const range = options[i].range; + if (range.includes("<")) { + const threshold = Number(range.replace("<", "")); + if (value >= threshold) { + this.formData[item.field] = threshold - 1; + break; + } + } else if (range.includes("-")) { + const [max, min] = range.split("-").map(Number); + if (value > max) { + this.formData[item.field] = max; + break; + } else if (value < min) { + this.formData[item.field] = min; + break; + } + } + } + } + }, + getBasicInfo() { + $.post("/platform/theRapyRecuperation/satisfactionEvaluate/basicInfo", { + enrollId: this.enrollId, + }).then((res) => { + if (res.code === 0) { + this.formData = res.data; + } else { + this.$toast(res.msg); + } + }); + }, + }, + style: /*language=CSS*/ ` + .satisfaction-wrapper { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #fff; + z-index: 999; + display: flex; + flex-direction: column; + } + + .satisfaction-header { + height: 44px; + line-height: 44px; + background-color: #1867b0; + color: white; + text-align: center; + position: relative; + font-size: 16px; + } + + .title { + font-weight: bold; + } + + .close-btn { + position: absolute; + right: 15px; + top: 0; + font-size: 24px; + cursor: pointer; + } + + .satisfaction-content { + flex: 1; + overflow-y: auto; + padding: 0 12px 20px; + } + + .form-title { + text-align: center; + font-size: 18px; + margin: 15px 0; + font-weight: normal; + } + + .form-row { + display: flex; + padding: 8px 0; + border-bottom: 1px solid #eee; + align-items: center; + } + + .form-row.signature-row { + flex-direction: column; + align-items: flex-start; + padding: 15px 0; + } + + .form-row.signature-row .form-label { + width: 100%; + margin-bottom: 10px; + } + + .form-row.signature-row .form-input { + width: 100%; + } + + .form-label { + width: 130px; + padding-right: 10px; + line-height: 38px; + color: #333; + } + + .form-input { + flex: 1; + } + + .form-input input { + width: 100%; + border: none; + outline: none; + font-size: 15px; + } + + .form-section { + margin: 15px 0; + } + + .section-title { + font-size: 16px; + font-weight: bold; + margin: 15px 0 5px 0; + color: #333; + border-left: 3px solid #1867b0; + padding-left: 8px; + } + + .evaluation-desc { + font-size: 14px; + color: #666; + margin-bottom: 10px; + } + + .score-table { + width: 100%; + border-collapse: collapse; + margin-top: 10px; + font-size: 14px; + } + + .score-table th, .score-table td { + border: 1px solid #ddd; + padding: 8px 4px; + text-align: center; + } + + .score-table th { + background-color: #f5f7fa; + font-weight: normal; + } + + .item-column { + width: 30%; + text-align: left; + padding-left: 8px !important; + } + + .score-column { + width: 15%; + } + + .item-name { + text-align: left; + padding-left: 8px !important; + } + + .option-cell { + cursor: pointer; + } + + .option-cell.selected { + background-color: #edf4ff; + color: #1867b0; + } + + .score-cell input { + width: 100%; + text-align: center; + border: none; + outline: none; + height: 32px; + } + + .total-row { + font-weight: bold; + } + + .total-label { + text-align: right !important; + padding-right: 8px !important; + } + + .total-value { + color: #f56c6c; + } + + .feedback-textarea { + width: 100%; + border: 1px solid #ddd; + padding: 8px; + font-size: 14px; + resize: vertical; + outline: none; + box-sizing: border-box; + min-height: 200px; + } + + .note-box { + background-color: #f9f9f9; + padding: 10px; + font-size: 13px; + color: #666; + line-height: 1.5; + margin: 15px 0; + } + + .submit-box { + margin: 20px 0; + text-align: center; + } + + .submit-btn { + background-color: #1867b0; + color: white; + border: none; + width: 100%; + height: 40px; + font-size: 16px; + outline: none; + } + + .form-text { + flex: 1; + font-size: 15px; + color: #333; + line-height: 38px; + } + `, +}; diff --git a/src/main/resources/views/mobile/therapyRecuperation/myRecuperation.html b/src/main/resources/views/mobile/therapyRecuperation/myRecuperation.html index 34dec75..196eef1 100644 --- a/src/main/resources/views/mobile/therapyRecuperation/myRecuperation.html +++ b/src/main/resources/views/mobile/therapyRecuperation/myRecuperation.html @@ -2,680 +2,841 @@ layout("/mobile/platform.html"){ #-->
- - - + + + - - - + + + - -
- - - -
{{item.label}} -
-
-
- - - - +
+ + + +
+ + + + + + + + + + + +
+ + +
+ + +
+
+ 您的评价让我们做的更好 +
+ +
+
+ 为本次疗休养打分
- - - - -
- - - - - - - - - - - +
+
+ 满意 +
+
+ 一般 +
+
+ 不满意 +
+
- -
- - -
- -
- 您的评价让我们做的更好 -
- -
-
为本次疗休养打分 -
-
-
满意
-
一般
-
不满意
-
-
- - -
-
-
-
- 提交 - -
-
+ +
+
+
+
+ 提交 + +
+ +