医疗互助补助模块

This commit is contained in:
2026-07-23 11:57:08 +08:00
parent 67e40e36ea
commit a17140fbd2
35 changed files with 5607 additions and 7 deletions
@@ -0,0 +1,15 @@
-- 医疗互助疾病类型基础表;脚本可重复执行。
CREATE TABLE IF NOT EXISTS `medical_disease_type` (
`id` varchar(32) NOT NULL COMMENT 'ID',
`diseaseName` varchar(50) NOT NULL COMMENT '疾病名称',
`diseaseCode` varchar(20) NOT NULL COMMENT '疾病编码',
`isMajorDiseases` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否重大疾病',
`createdBy` varchar(32) DEFAULT NULL COMMENT '创建人',
`createdAt` bigint DEFAULT NULL COMMENT '创建时间',
`updatedBy` varchar(32) DEFAULT NULL COMMENT '修改人',
`updatedAt` bigint DEFAULT NULL COMMENT '修改时间',
`delFlag` tinyint(1) DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (`id`),
KEY `idx_medical_disease_type_code` (`diseaseCode`),
KEY `idx_medical_disease_type_name` (`diseaseName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='医疗互助疾病类型表';
@@ -0,0 +1,71 @@
DROP TABLE IF EXISTS `tb_mutual_apply`;
CREATE TABLE `tb_mutual_apply` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`apply_no` varchar(50) DEFAULT NULL COMMENT '申请编号',
`user_id` varchar(50) DEFAULT NULL COMMENT '申请人用户ID',
`login_name` varchar(50) DEFAULT NULL COMMENT '申请人工号/登录名',
`user_name` varchar(50) NOT NULL COMMENT '申请人姓名',
`sex` varchar(20) DEFAULT NULL COMMENT '性别',
`birthday` date DEFAULT NULL COMMENT '出生年月',
`native_place` varchar(100) DEFAULT NULL COMMENT '籍贯',
`education` varchar(50) DEFAULT NULL COMMENT '学历',
`professional_title` varchar(100) DEFAULT NULL COMMENT '职称',
`dept_id` varchar(50) DEFAULT NULL COMMENT '工作部门ID',
`dept_name` varchar(200) DEFAULT NULL COMMENT '工作部门(系部)',
`id_card` varchar(30) DEFAULT NULL COMMENT '身份证号码',
`mobile` varchar(30) DEFAULT NULL COMMENT '联系电话',
`bank_card_no` varchar(50) DEFAULT NULL COMMENT '工资银行卡号',
`bank_name` varchar(200) DEFAULT NULL COMMENT '开户行',
`join_date` date DEFAULT NULL COMMENT '入会时间',
`join_year` int DEFAULT NULL COMMENT '加入年份',
`disease_type_id` varchar(32) DEFAULT NULL COMMENT '大病类型ID',
`disease_name` varchar(200) NOT NULL COMMENT '大病名称',
`hospital_desc` varchar(500) DEFAULT NULL COMMENT '何时何病住何医院',
`medical_total_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '全年医疗费用总金额',
`self_pay_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '自付金额',
`sign_file_id` varchar(50) DEFAULT NULL COMMENT '申请人签名文件ID',
`sign_time` datetime DEFAULT NULL COMMENT '申请人签名时间',
`status` tinyint NOT NULL DEFAULT 0 COMMENT '状态 0未审核 1已审核',
`submit_time` datetime DEFAULT NULL COMMENT '提交时间',
`audit_by` varchar(50) DEFAULT NULL COMMENT '审核人',
`audit_time` datetime DEFAULT NULL COMMENT '审核时间',
`audit_opinion` varchar(500) DEFAULT NULL COMMENT '审核意见',
`config_id` bigint DEFAULT NULL COMMENT '审核使用的互助金配置ID',
`config_year` int DEFAULT NULL COMMENT '审核使用的配置年度',
`subsidy_total_amount` decimal(12,2) DEFAULT NULL COMMENT '补助小计',
`bonus_ratio` decimal(5,2) DEFAULT NULL COMMENT '奖励/补助系数',
`actual_subsidy_amount` decimal(12,2) DEFAULT NULL COMMENT '实际补助金额',
`continuous_unapply_year` int DEFAULT NULL COMMENT '连续未申请年数',
`limit_amount` decimal(12,2) DEFAULT NULL COMMENT '本次适用最高补助限额',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_login_name` (`login_name`),
KEY `idx_dept_id` (`dept_id`),
KEY `idx_status` (`status`),
KEY `idx_disease_type_id` (`disease_type_id`),
KEY `idx_join_year` (`join_year`),
KEY `idx_submit_time` (`submit_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='互助金申请表';
DROP TABLE IF EXISTS `tb_mutual_apply_subsidy`;
CREATE TABLE `tb_mutual_apply_subsidy` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`apply_id` bigint NOT NULL COMMENT '申请ID',
`ratio_id` bigint DEFAULT NULL COMMENT '使用的补助比例配置ID',
`range_name` varchar(100) DEFAULT NULL COMMENT '区间名称',
`start_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '区间开始金额',
`end_amount` decimal(12,2) DEFAULT NULL COMMENT '区间结束金额(NULL表示无限)',
`ratio` decimal(5,2) NOT NULL DEFAULT '0.00' COMMENT '补助比例(%)',
`base_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '本区间参与计算金额',
`subsidy_amount` decimal(12,2) NOT NULL DEFAULT '0.00' COMMENT '本区间补助金额',
`sort` int DEFAULT 1 COMMENT '排序',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_apply_id` (`apply_id`),
KEY `idx_ratio_id` (`ratio_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='互助金补贴金额明细表';
@@ -0,0 +1,51 @@
-- 医疗互助疾病类型 PC 端与移动端菜单。
-- 使用 permission 做幂等判断,重复执行不会插入重复菜单。
-- PC 端一级菜单。
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService)
SELECT 'e5d7a110aa214cdf8505fd0000000001', '', LPAD(IFNULL(MAX(CAST(path AS UNSIGNED)), 0) + 1, 4, '0'), '医疗互助', 'Medical Mutual Aid', 'menu', '', '', 'ti-heart', 1, 0, 'medicalMutualAid', NULL, 992, 1, '', UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0, 'PC', NULL, NULL, 'y', 0, 0
FROM sys_menu
WHERE platform = 'PC' AND (parentId = '' OR parentId IS NULL) AND CHAR_LENGTH(path) = 4
HAVING NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'medicalMutualAid' AND platform = 'PC') t);
-- PC 端医疗管理分组。
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService)
SELECT 'e5d7a110aa214cdf8505fd0000000002', p.id, CONCAT(p.path, '0001'), '医疗管理', 'Medical Manage', 'menu', '', '', '', 1, 0, 'medicalMutualAid.medical', NULL, 1, 1, '', UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0, 'PC', NULL, NULL, 'y', 0, 0
FROM sys_menu p
WHERE p.permission = 'medicalMutualAid' AND p.platform = 'PC'
AND NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'medicalMutualAid.medical' AND platform = 'PC') t);
-- PC 端疾病种类页面。
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService)
SELECT 'e5d7a110aa214cdf8505fd0000000003', p.id, CONCAT(p.path, '0001'), '疾病种类', 'Disease Type', 'menu', '/platform/medicalMutualAid/medical/diseaseType', 'data-pjax', '', 1, 0, 'medicalMutualAid.medical.diseaseType', NULL, 1, 0, '', UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0, 'PC', NULL, NULL, 'j', 0, 0
FROM sys_menu p
WHERE p.permission = 'medicalMutualAid.medical' AND p.platform = 'PC'
AND NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'medicalMutualAid.medical.diseaseType' AND platform = 'PC') t);
-- 移动端一级菜单。
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService)
SELECT 'e5d7a110aa214cdf8505fd0000000004', '', LPAD(IFNULL(MAX(CAST(path AS UNSIGNED)), 0) + 1, 4, '0'), '医疗互助', 'Medical Mutual Aid', 'menu', '', '', 'heart-o', 1, 0, 'h5.medicalMutualAid', NULL, 992, 1, '', UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0, 'H5', NULL, NULL, 'y', 0, 0
FROM sys_menu
WHERE platform = 'H5' AND (parentId = '' OR parentId IS NULL) AND CHAR_LENGTH(path) = 4
HAVING NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'h5.medicalMutualAid' AND platform = 'H5') t);
-- 移动端疾病种类页面,权限严格使用 h5. 前缀。
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService)
SELECT 'e5d7a110aa214cdf8505fd0000000005', p.id, CONCAT(p.path, '0001'), '疾病种类', 'Disease Type', 'menu', '/platform/h5/medicalMutualAid/medical/diseaseType', 'data-pjax', '', 1, 0, 'h5.medicalMutualAid.medical.diseaseType', NULL, 1, 0, '', UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0, 'H5', NULL, NULL, 'j', 0, 0
FROM sys_menu p
WHERE p.permission = 'h5.medicalMutualAid' AND p.platform = 'H5'
AND NOT EXISTS (SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'h5.medicalMutualAid.medical.diseaseType' AND platform = 'H5') t);
-- 默认授予系统管理员,其他角色可在角色管理中按需分配。
INSERT INTO sys_role_menu (roleId, menuId)
SELECT r.id, m.id
FROM sys_role r
JOIN sys_menu m ON m.permission IN (
'medicalMutualAid',
'medicalMutualAid.medical',
'medicalMutualAid.medical.diseaseType',
'h5.medicalMutualAid',
'h5.medicalMutualAid.medical.diseaseType'
)
LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id
WHERE r.code = 'SYSADMIN' AND rm.roleId IS NULL;
@@ -0,0 +1,221 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.mutual-list-page { padding: 16px 20px; background: #f3f6fa; height: calc(100vh - 88px); box-sizing: border-box; display: flex; flex-direction: column; overflow: hidden; }
.search-panel { background: #fff; padding: 16px 42px; margin-bottom: 12px; box-sizing: border-box; flex-shrink: 0; }
.search-panel .el-form-item { margin-bottom: 0; margin-right: 14px; }
.content-panel { background: #fff; padding: 16px 20px 16px; box-sizing: border-box; flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.section-title { border-left: 4px solid #0079c2; padding-left: 10px; color: #0079c2; font-size: 16px; font-weight: 700; line-height: 22px; }
.table-actions .el-button { min-width: 54px; padding: 7px 14px; border-radius: 2px; }
.mutual-table.el-table th { background: #fafafa; color: #303133; font-weight: 700; }
.mutual-table.el-table td, .mutual-table.el-table th { padding: 11px 0; }
.pager { display: flex; justify-content: flex-start; align-items: center; padding-top: 12px; flex-shrink: 0; }
.pager .total-text { margin-right: 18px; color: #303133; }
</style>
<div id="app" v-cloak class="mutual-list-page">
<div class="search-panel">
<el-form :inline="true" :model="searchForm">
<el-form-item label="工号/姓名">
<el-input v-model="searchForm.keyword" clearable placeholder="请输入工号或姓名" style="width: 220px"></el-input>
</el-form-item>
<el-form-item label="大病名称">
<el-select v-model="searchForm.diseaseName" clearable filterable placeholder="请选择大病名称" style="width: 220px">
<el-option v-for="item in diseaseTypes" :key="item.id" :label="item.diseaseName" :value="item.diseaseName"></el-option>
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-select v-model="searchForm.status" clearable placeholder="请选择状态" style="width: 160px">
<el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadPage">查询</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="content-panel" ref="contentPanel">
<div class="panel-header" ref="panelHeader">
<div class="section-title">互助会审核</div>
</div>
<el-table class="mutual-table" :data="tableData" border v-loading="loading" :height="tableHeight" style="width: 100%">
<el-table-column type="index" label="序号" width="70" align="center"></el-table-column>
<el-table-column prop="loginName" label="申请人工号" width="130" align="center"></el-table-column>
<el-table-column prop="userName" label="申请人姓名" width="130" align="center"></el-table-column>
<el-table-column prop="joinDate" label="入会时间" width="130" align="center"></el-table-column>
<el-table-column prop="diseaseName" label="大病名称" min-width="200" align="center"></el-table-column>
<el-table-column label="全年医疗费用总金额(元)" width="190" align="center">
<template slot-scope="{row}">{{ formatMoney(row.medicalTotalAmount) }}</template>
</el-table-column>
<el-table-column label="自费金额(元)" width="150" align="center">
<template slot-scope="{row}">{{ formatMoney(row.selfPayAmount) }}</template>
</el-table-column>
<el-table-column label="状态" width="100" align="center">
<template slot-scope="{row}">
<el-tag v-if="isAudited(row)" type="success" size="mini">已审核</el-tag>
<el-tag v-else-if="isDiscarded(row)" type="danger" size="mini">已作废</el-tag>
<el-tag v-else type="warning" size="mini">未审核</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="260" align="center">
<template slot-scope="{row}">
<div class="table-actions">
<el-button size="mini" @click="goView(row)">查看</el-button>
<el-button v-if="isPending(row)" size="mini" type="primary" @click="goReview(row)">审核</el-button>
<el-button v-if="isAudited(row)" size="mini" type="warning" @click="cancelAudit(row)">弃审</el-button>
<el-button v-if="isPending(row)" size="mini" type="danger" @click="discard(row)">作废</el-button>
<el-button v-if="isDiscarded(row)" size="mini" type="warning" @click="cancelDiscard(row)">取消作废</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="pager" ref="pager">
<span class="total-text">共 {{ totalCount }} 条</span>
<el-pagination background layout="sizes, prev, pager, next" :current-page.sync="pageForm.pageNumber" :page-size.sync="pageForm.pageSize" :total="totalCount" @current-change="loadPage" @size-change="loadPage"></el-pagination>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
loading: false,
tableData: [],
diseaseTypes: [],
statusOptions: [
{ label: "未审核", value: 0 },
{ label: "已审核", value: 1 },
{ label: "作废", value: 2 }
],
totalCount: 0,
tableHeight: 360,
apiBase: "${base!}/platform/medicalMutualAid/apply/audit",
reviewPath: "${base!}/platform/medicalMutualAid/apply/audit/review",
diseaseTypeApi: "${base!}/platform/medicalMutualAid/medical/diseaseType",
searchForm: { keyword: "", diseaseName: "", status: "" },
pageForm: { pageNumber: 1, pageSize: 10 }
}
},
methods: {
// 加载互助疾病类型下拉,查询条件与申请页面共用疾病基础数据。
loadDiseaseTypes() {
this.$axios.post(this.diseaseTypeApi + "/pageData", { pageNumber: 1, pageSize: 999 }).then((resp) => {
if (resp.code === 0) {
this.diseaseTypes = resp.data.list || []
}
})
},
// 查询互助金待审核/已审核申请列表。
loadPage() {
this.loading = true
const params = Object.assign({}, this.pageForm, this.searchForm)
if (params.status === "" || params.status === null || params.status === undefined) {
delete params.status
}
this.$axios.post(this.apiBase + "/page", params).then((resp) => {
if (resp.code === 0) {
this.tableData = resp.data.list || []
this.totalCount = resp.data.totalCount || 0
}
}).finally(() => {
this.loading = false
this.$nextTick(this.updateTableHeight)
})
},
// 重置审核列表查询条件。
resetSearch() {
this.searchForm = { keyword: "", diseaseName: "", status: "" }
this.pageForm.pageNumber = 1
this.loadPage()
},
// 进入审核详情页,具体补助公式在详情页中展示。
goReview(row) {
commonUtil.pjaxPush(this.reviewPath + "?id=" + row.id)
},
// 查看复用审核详情页,通过 mode=view 控制页面只读并隐藏审核操作。
goView(row) {
commonUtil.pjaxPush(this.reviewPath + "?id=" + row.id + "&mode=view")
},
// 统一判断审核状态,兼容后端返回数字或字符串。
isAudited(row) {
return Number(row.status) === 1
},
// 未审核状态允许进入审核或作废。
isPending(row) {
return Number(row.status) === 0
},
// 作废状态只允许取消作废,不能继续审核或弃审。
isDiscarded(row) {
return Number(row.status) === 2
},
// 已审核申请支持弃审,恢复未审核状态并清理补助明细后刷新列表。
cancelAudit(row) {
this.$confirm("确定要弃审该互助金申请吗?", "提示", {
type: "warning"
}).then(() => {
this.$axios.post(this.apiBase + "/cancelAudit", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success("弃审成功")
this.loadPage()
}
})
}).catch(() => {})
},
// 作废未审核申请,后台会记录当前操作人为审核人并记录审核时间。
discard(row) {
this.$confirm("确定要作废该互助金申请吗?", "提示", {
type: "warning"
}).then(() => {
this.$axios.post(this.apiBase + "/discard", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success("作废成功")
this.loadPage()
}
})
}).catch(() => {})
},
// 取消作废后恢复未审核状态,并清空作废时写入的审核人和审核时间。
cancelDiscard(row) {
this.$confirm("确定要取消作废该互助金申请吗?", "提示", {
type: "warning"
}).then(() => {
this.$axios.post(this.apiBase + "/cancelDiscard", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success("取消作废成功")
this.loadPage()
}
})
}).catch(() => {})
},
formatMoney(value) {
const num = Number(value || 0)
return num.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
},
// 根据内容面板剩余空间计算表格高度,避免列表高度受数据条数影响。
updateTableHeight() {
const panel = this.$refs.contentPanel
if (!panel) {
return
}
const headerHeight = this.$refs.panelHeader ? this.$refs.panelHeader.offsetHeight : 0
const pagerHeight = this.$refs.pager ? this.$refs.pager.offsetHeight : 0
this.tableHeight = Math.max(panel.clientHeight - headerHeight - pagerHeight - 32, 220)
}
},
created() {
this.loadDiseaseTypes()
this.loadPage()
},
mounted() {
this.$nextTick(this.updateTableHeight)
window.addEventListener("resize", this.updateTableHeight)
},
beforeDestroy() {
window.removeEventListener("resize", this.updateTableHeight)
}
})
</script>
<!--#}#-->
@@ -0,0 +1,275 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.audit-review-page { background: #f5f7fa; height: calc(100vh - 88px); display: flex; flex-direction: column; overflow: hidden; box-sizing: border-box; }
.back-bar { background: #fff; padding: 14px 24px; margin-bottom: 12px; border-bottom: 1px solid #ebeef5; flex-shrink: 0; }
.back-bar .el-button { padding: 0; font-size: 15px; }
.audit-review-card { flex: 1; min-height: 0; height: auto !important; overflow: hidden; }
.audit-review-card .card-body { flex: 1; min-height: 0; overflow-y: auto; box-sizing: border-box; }
.audit-review-card .el-card__footer { flex-shrink: 0; }
.section-title { border-left: 4px solid #0079c2; padding-left: 10px; margin: 4px 0 14px; color: #0079c2; font-weight: 700; }
.required-star { color: #f56c6c; padding-right: 4px; font-weight: 700; }
.mutual-desc .el-descriptions-item__label { width: 150px; color: #303133; background: #fafafa; }
.mutual-desc .el-descriptions-item__content { min-width: 220px; }
.mutual-desc .el-form-item { margin-bottom: 0; }
.mutual-desc .el-input-number { width: 100%; }
.calc-block { margin-top: 16px; }
.calc-table .cell { line-height: 22px; }
.limit-tip { color: #f56c6c; font-size: 13px; line-height: 22px; margin: 12px 0 0; }
.audit-actions { text-align: right; }
</style>
<div id="app" v-cloak class="audit-review-page">
<div class="back-bar">
<el-button type="text" icon="el-icon-back" @click="goBack">返回</el-button>
</div>
<custom-card class="audit-review-card" v-loading="loading">
<div class="section-title">申请信息</div>
<el-form :model="apply" label-width="0">
<el-descriptions class="mutual-desc" :column="3" border>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>工号</template>
<el-input v-model="apply.loginName" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>姓名</template>
<el-input v-model="apply.userName" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">入会日期</template>
<el-input :value="formatDate(apply.joinDate)" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">入会时间(年)</template>
<el-input :value="calcJoinYears(apply.joinYear)" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">性别</template>
<el-input v-model="apply.sex" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">出生年月</template>
<el-input :value="formatDate(apply.birthday)" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">籍贯</template>
<el-input v-model="apply.nativePlace" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">工作部门(系部)</template>
<el-input v-model="apply.deptName" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">学历</template>
<el-input v-model="apply.education" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">职称</template>
<el-input v-model="apply.professionalTitle" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>身份证号码</template>
<el-input v-model="apply.idCard" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>联系电话</template>
<el-input v-model="apply.mobile" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>工资银行卡号</template>
<el-input v-model="apply.bankCardNo" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>开户行</template>
<el-input v-model="apply.bankName" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item :span="3">
<template slot="label"><span class="required-star">*</span>大病名称</template>
<el-input v-model="apply.diseaseName" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item :span="3">
<template slot="label"><span class="required-star">*</span>何时何病住何医院</template>
<el-input type="textarea" :rows="5" v-model="apply.hospitalDesc" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>全年医疗费用总金额(元)</template>
<el-input :value="formatMoney(apply.medicalTotalAmount)" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>自费金额(元)</template>
<el-input :value="formatMoney(apply.selfPayAmount)" readonly></el-input>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
</el-descriptions>
</el-form>
<div class="calc-block">
<div class="section-title">补助计算方法</div>
<el-table class="calc-table" :data="calcRows" border style="width: 100%">
<el-table-column type="index" label="序号" width="80" align="center"></el-table-column>
<el-table-column label="补助计算方法" align="center">
<el-table-column v-for="item in subsidies" :key="item.id || item.ratioId || item.sort" :label="item.rangeName" align="center" min-width="150">
<template slot-scope="{row}">{{ formatMoney(row.amounts[item.sort]) }}</template>
</el-table-column>
</el-table-column>
<el-table-column label="补助小计" align="center" min-width="140">
<template slot-scope="{row}">{{ formatMoney(row.total) }}</template>
</el-table-column>
<el-table-column label="补助比例" align="center" min-width="120">
<template slot-scope="{row}">{{ formatRatio(row.bonusRatio) }}</template>
</el-table-column>
<el-table-column label="实际补助金额(元)" align="center" min-width="160">
<template slot-scope="{row}">{{ formatMoney(row.actualSubsidyAmount) }}</template>
</el-table-column>
</el-table>
<el-descriptions class="mutual-desc" :column="3" border style="margin-top: 12px">
<el-descriptions-item :span="3">
<template slot="label">备注</template>
<el-input type="textarea" :rows="3" maxlength="500" show-word-limit v-model="auditForm.remark" :readonly="isViewMode" placeholder="请输入备注(选填)"></el-input>
</el-descriptions-item>
</el-descriptions>
</div>
<div class="limit-tip" v-if="showYearLimitTip">
当前申报人本年度已申报:{{ formatMoney(yearLimit.yearUsedAmount) }},剩余可申报金额:{{ formatMoney(yearLimit.yearRemainAmount) }}
</div>
<template slot="footer" v-if="!isViewMode">
<div class="audit-actions">
<el-button @click="goBack">返回</el-button>
<el-button type="primary" @click="approve">审核通过</el-button>
</div>
</template>
</custom-card>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
loading: false,
id: "",
pageMode: "audit",
apiBase: "${base!}/platform/medicalMutualAid/apply/audit/review",
auditPath: "${base!}/platform/medicalMutualAid/apply/audit",
apply: {},
subsidies: [],
yearLimit: { yearUsedAmount: 0, yearRemainAmount: 0, yearLimitAmount: 0 },
auditForm: { bonusRatio: "", actualSubsidyAmount: "", remark: "" }
}
},
computed: {
// 查看模式由列表页传入,统一控制审核详情页隐藏操作按钮和锁定可编辑项。
isViewMode() {
return this.pageMode === "view"
},
// 年度同病种限额提示仅在审核计算结果返回后展示。
showYearLimitTip() {
return this.yearLimit.yearLimitAmount !== undefined && this.yearLimit.yearLimitAmount !== null
},
// 审核详情只展示一条申请的动态补助结果,表格列由后台配置区间决定。
calcRows() {
const amounts = {}
let total = 0
this.subsidies.forEach((item) => {
amounts[item.sort] = item.subsidyAmount
total += Number(item.subsidyAmount || 0)
})
return [{
amounts: amounts,
total: total,
bonusRatio: this.apply.bonusRatio,
actualSubsidyAmount: this.apply.actualSubsidyAmount
}]
}
},
methods: {
// 从 URL 中读取审核申请 ID,保持审核列表跳转参数简单明确。
getQuery(name) {
const query = window.location.search ? window.location.search.substring(1) : ""
const parts = query.split("&")
for (let i = 0; i < parts.length; i++) {
const pair = parts[i].split("=")
if (decodeURIComponent(pair[0] || "") === name) {
return decodeURIComponent(pair[1] || "")
}
}
return ""
},
// 加载审核详情,后台会同步返回基金会员入会信息和本年度启用配置计算结果。
loadDetail() {
this.loading = true
this.$axios.post(this.apiBase + "/detail", { id: this.id }).then((resp) => {
if (resp.code === 0) {
this.apply = resp.data.apply || {}
this.subsidies = resp.data.subsidies || []
this.yearLimit = {
yearUsedAmount: resp.data.yearUsedAmount || 0,
yearRemainAmount: resp.data.yearRemainAmount || 0,
yearLimitAmount: resp.data.yearLimitAmount || 0
}
this.auditForm.bonusRatio = this.formatRatio(this.apply.bonusRatio)
this.auditForm.actualSubsidyAmount = this.formatMoney(this.apply.actualSubsidyAmount)
this.auditForm.remark = this.apply.remark || ""
}
}).finally(() => {
this.loading = false
})
},
// 审核通过时提交后台重算后的补助比例、实际补助金额和审核备注。
approve() {
const params = {
id: this.id,
bonusRatio: this.apply.bonusRatio,
actualSubsidyAmount: this.apply.actualSubsidyAmount,
remark: this.auditForm.remark
}
this.$axios.post(this.apiBase + "/approve", params).then((resp) => {
if (resp.code === 0) {
this.$message.success("审核通过")
this.goBack()
}
})
},
goBack() {
commonUtil.pjaxPush(this.auditPath)
},
formatDate(value) {
if (!value) {
return ""
}
return this.$moment(value).format("YYYY-MM-DD")
},
formatRatio(value) {
if (value === undefined || value === null || value === "") {
return ""
}
return Number(value).toFixed(2)
},
// 入会时间(年)只表达基金会员入会年限,不参与表格展示列控制。
calcJoinYears(joinYear) {
if (!joinYear) {
return ""
}
const currentYear = new Date().getFullYear()
return Math.max(currentYear - Number(joinYear), 0)
},
formatMoney(value) {
const num = Number(value || 0)
const fixed = Math.floor(num * 100) / 100
const parts = fixed.toFixed(2).split(".")
return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + "." + parts[1]
}
},
created() {
this.id = this.getQuery("id")
this.pageMode = this.getQuery("mode") || "audit"
this.loadDetail()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,258 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.mutual-apply-page { padding: 12px; background: #f5f7fa; min-height: calc(100vh - 24px); }
.mutual-apply-card { background: #fff; border: 1px solid #e4e7ed; border-radius: 4px; padding: 16px; }
.section-title { border-left: 4px solid #0079c2; padding-left: 10px; margin: 8px 0 14px; color: #0079c2; font-weight: 700; }
.required-star { color: #f56c6c; padding-right: 4px; font-weight: 700; }
.mutual-desc .el-descriptions-item__label { width: 150px; color: #303133; background: #fafafa; }
.mutual-desc .el-descriptions-item__content { min-width: 220px; }
.mutual-desc .el-form-item { margin-bottom: 0; }
.mutual-desc .el-form-item__error { padding-top: 2px; }
.mutual-desc .el-input-number { width: 100%; }
.actions { text-align: right; padding-top: 18px; }
</style>
<div id="app" v-cloak class="mutual-apply-page">
<div class="mutual-apply-card">
<div class="section-title">申请信息</div>
<el-form :model="formData" ref="form" :rules="formRules" label-width="0" v-loading="loading">
<el-descriptions class="mutual-desc" :column="3" border>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>工号</template>
<el-form-item prop="loginName">
<el-input v-model="formData.loginName" readonly placeholder="请输入工号"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>姓名</template>
<el-form-item prop="userName">
<el-input v-model="formData.userName" readonly placeholder="请输入姓名"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">性别</template>
<el-form-item prop="sex">
<el-select v-model="formData.sex" disabled placeholder="请选择性别" style="width: 100%">
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">出生年月</template>
<el-form-item prop="birthday">
<el-date-picker v-model="formData.birthday" disabled value-format="yyyy-MM-dd" type="date" placeholder="请选择出生年月" style="width: 100%"></el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">籍贯</template>
<el-form-item prop="nativePlace">
<el-input v-model="formData.nativePlace" readonly placeholder="请输入籍贯"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">工作部门(系部)</template>
<el-form-item prop="deptName">
<el-input v-model="formData.deptName" readonly placeholder="请输入工作部门(系部)"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">学历</template>
<el-form-item prop="education">
<el-input v-model="formData.education" readonly placeholder="请输入学历"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">职称</template>
<el-form-item prop="professionalTitle">
<el-input v-model="formData.professionalTitle" readonly placeholder="请输入职称"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>身份证号码</template>
<el-form-item prop="idCard">
<el-input v-model="formData.idCard" placeholder="请输入身份证号码"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>联系电话</template>
<el-form-item prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入联系电话"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>工资银行卡号</template>
<el-form-item prop="bankCardNo">
<el-input v-model="formData.bankCardNo" placeholder="请输入工资银行卡号"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>开户行</template>
<el-form-item prop="bankName">
<el-input v-model="formData.bankName" placeholder="请输入开户行"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item :span="3">
<template slot="label"><span class="required-star">*</span>大病名称</template>
<el-form-item prop="diseaseTypeId">
<el-select v-model="formData.diseaseTypeId" filterable placeholder="请选择大病名称" style="width: 100%" @change="handleDiseaseChange">
<el-option v-for="item in diseaseTypes" :key="item.id" :label="item.diseaseName" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item :span="3">
<template slot="label"><span class="required-star">*</span>何时何病住何医院</template>
<el-form-item prop="hospitalDesc">
<el-input type="textarea" :rows="7" show-word-limit v-model="formData.hospitalDesc" placeholder="请详细说明何时何病住何医院"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>全年医疗费用总金额(元)</template>
<el-form-item prop="medicalTotalAmount">
<el-input-number v-model="formData.medicalTotalAmount" :min="0" :precision="2" :step="100" controls-position="right"></el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>自付金额(元)</template>
<el-form-item prop="selfPayAmount">
<el-input-number v-model="formData.selfPayAmount" :min="0" :precision="2" :step="100" controls-position="right"></el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item :span="3">
<template slot="label"><span class="required-star">*</span>申请人签字</template>
<el-form-item prop="signFileId">
<pc-signature v-model="formData.signFileId"></pc-signature>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<div class="actions">
<el-button @click="goMine">返回</el-button>
<el-button @click="saveDraft">暂存</el-button>
<el-button type="primary" @click="submitApply">提交申请</el-button>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
loading: false,
diseaseTypes: [],
apiBase: "${base!}/platform/medicalMutualAid/apply/form",
minePath: "${base!}/platform/medicalMutualAid/apply/mine",
formRules: {
loginName: [{required: true, message: "必填", trigger: ["change", "blur"]}],
userName: [{required: true, message: "必填", trigger: ["change", "blur"]}],
idCard: [{required: true, message: "必填", trigger: ["change", "blur"]}],
mobile: [{required: true, message: "必填", trigger: ["change", "blur"]}],
bankCardNo: [{required: true, message: "必填", trigger: ["change", "blur"]}],
bankName: [{required: true, message: "必填", trigger: ["change", "blur"]}],
diseaseTypeId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
hospitalDesc: [{required: true, message: "必填", trigger: ["change", "blur"]}],
medicalTotalAmount: [{required: true, message: "必填", trigger: ["change", "blur"]}],
selfPayAmount: [{required: true, message: "必填", trigger: ["change", "blur"]}],
signFileId: [{required: true, message: "请签字", trigger: ["change", "blur"]}]
},
formData: {
status: 0,
medicalTotalAmount: 0,
selfPayAmount: 0
}
}
},
methods: {
// 初始化新增申请页面:疾病类型由后端提供,当前登录用户信息从 Vuex store 回填。
initPage() {
this.fillCurrentUser()
this.loading = true
this.$axios.post(this.apiBase + "/initApplyData").then((resp) => {
if (resp.code === 0) {
this.diseaseTypes = resp.data.diseaseTypes || []
}
}).finally(() => {
this.loading = false
})
},
// 使用平台全局 store 中的当前登录用户信息回填申请人基础字段。
fillCurrentUser() {
const user = this.$store.state.user || {}
const unit = user.unit || {}
const joinDate = user.memberJoinTime || user.joinDate || user.joinTime || ""
this.formData = Object.assign({}, this.formData, {
userId: user.id,
loginName: user.loginname,
userName: user.username,
sex: user.sex,
birthday: user.birthday,
nativePlace: user.nativePlace || user.nativeplace || "",
deptId: unit.id,
deptName: unit.name,
joinDate: joinDate,
joinYear: this.getYear(joinDate),
education: user.education || user.educationName || "",
professionalTitle: user.professionalTitle || user.title || user.positionTitle || "",
idCard: user.idCard || user.idcard || "",
mobile: user.mobile
})
},
// 从入会时间中提取年份,字段不展示但随 formData 一起提交给后台保存。
getYear(value) {
if (!value) {
return null
}
const text = String(value)
const year = Number(text.substring(0, 4))
return isNaN(year) ? null : year
},
// 选择疾病类型时同步疾病名称,避免后续档案改名影响历史申请展示。
handleDiseaseChange(value) {
const item = this.diseaseTypes.find((disease) => disease.id === value)
this.formData.diseaseName = item ? item.diseaseName : ""
},
// 暂存申请,不改变审核状态。
saveDraft() {
this.$refs.form.validate((valid) => {
if (valid) {
this.$axios.post(this.apiBase + "/saveDraft", this.formData).then((resp) => {
if (resp.code === 0) {
this.formData = resp.data
this.$message.success(resp.msg)
}
})
}
})
},
// 提交申请,状态仍为未审核,等待互助会审核。
submitApply() {
this.$refs.form.validate((valid) => {
if (valid) {
this.$axios.post(this.apiBase + "/submitApply", this.formData).then((resp) => {
if (resp.code === 0) {
this.formData = resp.data
this.$message.success(resp.msg)
window.location.href = this.minePath
}
})
}
})
},
// 返回我的申请列表,查看模式和编辑完成后共用该入口。
goMine() {
window.location.href = this.minePath
}
},
created() {
this.initPage()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,281 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.mine-form-page { background: #f5f7fa; height: calc(100vh - 88px); display: flex; flex-direction: column; overflow: hidden; box-sizing: border-box; }
.back-bar { background: #fff; padding: 14px 24px; margin-bottom: 12px; border-bottom: 1px solid #ebeef5; flex-shrink: 0; }
.back-bar .el-button { padding: 0; font-size: 15px; }
.mine-form-card { flex: 1; min-height: 0; height: auto !important; overflow: hidden; }
.mine-form-card .card-body { flex: 1; min-height: 0; overflow-y: auto; box-sizing: border-box; }
.mine-form-card .el-card__footer { flex-shrink: 0; }
.required-star { color: #f56c6c; padding-right: 4px; font-weight: 700; }
.mutual-desc .el-descriptions-item__label { width: 150px; color: #303133; background: #fafafa; }
.mutual-desc .el-descriptions-item__content { min-width: 220px; }
.mutual-desc .el-form-item { margin-bottom: 0; }
.mutual-desc .el-form-item__error { padding-top: 2px; }
.mutual-desc .el-input-number { width: 100%; }
.signature-readonly { pointer-events: none; }
.actions { text-align: right; padding-top: 18px; }
</style>
<div id="app" v-cloak class="mine-form-page">
<div class="back-bar">
<el-button type="text" icon="el-icon-back" @click="goMine">返回</el-button>
</div>
<custom-card class="mine-form-card">
<el-form :model="formData" ref="form" :rules="formRules" label-width="0" v-loading="loading">
<el-descriptions class="mutual-desc" :column="3" border>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>工号</template>
<el-form-item prop="loginName">
<el-input v-model="formData.loginName" readonly placeholder="请输入工号"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>姓名</template>
<el-form-item prop="userName">
<el-input v-model="formData.userName" readonly placeholder="请输入姓名"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">性别</template>
<el-form-item prop="sex">
<el-select v-model="formData.sex" disabled placeholder="请选择性别" style="width: 100%">
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">出生年月</template>
<el-form-item prop="birthday">
<el-date-picker v-model="formData.birthday" disabled value-format="yyyy-MM-dd" type="date" placeholder="请选择出生年月" style="width: 100%"></el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">籍贯</template>
<el-form-item prop="nativePlace">
<el-input v-model="formData.nativePlace" readonly placeholder="请输入籍贯"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">工作部门(系部)</template>
<el-form-item prop="deptName">
<el-input v-model="formData.deptName" readonly placeholder="请输入工作部门(系部)"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">学历</template>
<el-form-item prop="education">
<el-input v-model="formData.education" readonly placeholder="请输入学历"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label">职称</template>
<el-form-item prop="professionalTitle">
<el-input v-model="formData.professionalTitle" readonly placeholder="请输入职称"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>身份证号码</template>
<el-form-item prop="idCard">
<el-input v-model="formData.idCard" :readonly="readonlyMode" placeholder="请输入身份证号码"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>联系电话</template>
<el-form-item prop="mobile">
<el-input v-model="formData.mobile" :readonly="readonlyMode" placeholder="请输入联系电话"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>工资银行卡号</template>
<el-form-item prop="bankCardNo">
<el-input v-model="formData.bankCardNo" :readonly="readonlyMode" placeholder="请输入工资银行卡号"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>开户行</template>
<el-form-item prop="bankName">
<el-input v-model="formData.bankName" :readonly="readonlyMode" placeholder="请输入开户行"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item :span="3">
<template slot="label"><span class="required-star">*</span>大病名称</template>
<el-form-item prop="diseaseTypeId">
<el-select v-model="formData.diseaseTypeId" filterable :disabled="readonlyMode" placeholder="请选择大病名称" style="width: 100%" @change="handleDiseaseChange">
<el-option v-for="item in diseaseTypes" :key="item.id" :label="item.diseaseName" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item :span="3">
<template slot="label"><span class="required-star">*</span>何时何病住何医院</template>
<el-form-item prop="hospitalDesc">
<el-input type="textarea" :rows="7" show-word-limit v-model="formData.hospitalDesc" :readonly="readonlyMode" placeholder="请详细说明何时何病住何医院"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>全年医疗费用总金额(元)</template>
<el-form-item prop="medicalTotalAmount">
<el-input-number v-model="formData.medicalTotalAmount" :disabled="readonlyMode" :min="0" :precision="2" :step="100" controls-position="right"></el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item>
<template slot="label"><span class="required-star">*</span>自付金额(元)</template>
<el-form-item prop="selfPayAmount">
<el-input-number v-model="formData.selfPayAmount" :disabled="readonlyMode" :min="0" :precision="2" :step="100" controls-position="right"></el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item :span="3">
<template slot="label"><span class="required-star">*</span>申请人签字</template>
<el-form-item prop="signFileId">
<div :class="{'signature-readonly': readonlyMode}">
<pc-signature v-model="formData.signFileId"></pc-signature>
</div>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<template slot="footer" v-if="!readonlyMode">
<el-button @click="saveDraft">暂存</el-button>
<el-button type="primary" @click="submitApply">提交申请</el-button>
</template>
</custom-card>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
loading: false,
diseaseTypes: [],
applyId: "",
pageMode: "add",
apiBase: "${base!}/platform/medicalMutualAid/apply/mine/form",
minePath: "${base!}/platform/medicalMutualAid/apply/mine",
formRules: {
loginName: [{required: true, message: "必填", trigger: ["change", "blur"]}],
userName: [{required: true, message: "必填", trigger: ["change", "blur"]}],
idCard: [{required: true, message: "必填", trigger: ["change", "blur"]}],
mobile: [{required: true, message: "必填", trigger: ["change", "blur"]}],
bankCardNo: [{required: true, message: "必填", trigger: ["change", "blur"]}],
bankName: [{required: true, message: "必填", trigger: ["change", "blur"]}],
diseaseTypeId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
hospitalDesc: [{required: true, message: "必填", trigger: ["change", "blur"]}],
medicalTotalAmount: [{required: true, message: "必填", trigger: ["change", "blur"]}],
selfPayAmount: [{required: true, message: "必填", trigger: ["change", "blur"]}],
signFileId: [{required: true, message: "请签字", trigger: ["change", "blur"]}]
},
formData: {
status: 0,
medicalTotalAmount: 0,
selfPayAmount: 0
}
}
},
computed: {
// 查看模式下页面只负责展示历史申请,所有表单控件统一禁止操作。
readonlyMode() {
return this.pageMode === "view"
}
},
methods: {
// 初始化我的申请维护页面:必须携带申请ID,按模式控制查看或编辑。
initPage() {
this.applyId = this.getQueryValue("id")
this.pageMode = this.getQueryValue("mode") || "add"
if (!this.applyId) {
this.$message.error("申请ID不能为空")
this.goMine()
return
}
this.loading = true
this.$axios.post(this.apiBase + "/initApplyData").then((resp) => {
if (resp.code === 0) {
this.diseaseTypes = resp.data.diseaseTypes || []
if (this.applyId) {
return this.loadApplyDetail()
}
}
}).finally(() => {
if (!this.applyId) {
this.loading = false
}
})
},
// 读取 URL 查询参数,避免引入额外公共依赖。
getQueryValue(name) {
const query = window.location.search ? window.location.search.substring(1) : ""
const parts = query.split("&")
for (let i = 0; i < parts.length; i++) {
const item = parts[i].split("=")
if (decodeURIComponent(item[0] || "") === name) {
return decodeURIComponent(item[1] || "")
}
}
return ""
},
// 根据申请ID加载历史申请,供我的申请查看和编辑复用当前页面。
loadApplyDetail() {
return this.$axios.post(this.apiBase + "/detail", {id: this.applyId}).then((resp) => {
if (resp.code === 0) {
this.formData = resp.data || {}
}
}).finally(() => {
this.loading = false
})
},
// 选择疾病类型时同步疾病名称,避免后续档案改名影响历史申请展示。
handleDiseaseChange(value) {
const item = this.diseaseTypes.find((disease) => disease.id === value)
this.formData.diseaseName = item ? item.diseaseName : ""
},
// 暂存申请,不改变审核状态。
saveDraft() {
if (this.readonlyMode) {
return
}
this.$refs.form.validate((valid) => {
if (valid) {
this.$axios.post(this.apiBase + "/saveDraft", this.formData).then((resp) => {
if (resp.code === 0) {
this.formData = resp.data
this.$message.success(resp.msg)
}
})
}
})
},
// 提交申请,状态仍为未审核,等待互助会审核。
submitApply() {
if (this.readonlyMode) {
return
}
this.$refs.form.validate((valid) => {
if (valid) {
this.$axios.post(this.apiBase + "/submitApply", this.formData).then((resp) => {
if (resp.code === 0) {
this.formData = resp.data
this.$message.success(resp.msg)
commonUtil.pjaxPush(this.minePath)
}
})
}
})
},
// 返回我的申请列表,查看模式和编辑完成后共用该入口。
goMine() {
commonUtil.pjaxPush(this.minePath)
}
},
created() {
this.initPage()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,213 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
#sub-app-container-main-content { overflow: hidden; }
#sub-app-container-main-content-body { height: 100%; overflow: hidden; }
.mine-list-page { padding: 16px 20px; background: #f3f6fa; height: 100%; box-sizing: border-box; display: flex; flex-direction: column; overflow: hidden; }
.mine-search-panel { background: #fff; padding: 16px 42px; margin-bottom: 12px; box-sizing: border-box; flex-shrink: 0; }
.mine-search-panel .el-form-item { margin-bottom: 0; margin-right: 28px; }
.mine-content-panel { background: #fff; padding: 16px 20px; box-sizing: border-box; flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.mine-panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; flex-shrink: 0; }
.mine-section-title { border-left: 4px solid #0079c2; padding-left: 10px; color: #0079c2; font-size: 16px; font-weight: 700; line-height: 22px; }
.mine-table.el-table th { background: #fafafa; color: #303133; font-weight: 700; }
.mine-table.el-table td, .mine-table.el-table th { padding: 11px 0; }
.mine-actions { display: flex; align-items: center; justify-content: center; gap: 8px; }
.mine-actions .el-button { min-width: 54px; padding: 7px 14px; border-radius: 2px; margin-left: 0; }
.mine-pager { display: flex; justify-content: flex-start; align-items: center; padding-top: 12px; flex-shrink: 0; }
.mine-pager .total-text { margin-right: 18px; color: #303133; }
</style>
<div id="app" v-cloak class="mine-list-page">
<div class="mine-search-panel">
<el-form :inline="true" :model="searchForm">
<el-form-item label="大病名称">
<el-select v-model="searchForm.diseaseName" clearable filterable placeholder="请选择大病名称" style="width: 260px">
<el-option v-for="item in diseaseTypes" :key="item.id" :label="item.diseaseName" :value="item.diseaseName"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="search">搜索</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="mine-content-panel" ref="contentPanel">
<div class="mine-panel-header" ref="panelHeader">
<div class="mine-section-title">我的申请</div>
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
互助金申请
</el-button>
</div>
<el-table ref="mineTable" class="mine-table" :data="tableData" border v-loading="loading" :height="tableHeight" style="width: 100%">
<el-table-column type="index" label="序号" width="70" align="center"></el-table-column>
<el-table-column prop="loginName" label="工号" width="130" align="center"></el-table-column>
<el-table-column prop="userName" label="姓名" width="120" align="center"></el-table-column>
<el-table-column prop="diseaseName" label="大病名称" min-width="300" align="center" show-overflow-tooltip></el-table-column>
<el-table-column label="全年医疗费用总金额(元)" width="190" align="center">
<template slot-scope="{row}">{{ formatMoney(row.medicalTotalAmount) }}</template>
</el-table-column>
<el-table-column label="自费金额(元)" width="160" align="center">
<template slot-scope="{row}">{{ formatMoney(row.selfPayAmount) }}</template>
</el-table-column>
<el-table-column label="状态" width="100" align="center">
<template slot-scope="{row}">
<el-tag v-if="isAudited(row)" type="success" size="mini">已审核</el-tag>
<el-tag v-else-if="isDiscarded(row)" type="danger" size="mini">已作废</el-tag>
<el-tag v-else type="warning" size="mini">未审核</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="280" align="center" fixed="right">
<template slot-scope="{row}">
<div class="mine-actions">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onExportApplyForm(row)" size="mini" type="primary">导出申请单</el-button>
<el-button v-if="isPending(row)" @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button v-if="isPending(row)" @click="onDeleteTip" size="mini" type="danger">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="mine-pager" ref="pager">
<span class="total-text">共 {{ totalCount }} 条</span>
<el-pagination background layout="sizes, prev, pager, next" :current-page.sync="pageForm.pageNumber" :page-size.sync="pageForm.pageSize" :page-sizes="[5, 10, 20, 30, 50]" :total="totalCount" @current-change="loadPage" @size-change="loadPage"></el-pagination>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
loading: false,
tableData: [],
diseaseTypes: [],
totalCount: 0,
tableHeight: 360,
layoutTimer: null,
apiBase: "${base!}/platform/medicalMutualAid/apply/mine",
diseaseTypeApi: "${base!}/platform/medicalMutualAid/medical/diseaseType",
searchForm: { diseaseName: "" },
pageForm: { pageNumber: 1, pageSize: 10 }
}
},
methods: {
// 加载互助疾病类型下拉,和互助金申请页面保持同一疾病基础数据来源。
loadDiseaseTypes() {
this.$axios.post(this.diseaseTypeApi + "/pageData", { pageNumber: 1, pageSize: 999 }).then((resp) => {
if (resp.code === 0) {
this.diseaseTypes = resp.data.list || []
}
})
},
// 查询我的申请列表,使用独立分页结构保证列表高度不受通用组件影响。
loadPage() {
this.loading = true
const params = Object.assign({}, this.pageForm, this.searchForm)
this.$axios.post(this.apiBase + "/page", params).then((resp) => {
if (resp.code === 0) {
this.tableData = resp.data.list || []
this.totalCount = resp.data.totalCount || 0
}
}).finally(() => {
this.loading = false
this.scheduleTableLayout()
})
},
search() {
this.pageForm.pageNumber = 1
this.loadPage()
},
resetSearch() {
this.searchForm = { diseaseName: "" }
this.pageForm.pageNumber = 1
this.loadPage()
},
// 新增申请按平台通用页面跳转方式进入申请页。
onAdd() {
commonUtil.pjaxPush("${base!}/platform/medicalMutualAid/apply/form")
},
// 查看申请进入我的申请独立维护页,查看模式由 mode 参数控制。
onView(row) {
commonUtil.pjaxPush("${base!}/platform/medicalMutualAid/apply/mine/form?id=" + row.id + "&mode=view")
},
// 编辑申请进入我的申请独立维护页,编辑模式由 mode 参数控制。
onEdit(row) {
commonUtil.pjaxPush("${base!}/platform/medicalMutualAid/apply/mine/form?id=" + row.id + "&mode=edit")
},
// 按当前行申请ID导出申请单,后端通过系统模板管理中的 Word 模板完成参数渲染。
onExportApplyForm(row) {
window.open(this.apiBase + "/exportApplyForm?id=" + row.id)
},
onDeleteTip() {
this.$message.info("删除逻辑后续接入")
},
// 未审核申请允许个人继续编辑和删除。
isPending(row) {
return Number(row.status) === 0
},
// 已审核申请只允许查看,不能再编辑或删除。
isAudited(row) {
return Number(row.status) === 1
},
// 已作废申请只允许查看,不能再编辑或删除。
isDiscarded(row) {
return Number(row.status) === 2
},
formatMoney(value) {
if (value === null || value === undefined || value === "") {
return ""
}
return Number(value).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
},
// 根据内容面板剩余空间计算表格高度,保证列表铺满且页面不出现纵向滚动条。
updateTableHeight() {
const panel = this.$refs.contentPanel
if (!panel) {
return
}
const headerHeight = this.$refs.panelHeader ? this.$refs.panelHeader.offsetHeight : 0
const pagerHeight = this.$refs.pager ? this.$refs.pager.offsetHeight : 0
this.tableHeight = Math.max(panel.clientHeight - headerHeight - pagerHeight - 32, 260)
this.$nextTick(() => {
if (this.$refs.mineTable) {
this.$refs.mineTable.doLayout()
}
})
},
// 数据加载和窗口变化后延迟重算,避开菜单/顶部栏刷新时机导致的首屏高度误差。
scheduleTableLayout() {
if (this.layoutTimer) {
clearTimeout(this.layoutTimer)
}
this.$nextTick(() => {
this.updateTableHeight()
const vm = this
this.layoutTimer = setTimeout(function () {
vm.updateTableHeight()
}, 80)
})
}
},
created() {
this.loadDiseaseTypes()
this.loadPage()
},
mounted() {
this.scheduleTableLayout()
window.addEventListener("resize", this.scheduleTableLayout)
},
beforeDestroy() {
if (this.layoutTimer) {
clearTimeout(this.layoutTimer)
}
window.removeEventListener("resize", this.scheduleTableLayout)
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,200 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.mutual-list-page { padding: 16px 20px; background: #f3f6fa; height: calc(100vh - 88px); box-sizing: border-box; display: flex; flex-direction: column; overflow: hidden; }
.search-panel { background: #fff; padding: 16px 42px; margin-bottom: 12px; box-sizing: border-box; flex-shrink: 0; }
.search-panel .el-form-item { margin-bottom: 0; margin-right: 14px; }
.content-panel { background: #fff; padding: 16px 20px 16px; box-sizing: border-box; flex: 1; min-height: 0; display: flex; flex-direction: column; }
.panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.section-title { border-left: 4px solid #0079c2; padding-left: 10px; color: #0079c2; font-size: 16px; font-weight: 700; line-height: 22px; }
.mutual-table.el-table th { background: #fafafa; color: #303133; font-weight: 700; }
.mutual-table.el-table td, .mutual-table.el-table th { padding: 11px 0; }
.pager { display: flex; justify-content: flex-start; align-items: center; padding-top: 12px; flex-shrink: 0; }
.pager .total-text { margin-right: 18px; color: #303133; }
</style>
<div id="app" v-cloak class="mutual-list-page">
<div class="search-panel">
<el-form :inline="true" :model="searchForm">
<el-form-item label="所在单位">
<el-input v-model="searchForm.deptName" placeholder="请输入所在单位" style="width: 240px"></el-input>
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="searchForm.userName" placeholder="请输入姓名" style="width: 220px"></el-input>
</el-form-item>
<el-form-item label="加入年份">
<el-date-picker v-model="searchForm.joinYear" type="year" value-format="yyyy" placeholder="请选择加入年份" style="width: 220px"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadPage">查询</el-button>
<el-button @click="resetSearch">重置</el-button>
<el-button icon="el-icon-upload2" @click="exportTip">导出</el-button>
</el-form-item>
</el-form>
</div>
<div class="content-panel" ref="contentPanel">
<div class="panel-header" ref="panelHeader">
<div class="section-title">医疗互助汇总</div>
</div>
<el-table ref="summaryTable" class="mutual-table" :data="tableData" border v-loading="loading" :height="tableHeight" style="width: 100%">
<el-table-column type="index" label="序号" width="70" align="center"></el-table-column>
<el-table-column prop="deptName" label="所在单位" min-width="140" align="center"></el-table-column>
<el-table-column prop="userName" label="姓名" width="110" align="center"></el-table-column>
<el-table-column prop="joinYear" label="加入时间(年)" width="120" align="center"></el-table-column>
<el-table-column prop="diseaseText" label="大病名称及病情" min-width="190" align="center"></el-table-column>
<el-table-column label="符合规定发票金额(元)" width="160" align="center">
<template slot-scope="{row}">{{ formatMoney(row.medicalTotalAmount) }}</template>
</el-table-column>
<el-table-column label="补助计算方法" align="center">
<el-table-column v-for="item in subsidyRanges" :key="item" :label="item" min-width="130" align="center">
<template slot-scope="{row}">{{ formatMoney(row.subsidyMap[item]) }}</template>
</el-table-column>
<el-table-column label="补助小计" width="120" align="center">
<template slot-scope="{row}">{{ formatMoney(row.subsidyTotalAmount) }}</template>
</el-table-column>
</el-table-column>
<el-table-column label="补助比例" width="100" align="center">
<template slot-scope="{row}">{{ row.bonusRatio || "" }}</template>
</el-table-column>
<el-table-column label="实际补助金额(元)" width="150" align="center">
<template slot-scope="{row}">{{ formatMoney(row.actualSubsidyAmount) }}</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="120" align="center"></el-table-column>
</el-table>
<div class="pager" ref="pager">
<span class="total-text">共 {{ totalCount }} 条</span>
<el-pagination background layout="sizes, prev, pager, next" :current-page.sync="pageForm.pageNumber" :page-size.sync="pageForm.pageSize" :total="totalCount" @current-change="loadPage" @size-change="loadPage"></el-pagination>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
loading: false,
tableData: [],
subsidyRanges: [],
totalCount: 0,
tableHeight: 360,
apiBase: "${base!}/platform/medicalMutualAid/apply/summary",
searchForm: { deptName: "", userName: "", joinYear: "" },
pageForm: { pageNumber: 1, pageSize: 10 }
}
},
methods: {
// 查询审核通过的互助金申请,并把补助明细转换成动态列数据。
loadPage() {
this.loading = true
const params = Object.assign({}, this.pageForm, this.searchForm)
this.$axios.post(this.apiBase + "/page", params).then((resp) => {
if (resp.code === 0) {
const rows = resp.data.list || []
this.tableData = rows.map((item) => this.buildRow(item))
this.totalCount = resp.data.totalCount || 0
this.refreshRanges()
}
}).finally(() => {
this.loading = false
this.scheduleTableLayout()
})
},
// 将后端主表与补助明细组合为列表展示行。
buildRow(item) {
const apply = item.apply || {}
const subsidies = item.subsidies || []
const subsidyMap = {}
subsidies.forEach((subsidy) => {
subsidyMap[subsidy.rangeName] = subsidy.subsidyAmount
})
return {
deptName: apply.deptName,
userName: apply.userName,
joinYear: apply.joinYear,
diseaseText: apply.diseaseName,
medicalTotalAmount: apply.medicalTotalAmount,
subsidyTotalAmount: apply.subsidyTotalAmount,
bonusRatio: apply.bonusRatio,
actualSubsidyAmount: apply.actualSubsidyAmount,
remark: apply.remark,
subsidies: subsidies,
subsidyMap: subsidyMap
}
},
// 根据当前页明细刷新动态补助区间表头。
refreshRanges() {
const names = []
this.tableData.forEach((row) => {
row.subsidies.forEach((item) => {
if (names.indexOf(item.rangeName) === -1) {
names.push(item.rangeName)
}
})
})
this.subsidyRanges = names
this.scheduleTableLayout()
},
resetSearch() {
this.searchForm = { deptName: "", userName: "", joinYear: "" }
this.pageForm.pageNumber = 1
this.loadPage()
},
exportTip() {
const params = []
if (this.searchForm.deptName) {
params.push("deptName=" + encodeURIComponent(this.searchForm.deptName))
}
if (this.searchForm.userName) {
params.push("userName=" + encodeURIComponent(this.searchForm.userName))
}
if (this.searchForm.joinYear) {
params.push("joinYear=" + encodeURIComponent(this.searchForm.joinYear))
}
window.open(this.apiBase + "/exportExcel" + (params.length ? "?" + params.join("&") : ""))
},
formatMoney(value) {
if (value === undefined || value === null || value === "") {
return ""
}
const num = Number(value || 0)
return num.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
},
// 根据内容面板剩余空间计算表格高度,汇总动态列只影响横向滚动,不影响页面纵向高度。
updateTableHeight() {
const panel = this.$refs.contentPanel
if (!panel) {
return
}
const headerHeight = this.$refs.panelHeader ? this.$refs.panelHeader.offsetHeight : 0
const pagerHeight = this.$refs.pager ? this.$refs.pager.offsetHeight : 0
this.tableHeight = Math.max(panel.clientHeight - headerHeight - pagerHeight - 32, 220)
this.$nextTick(() => {
if (this.$refs.summaryTable) {
this.$refs.summaryTable.doLayout()
}
})
},
// F5 刷新时动态二级表头渲染和外层布局完成顺序不稳定,延迟触发表格重排保证列宽不乱。
scheduleTableLayout() {
this.$nextTick(() => {
this.updateTableHeight()
const vm = this
setTimeout(function () {
vm.updateTableHeight()
}, 80)
})
}
},
created() {
this.loadPage()
},
mounted() {
this.scheduleTableLayout()
window.addEventListener("resize", this.scheduleTableLayout)
},
beforeDestroy() {
window.removeEventListener("resize", this.scheduleTableLayout)
}
})
</script>
<!--#}#-->
@@ -0,0 +1,689 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.mutual-config-page {
padding: 16px 20px;
background: #f5f7fa;
height: calc(100vh - 88px);
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow: hidden;
}
.mutual-config-page .search-panel,
.mutual-config-page .list-panel {
background: #fff;
border-radius: 2px;
padding: 16px 20px;
box-sizing: border-box;
}
.mutual-config-page .search-panel {
margin-bottom: 12px;
flex-shrink: 0;
}
.mutual-config-page .list-panel {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.mutual-config-page .list-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
flex-shrink: 0;
}
.mutual-config-page .list-title-text {
border-left: 4px solid #0079c2;
padding-left: 10px;
color: #0079c2;
font-size: 16px;
font-weight: 700;
}
.mutual-config-page .pager-bar {
display: flex;
align-items: center;
padding-top: 12px;
flex-shrink: 0;
}
.el-dialog.mutual-edit-dialog {
margin-top: 3vh !important;
}
.mutual-edit-dialog .el-dialog__body {
height: 700px;
overflow: hidden;
padding: 16px 20px;
}
.mutual-config-page .config-dialog-body {
height: 100%;
overflow: hidden;
box-sizing: border-box;
}
.mutual-config-page .config-dialog-body .el-tabs {
display: flex;
flex-direction: column;
height: 100%;
}
.mutual-config-page .config-dialog-body .el-tabs__header {
flex: none;
margin-bottom: 0;
}
.mutual-config-page .config-dialog-body .el-tabs__content {
flex: 1;
overflow: hidden;
padding-top: 16px;
}
.mutual-config-page .config-dialog-body .el-tab-pane {
height: 100%;
overflow-y: auto;
overflow-x: hidden;
padding-right: 10px;
box-sizing: border-box;
}
.mutual-config-page .dialog-section {
border-top: 1px dashed #dcdfe6;
padding-top: 18px;
margin-top: 18px;
max-width: 100%;
overflow-x: hidden;
box-sizing: border-box;
}
.mutual-config-page .dialog-section:first-child {
border-top: 0;
padding-top: 0;
margin-top: 0;
}
.mutual-config-page .dialog-section-title {
border-left: 4px solid #0079c2;
padding-left: 10px;
margin-bottom: 16px;
color: #0079c2;
font-size: 15px;
font-weight: 700;
}
.mutual-config-page .section-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.mutual-config-page .config-dialog-body .el-form-item__label {
white-space: normal;
line-height: 20px;
padding-top: 0;
}
.mutual-config-page .config-dialog-body .aid-limit-label.is-required .el-form-item__label:before {
content: "";
margin-right: 0;
}
.mutual-config-page .config-dialog-body .aid-limit-label-text {
display: inline-block;
line-height: 20px;
text-align: right;
vertical-align: middle;
}
.mutual-config-page .config-dialog-body .aid-limit-label-star {
color: #F56C6C;
margin-right: 4px;
}
.mutual-config-page .config-dialog-body .el-table {
max-width: 100%;
}
.mutual-config-page .config-dialog-body .el-table__body-wrapper {
overflow-x: hidden;
}
.mutual-config-page .dialog-footer {
text-align: right;
}
</style>
<div id="app" v-cloak class="mutual-config-page">
<div class="search-panel">
<el-form :inline="true" :model="searchForm" label-width="70px">
<el-form-item label="年度">
<el-select v-model="searchForm.year" clearable placeholder="请选择年度" style="width: 220px">
<el-option v-for="year in yearOptions" :key="year" :label="year" :value="year"></el-option>
</el-select>
</el-form-item>
<el-form-item label="配置名称">
<el-input v-model="searchForm.configName" clearable placeholder="请输入配置名称" style="width: 260px"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="loadConfigList">搜索</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="list-panel" ref="listPanel" v-loading="loading">
<div class="list-title" ref="listTitle">
<span class="list-title-text">医疗互助配置</span>
<el-button type="primary" icon="el-icon-plus" @click="openConfigDialog()">新增</el-button>
</div>
<el-table :data="pageList" border :height="tableHeight" style="width: 100%">
<el-table-column type="index" width="70" label="序号" align="center"></el-table-column>
<el-table-column prop="year" label="年度" width="110" align="center"></el-table-column>
<el-table-column prop="configName" label="配置名称" min-width="260" align="center"></el-table-column>
<el-table-column label="起补金额(元)" width="150" align="center">
<template slot-scope="{row}">{{ formatMoney(row.startAmount) }}</template>
</el-table-column>
<el-table-column label="第一年最高补助(元)" width="170" align="center">
<template slot-scope="{row}">{{ formatMoney(row.firstYearMaxAmount) }}</template>
</el-table-column>
<el-table-column label="其他年度最高补助(元)" width="190" align="center">
<template slot-scope="{row}">{{ formatMoney(row.otherYearMaxAmount) }}</template>
</el-table-column>
<el-table-column label="是否启用" width="110" align="center">
<template slot-scope="{row}">
<el-tag v-if="row.status === 1" type="success" size="mini">启用</el-tag>
<el-tag v-else type="info" size="mini">停用</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="170" align="center">
<template slot-scope="{row}">
<el-button type="primary" size="mini" @click="openConfigDialog(row)">编辑</el-button>
<el-button type="danger" size="mini" @click="deleteConfig(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pager-bar" ref="pagerBar">
<span style="margin-right: 14px">共 {{ configList.length }} 条</span>
<el-pagination
background
layout="sizes, prev, pager, next"
:current-page.sync="pageNumber"
:page-size.sync="pageSize"
:page-sizes="[10, 20, 50]"
:total="configList.length">
</el-pagination>
</div>
</div>
<el-dialog :title="configDialogTitle" :visible.sync="configDialogVisible" width="1320px" custom-class="mutual-edit-dialog" :close-on-click-modal="false">
<div class="config-dialog-body" v-loading="dialogLoading">
<el-tabs v-model="activeTab" type="card">
<el-tab-pane label="互助金补助配置" name="subsidy">
<div class="dialog-section">
<div class="dialog-section-title">基本信息</div>
<el-form :model="configForm" :rules="configRules" ref="configFormRef" label-width="160px">
<el-row :gutter="28">
<el-col :span="12">
<el-form-item label="年度" prop="year">
<el-select v-model="configForm.year" style="width: 100%" placeholder="请选择年度">
<el-option v-for="year in yearOptions" :key="year" :label="year" :value="year"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="配置名称" prop="configName">
<el-input v-model="configForm.configName" maxlength="100" placeholder="请输入配置名称"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="28">
<el-col :span="12">
<el-form-item label="起补金额(元)" prop="startAmount">
<el-input-number v-model="configForm.startAmount" :min="0" :precision="2" :step="1000" controls-position="right" style="width: 100%"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否启用" prop="status">
<el-radio-group v-model="configForm.status">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="28">
<el-col :span="12">
<el-form-item class="aid-limit-label" prop="firstYearMaxAmount">
<template slot="label">
<span class="aid-limit-label-text"><span class="aid-limit-label-star">*</span>第一年最高补助<br>(元)</span>
</template>
<el-input-number v-model="configForm.firstYearMaxAmount" :min="0" :precision="2" :step="1000" controls-position="right" style="width: 100%"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item class="aid-limit-label" prop="otherYearMaxAmount">
<template slot="label">
<span class="aid-limit-label-text"><span class="aid-limit-label-star">*</span>其他年度最高补助<br>(元)</span>
</template>
<el-input-number v-model="configForm.otherYearMaxAmount" :min="0" :precision="2" :step="1000" controls-position="right" style="width: 100%"></el-input-number>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<div class="dialog-section">
<div class="section-toolbar">
<div class="dialog-section-title" style="margin-bottom: 0">补助比例配置(超额累计计算)</div>
<el-button type="primary" size="small" icon="el-icon-plus" @click="addRatioRow">新增比例</el-button>
</div>
<el-table :data="ratioList" border style="width: 100%">
<el-table-column type="index" width="70" label="序号" align="center"></el-table-column>
<el-table-column label="开始金额(元)" align="center">
<template slot-scope="{row}">
<el-input-number v-model="row.startAmount" :min="0" :precision="2" :step="1000" controls-position="right" style="width: 100%"></el-input-number>
</template>
</el-table-column>
<el-table-column label="结束金额(元)" align="center">
<template slot-scope="{row}">
<el-input-number v-model="row.endAmount" :min="0" :precision="2" :step="1000" controls-position="right" style="width: 100%"></el-input-number>
</template>
</el-table-column>
<el-table-column label="补助比例(%)" align="center">
<template slot-scope="{row}">
<el-input-number v-model="row.ratio" :min="0" :max="100" :precision="2" :step="1" controls-position="right" style="width: 100%"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="remark" label="说明" min-width="220" align="center">
<template slot-scope="{row}">
<el-input v-model="row.remark" maxlength="200" placeholder="请输入说明"></el-input>
</template>
</el-table-column>
<el-table-column label="排序" width="120" align="center">
<template slot-scope="{row}">
<el-input-number v-model="row.sort" :min="1" :step="1" controls-position="right" style="width: 100%"></el-input-number>
</template>
</el-table-column>
<el-table-column label="操作" width="90" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="removeRatio(scope.row, scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="dialog-section">
<div class="section-toolbar">
<div class="dialog-section-title" style="margin-bottom: 0">连续未申请奖励配置</div>
<el-button type="primary" size="small" icon="el-icon-plus" @click="addBonusRow">新增奖励</el-button>
</div>
<el-table :data="bonusList" border style="width: 100%">
<el-table-column type="index" width="70" label="序号" align="center"></el-table-column>
<el-table-column prop="continuousYear" label="连续未申请年数(年)" align="center">
<template slot-scope="{row}">
<el-input-number v-model="row.continuousYear" :min="1" :step="1" controls-position="right" style="width: 100%"></el-input-number>
</template>
</el-table-column>
<el-table-column label="增加比例(%)" align="center">
<template slot-scope="{row}">
<el-input-number v-model="row.increaseRatio" :min="0" :max="100" :precision="2" :step="1" controls-position="right" style="width: 100%"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="remark" label="说明" min-width="260" align="center">
<template slot-scope="{row}">
<el-input v-model="row.remark" maxlength="200" placeholder="请输入说明"></el-input>
</template>
</el-table-column>
<el-table-column label="操作" width="90" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" @click="removeBonus(scope.row, scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane label="会员缴费配置" name="member">
<div class="dialog-section">
<div class="dialog-section-title">会员缴费配置</div>
<el-form :model="memberForm" :rules="memberRules" ref="memberFormRef" label-width="190px" style="max-width: 760px">
<el-form-item label="每月缴纳互助金额(元)" prop="monthAmount">
<el-input-number v-model="memberForm.monthAmount" :min="0" :precision="2" :step="1" controls-position="right" style="width: 320px"></el-input-number>
</el-form-item>
<el-form-item label="缴费减半年限" prop="halfPriceYear">
<el-input-number v-model="memberForm.halfPriceYear" :min="1" :step="1" controls-position="right" style="width: 320px"></el-input-number>
<span style="margin-left: 10px; color: #909399">连续缴费满该年限后,次年缴费减半</span>
</el-form-item>
</el-form>
</div>
</el-tab-pane>
</el-tabs>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="configDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="dialogSaving" @click="confirmConfigDialog">确认</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
loading: false,
dialogLoading: false,
dialogSaving: false,
yearOptions: [],
searchForm: {
year: null,
configName: ""
},
configList: [],
pageNumber: 1,
pageSize: 10,
tableHeight: 360,
configDialogVisible: false,
configDialogTitle: "新增医疗互助配置",
activeTab: "subsidy",
configForm: {},
memberForm: {},
ratioList: [],
bonusList: [],
deletedRatioIds: [],
deletedBonusIds: [],
configRules: {
year: [{ required: true, message: "请选择年度", trigger: "change" }],
configName: [{ required: true, message: "请输入配置名称", trigger: "blur" }],
startAmount: [{ required: true, message: "请输入起补金额", trigger: "change" }],
firstYearMaxAmount: [{ required: true, message: "请输入第一年最高补助", trigger: "change" }],
otherYearMaxAmount: [{ required: true, message: "请输入其他年度最高补助", trigger: "change" }],
status: [{ required: true, message: "请选择状态", trigger: "change" }]
},
memberRules: {
monthAmount: [{ required: true, message: "请输入每月缴纳互助金额", trigger: "change" }],
halfPriceYear: [{ required: true, message: "请输入缴费减半年限", trigger: "change" }]
}
}
},
computed: {
pageList() {
const start = (this.pageNumber - 1) * this.pageSize
return this.configList.slice(start, start + this.pageSize)
}
},
methods: {
// 初始化年度选项,列表查询和弹窗年度录入共用同一组选项。
initYearOptions() {
const currentYear = new Date().getFullYear()
const years = []
for (let year = currentYear - 5; year <= currentYear + 2; year++) {
years.push(year)
}
this.yearOptions = years.reverse()
},
// 查询年度配置列表,每年一条配置,供页面主列表展示和检索。
loadConfigList() {
this.loading = true
this.$axios.post(loc() + "/listConfigs", this.searchForm).then((resp) => {
if (resp.code === 0) {
this.configList = resp.data || []
this.pageNumber = 1
}
}).finally(() => {
this.loading = false
this.$nextTick(this.updateTableHeight)
})
},
// 重置列表查询条件,并重新加载全部年度配置。
resetSearch() {
this.searchForm = {
year: null,
configName: ""
}
this.loadConfigList()
},
// 打开新增或编辑弹窗,编辑时加载该年度完整配置,新增时使用当前年度默认值。
openConfigDialog(row) {
this.configDialogTitle = row ? "编辑医疗互助配置" : "新增医疗互助配置"
this.activeTab = "subsidy"
this.deletedRatioIds = []
this.deletedBonusIds = []
this.configDialogVisible = true
if (!row) {
this.resetDialogForm()
return
}
this.dialogLoading = true
const year = row ? row.year : new Date().getFullYear()
this.$axios.post(loc() + "/configData", { year: year }).then((resp) => {
if (resp.code === 0) {
this.configForm = resp.data.config || this.defaultConfig(year)
this.memberForm = resp.data.memberConfig || this.defaultMemberConfig()
this.ratioList = resp.data.ratios || []
this.bonusList = resp.data.bonuses || []
}
}).finally(() => {
this.dialogLoading = false
this.$nextTick(() => {
this.$refs.configFormRef && this.$refs.configFormRef.clearValidate()
this.$refs.memberFormRef && this.$refs.memberFormRef.clearValidate()
})
})
},
// 新增弹窗初始化,仅保留年度、配置名称、启用状态和会员缴费配置默认值。
resetDialogForm() {
const year = new Date().getFullYear()
this.dialogLoading = false
this.configForm = this.defaultConfig(year)
this.memberForm = this.defaultMemberConfig()
this.ratioList = []
this.bonusList = []
this.$nextTick(() => {
this.$refs.configFormRef && this.$refs.configFormRef.clearValidate()
this.$refs.memberFormRef && this.$refs.memberFormRef.clearValidate()
})
},
// 删除年度主配置会同步删除后端已关联的比例和奖励配置。
deleteConfig(id) {
this.$confirm("确定删除此年度医疗互助配置吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post(loc() + "/deleteConfig", { id: id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.loadConfigList()
}
})
}).catch(() => {})
},
// 弹窗确认时统一保存两个页签数据,避免每个页签出现独立保存按钮。
confirmConfigDialog() {
this.$refs.configFormRef.validate((configValid) => {
if (!configValid) {
this.activeTab = "subsidy"
return
}
this.$refs.memberFormRef.validate((memberValid) => {
if (!memberValid) {
this.activeTab = "member"
return
}
if (!this.validateDetailRows()) {
this.activeTab = "subsidy"
return
}
this.saveDialogData()
})
})
},
// 先保存基础配置拿到主键,再保存会员缴费、比例和奖励明细。
saveDialogData() {
this.dialogSaving = true
this.$axios.post(loc() + "/saveConfig", this.configForm).then((resp) => {
if (resp.code !== 0) {
return Promise.reject(resp)
}
const savedConfig = resp.data
const tasks = [this.$axios.post(loc() + "/saveMemberConfig", this.memberForm)]
this.deletedRatioIds.forEach((id) => {
tasks.push(this.$axios.post(loc() + "/deleteRatio", { id: id }))
})
this.deletedBonusIds.forEach((id) => {
tasks.push(this.$axios.post(loc() + "/deleteBonus", { id: id }))
})
this.ratioList.forEach((row) => {
const payload = this.cleanPayload(row)
payload.configId = savedConfig.id
tasks.push(this.$axios.post(loc() + "/saveRatio", payload))
})
this.bonusList.forEach((row) => {
const payload = this.cleanPayload(row)
payload.configId = savedConfig.id
tasks.push(this.$axios.post(loc() + "/saveBonus", payload))
})
return Promise.all(tasks).then((results) => {
for (let index = 0; index < results.length; index++) {
if (results[index].code !== 0) {
return Promise.reject(results[index])
}
}
return results
})
}).then(() => {
this.$message.success("保存成功")
this.configDialogVisible = false
this.loadConfigList()
}).catch((resp) => {
if (resp && resp.msg) {
this.$message.error(resp.msg)
}
}).finally(() => {
this.dialogSaving = false
})
},
// 新增比例时直接追加可编辑行,主弹窗确认前仅保存在前端列表中。
addRatioRow() {
this.ratioList.push({
startAmount: null,
endAmount: null,
ratio: null,
sort: null,
remark: ""
})
},
// 从弹窗内存列表移除比例,已有主键的记录延迟到主弹窗确认时删除。
removeRatio(row, index) {
if (row.id) {
this.deletedRatioIds.push(row.id)
}
this.ratioList.splice(index, 1)
},
// 新增奖励时直接追加可编辑行,主弹窗确认前仅保存在前端列表中。
addBonusRow() {
this.bonusList.push({
continuousYear: null,
increaseRatio: null,
remark: ""
})
},
// 从弹窗内存列表移除奖励,已有主键的记录延迟到主弹窗确认时删除。
removeBonus(row, index) {
if (row.id) {
this.deletedBonusIds.push(row.id)
}
this.bonusList.splice(index, 1)
},
// 统一保存前校验行内明细,避免新增空行或缺少关键字段的数据提交到后台。
validateDetailRows() {
for (let index = 0; index < this.ratioList.length; index++) {
const row = this.ratioList[index]
if (row.startAmount === null || row.startAmount === undefined || row.ratio === null || row.ratio === undefined || row.sort === null || row.sort === undefined) {
this.$message.error("请完善第 " + (index + 1) + " 行补助比例配置")
return false
}
}
for (let index = 0; index < this.bonusList.length; index++) {
const row = this.bonusList[index]
if (row.continuousYear === null || row.continuousYear === undefined || row.increaseRatio === null || row.increaseRatio === undefined) {
this.$message.error("请完善第 " + (index + 1) + " 行奖励配置")
return false
}
}
return true
},
// 新增弹窗默认基础配置,仅设置用户要求保留默认值的基础字段。
defaultConfig(year) {
return {
year: year,
configName: year + "年医疗互助补助配置",
status: 1
}
},
// 会员缴费配置为全局单条配置,未配置时给出可编辑默认值。
defaultMemberConfig() {
return {
monthAmount: 0,
halfPriceYear: 1
}
},
// 清理前端临时字段,避免弹窗编辑辅助字段传到后端实体。
cleanPayload(row) {
const payload = this.copy(row)
delete payload._editIndex
return payload
},
// 金额展示统一保留两位小数,并添加千分位分隔。
formatMoney(value) {
if (value === null || value === undefined || value === "") {
return ""
}
return Number(value).toLocaleString("zh-CN", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})
},
// 复制行数据,避免弹窗编辑时直接污染列表原数据。
copy(row) {
return JSON.parse(JSON.stringify(row))
},
// 根据列表面板剩余空间计算主表格高度,避免页面外层出现滚动条。
updateTableHeight() {
const panel = this.$refs.listPanel
if (!panel) {
return
}
const titleHeight = this.$refs.listTitle ? this.$refs.listTitle.offsetHeight : 0
const pagerHeight = this.$refs.pagerBar ? this.$refs.pagerBar.offsetHeight : 0
this.tableHeight = Math.max(panel.clientHeight - titleHeight - pagerHeight - 32, 220)
}
},
created() {
this.initYearOptions()
this.loadConfigList()
},
mounted() {
this.$nextTick(this.updateTableHeight)
window.addEventListener("resize", this.updateTableHeight)
},
beforeDestroy() {
window.removeEventListener("resize", this.updateTableHeight)
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,131 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="疾病种类">
<el-input placeholder="请输入疾病种类" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool label="疾病种类">
<el-button @click="openAdd" icon="el-icon-plus" size="small" type="primary">
新增疾病种类
</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%" v-loading="tableLoading">
<el-table-column label="编号" prop="diseaseCode"></el-table-column>
<el-table-column label="疾病种类" prop="diseaseName"></el-table-column>
<el-table-column label="是否重大疾病" prop="isMajorDiseases">
<template v-slot="{row}">
<el-tag v-if="row.isMajorDiseases" type="danger">是</el-tag>
<el-tag v-else>否</el-tag>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="180px">
<template slot-scope="{row}">
<el-button @click="openEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="doDelete(row.id)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</guava>
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="50%">
<el-form :model="formData" :rules="rules" label-width="120px" ref="form">
<el-form-item label="疾病名称" prop="diseaseName">
<el-input maxlength="50" show-word-limit v-model="formData.diseaseName"></el-input>
</el-form-item>
<el-form-item label="编号" prop="diseaseCode">
<el-input maxlength="20" v-model="formData.diseaseCode"></el-input>
</el-form-item>
<el-form-item label="是否重大疾病" prop="isMajorDiseases">
<el-radio-group v-model="formData.isMajorDiseases" size="small">
<el-radio :label="true" border>是</el-radio>
<el-radio :label="false" border>否</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<el-row justify="end" type="flex">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button @click="doSubmit" class="ml10" type="primary">确定</el-button>
</el-row>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
dialogVisible: false,
dialogTitle: "新增疾病种类",
formData: {
isMajorDiseases: true
},
rules: {
diseaseName: [{ required: true, message: "请输入疾病名称", trigger: ["change", "blur"] }],
diseaseCode: [{ required: true, message: "请输入疾病编号", trigger: ["change", "blur"] }]
}
}
},
methods: {
// 删除前要求用户二次确认,避免误删疾病基础数据。
doDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post(loc() + "/doDelete", { id: id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.pageData()
}
})
}).catch(() => {})
},
// 打开编辑弹窗时复制行数据,防止未保存操作直接修改列表。
openEdit(row) {
this.formData = clone(row)
this.dialogTitle = "编辑疾病种类"
this.dialogVisible = true
},
// 表单校验通过后提交,成功时关闭弹窗并刷新列表。
doSubmit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.$axios.post(loc() + "/doSubmit", this.formData).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.dialogVisible = false
this.pageData()
}
})
}
})
},
// 新增时重置默认值,确保重大疾病选项默认选中“是”。
openAdd() {
this.formData = { isMajorDiseases: true }
this.dialogTitle = "新增疾病种类"
this.dialogVisible = true
}
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,210 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.disease-type-page {
min-height: 100vh;
background: #f7f8fa;
}
.search-toolbar {
display: flex;
align-items: center;
padding: 8px 12px;
background: #fff;
}
.search-toolbar .van-search {
flex: 1;
padding: 0 8px 0 0;
}
.disease-card {
margin: 10px 12px;
padding: 14px;
background: #fff;
border-radius: 8px;
}
.disease-card__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.disease-card__name {
font-size: 16px;
font-weight: 600;
color: #323233;
}
.disease-card__code {
margin-bottom: 12px;
color: #969799;
}
.disease-card__actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.popup-title {
padding: 18px 16px 8px;
font-size: 18px;
font-weight: 600;
text-align: center;
}
.popup-actions {
padding: 16px;
}
</style>
<div class="disease-type-page" id="app">
<van-nav-bar title="疾病种类" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<div class="search-toolbar">
<van-search v-model="pageForm.searchKeyword" placeholder="请输入疾病种类"
@clear="doSearch" @search="doSearch"></van-search>
<van-button size="small" type="info" icon="plus" @click="openAdd">新增</van-button>
</div>
</van-sticky>
<van-pull-refresh v-model="refreshing" @refresh="doSearch">
<van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="loadData">
<div class="disease-card" v-for="row in list" :key="row.id">
<div class="disease-card__header">
<span class="disease-card__name">{{row.diseaseName}}</span>
<van-tag :type="row.isMajorDiseases ? 'danger' : 'primary'">
{{row.isMajorDiseases ? "重大疾病" : "普通疾病"}}
</van-tag>
</div>
<div class="disease-card__code">编号:{{row.diseaseCode}}</div>
<div class="disease-card__actions">
<van-button plain size="small" type="info" @click="openEdit(row)">编辑</van-button>
<van-button plain size="small" type="danger" @click="doDelete(row.id)">删除</van-button>
</div>
</div>
</van-list>
</van-pull-refresh>
<van-popup v-model="dialogVisible" position="bottom" round :style="{ height: '68%' }">
<div class="popup-title">{{dialogTitle}}</div>
<van-form ref="form" @submit="doSubmit">
<van-field v-model="formData.diseaseName" name="diseaseName" label="疾病名称"
maxlength="50" placeholder="请输入疾病名称"
:rules="[{ required: true, message: '请输入疾病名称' }]"></van-field>
<van-field v-model="formData.diseaseCode" name="diseaseCode" label="编号"
maxlength="20" placeholder="请输入疾病编号"
:rules="[{ required: true, message: '请输入疾病编号' }]"></van-field>
<van-field name="isMajorDiseases" label="重大疾病">
<template #input>
<van-switch v-model="formData.isMajorDiseases" size="22"></van-switch>
</template>
</van-field>
<div class="popup-actions">
<van-button block round type="info" native-type="submit">确定</van-button>
</div>
</van-form>
</van-popup>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
apiPath: "/platform/h5/medicalMutualAid/medical/diseaseType",
list: [],
loading: false,
refreshing: false,
finished: false,
dialogVisible: false,
dialogTitle: "新增疾病种类",
formData: {
isMajorDiseases: true
},
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: ""
}
}
},
methods: {
// 分页加载疾病类型,刷新时替换列表,翻页时追加列表。
loadData() {
this.$axios.post(this.apiPath + "/pageData", this.pageForm).then((resp) => {
if (resp.code === 0) {
const rows = resp.data && resp.data.list ? resp.data.list : []
if (this.pageForm.pageNumber === 1) {
this.list = rows
} else {
this.list = this.list.concat(rows)
}
this.pageForm.totalCount = resp.data ? resp.data.totalCount : 0
if (this.list.length >= this.pageForm.totalCount || rows.length === 0) {
this.finished = true
} else {
this.pageForm.pageNumber += 1
}
} else {
this.$toast.fail(resp.msg)
this.finished = true
}
}).finally(() => {
this.loading = false
this.refreshing = false
})
},
// 重置分页状态并按当前关键字重新查询。
doSearch() {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.finished = false
this.list = []
this.loading = true
this.loadData()
},
// 新增时初始化默认表单。
openAdd() {
this.formData = { isMajorDiseases: true }
this.dialogTitle = "新增疾病种类"
this.dialogVisible = true
},
// 编辑时复制列表数据,避免关闭弹窗前污染原列表。
openEdit(row) {
this.formData = Object.assign({}, row)
this.dialogTitle = "编辑疾病种类"
this.dialogVisible = true
},
// Vant 表单校验成功后保存疾病类型。
doSubmit() {
this.$axios.post(this.apiPath + "/doSubmit", this.formData).then((resp) => {
if (resp.code === 0) {
this.$toast.success(resp.msg)
this.dialogVisible = false
this.doSearch()
} else {
this.$toast.fail(resp.msg)
}
})
},
// 删除前二次确认,成功后从第一页重新加载。
doDelete(id) {
this.$dialog.confirm({
title: "提示",
message: "您确定要删除吗?"
}).then(() => {
this.$axios.post(this.apiPath + "/doDelete", { id: id }).then((resp) => {
if (resp.code === 0) {
this.$toast.success(resp.msg)
this.doSearch()
} else {
this.$toast.fail(resp.msg)
}
})
}).catch(() => {})
}
}
})
</script>
<!--#
}
#-->