This commit is contained in:
Paidax
2025-05-21 18:12:08 +08:00
parent dd5aae6b9f
commit 4818e5bcfe
8 changed files with 658 additions and 195 deletions
@@ -284,7 +284,7 @@ public class ActivityBasicScopeController {
addv("is_H04", ShiroUtil.hasRole("H04"));
addv("is_H02", ShiroUtil.hasRole("club01"));
addv("is_H03", ShiroUtil.hasRole("SchoolUnionMemberAdmin"));
addv("is_sysadmin", ShiroUtil.hasRole("sysadmin,SCHOOL_UNION_SPORTS_ADMIN"));
addv("is_sysadmin", ShiroUtil.hasAnyRoles("sysadmin,SCHOOL_UNION_SPORTS_ADMIN"));
addv("unionid", Vi.getUnionId());
}};
}
@@ -3,13 +3,14 @@ package io.v.nutz.zhgh.healthCheckup.controller;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.page.Pagination;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.result.Result;
import io.v.nutz.base.utils.Vi;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.healthCheckup.model.HealthCheckupProject;
import io.v.nutz.zhgh.healthCheckup.model.HealthCheckupProjectSubject;
import io.v.nutz.zhgh.healthCheckup.model.HealthCheckupUserSelection;
import io.v.nutz.zhgh.healthCheckup.service.HealthCheckupProjectService;
import io.v.nutz.base.query.PageForm;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
@@ -117,28 +118,53 @@ public class HealthCheckupListController {
@ViReturn
@Aop(TransAop.READ_COMMITTED)
@RequiresPermissions("healthCheckup.list.mange")
public Object doEditHealthCheckupData(String subjectId, String campus, String projectId, String userId) {
public Object doEditHealthCheckupData(HealthCheckupUserSelection selection) {
if (Lang.isEmpty(selection)) {
return Result.error("数据传递异常");
}
if (Lang.isEmpty(selection.getSelectUserId())) {
return Result.error("请选择用户");
}
//查询用户有没有选择过套餐
HealthCheckupUserSelection userSelection = healthCheckupProjectService.dao().fetch(HealthCheckupUserSelection.class,
Cnd.where("projectId", "=", projectId).and("selectUserId", "=", userId));
Cnd.where("projectId", "=", selection.getProjectId()).and("selectUserId", "=", selection.getSelectUserId()));
//如果选择过套餐就修改选择的套餐id
if (Lang.isNotEmpty(userSelection)) {
userSelection.setSubjectId(subjectId);
userSelection.setCampus(campus);
healthCheckupProjectService.update(userSelection);
} else {
//如果没有选择过套餐添加一条记录
HealthCheckupUserSelection checkupUserSelection = new HealthCheckupUserSelection();
checkupUserSelection.setSelectUserId(userId);
checkupUserSelection.setProjectId(projectId);
checkupUserSelection.setSubjectId(subjectId);
checkupUserSelection.setCampus(campus);
checkupUserSelection.setSelectTime(new Date());
healthCheckupProjectService.insert(checkupUserSelection);
selection.setId(userSelection.getId());
}
selection.setSelectTime(new Date());
healthCheckupProjectService.dao().insertOrUpdate(selection);
return null;
}
@At
@ViReturn
@RequiresPermissions("healthCheckup.list.mange")
public Object getHealthEditData(String userId, String projectId){
// 先去查询有没有选择,选择了直接返回数据
HealthCheckupUserSelection userSelection = healthCheckupProjectService.dao().fetch(HealthCheckupUserSelection.class,
Cnd.where("projectId", "=", projectId).and("selectUserId", "=", userId));
// 没有选择去查询基本信息
if (Lang.isNotEmpty(userSelection)) {
return userSelection;
} else {
Sql sql = Sqls.create("""
SELECT
id,
loginname,
username,
sex,
mobile,
idcard,
TIMESTAMPDIFF(YEAR, STR_TO_DATE(SUBSTRING(idcard, 7, 8), '%Y%m%d'), CURDATE()) AS age
FROM
sys_user
WHERE id = @userId
""").setParam("userId", userId);
sql.setCallback(Sqls.callback.map());
healthCheckupProjectService.dao().execute(sql);
return sql.getResult();
}
}
}
@@ -43,6 +43,31 @@ public class HealthCheckupUserSelection {
@ColDefine(type = ColType.VARCHAR, width = 32)
private String campus;
@Column
@Comment("用户名")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String username;
@Column
@Comment("性别")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String sex;
@Column
@Comment("年龄")
@ColDefine(type = ColType.INT)
private Integer age;
@Column
@Comment("身份证号")
@ColDefine(type = ColType.VARCHAR, width = 18)
private String idcard;
@Column
@Comment("联系方式")
@ColDefine(type = ColType.VARCHAR, width = 20)
private String mobile;
@Column
@Comment("选择时间")
@ColDefine(type = ColType.DATETIME)
@@ -5,14 +5,16 @@ import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.page.Pagination;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.service.BaseService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.healthCheckup.model.HealthCheckupCampus;
import io.v.nutz.zhgh.healthCheckup.model.HealthCheckupProject;
import io.v.nutz.zhgh.healthCheckup.model.HealthCheckupUserSelection;
import io.v.nutz.zhgh.healthCheckup.service.HealthCheckupProjectService;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.web.commons.utils.ShiroUtil;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
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;
@@ -31,25 +33,25 @@ import java.util.Date;
@At("/mobile/healthCheckup")
public class MHealthCheckupListController {
@Inject
private Dao dao;
@Inject
private BaseService baseService;
@Inject
private HealthCheckupProjectService healthCheckupProjectService;
@At("/list")
@RequiresAuthentication
@Ok("beetl:/mobile/healthCheckup/list.html")
public void index() {
}
public void index() {}
@At("/checkUp")
@RequiresAuthentication
@Ok("beetl:/mobile/healthCheckup/checkUp.html")
public void checkUp() {
}
public void checkUp() {}
@At("/mine")
@RequiresAuthentication
@Ok("beetl:/mobile/healthCheckup/mine.html")
public void mine() {
@@ -57,16 +59,29 @@ public class MHealthCheckupListController {
@At
@ViReturn
@RequiresAuthentication
public Object pageData(PageForm pageForm, @Param(value = "tabName", required = false) String tabName) {
// Sql sql = Sqls.create("""
// select
// p.*,
// (select count(*) from health_checkup_user_selection s where s.projectId=p.id and s.selectUserId=@userId) as selectCount
// from
// health_checkup_project p
// LEFT JOIN health_checkup_user hcu on hcu.projectId = p.id
// $condition
// """).setParam("userId", ShiroUtil.getUserId());
Sql sql = Sqls.create("""
select
p.*,
(select count(*) from health_checkup_user_selection s where s.projectId=p.id and s.selectUserId=@userId) as selectCount
from
health_checkup_project p
LEFT JOIN health_checkup_user hcu on hcu.projectId = p.id
SELECT
p.*,
sum(IF(hs.id is not null,1,0)) AS selectCount,
hs.id AS selectId
FROM
health_checkup_project p
LEFT JOIN health_checkup_user hcu ON hcu.projectId = p.id
LEFT JOIN health_checkup_user_selection hs ON hs.selectUserId = hcu.userId
$condition
""").setParam("userId", ShiroUtil.getUserId());
""");
Cnd cnd = Cnd.NEW();
cnd.and("hcu.userId", "=", ShiroUtil.getUserId());
if ("ing".equals(tabName)) {
@@ -74,6 +89,7 @@ public class MHealthCheckupListController {
} else if ("end".equals(tabName)) {
cnd.and("p.choiceTimeEnd", "<", DateUtil.now());
}
cnd.groupBy("p.id");
cnd.asc("selectCount");
sql.setCondition(cnd);
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
@@ -82,6 +98,7 @@ public class MHealthCheckupListController {
@At
@ViReturn
@RequiresAuthentication
public Object mineData(PageForm pageForm, @Param(value = "tabName", required = false) String tabName) {
Sql sql = Sqls.create("""
SELECT
@@ -109,6 +126,7 @@ public class MHealthCheckupListController {
@At
@ViReturn
@RequiresAuthentication
public Object doSubmit(@Param("userSelection") HealthCheckupUserSelection userSelection) {
Trans.exec(() -> {
if (userSelection.getId() == null) {
@@ -126,6 +144,7 @@ public class MHealthCheckupListController {
@At
@ViReturn
@RequiresAuthentication
public Object cancel(String id, String projectId) {
HealthCheckupProject checkupProject = baseService.dao().fetch(HealthCheckupProject.class, projectId);
if (DateUtil.compare(new Date(), checkupProject.getChoiceTimeEnd()) > 0) {
@@ -141,6 +160,7 @@ public class MHealthCheckupListController {
@At
@ViReturn
@RequiresAuthentication
public Object getSelectInfo(String id) {
HealthCheckupUserSelection selection = baseService.dao().fetch(HealthCheckupUserSelection.class, id);
baseService.dao().fetchLinks(selection, "companionList");
@@ -155,12 +175,14 @@ public class MHealthCheckupListController {
@At
@ViReturn
@RequiresAuthentication
public Object getCampus() {
return baseService.dao().query(HealthCheckupCampus.class, Cnd.NEW().asc("campusCode"));
}
@At
@ViReturn
@RequiresAuthentication
public Object validCondition(String cndId) {
if (StrUtil.isBlank(cndId)) {
return Result.success();
@@ -171,4 +193,26 @@ public class MHealthCheckupListController {
}
return null;
}
@At
@ViReturn
@RequiresAuthentication
public Object getUserInfo(){
Sql sql = Sqls.create("""
SELECT
loginname,
username,
sex,
mobile,
idcard,
TIMESTAMPDIFF(YEAR, STR_TO_DATE(SUBSTRING(idcard, 7, 8), '%Y%m%d'), CURDATE()) AS age
FROM
sys_user
WHERE id = @userId
""").setParam("userId", ShiroUtil.getUserId());
sql.setCallback(Sqls.callback.map());
dao.execute(sql);
return sql.getResult();
}
}
@@ -122,7 +122,7 @@ layout("/mobile/platform.html"){
<div id="app" v-cloak>
<van-sticky>
<van-nav-bar title="体检套餐选择" left-arrow @click-left="pjaxReplace('/mobile/index')"></van-nav-bar>
<van-nav-bar title="体检套餐选择" left-arrow @click-left="pjaxReplace('/mobile/healthCheckup/list')"></van-nav-bar>
</van-sticky>
<div class="join_content">
@@ -163,6 +163,7 @@ layout("/mobile/platform.html"){
<van-field
@click="campusVisible = true"
readonly
required
is-link
label="院区"
name="campus"
@@ -170,6 +171,55 @@ layout("/mobile/platform.html"){
v-model="formData.campusName"
:rules="[{ required: true }]"
></van-field>
<van-field
label="姓名"
name="username"
required
placeholder="请填写姓名"
v-model="formData.username"
:rules="[{ required: true }]"
></van-field>
<van-field
required
readonly
label="性别"
name="sex"
placeholder="输入身份证后自动匹配"
:rules="[{ required: true }]"
v-model="formData.sex"
></van-field>
<van-field
label="年龄"
name="age"
required
readonly
placeholder="输入身份证后自动计算"
type="digit"
:rules="[{ required: true }]"
v-model="formData.age"
></van-field>
<span style="font-size: 13px; margin-left: 1.4vh; color: #bc2a25">输入身份证后自动匹配性别和年龄</span>
<van-field
label="联系方式"
name="mobile"
required
placeholder="请填写联系方式"
type="digit"
maxlength="11"
:rules="[{ required: true }]"
v-model="formData.mobile"
></van-field>
<van-field
label="身份证号"
name="idcard"
required
maxlength="18"
placeholder="请填写身份证号"
@input="getAgeAndSex"
:rules="[{ required: true }]"
v-model="formData.idcard"
></van-field>
<!-- <van-field :rules="[{ required: true, message: '请选择家属是否体检' }]" label="家属体检" name="validator">
<template #input>
<van-radio-group direction="horizontal" v-model="formData.isFamily" disabled>
@@ -270,6 +320,13 @@ layout("/mobile/platform.html"){
<van-popup position="bottom" round v-model="descVisible" :style="{ height: '60%' }">
<div v-html="desc" class="pre_text"></div>
</van-popup>
<div>
<van-tabbar v-model="tarBarActive">
<van-tabbar-item icon="home-o" replace url="/mobile/healthCheckup/list">体检选择</van-tabbar-item>
<van-tabbar-item icon="manager-o" replace url="/mobile/healthCheckup/mine">我的体检</van-tabbar-item>
</van-tabbar>
</div>
</div>
<script>
const vue = new Vue({
@@ -277,6 +334,7 @@ layout("/mobile/platform.html"){
mixins: [mobileMixins],
data() {
return {
tarBarActive: 0,
id: "",
selectId: "",
active: 0,
@@ -292,6 +350,82 @@ layout("/mobile/platform.html"){
}
},
methods: {
getAgeAndSex(value) {
try {
const age = this.calculateAgeFromIdCard(value)
this.$set(this.formData, "age", age)
const sex = this.getGenderFromIdCard(value)
this.$set(this.formData, "sex", sex)
} catch (error) {
console.log(error)
}
},
calculateAgeFromIdCard(idCard) {
// 检查身份证号码是否合法
if (!idCard) {
throw new Error("Invalid ID card format")
}
let birthDateStr
let birthYear, birthMonth, birthDay
// 处理18位身份证号码
if (idCard.length === 18) {
birthDateStr = idCard.substring(6, 14)
birthYear = parseInt(birthDateStr.substring(0, 4), 10)
birthMonth = parseInt(birthDateStr.substring(4, 6), 10) - 1 // 月份从0开始
birthDay = parseInt(birthDateStr.substring(6, 8), 10)
}
// 处理15位身份证号码
else if (idCard.length === 15) {
birthDateStr = idCard.substring(6, 12)
birthYear = parseInt("19" + birthDateStr.substring(0, 2), 10) // 使用字符串拼接
birthMonth = parseInt(birthDateStr.substring(2, 4), 10) - 1 // 月份从0开始
birthDay = parseInt(birthDateStr.substring(4, 6), 10)
} else {
throw new Error("Invalid ID card format. Only 15 or 18 digits are supported.")
}
// 获取当前日期
const currentDate = new Date()
// 计算年龄
let age = currentDate.getFullYear() - birthYear
// 如果当前日期还没过生日,则年龄减1
if (currentDate.getMonth() < birthMonth || (currentDate.getMonth() === birthMonth && currentDate.getDate() < birthDay)) {
age -= 1
}
return age
},
getGenderFromIdCard(idCard) {
// 检查身份证号码是否合法
if (!idCard) {
throw new Error("Invalid ID card format")
}
let genderDigit
// 处理18位身份证号码
if (idCard.length === 18) {
genderDigit = parseInt(idCard.charAt(16), 10) // 第17位
}
// 处理15位身份证号码
else if (idCard.length === 15) {
genderDigit = parseInt(idCard.charAt(14), 10) // 第15位
} else {
throw new Error("Invalid ID card format. Only 15 or 18 digits are supported.")
}
// 判断性别
if (genderDigit % 2 === 0) {
return "女"
} else {
return "男"
}
},
viewDesc(o) {
if (o.description) {
this.desc = o.description
@@ -305,6 +439,16 @@ layout("/mobile/platform.html"){
vant.Toast("请选择体检套餐")
return
}
if (!this.validatePhoneNumber(this.formData.mobile)) {
vant.Toast("请填写正确的手机号")
return
}
if (!this.validateIdCard(this.formData.idcard)) {
vant.Toast("请填写正确的身份证号")
return
}
//如果等于家属
if (this.project.healthCheckupType === "js" && this.formData.companionList && this.formData.companionList.length === 0) {
vant.Toast("当前体检项目需要填写家属信息,请填写家属信息。")
@@ -389,6 +533,57 @@ layout("/mobile/platform.html"){
this.formData = resp.data
const o = this.campusList.find((o) => o.id === this.formData.campus)
this.formData.campusName = o.campusName
},
async getUserInfo() {
const resp = await $.post("/mobile/healthCheckup/getUserInfo")
if (resp.code === 0) {
this.$set(this.formData, "username", resp.data.username)
this.$set(this.formData, "sex", resp.data.sex)
this.$set(this.formData, "mobile", resp.data.mobile)
this.$set(this.formData, "idcard", resp.data.idcard)
this.$set(this.formData, "age", resp.data.age)
}
},
validateIdCard(idCard) {
if (!idCard) {
return false
}
// 18位身份证号码校验
if (idCard.length === 18) {
const idCardRegex = /^[1-9]\d{5}(18|19|20)?\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}(\d|[Xx])$/
if (!idCardRegex.test(idCard)) {
return false
}
// 校验码计算
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
const checksums = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"]
let sum = 0
for (let i = 0; i < 17; i++) {
sum += idCard[i] * weights[i]
}
const checksum = checksums[sum % 11]
return checksum === idCard[17].toUpperCase()
}
// 15位身份证号码校验
else if (idCard.length === 15) {
const idCardRegex = /^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/
return idCardRegex.test(idCard)
}
// 外国人或其他情况
else {
return false
}
},
validatePhoneNumber(phoneNumber) {
if (!phoneNumber) {
return false
}
const phoneRegex = /^1[3-9]\d{9}$/
return phoneRegex.test(phoneNumber)
}
},
async created() {
@@ -397,6 +592,8 @@ layout("/mobile/platform.html"){
await this.getCampus()
if (GetQueryString("selectId")) {
await this.getSelectInfo()
} else {
this.getUserInfo()
}
await this.findSubject()
}
@@ -124,6 +124,13 @@ layout("/mobile/platform.html"){
</van-list>
<van-empty v-else description="暂无数据"></van-empty>
</template>
<div>
<van-tabbar v-model="tarBarActive">
<van-tabbar-item icon="home-o" replace url="/mobile/healthCheckup/list">体检选择</van-tabbar-item>
<van-tabbar-item icon="manager-o" replace url="/mobile/healthCheckup/mine">我的体检</van-tabbar-item>
</van-tabbar>
</div>
</div>
<script>
new Vue({
@@ -131,18 +138,13 @@ layout("/mobile/platform.html"){
mixins: [mobileMixins],
data() {
return {
tarBarActive: 0,
tabName: "ing"
}
},
methods: {
toCheckUp(o) {
if (o.selectCount > 0) {
vant.Dialog.alert({
title: "温馨提示",
message: "此项活动您已选择"
})
return
}
console.log(o)
//当前时间
const nowDate = moment().unix()
//结束时间
@@ -153,6 +155,22 @@ layout("/mobile/platform.html"){
message: "选择时间已过"
})
} else {
if (o.selectCount > 0) {
vant.Dialog.confirm({
title: "温馨提示",
message: "此项活动您已选择,是否前往修改"
})
.then(() => {
setTimeout(() => {
location.href = "/mobile/healthCheckup/checkUp?projectId=" + o.id + "&selectId=" + o.selectId
}, 500)
})
.catch(() => {
//取消
})
return
}
location.href = "/mobile/healthCheckup/checkUp?projectId=" + o.id
}
},
@@ -117,13 +117,22 @@ layout("/mobile/platform.html"){
</van-list>
<van-empty v-else description="暂无数据"></van-empty>
</template>
<div>
<van-tabbar v-model="tarBarActive">
<van-tabbar-item icon="home-o" replace url="/mobile/healthCheckup/list">体检选择</van-tabbar-item>
<van-tabbar-item icon="manager-o" replace url="/mobile/healthCheckup/mine">我的体检</van-tabbar-item>
</van-tabbar>
</div>
</div>
<script>
new Vue({
el: "#app",
mixins: [mobileMixins],
data() {
return {}
return {
tarBarActive: 1
}
},
methods: {
edit(o) {
@@ -1,66 +1,65 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div class="platform" id="app" v-cloak>
<guava padding="0 5%" ref="guava">
<template>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年度:</div>
<div class="search-item-option">
<el-date-picker
:clearable="true"
@change="yearChange"
placeholder="选择年"
style="width: 100%;"
type="year"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
:clearable="true"
@change="yearChange"
placeholder="选择年"
style="width: 100%"
type="year"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">体检项目:</div>
<div class="search-item-option">
<el-select @change="doSearch();getHealthCheckupSubject();"
style="width: 100%;"
v-model="pageForm.projectId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in projectOptions"></el-option>
<el-select @change="doSearch();getHealthCheckupSubject();" style="width: 100%" v-model="pageForm.projectId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in projectOptions"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">职工信息:</div>
<div class="search-item-option">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
style="width: 100%" v-model="pageForm.searchKeyword">
<el-select slot="prepend" style="width: 80px;"
v-model="pageForm.searchName">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入内容"
style="width: 100%"
v-model="pageForm.searchKeyword"
>
<el-select slot="prepend" style="width: 80px" v-model="pageForm.searchName">
<el-option label="姓名" value="hcu.username"></el-option>
<el-option label="工号" value="hcu.loginname"></el-option>
</el-select>
</el-input>
</div>
</div>
<div class="search-item"
v-if="${@shiro.hasRole('sysadmin')||@shiro.hasRole('SchoolUnionAdmin')||@shiro.hasRole('H03')}">
<div class="search-item" v-if="${@shiro.hasRole('sysadmin')||@shiro.hasRole('SchoolUnionAdmin')||@shiro.hasRole('H03')}">
<div class="search-item-label">所属工会:</div>
<div class="search-item-option">
<el-select @change="flushUnits" @clear="flushUnits"
clearable
filterable="true"
placeholder="请选择所属工会" style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.unionname" :value="item.id"
v-for="item in unions"></el-option>
<el-select
@change="flushUnits"
@clear="flushUnits"
clearable
filterable="true"
placeholder="请选择所属工会"
style="width: 100%"
v-model="pageForm.unionId"
>
<el-option :label="item.unionname" :value="item.id" v-for="item in unions"></el-option>
</el-select>
</div>
</div>
@@ -68,12 +67,8 @@ layout("/layouts/platform.html"){
<div class="search-item">
<div class="search-item-label">所属单位:</div>
<div class="search-item-option">
<el-select clearable filterable
placeholder="所属单位"
style="width: 100%;"
v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
<el-select clearable filterable placeholder="所属单位" style="width: 100%" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id" v-for="item in units"></el-option>
</el-select>
</div>
</div>
@@ -82,17 +77,15 @@ layout("/layouts/platform.html"){
<div class="search-item">
<div class="search-item-label">工会小组:</div>
<div class="search-item-option">
<el-select @change="getThreeUnits" clearable
filterable
placeholder="请选择"
style="width: 100%"
v-model="pageForm.unionGroupId">
<el-option
:key="item.id"
:label="item.groupName"
:value="item.id"
v-for="item in unionGroups">
</el-option>
<el-select
@change="getThreeUnits"
clearable
filterable
placeholder="请选择"
style="width: 100%"
v-model="pageForm.unionGroupId"
>
<el-option :key="item.id" :label="item.groupName" :value="item.id" v-for="item in unionGroups"></el-option>
</el-select>
</div>
</div>
@@ -100,124 +93,133 @@ layout("/layouts/platform.html"){
<div class="search-item">
<div class="search-item-label">组成科室:</div>
<div class="search-item-option">
<el-select clearable filterable placeholder="请选择"
style="width: 100%"
v-model="pageForm.threeUnitId">
<el-option
:key="item.id"
:label="item.name"
:value="item.id"
v-for="item in threeUnits">
</el-option>
<el-select clearable filterable placeholder="请选择" style="width: 100%" v-model="pageForm.threeUnitId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in threeUnits"></el-option>
</el-select>
</div>
</div>
</template>
<div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索
</el-button>
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索</el-button>
</div>
</div>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool :app="this" label="体检项目">
<template #func>
</template>
<template #func></template>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
class="vi-table" ref="table"
row-key="id" style="width: 100%" v-loading="tableLoading">
<el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index"
width="80px"></el-table-column>
<el-table
:data="tableData"
:size="tableSize"
@sort-change="pageOrder"
class="vi-table"
ref="table"
row-key="id"
style="width: 100%"
v-loading="tableLoading"
>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
align="center"
header-align="center"
min-width="100px" show-overflow-tooltip v-for="column in tableColumns">
<template scope="{row}" v-if="column.prop=='optionName'">
{{row.optionName?row.optionName:''}}
</template>
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
align="center"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='optionName'">{{row.optionName?row.optionName:''}}</template>
<template scope="{row}" v-else-if="column.prop=='userSign'">
<el-image :src="row.userSign"
fit="cover"
style="height: 60px" v-if="row.userSign"></el-image>
<el-image :src="row.userSign" fit="cover" style="height: 60px" v-if="row.userSign"></el-image>
</template>
</el-table-column>
<el-table-column align="center" fixed="right" header-align="center"
label="操作" prop="userOnline"
width="300px">
<el-table-column align="center" fixed="right" header-align="center" label="操作" prop="userOnline" width="300px">
<template scope="{row}">
<el-button @click="openEditHealthCheckup(row)" size="mini"
type="primary">
编辑
</el-button>
<el-button @click="openEditHealthCheckup(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="deleteHealthCheckup(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
</guava>
<el-dialog :close-on-click-modal="false" :visible.sync="exportHealthCheckupDialog" title="修改套餐"
width="50%">
<el-form :model="editHealthCheckupData" label-width="120px" ref="editHealthCheckupForm">
<el-form-item label="姓名">
<el-input :value="editHealthCheckupData.username"></el-input>
</el-form-item>
<el-dialog :close-on-click-modal="false" :visible.sync="exportHealthCheckupDialog" title="修改体检" width="50%">
<el-form :model="editHealthCheckupData" label-width="120px" ref="editHealthCheckupForm" :rules="editRules">
<el-form-item label="工号">
<el-input :value="editHealthCheckupData.loginname"></el-input>
<el-input v-model="editHealthCheckupData.loginname" readonly></el-input>
</el-form-item>
<el-form-item :rules="[{required:true,message:'请选择',trigger:['change','blur']}]"
label="套餐"
prop="subjectId">
<el-form-item label="姓名">
<el-input v-model="editHealthCheckupData.username" readonly></el-input>
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="性别" prop="sex">
<el-input v-model="editHealthCheckupData.sex" readonly placeholder="输入身份证后自动匹配性别"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="年龄" prop="age">
<el-input v-model="editHealthCheckupData.age" readonly placeholder="输入身份证后自动计算年龄"></el-input>
</el-form-item>
</el-col>
<div style="margin-left: 130px">
<span style="color: #bc2a25">输入身份证后自动匹配性别和年龄</span>
</div>
</el-row>
<el-form-item label="联系方式" prop="mobile">
<el-input v-model="editHealthCheckupData.mobile" placeholder="请输入手机号码" maxlength="11" type="text" show-word-limit></el-input>
</el-form-item>
<el-form-item label="身份证号" prop="idcard">
<el-input
v-model="editHealthCheckupData.idcard"
@input="getAgeAndSex"
placeholder="请输入身份证号"
maxlength="18"
type="text"
show-word-limit
></el-input>
</el-form-item>
<el-form-item label="套餐" prop="subjectId">
<el-select style="width: 100%" v-model="editHealthCheckupData.subjectId">
<el-option :key="item.id" :label="item.optionName" :value="item.id"
v-for="item in projectSubjectOptions"></el-option>
<el-option :key="item.id" :label="item.optionName" :value="item.id" v-for="item in projectSubjectOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item :rules="[{required:true,message:'请选择',trigger:['change','blur']}]"
label="院区"
prop="campus">
<el-form-item label="院区" prop="campus">
<el-select style="width: 100%" v-model="editHealthCheckupData.campus">
<el-option :key="item.id" :label="item.campusName" :value="item.id"
v-for="item in campusOptions"></el-option>
<el-option :key="item.id" :label="item.campusName" :value="item.id" v-for="item in campusOptions"></el-option>
</el-select>
</el-form-item>
</el-form>
<el-row justify="end" type="flex">
<el-button @click="exportHealthCheckupDialog=false" plain type="primary">取消</el-button>
<el-button @click="doEditHealthCheckupData" type="primary" v-loading="loading">确定
</el-button>
<el-button @click="doEditHealthCheckupData" type="primary" v-loading="loading">确定</el-button>
</el-row>
</el-dialog>
</div>
<script>
const vue = new Vue({
el: '#app',
el: "#app",
mixins: [initTableMixins],
data() {
return {
pageForm: {
year: moment().format('YYYY'),
searchName: "hcu.username",
year: moment().format("YYYY"),
searchName: "hcu.username"
},
threeUnits: [],
unionGroups: [],
@@ -226,56 +228,198 @@ layout("/layouts/platform.html"){
projectOptions: [],
projectSubjectOptions: [],
tableColumns: [
{prop: 'loginname', label: '工号'},
{prop: 'username', label: '姓名'},
{prop: 'sex', label: '性别', sortable: true, width: '100px'},
{prop: 'unionname', label: '所属工会', sortable: true},
{prop: 'unitname', label: '所属单位', sortable: true},
{prop: 'threeUnitName', label: '所在科室', sortable: true, checked: 0},
{prop: 'unionGroupName', label: '工会小组', sortable: true, checked: 0},
{prop: 'optionName', label: '所选套餐', width: "100px"},
{ prop: "loginname", label: "工号" },
{ prop: "username", label: "姓名" },
{ prop: "sex", label: "性别", sortable: true, width: "100px" },
{ prop: "unionname", label: "所属工会", sortable: true },
{ prop: "unitname", label: "所属单位", sortable: true },
{ prop: "threeUnitName", label: "所在科室", sortable: true, checked: 0 },
{ prop: "unionGroupName", label: "工会小组", sortable: true, checked: 0 },
{ prop: "optionName", label: "所选套餐", width: "100px" }
// {prop: 'userSign', label: '签字', width: "100px"},
],
exportHealthCheckupDialog: false,
editHealthCheckupData: {},
editRules: {
sex: [{ required: true, message: "请选择性别", trigger: ["change", "blur"] }],
age: [{ required: true, message: "请输入年龄", trigger: ["change", "blur"] }],
mobile: [
{
required: true,
validator: (rule, value, callback) => {
if (!value) {
callback(new Error("请输入联系方式"))
} else if (/^[1][345789][0-9]{9}$/.test(value)) {
// 手机号格式正确
callback()
} else if (/^\d+-\d+$/.test(value) && value.length <= 16) {
// 座机号格式正确
callback()
} else {
// 格式错误,返回错误信息
callback(new Error(value.includes("-") ? "座机号码格式错误" : "手机号码格式错误"))
}
},
trigger: ["change", "blur"]
}
],
idcard: [
{
required: true,
validator: (rule, value, callback) => {
if (!value) {
// 如果值为空,直接通过校验
callback()
} else if (
/^[1-9]\d{5}(18|19|20)?\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}(\d|[Xx])$/.test(value)
) {
// 18位身份证号码格式正确
callback()
} else if (/^[1-9]\d{7}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 15位身份证号码格式正确
callback()
} else if (/^[1-9]\d{5}(18|19|20)?\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 外国人身份证号码格式正确(18位)
callback()
} else if (/^[1-9]\d{7}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 外国人身份证号码格式正确(15位)
callback()
} else {
// 格式错误,返回错误信息
callback(new Error("身份证号码格式错误"))
}
},
trigger: ["change", "blur"]
}
],
subjectId: [{ required: true, message: "请选择套餐", trigger: ["change", "blur"] }],
campus: [{ required: true, message: "请选择院区", trigger: ["change", "blur"] }]
},
loading: false,
campusOptions: [],
isThreeUnit: null,
isThreeUnit: null
}
},
components: {},
methods: {
getAgeAndSex(value) {
try {
const age = this.calculateAgeFromIdCard(value)
this.$set(this.editHealthCheckupData, "age", age)
const sex = this.getGenderFromIdCard(value)
this.$set(this.editHealthCheckupData, "sex", sex)
} catch (error) {
console.log(error)
}
},
calculateAgeFromIdCard(idCard) {
// 检查身份证号码是否合法
if (!idCard) {
throw new Error("Invalid ID card format")
}
let birthDateStr
let birthYear, birthMonth, birthDay
// 处理18位身份证号码
if (idCard.length === 18) {
birthDateStr = idCard.substring(6, 14)
birthYear = parseInt(birthDateStr.substring(0, 4), 10)
birthMonth = parseInt(birthDateStr.substring(4, 6), 10) - 1 // 月份从0开始
birthDay = parseInt(birthDateStr.substring(6, 8), 10)
}
// 处理15位身份证号码
else if (idCard.length === 15) {
birthDateStr = idCard.substring(6, 12)
birthYear = parseInt("19" + birthDateStr.substring(0, 2), 10) // 使用字符串拼接
birthMonth = parseInt(birthDateStr.substring(2, 4), 10) - 1 // 月份从0开始
birthDay = parseInt(birthDateStr.substring(4, 6), 10)
} else {
throw new Error("Invalid ID card format. Only 15 or 18 digits are supported.")
}
// 获取当前日期
const currentDate = new Date()
// 计算年龄
let age = currentDate.getFullYear() - birthYear
// 如果当前日期还没过生日,则年龄减1
if (currentDate.getMonth() < birthMonth || (currentDate.getMonth() === birthMonth && currentDate.getDate() < birthDay)) {
age -= 1
}
return age
},
getGenderFromIdCard(idCard) {
// 检查身份证号码是否合法
if (!idCard) {
throw new Error("Invalid ID card format")
}
let genderDigit
// 处理18位身份证号码
if (idCard.length === 18) {
genderDigit = parseInt(idCard.charAt(16), 10) // 第17位
}
// 处理15位身份证号码
else if (idCard.length === 15) {
genderDigit = parseInt(idCard.charAt(14), 10) // 第15位
} else {
throw new Error("Invalid ID card format. Only 15 or 18 digits are supported.")
}
// 判断性别
if (genderDigit % 2 === 0) {
return "女"
} else {
return "男"
}
},
doEditHealthCheckupData() {
this.$refs['editHealthCheckupForm'].validate(async valid => {
this.$refs["editHealthCheckupForm"].validate(async (valid) => {
if (valid) {
this.loading = true
const resp = await $.post(loc() + "/doEditHealthCheckupData", this.editHealthCheckupData)
this.exportHealthCheckupDialog = false
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.doSearch()
} else {
this.notifyWarning(resp.msg)
}
this.loading = false
// 确定要提交吗?
this.$confirm("确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await $.post(loc() + "/doEditHealthCheckupData", this.editHealthCheckupData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
this.exportHealthCheckupDialog = false
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
async openEditHealthCheckup(row) {
this.editHealthCheckupData = {
username: row.username,
loginname: row.loginname,
subjectId: row.subjectId,
campus: row.campus,
projectId: this.pageForm.projectId,
userId: row.id
const resp = await $.post("/platform/healthCheckup/list/mange/getHealthEditData", {
userId: row.id,
projectId: this.pageForm.projectId
})
if (resp.code === 0) {
console.log(resp.data)
this.editHealthCheckupData = resp.data
this.editHealthCheckupData.id = null
this.editHealthCheckupData.projectId = this.pageForm.projectId
this.$set(this.editHealthCheckupData, "selectUserId", row.id)
if (resp.data.subjectId) {
this.$set(this.editHealthCheckupData, "loginname", row.loginname)
}
}
this.exportHealthCheckupDialog = true
this.exportHealthCheckupDialog = true
},
async yearChange() {
const resp = await $.get("/platform/healthCheckup/project/mange/getHealthCheckupProject", {year: this.pageForm.year})
const resp = await $.get("/platform/healthCheckup/project/mange/getHealthCheckupProject", { year: this.pageForm.year })
if (resp.code === 0) {
this.projectOptions = resp.data
if (resp.data && resp.data.length > 0) {
@@ -289,7 +433,7 @@ layout("/layouts/platform.html"){
}
},
async getHealthCheckupSubject() {
const resp = await $.get("/platform/healthCheckup/project/mange/findOne", {id: this.pageForm.projectId})
const resp = await $.get("/platform/healthCheckup/project/mange/findOne", { id: this.pageForm.projectId })
if (resp.code === 0) {
this.projectSubjectOptions = resp.data.healthCheckupProjectSubjects
} else {
@@ -310,22 +454,22 @@ layout("/layouts/platform.html"){
},
async flushUnits() {
this.$set(this.pageForm, "unitId", "")
if ("${@shiro.hasRole('sysadmin')||@shiro.hasRole('SchoolUnionAdmin')||@shiro.hasRole('H03')}" === 'true') {
if ("${@shiro.hasRole('sysadmin')||@shiro.hasRole('SchoolUnionAdmin')||@shiro.hasRole('H03')}" === "true") {
this.units = await getUnits(this.pageForm.unionId)
} else {
this.units = await getUnits("${@shiro.getPrincipalProperty('unit').getUnionid()}")
}
this.unionGroups = await unionGroupsByUnionId(this.pageForm.unionId)
if ("${@shiro.hasRole('ghxzzz')}" === 'true') {
this.$set(this.pageForm, 'unionGroupId', this.unionGroups[0].id)
if ("${@shiro.hasRole('ghxzzz')}" === "true") {
this.$set(this.pageForm, "unionGroupId", this.unionGroups[0].id)
await this.getThreeUnits()
}
},
}
},
async created() {
this.isThreeUnit = await getConfigKey('isThreeUnit') === 'true'
this.isThreeUnit = (await getConfigKey("isThreeUnit")) === "true"
if (this.isThreeUnit) {
this.tableColumns.forEach(v => {
this.tableColumns.forEach((v) => {
if (["threeUnitName", "unionGroupName"].includes(v.prop)) {
v.checked = 1
}