This commit is contained in:
zhouhefeng
2026-04-24 16:39:14 +08:00
147 changed files with 5706 additions and 881 deletions
@@ -8,6 +8,7 @@
:on-success="handleSuccess"
:on-preview="handlePreview"
:on-exceed="handleExceed"
:on-remove="handleRemove"
:before-upload="beforeUpload"
:limit="upload_number"
:accept="fileAccept"
@@ -82,6 +82,7 @@ layout("/layouts/platform.html"){
:expand-on-click-node="false"
:props="{ children: 'children', label: 'name' }"
node-key="id"
:default-expanded-keys="defaultExpandedKeys"
@node-click="treeNodeClick"
:filter-node-method="filterNode"
highlight-current
@@ -156,6 +157,7 @@ layout("/layouts/platform.html"){
filterText: null,
currentTreeNode: null,
currentTreeData: null,
defaultExpandedKeys: [],
treeData: []
}
},
@@ -175,6 +177,7 @@ layout("/layouts/platform.html"){
this.treeData = res.data
if (this.treeData) {
this.currentTreeData = this.treeData[0]
this.defaultExpandedKeys = this.treeData.length > 0 ? [this.treeData[0].id] : []
}
})
},
@@ -456,6 +456,8 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
complete_result></file-upload>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="40">
<el-col :span="12">
<el-form-item label="其他" prop="otherFiles">
<file-upload :value.sync="formData.otherFiles" accept=".jpg,.jpeg,.png"
@@ -107,7 +107,7 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
:disabled="row.projectTypeCode==50004">
编辑
</el-dropdown-item>
<el-dropdown-item
<el-dropdown-item u
v-if="row.canRevoke" :command="{type:'Revoke',row}">
撤回
</el-dropdown-item>
@@ -80,7 +80,7 @@ layout("/layouts/platform.html"){
})
},
openAnnualLimit() {
window.location.href = '/platform/trainSignUp/annualLimit'
commonUtil.pjaxPush('/platform/trainSignUp/annualLimit')
},
openAdd() {
this.$refs.guava.edit(() => {
@@ -571,6 +571,11 @@ layout("/layouts/platform.html"){
{{formatNumber(row.support)}}
</template>
</el-table-column>
<el-table-column label="其他收入(元)" prop="otherIncome">
<template slot-scope="{row}">
{{formatNumber(row.otherIncome)}}
</template>
</el-table-column>
<el-table-column label="年度总支出(元)" prop="totalExpend">
<template slot-scope="{row}">
{{formatNumber(row.totalExpend)}}
@@ -662,7 +667,7 @@ layout("/layouts/platform.html"){
// 财务数据
financeData: {
incomeDetailed: [], // 收支明细
incomeCensus: [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, totalExpend: 0, surplus: 0 }] // 收支统计
incomeCensus: [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, otherIncome: 0, totalExpend: 0, surplus: 0 }] // 收支统计
},
// 表单校验规则
@@ -680,12 +685,13 @@ layout("/layouts/platform.html"){
{ label: "校工会拨款", value: "校工会拨款" },
{ label: "年度结余", value: "年度结余" },
{ label: "社会赞助", value: "社会赞助" },
{ label: "其他收入", value: "其他收入" },
{ label: "支出", value: "支出" }
];
},
// 收入类型集合
INCOME_TYPES() {
return ["会费收入", "校工会拨款", "社会赞助", "其"];
return ["会费收入", "校工会拨款", "社会赞助", "其他收入"];
},
// 支出类型集合
EXPEND_TYPES() {
@@ -730,8 +736,9 @@ layout("/layouts/platform.html"){
const income = row.income || 0;
const allocate = row.allocate || 0;
const support = row.support || 0;
const otherIncome = row.otherIncome || 0;
const totalExpend = row.totalExpend || 0;
const total = Number(lastYearSurplusVal) + Number(income) + Number(allocate) + Number(support) - Number(totalExpend);
const total = Number(lastYearSurplusVal) + Number(income) + Number(allocate) + Number(support) + Number(otherIncome) - Number(totalExpend);
return this.formatNumber(total);
},
// 表单校验通用方法
@@ -788,7 +795,7 @@ layout("/layouts/platform.html"){
data.year = data.year?.toString() || new Date().getFullYear() + "";
this.formData = data;
// 初始化财务数据
this.financeData.incomeCensus = data.incomeCensus || [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, totalExpend: 0, surplus: 0 }];
this.financeData.incomeCensus = data.incomeCensus || [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, otherIncome: 0, totalExpend: 0, surplus: 0 }];
// 从统计数据中提取去年年度结余
if (this.financeData.incomeCensus && this.financeData.incomeCensus.length > 0) {
@@ -948,6 +955,8 @@ layout("/layouts/platform.html"){
this.financeData.incomeCensus[0].allocate = (this.financeData.incomeCensus[0].allocate || 0) - income;
} else if (row.incomeType === "社会赞助") {
this.financeData.incomeCensus[0].support = (this.financeData.incomeCensus[0].support || 0) - income;
} else if (row.incomeType === "其他收入") {
this.financeData.incomeCensus[0].otherIncome = (this.financeData.incomeCensus[0].otherIncome || 0) - income;
} else if (row.incomeType === "支出") {
this.financeData.incomeCensus[0].totalExpend = (this.financeData.incomeCensus[0].totalExpend || 0) - expend;
}
@@ -968,6 +977,10 @@ layout("/layouts/platform.html"){
this.$set(row, "expend", null);
this.calcSupportTotal();
break;
case "其他收入":
this.$set(row, "expend", null);
this.calcOtherIncomeTotal();
break;
case "支出":
this.$set(row, "income", null);
this.calcExpendTotal();
@@ -993,6 +1006,8 @@ layout("/layouts/platform.html"){
this.calcAllocateTotal();
} else if (row.incomeType === "会费收入") {
this.calcDueIncomeTotal();
} else if (row.incomeType === "其他收入") {
this.calcOtherIncomeTotal();
}
// 重新计算所有统计数据,确保一致性
this.recalculateCensus();
@@ -1018,6 +1033,13 @@ layout("/layouts/platform.html"){
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
this.financeData.incomeCensus[0].support = total;
},
// 计算其他收入合计
calcOtherIncomeTotal() {
const total = this.financeData.incomeDetailed
.filter(item => item.incomeType === "其他收入")
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
this.financeData.incomeCensus[0].otherIncome = total;
},
// 计算会费收入合计
calcDueIncomeTotal() {
const total = this.financeData.incomeDetailed
@@ -1049,6 +1071,11 @@ layout("/layouts/platform.html"){
.filter(item => item.incomeType === "社会赞助")
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
// 计算其他收入总额
const otherIncomeTotal = this.financeData.incomeDetailed
.filter(item => item.incomeType === "其他收入")
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
// 计算总支出
const totalExpend = this.financeData.incomeDetailed
.filter(item => item.incomeType === "支出")
@@ -1058,9 +1085,12 @@ layout("/layouts/platform.html"){
this.financeData.incomeCensus[0].income = dueIncomeTotal;
this.financeData.incomeCensus[0].allocate = allocateTotal;
this.financeData.incomeCensus[0].support = supportTotal;
this.financeData.incomeCensus[0].otherIncome = otherIncomeTotal;
this.financeData.incomeCensus[0].totalExpend = totalExpend;
// 确保去年年度结余不丢失
this.financeData.incomeCensus[0].lastYearSurplus = this.lastYearSurplus;
// 同步写回结余,避免保存后统计值与页面展示不一致
this.financeData.incomeCensus[0].surplus = Number(this.calcSurplus(this.financeData.incomeCensus[0]));
// 同步更新全局变量
this.dueIncome = dueIncomeTotal;
@@ -1134,6 +1164,7 @@ layout("/layouts/platform.html"){
// 保存
async handleSave() {
try {
this.recalculateCensus();
const resp = await this.$axios.post("/platform/club/examine/apply/save", {
data: JSON.stringify(this.formData),
incomeDetailed: JSON.stringify(this.financeData.incomeDetailed),
@@ -1150,6 +1181,7 @@ layout("/layouts/platform.html"){
// 提交(新增)
async handleSubmit() {
try {
this.recalculateCensus();
await this.$confirm("确定要提交此申请吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
@@ -1175,6 +1207,7 @@ layout("/layouts/platform.html"){
// 提交(任务处理)
async handleFinishTask() {
try {
this.recalculateCensus();
await this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
@@ -68,8 +68,12 @@ const EXAMINE_INFO_COMPONENT = {
<el-table-column label="会费收入" prop="income"></el-table-column>
<el-table-column label="校工会拨款" prop="allocate"></el-table-column>
<el-table-column label="社会赞助" prop="support"></el-table-column>
<el-table-column label="其他收入" prop="otherIncome"></el-table-column>
<el-table-column label="年度总支出" prop="totalExpend"></el-table-column>
<el-table-column label="本年度结余" prop="surplus">
<template slot-scope="{row}">
{{ getIncomeCensusSurplus(row) }}
</template>
</el-table-column>
</el-table>
</el-tab-pane>
@@ -132,6 +136,19 @@ const EXAMINE_INFO_COMPONENT = {
}
},
methods: {
// 历史数据可能没有落库存量结余,这里按统计项兜底重算
getIncomeCensusSurplus(row) {
if (!row) {
return 0
}
const lastYearSurplus = Number(row.lastYearSurplus) || 0
const income = Number(row.income) || 0
const allocate = Number(row.allocate) || 0
const support = Number(row.support) || 0
const otherIncome = Number(row.otherIncome) || 0
const totalExpend = Number(row.totalExpend) || 0
return lastYearSurplus + income + allocate + support + otherIncome - totalExpend
},
async onOpen(row) {
this.row = row
const resp = await this.$axios.post("/platform/club/examine/common/findOne", { id: row.id })
@@ -0,0 +1,100 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="所属社团">
<el-select v-model="pageForm.clubId" placeholder="请选择社团" clearable filterable style="width: 100%">
<el-option v-for="item in clubList" :key="item.id" :label="item.clubName" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="教职工类别">
<dict-select code="USER_PERSON_TYPE" placeholder="请选择人员类型" clearable v-model="pageForm.personType"></dict-select>
</search-item>
<search-item label="在职状态">
<dict-select code="USER_STATE" placeholder="请选择人员状态" clearable v-model="pageForm.userState"></dict-select>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="退会人员列表"></table-tool>
<el-table :data="tableData">
<el-table-column :index="indexMethod" label="序号" type="index" width="70"></el-table-column>
<el-table-column label="工号" prop="loginName" show-overflow-tooltip></el-table-column>
<el-table-column label="姓名" prop="userName" show-overflow-tooltip></el-table-column>
<el-table-column label="性别" prop="sex" show-overflow-tooltip></el-table-column>
<el-table-column label="电话" prop="mobile" show-overflow-tooltip></el-table-column>
<el-table-column label="所属社团" prop="clubName" show-overflow-tooltip></el-table-column>
<el-table-column label="所属单位" prop="unitName" show-overflow-tooltip></el-table-column>
<el-table-column label="身份" prop="roleName" show-overflow-tooltip></el-table-column>
<el-table-column label="入会时间" prop="joinTime" show-overflow-tooltip></el-table-column>
<el-table-column label="退会时间" prop="exitTime" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="120">
<template v-slot="{row}">
<el-button size="mini" type="primary" @click="onView(row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"info": clubExitInfo,
},
data() {
return {
clubList: []
}
},
methods: {
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
async getClubList() {
const resp = await this.$axios.post("/platform/club/infoManage/exitManage/getClubList")
if (resp.code === 0) {
this.clubList = resp.data
}
},
async pageData() {
const resp = await this.$axios.post("/platform/club/infoManage/exitManage/pageData", this.pageForm)
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
} else {
this.$message.warning(resp.msg)
}
}
},
async created() {
await this.getClubList()
await this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,95 @@
const clubExitInfo = {
template:
/*language=HTML*/
`
<div>
<div class="process-title">
退会信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions border>
<el-descriptions-item label="姓名">{{viewData.userName}}</el-descriptions-item>
<el-descriptions-item label="工号">{{viewData.loginName}}</el-descriptions-item>
<el-descriptions-item label="性别">{{viewData.sex}}</el-descriptions-item>
<el-descriptions-item label="出生年月">{{$moment(viewData.birthday).format('YYYY-MM-DD')}}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{viewData.mobile}}</el-descriptions-item>
<el-descriptions-item label="电子信箱">{{viewData.email}}</el-descriptions-item>
<el-descriptions-item label="分工会">{{viewData.unionName}}</el-descriptions-item>
<el-descriptions-item label="部门" :span="2">{{viewData.unitName}}</el-descriptions-item>
<el-descriptions-item label="职务">{{viewData.position}}</el-descriptions-item>
<el-descriptions-item label="职称" :span="2">{{viewData.technicalTitle}}</el-descriptions-item>
<el-descriptions-item label="学历">{{viewData.education}}</el-descriptions-item>
<el-descriptions-item label="学位" :span="2">{{viewData.academicDegree}}</el-descriptions-item>
<el-descriptions-item label="同时参加其他社团情况" :span="3">{{viewData.sameTimeJoinOtherClubSituation}}</el-descriptions-item>
<el-descriptions-item label="文化、体育方面的活动经历、获奖情况" :span="3">{{viewData.awardsExperience}}</el-descriptions-item>
<el-descriptions-item label="照片" :span="3">
<img :src="viewData.avatar" alt="" style="width: 120px;height: 150px" v-if="viewData.avatar">
</el-descriptions-item>
<el-descriptions-item label="签字" :span="3">
<el-image v-if="viewData.signature" :src="viewData.signature" class="signature-image"></el-image>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
<div class="mt10">
<div class="process-title">{{ task.displayName }}</div>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-if="task.ext.isFirstTaskNode">
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ task.finishTime }}</el-descriptions-item>
<el-descriptions-item label="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
</el-descriptions-item>
</el-descriptions>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else>
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})</el-descriptions-item>
<el-descriptions-item label="办理时间">{{ task.finishTime }}</el-descriptions-item>
<el-descriptions-item label="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="办理意见" v-if="!task.ext.isFirstTaskNode">{{ task.taskFormData.opinion }}</el-descriptions-item>
</el-descriptions>
</div>
</template>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
viewData: {},
row: {},
doneTasks: [],
}
},
methods: {
onOpen(row) {
this.row = row
this.$axios.post("/platform/club/infoManage/exitManage/info", { id: row.id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
this.getDoneTasks()
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
openChart(){
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
}
},
style: /*language=CSS*/ `
.el-descriptions-item__label {
width: 200px;
min-width: 200px;
max-width: 200px;
}
.el-tabs__header {
margin: 0;
}
`
}
@@ -37,6 +37,7 @@ const CLUB_INFO_MANAGE_TEMPLATE = {
<el-table-column label="电话" prop="mobile" show-overflow-tooltip></el-table-column>
<el-table-column label="所属单位" prop="unitName" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="身份" prop="roleName" show-overflow-tooltip></el-table-column>
<el-table-column label="入会时间" prop="joinTime" show-overflow-tooltip sortable></el-table-column>
<el-table-column label="操作">
<template slot-scope="{row}">
<el-dropdown>
@@ -58,7 +58,8 @@ const CLUB_SPONSOR_TEMPLATE = {
`,
data() {
return {
sponsorData: [],
// 发起人至少需要 3 人,默认先展示 3 行,方便录入。
sponsorData: [{}, {}, {}],
userOptions: []
}
},
@@ -91,6 +92,10 @@ const CLUB_SPONSOR_TEMPLATE = {
})
},
sponsorDeleteRow(row, index) {
if (this.sponsorData.length <= 3) {
this.$message.warning("发起人至少保留3行")
return
}
this.sponsorData.splice(index, 1)
}
},
@@ -38,7 +38,7 @@ layout("/layouts/platform.html"){
<el-button v-if="activeName === 1" type="primary" @click="activeName = 0">上一步</el-button>
<el-button v-if="activeName === 2" type="primary" @click="activeName = 1">上一步</el-button>
<el-button v-if="activeName === 0" type="primary" @click="nextStep">下一步</el-button>
<el-button v-if="activeName === 1" type="primary" @click="activeName = 2">下一步</el-button>
<el-button v-if="activeName === 1" type="primary" @click="nextSponsorStep">下一步</el-button>
<el-button type="primary" plain @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
@@ -73,6 +73,14 @@ layout("/layouts/platform.html"){
}
},
methods: {
validateSponsorCount() {
const sponsorList = this.$refs.clubSponsorRef.sponsorData.filter((o) => o.userId !== "" && o.userId !== undefined)
if (sponsorList.length < 3) {
this.$message.warning({ title: "温馨提醒", message: "发起人不少于3人" })
return false
}
return true
},
nextStep() {
let valid = true
this.$refs.clubFormRef.$refs.form.validateField(["clubName"], (errMsg) => {
@@ -85,6 +93,13 @@ layout("/layouts/platform.html"){
if (valid) return
this.activeName = 1
},
nextSponsorStep() {
// 第二步进入第三步前,先校验发起人数量,避免遗漏必填人数要求。
if (!this.validateSponsorCount()) {
return
}
this.activeName = 2
},
async onSave() {
let valid = true
this.$refs.clubFormRef.$refs.form.validateField("clubName", (errMsg) => {
@@ -122,8 +137,7 @@ layout("/layouts/platform.html"){
formData.sponsor = this.$refs.clubSponsorRef.sponsorData
.filter((o) => o.userId !== "" && o.userId !== undefined)
.map((o) => o.userId)
if (['onFinishTask', 'onSubmit'].includes(type) && formData.sponsor && formData.sponsor.length < 3) {
this.$message.warning({ title: "警告", message: "发起人要求不少于3人" })
if (['onFinishTask', 'onSubmit'].includes(type) && !this.validateSponsorCount()) {
return
}
let manageValid = false
@@ -200,7 +214,6 @@ layout("/layouts/platform.html"){
let users = resp.data.clubUser.map((o) => o.userId)
let array = []
if (resp.data.sponsor) {
this.sponsorData = []
array = resp.data.sponsor.split(",")
formData.sponsor = array
}
@@ -211,12 +224,16 @@ layout("/layouts/platform.html"){
if (users) {
this.$refs.clubManagerRef.userOptions = await this.queryUserByIds(users)
}
this.$refs.clubSponsorRef.sponsorData = []
array.forEach((item, index) => {
let row = {}
row.userId = item
this.$refs.clubSponsorRef.sponsorPersonChange(item, row, index)
this.$refs.clubSponsorRef.sponsorData.push(row)
})
while (this.$refs.clubSponsorRef.sponsorData.length < 3) {
this.$refs.clubSponsorRef.sponsorData.push({})
}
this.$refs.clubFormRef.formData = formData
this.$refs.clubFormRef.concatPersonChange(resp.data.concatPerson)
}
@@ -31,12 +31,14 @@ layout("/layouts/platform.html"){
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="温馨提示:请先更新拨付金额后再点击核对按钮">
<el-button @click="closeAudit(false)" size="mini" type="primary">
开启核对入口
</el-button>
<el-button @click="closeAudit(true)" size="mini" type="danger">
取消核对入口
</el-button>
<template v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_CLUB_ADMIN'])">
<el-button @click="closeAudit(false)" size="mini" type="primary">
开启核对入口
</el-button>
<el-button @click="closeAudit(true)" size="mini" type="danger">
取消核对入口
</el-button>
</template>
</table-tool>
<el-table :data="tableData" style="width: 100%" row-key="id"
v-loading="tableLoading" :size="tableSize" class="vi-table">
@@ -228,7 +228,9 @@ const basicForm = {
}
})
} else {
this.formData = {}
this.formData = {
category: 'QUIZ'
}
}
},
onSubmit() {
@@ -91,7 +91,7 @@ const subjectForm = {
<div class="option-content">
<el-input
v-model="option.text"
:placeholder="'选项'+optionIndex + 1">
:placeholder="'选项' + (optionIndex + 1)">
<template slot="prepend">选项{{optionIndex + 1}}</template>
</el-input>
<!-- <el-input-->
@@ -119,7 +119,8 @@ const subjectForm = {
<el-switch
v-if="activity.category==='QUIZ'"
v-model="option.isCorrect"
active-text="正确答案">
active-text="正确答案"
@change="handleCorrectAnswerChange(subject, optionIndex)">
</el-switch>
<el-button
@@ -286,6 +287,12 @@ const subjectForm = {
//题目类型切换
subjectTypeChange(subject, subjectIndex) {
// 切换题型时先清空当前题目的正确答案状态,避免沿用旧题型下的答案配置。
;(subject.options || []).forEach((option) => {
if (option) {
this.$set(option, 'isCorrect', false)
}
})
if (subject.type === 'text') {
subject.options = []
}
@@ -310,7 +317,7 @@ const subjectForm = {
addOption(subject) {
subject.options.push({
id: this.generateId(),
text: "选项" + subject.options.length + 1,
text: "选项" + (subject.options.length + 1),
hint: "",
imgUrl: null,
isCorrect: false
@@ -393,10 +400,67 @@ const subjectForm = {
},
// 单选题切换正确答案时保持只有一个正确选项,避免界面状态与题型规则不一致。
handleCorrectAnswerChange(subject, optionIndex) {
if (!subject || subject.type !== 'radio') {
return
}
const options = subject.options || []
const currentOption = options[optionIndex]
if (!currentOption || !currentOption.isCorrect) {
return
}
for (let index = 0; index < options.length; index++) {
if (index !== optionIndex) {
this.$set(options[index], 'isCorrect', false)
}
}
},
// 保存前校验选项内容,避免题目存在空选项或缺少正确答案时仍然提交到后端。
validateSubjectOptions() {
for (let subjectIndex = 0; subjectIndex < this.subjects.length; subjectIndex++) {
const subject = this.subjects[subjectIndex]
if (!subject || subject.type === 'text') {
continue
}
const options = subject.options || []
if (options.length === 0) {
this.$message.warning('请设置第' + (subjectIndex + 1) + '题的选项')
return false
}
let correctAnswerCount = 0
for (let optionIndex = 0; optionIndex < options.length; optionIndex++) {
const option = options[optionIndex]
const optionText = option && option.text ? option.text.trim() : ''
if (!optionText) {
this.$message.warning('第' + (subjectIndex + 1) + '题的第' + (optionIndex + 1) + '个选项不能为空')
return false
}
if (option && option.isCorrect) {
correctAnswerCount++
}
}
if (this.activity.category === 'QUIZ') {
if (subject.type === 'radio' && correctAnswerCount > 1) {
this.$message.warning('第' + (subjectIndex + 1) + '题为单选题,只能设置一个正确答案')
return false
}
if (correctAnswerCount === 0) {
this.$message.warning('第' + (subjectIndex + 1) + '题请至少设置一个正确答案')
return false
}
}
}
return true
},
//保存
saveQuestionnaire() {
$
.post("/platform/qsv/activity/saveSubjects", {
if (!this.validateSubjectOptions()) {
return
}
$.post("/platform/qsv/activity/saveSubjects", {
activityId: this.id,
subjects: JSON.stringify(this.subjects)
})
@@ -53,7 +53,7 @@ const answer = {
$.post("/platform/qsv/survey/deleteUserAnswer", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.list()
this.pageData()()
}
})
})
@@ -2,6 +2,42 @@
layout("/layouts/platform.html"){
#-->
<style>
.reimbursement-tabs {
margin-top: 10px;
}
.invoice-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 16px;
}
.invoice-toolbar-title {
font-size: 14px;
color: #1867b0;
font-weight: 600;
}
.invoice-summary-tip {
margin-top: 8px;
font-size: 12px;
color: #909399;
}
.invoice-file-name {
color: #1867b0;
cursor: pointer;
}
.invoice-file-name:hover {
text-decoration: underline;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<template #header>
@@ -12,7 +48,9 @@ layout("/layouts/platform.html"){
</template>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-descriptions :column="2" border>
<el-tabs class="reimbursement-tabs" v-model="activeTabName">
<el-tab-pane label="申请基本信息" name="basic">
<el-descriptions :column="2" border>
<el-descriptions-item label="经办人">{{formData.userName}}</el-descriptions-item>
<el-descriptions-item label="工号">{{formData.loginName}}</el-descriptions-item>
<!-- <el-descriptions-item label="报销类别">-->
@@ -26,7 +64,7 @@ layout("/layouts/platform.html"){
<!-- </el-descriptions-item>-->
<el-descriptions-item label="报销项目" span="2">
<el-form-item label="报销项目" prop="reimburseProject">
<el-radio-group v-model="formData.reimburseProject" size="medium">
<el-radio-group v-model="formData.reimburseProject" size="medium" @change="handleReimburseProjectChange">
<el-radio :label="item.code" border v-for="item in reimburseProjectList">
{{item.name}}
</el-radio>
@@ -82,11 +120,32 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="户名" v-if="formData.paymentWay === 'UNION_REIMBURSE_PAYMENT_WAY_2'">
<el-form-item label="户名" prop="bankUserName">
<el-select
v-model="formData.bankUserName"
@change="handleBankUserNameChange"
clearable
filterable
allow-create
default-first-option
placeholder="请输入户名"
style="width: 100%">
<el-option
v-for="(item, index) in bankHistoryUserNames"
:key="index"
:label="item"
:value="item">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="开户行" v-if="formData.paymentWay === 'UNION_REIMBURSE_PAYMENT_WAY_2'">
<el-form-item label="开户行" prop="bankOfDeposit">
<el-select
v-model="formData.bankOfDeposit"
@change="getUserBankHistory"
@change="fillBankInfoFromHistory"
clearable
filterable
allow-create
@@ -107,7 +166,7 @@ layout("/layouts/platform.html"){
<el-form-item label="银行卡号" prop="bankCardNumber" >
<el-select
v-model="formData.bankCardNumber"
@change="getUserBankHistory"
@change="fillBankInfoFromHistory"
clearable
filterable
allow-create
@@ -268,8 +327,7 @@ layout("/layouts/platform.html"){
<el-descriptions-item label="报销金额" v-if="formData.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1'">
<el-form-item label="报销金额" prop="money">
<el-input v-model="formData.money" placeholder="输入报销金额"
type="number"></el-input>
<el-input v-model="formData.money" placeholder="自动汇总发票金额" readonly></el-input>
</el-form-item>
</el-descriptions-item>
@@ -282,15 +340,6 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="发票张数">
<el-form-item label="发票张数" prop="invoiceNumber">
<el-input-number v-model="formData.invoiceNumber"
:max="1000" :min="0" controls-position="right"
placeholder="请填写发票张数"
style="width: 100%"></el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="慰问时间" v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
<el-form-item label="慰问时间" prop="condolenceTime">
<el-date-picker v-model="formData.condolenceTime"
@@ -396,13 +445,13 @@ layout("/layouts/platform.html"){
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="报销事由" :span="2">
<el-descriptions-item label="报销事由" :span="2" v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
<el-form-item prop="paymentNotes" label="报销事由">
<el-input maxlength="500" v-model="formData.paymentNotes" placeholder="请填写报销事由"
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">
<el-descriptions-item label="备注" :span="2" v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
<el-form-item prop="notes" label="备注">
<el-input maxlength="500" v-model="formData.notes" placeholder="需要填写:发票编号、开具方、金额"
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
@@ -436,7 +485,83 @@ layout("/layouts/platform.html"){
<!-- <pc-signature v-model="formData.userSign"></pc-signature>-->
<!-- </el-form-item>-->
<!-- </el-descriptions-item>-->
</el-descriptions>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="发票信息" name="invoice" v-if="showInvoiceTab">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报销金额" prop="money">
<el-input v-model="formData.money" placeholder="自动汇总发票金额" readonly></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发票张数" prop="invoiceNumber">
<el-input v-model="formData.invoiceNumber" placeholder="自动统计发票数量" readonly></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="paymentNotes" label="支付内容">
<el-input maxlength="500" v-model="formData.paymentNotes" placeholder="请填写支付内容"
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="notes" label="备注">
<el-input maxlength="500" v-model="formData.notes" placeholder="补充说明"
type="textarea" :autosize="{ minRows: 3, maxRows: 6}"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<div class="invoice-toolbar">
<div>
<div class="invoice-toolbar-title">发票明细列表</div>
<div class="invoice-summary-tip">
每条明细对应一个发票文件,可上传图片或 PDF;报销金额和发票张数会根据下表自动汇总。
</div>
</div>
<div>
<el-switch
v-model="formData.invoiceVerifyEnabled"
@change="handleVerifySwitchChange"
active-text="自动校验"
inactive-text="手工录入">
</el-switch>
<el-button @click="openInvoiceDialog('add')" plain type="primary" style="margin-left: 12px">新增发票</el-button>
</div>
</div>
<el-table :data="formData.invoiceDetails" border empty-text="暂无发票明细">
<el-table-column align="center" label="序号" type="index" width="70"></el-table-column>
<el-table-column label="文件名称" min-width="170">
<template slot-scope="scope">
<span class="invoice-file-name"
v-if="getInvoiceFile(scope.row)"
@click="previewInvoiceFile(scope.row)">
{{ getInvoiceFile(scope.row).name || getInvoiceFile(scope.row).filename }}
</span>
<span v-else>未上传</span>
</template>
</el-table-column>
<el-table-column label="发票号码" min-width="140" prop="invoiceNo"></el-table-column>
<el-table-column align="right" label="发票金额" min-width="110" prop="invoiceAmount"></el-table-column>
<el-table-column label="销售方信息名称" min-width="180" prop="sellerName"></el-table-column>
<el-table-column label="项目名称" min-width="180" prop="itemName"></el-table-column>
<el-table-column label="备注" min-width="150" prop="remark"></el-table-column>
<el-table-column align="center" fixed="right" label="操作" width="160">
<template slot-scope="scope">
<el-button @click="openInvoiceDialog('edit', scope.row, scope.$index)" size="mini" type="text">
编辑
</el-button>
<el-button @click="removeInvoiceDetail(scope.$index)" size="mini" type="text">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</el-form>
<el-row type="flex" justify="end" class="mt20">
<el-button type="primary" plain @click="onSave">保存</el-button>
@@ -444,6 +569,70 @@ layout("/layouts/platform.html"){
<el-button type="primary" @click="onFinishTask" v-else>提交</el-button>
</el-row>
</el-card>
<el-dialog :close-on-click-modal="false"
:title="invoiceDialogMode === 'edit' ? '编辑发票明细' : '新增发票明细'"
:visible.sync="invoiceDialogVisible"
append-to-body
width="820px">
<el-form :model="detailForm" :rules="detailRules" label-position="right"
label-suffix="" label-width="120px" ref="invoiceDetailForm">
<el-row :gutter="30">
<el-col :span="24">
<el-form-item label="发票文件" prop="invoiceFiles">
<file-upload
:value.sync="detailForm.invoiceFiles"
:upload_number="1"
upload_return_id_api="/platform/sys/file/uploadDynamicReturnUrl"
upload_result_type="id"
upload_result_category="array"
complete_result
upload_mode="drag"
accept=".jpg,.jpeg,.png,.pdf">
</file-upload>
<div class="invoice-summary-tip">
上传发票文件后会自动识别发票号码、金额、销售方信息名称和项目名称;如已开启自动校验,还会继续校验发票信息。
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发票号码" prop="invoiceNo">
<el-input placeholder="请输入发票号码" v-model="detailForm.invoiceNo"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发票金额" prop="invoiceAmount">
<el-input-number :controls="false" :min="0" :precision="2"
placeholder="请输入发票金额" style="width: 100%"
v-model="detailForm.invoiceAmount"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="销售方信息名称" prop="sellerName">
<el-input placeholder="请输入销售方信息名称" v-model="detailForm.sellerName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目名称" prop="itemName">
<el-input placeholder="请输入项目名称" v-model="detailForm.itemName"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input :autosize="{ minRows: 3, maxRows: 5}"
placeholder="请输入备注"
type="textarea"
v-model="detailForm.remark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<span class="dialog-footer" slot="footer">
<el-button @click="invoiceDialogVisible = false">取 消</el-button>
<el-button @click="saveInvoiceDetail" type="primary">保 存</el-button>
</span>
</el-dialog>
</div>
@@ -456,12 +645,31 @@ layout("/layouts/platform.html"){
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
activeTabName: "basic",
formData: {
reimburseType: "",
hospitalizationTimeRange: [],
reimburseProject:''
reimburseProject:'',
invoiceDetails: [],
invoiceVerifyEnabled: true
},
historyData: [],
invoiceDialogVisible: false,
invoiceDialogMode: "add",
detailFormIndex: -1,
lastRecognizedFileId: "",
recognizingInvoice: false,
detailForm: {
invoiceFiles: [],
invoiceNo: "",
invoiceAmount: null,
sellerName: "",
itemName: "",
remark: "",
invoiceCode: "",
invoiceDate: "",
invoiceCheckCode: ""
},
condolenceWays: [
{label: "慰问金(A", value: "慰问金(A"},
{label: "提货券(B", value: "提货券(B"},
@@ -492,7 +700,10 @@ layout("/layouts/platform.html"){
paymentNotes: [{required: true, message: "请填写支付内容", trigger: ["change", "blur"]}],
activityName: [{required: true, message: "请填写活动名称", trigger: ["change", "blur"]}],
money: [{required: true, message: "请填写报销金额", trigger: ["change", "blur"]}],
mobile: [{required: true, message: "请填写联系方式", trigger: ["change", "blur"]}],
mobile: [
{required: true, message: "请填写联系方式", trigger: ["change", "blur"]},
{pattern: /^(1[3-9]\d{9}|0\d{2,3}-?\d{7,8})$/, message: "请输入正确的联系方式", trigger: "blur"}
],
files: [{required: true, message: "请上传附件", trigger: ["change", "blur"]}],
userSign: [{required: true, message: "请签名", trigger: ["change", "blur"]}],
// certifierUserId: [{required: true, message: "请填写认证人", trigger: ["change", "blur"]}],
@@ -508,6 +719,13 @@ layout("/layouts/platform.html"){
activityTime: [{required: true, message: "请选择活动时间", trigger: ["change", "blur"]}],
activityNumber: [{required: true, message: "请输入活动人数", trigger: ["change", "blur"]}]
},
detailRules: {
invoiceFiles: [{required: true, message: "请上传发票文件", trigger: ["change", "blur"]}],
invoiceNo: [{required: true, message: "请输入发票号码", trigger: ["change", "blur"]}],
invoiceAmount: [{required: true, message: "请输入发票金额", trigger: ["change", "blur"]}],
sellerName: [{required: true, message: "请输入销售方信息名称", trigger: ["change", "blur"]}],
itemName: [{required: true, message: "请输入项目名称", trigger: ["change", "blur"]}]
},
chooseType: {},
userOptions: [],
typeOptions: [],
@@ -519,7 +737,37 @@ layout("/layouts/platform.html"){
payerOptions: []
}
},
computed: {
showInvoiceTab() {
return this.formData.reimburseProject !== "UNION_REIMBURSE_PROJECT_1"
},
bankHistoryUserNames() {
const userNameMap = {}
return (this.historyData || []).reduce((result, item) => {
if (item.bankUserName && !userNameMap[item.bankUserName]) {
userNameMap[item.bankUserName] = true
result.push(item.bankUserName)
}
return result
}, [])
}
},
watch: {
"detailForm.invoiceFiles": {
handler(newVal) {
const file = newVal && newVal.length ? newVal[0] : null
const currentFileId = this.getInvoiceFileId(file)
if (!currentFileId) {
this.lastRecognizedFileId = ""
return
}
if (currentFileId === this.lastRecognizedFileId) {
return
}
this.recognizeCurrentInvoice(false)
},
deep: true
},
"formData.hospitalizationTimeRange"(newVal) {
if (newVal && newVal.length === 2) {
this.$set(this.formData, "hospitalizationStartTime", newVal[0]);
@@ -543,12 +791,38 @@ layout("/layouts/platform.html"){
}
},
methods: {
buildDefaultDetailForm() {
return {
invoiceFiles: [],
invoiceNo: "",
invoiceAmount: null,
sellerName: "",
itemName: "",
remark: "",
invoiceCode: "",
invoiceDate: "",
invoiceCheckCode: ""
}
},
ensureFormData(formData) {
const nextFormData = formData || {}
if (!Array.isArray(nextFormData.invoiceDetails)) {
this.$set(nextFormData, "invoiceDetails", [])
}
if (!Array.isArray(nextFormData.files)) {
this.$set(nextFormData, "files", [])
}
if (typeof nextFormData.invoiceVerifyEnabled !== "boolean") {
this.$set(nextFormData, "invoiceVerifyEnabled", true)
}
return nextFormData
},
createRemoteMethodForPayer(keyword) {
this.selectQueryUserForPayer(keyword, this.payerOptions)
},
selectQueryUserForPayer(keyword, options) {
options.length = 0
this.$axios.post("/platform/UnionReimburse/apply/listUser", {keyword: keyword}).then((res) => {
this.$axios.post("/platform/unionReimburse/apply/listUser", {keyword: keyword}).then((res) => {
if (res.code === 0) {
options.push(...res.data)
}
@@ -585,10 +859,44 @@ layout("/layouts/platform.html"){
}
})
},
fillBankInfoFromHistory() {
const matchItem = this.historyData.find((item) => {
if (this.formData.bankUserName && item.bankUserName !== this.formData.bankUserName) {
return false
}
if (this.formData.bankCardNumber && item.bankCardNumber !== this.formData.bankCardNumber) {
return false
}
if (this.formData.bankOfDeposit && item.bankOfDeposit !== this.formData.bankOfDeposit) {
return false
}
return true
})
if (matchItem) {
this.$set(this.formData, "bankUserName", matchItem.bankUserName)
this.$set(this.formData, "bankCardNumber", matchItem.bankCardNumber)
this.$set(this.formData, "bankOfDeposit", matchItem.bankOfDeposit)
}
},
handleBankUserNameChange(value) {
const matchItem = this.historyData.find((item) => item.bankUserName === value)
if (matchItem) {
this.$set(this.formData, "bankCardNumber", matchItem.bankCardNumber)
this.$set(this.formData, "bankOfDeposit", matchItem.bankOfDeposit)
}
},
handleVerifySwitchChange(value) {
this.$set(this.formData, "invoiceVerifyEnabled", !!value)
if (value && this.invoiceDialogVisible) {
this.recognizeCurrentInvoice(true)
}
},
async payerUserChange(){
if (this.formData.payer) {
await this.getUserBankHistory();
} else {
this.historyData = []
}
const user = this.payerOptions.find(o => o.id === this.formData.payer)
if (user) {
@@ -637,6 +945,253 @@ layout("/layouts/platform.html"){
this.$set(this.formData, "typeName", name)
}
},
handleReimburseProjectChange(value) {
if (value === "UNION_REIMBURSE_PROJECT_1") {
this.$set(this, "activeTabName", "basic")
this.$set(this.formData, "invoiceDetails", [])
this.$set(this.formData, "invoiceNumber", "")
this.$set(this.formData, "money", null)
} else {
this.rebuildInvoiceSummary()
}
},
openInvoiceDialog(mode, row, index) {
this.invoiceDialogMode = mode
this.detailFormIndex = typeof index === "number" ? index : -1
this.lastRecognizedFileId = ""
if (mode === "edit" && row) {
this.$set(this, "detailForm", JSON.parse(JSON.stringify(row)))
} else {
this.$set(this, "detailForm", this.buildDefaultDetailForm())
}
this.invoiceDialogVisible = true
this.$nextTick(() => {
if (this.$refs.invoiceDetailForm) {
this.$refs.invoiceDetailForm.clearValidate()
}
})
},
getInvoiceFile(row) {
if (!row || !row.invoiceFiles || row.invoiceFiles.length === 0) {
return null
}
return row.invoiceFiles[0]
},
/**
* 兼容上传组件返回完整对象、历史地址回显等多种场景,统一提取文件 id 给识别接口使用。
*/
getInvoiceFileId(file) {
if (!file) {
return ""
}
if (file.id) {
return file.id
}
if (file.response && file.response.data) {
if (typeof file.response.data === "string") {
const data = file.response.data
const idIndex = data.indexOf("id=")
if (idIndex > -1) {
return data.substring(idIndex + 3)
}
return data
}
if (file.response.data.id) {
return file.response.data.id
}
}
if (file.downloadPath && typeof file.downloadPath === "string") {
const downloadPath = file.downloadPath
const idIndex = downloadPath.indexOf("id=")
if (idIndex > -1) {
return downloadPath.substring(idIndex + 3)
}
}
if (file.url && typeof file.url === "string") {
const url = file.url
const idIndex = url.indexOf("id=")
if (idIndex > -1) {
return url.substring(idIndex + 3)
}
}
return ""
},
previewInvoiceFile(row) {
const file = this.getInvoiceFile(row)
const fileId = this.getInvoiceFileId(file)
if (!fileId) {
this.$message.warning("暂无发票文件")
return
}
window.open("/platform/sys/file/download?id=" + fileId)
},
recognizeCurrentInvoice(showLoading) {
const invoiceFile = this.getInvoiceFile(this.detailForm)
const invoiceFileId = this.getInvoiceFileId(invoiceFile)
if (!invoiceFileId) {
return Promise.resolve()
}
this.lastRecognizedFileId = invoiceFileId
this.recognizingInvoice = !!showLoading
return this.$axios.get("/platform/unionReimburse/apply/recognizeInvoice", {
params: {
fileId: invoiceFileId,
verifySwitch: this.formData.invoiceVerifyEnabled
}
}).then((resp) => {
if (resp.code !== 0) {
this.$message.warning(resp.msg)
return false
}
const data = resp.data || {}
if (data.invoiceNo) {
this.$set(this.detailForm, "invoiceNo", data.invoiceNo)
}
if (data.invoiceAmount !== null && data.invoiceAmount !== undefined && data.invoiceAmount !== "") {
this.$set(this.detailForm, "invoiceAmount", Number(data.invoiceAmount))
}
if (data.sellerName) {
this.$set(this.detailForm, "sellerName", data.sellerName)
}
if (data.itemName) {
this.$set(this.detailForm, "itemName", data.itemName)
}
if (data.invoiceCode) {
this.$set(this.detailForm, "invoiceCode", data.invoiceCode)
}
if (data.invoiceDate) {
this.$set(this.detailForm, "invoiceDate", data.invoiceDate)
}
if (data.invoiceCheckCode) {
this.$set(this.detailForm, "invoiceCheckCode", data.invoiceCheckCode)
}
if (this.detailForm.invoiceNo) {
return this.validateInvoiceDuplicateBeforeSave()
}
return true
}).catch((error) => {
const errorMsg = error && error.response && error.response.data && error.response.data.msg
? error.response.data.msg
: (error && error.msg ? error.msg : "发票识别请求失败,请稍后重试")
this.$message.error(errorMsg)
return false
}).finally(() => {
this.recognizingInvoice = false
})
},
async validateInvoiceDuplicateBeforeSave() {
const invoiceNo = this.detailForm.invoiceNo ? String(this.detailForm.invoiceNo).trim() : ""
if (!invoiceNo) {
return false
}
const duplicateRows = []
const invoiceDetails = this.formData.invoiceDetails || []
for (let i = 0; i < invoiceDetails.length; i++) {
if (this.detailFormIndex > -1 && i === this.detailFormIndex) {
continue
}
const currentNo = invoiceDetails[i].invoiceNo ? String(invoiceDetails[i].invoiceNo).trim() : ""
if (currentNo && currentNo === invoiceNo) {
duplicateRows.push(i + 1)
}
}
if (duplicateRows.length > 0) {
this.$message.warning("发票号码【" + invoiceNo + "】与本次提交的第" + duplicateRows.join("、") + "条发票重复,不能保存")
return false
}
const resp = await this.$axios.get("/platform/unionReimburse/apply/checkInvoiceDuplicate", {
params: {
invoiceNo: invoiceNo,
reimburseId: this.formData.id || ""
}
})
if (resp.code !== 0) {
this.$message.warning(resp.msg)
return false
}
return true
},
async saveInvoiceDetail() {
this.$refs.invoiceDetailForm.validate(async (valid) => {
if (!valid) {
return
}
const duplicateValid = await this.validateInvoiceDuplicateBeforeSave()
if (!duplicateValid) {
return
}
const detailData = JSON.parse(JSON.stringify(this.detailForm))
if (this.detailFormIndex > -1) {
this.$set(this.formData.invoiceDetails, this.detailFormIndex, detailData)
} else {
this.formData.invoiceDetails.push(detailData)
}
this.rebuildInvoiceSummary()
this.invoiceDialogVisible = false
})
},
removeInvoiceDetail(index) {
this.$confirm("确定删除这条发票明细吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formData.invoiceDetails.splice(index, 1)
this.rebuildInvoiceSummary()
})
},
rebuildInvoiceSummary() {
if (this.formData.reimburseProject === "UNION_REIMBURSE_PROJECT_1") {
return
}
let totalMoney = 0
let fileCount = 0
const invoiceDetails = this.formData.invoiceDetails || []
for (let i = 0; i < invoiceDetails.length; i++) {
if (invoiceDetails[i].invoiceAmount !== null && invoiceDetails[i].invoiceAmount !== undefined && invoiceDetails[i].invoiceAmount !== "") {
totalMoney = totalMoney + Number(invoiceDetails[i].invoiceAmount)
}
if (invoiceDetails[i].invoiceFiles && invoiceDetails[i].invoiceFiles.length > 0) {
fileCount = fileCount + 1
}
}
this.$set(this.formData, "money", totalMoney ? totalMoney.toFixed(2) : "0.00")
this.$set(this.formData, "invoiceNumber", String(fileCount))
},
validateInvoiceDetailsBeforeSubmit() {
if (this.formData.reimburseProject === "UNION_REIMBURSE_PROJECT_1") {
return true
}
const invoiceDetails = this.formData.invoiceDetails || []
if (!invoiceDetails.length) {
this.$message.warning("请至少维护一条发票明细")
return false
}
for (let i = 0; i < invoiceDetails.length; i++) {
const currentDetail = invoiceDetails[i]
if (!currentDetail.invoiceFiles || currentDetail.invoiceFiles.length === 0) {
this.$message.warning("第" + (i + 1) + "条发票明细请上传发票文件")
return false
}
if (!currentDetail.invoiceNo) {
this.$message.warning("第" + (i + 1) + "条发票明细请填写发票号码")
return false
}
if (!currentDetail.invoiceAmount || Number(currentDetail.invoiceAmount) <= 0) {
this.$message.warning("第" + (i + 1) + "条发票明细请填写正确的发票金额")
return false
}
if (!currentDetail.sellerName) {
this.$message.warning("第" + (i + 1) + "条发票明细请填写销售方信息名称")
return false
}
if (!currentDetail.itemName) {
this.$message.warning("第" + (i + 1) + "条发票明细请填写项目名称")
return false
}
}
return true
},
//
// typeChange(id) {
// this.chooseType = this.typeOptions.find(o => o.id === id)
@@ -647,6 +1202,7 @@ layout("/layouts/platform.html"){
// },
// 保存
onSave() {
this.rebuildInvoiceSummary()
this.$confirm("您确定保存吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
@@ -665,6 +1221,12 @@ layout("/layouts/platform.html"){
return new Promise((resolve) => {
this.$refs.formRef.validate((valid) => {
if (valid) {
if (!this.validateInvoiceDetailsBeforeSubmit()) {
this.$set(this, "activeTabName", "invoice")
resolve(false)
return
}
this.rebuildInvoiceSummary()
resolve(true)
} else {
this.$message.warning("请完善必填信息")
@@ -842,14 +1404,15 @@ layout("/layouts/platform.html"){
if (this.bizId) {
this.$axios.post("/platform/unionReimburse/apply/info", {id: this.bizId}).then(async (res) => {
if (res.code === 0) {
this.formData = res.data
this.formData = this.ensureFormData(res.data)
await this.selectQueryUser(this.formData.certifierLoginName, this.userOptions)
this.rebuildInvoiceSummary()
// this.chooseType = this.typeOptions.find(o => o.id === this.formData.type)
}
})
} else {
const {username, loginname, id, unit, union, mobile} = this.$store.state.user
this.formData = {
this.formData = this.ensureFormData({
userName: username,
loginName: loginname,
unitId: unit?.id,
@@ -861,7 +1424,7 @@ layout("/layouts/platform.html"){
paymentWay: 'UNION_REIMBURSE_PAYMENT_WAY_2',
mobile: mobile,
userId: id,
}
})
}
}
},
@@ -12,7 +12,7 @@ layout("/layouts/platform.html"){
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<search-item label="所属工会" v-if="isAdmin">
<el-select v-model="pageForm.unionId" @change="doSearch" style="width: 100%"
placeholder="请选择所属工会" clearable>
<el-option v-for="item in unionOptions"
@@ -22,7 +22,7 @@ layout("/layouts/platform.html"){
></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<search-item label="所属单位" v-if="isAdmin">
<el-select v-model="pageForm.unitId" @change="doSearch" style="width: 100%"
placeholder="请选择所属单位" clearable>
<el-option v-for="item in unitOptions"
@@ -53,10 +53,10 @@ layout("/layouts/platform.html"){
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
<el-table-column prop="loginName" label="经办人工号"></el-table-column>
<el-table-column prop="loginName" label="经办人工号" sortable="custom"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="unionName" label="所属工会"></el-table-column>
<el-table-column prop="unitName" label="所属单位"></el-table-column>
<el-table-column prop="unionName" label="所属工会" sortable="custom"></el-table-column>
<el-table-column prop="unitName" label="所属单位" sortable="custom"></el-table-column>
<el-table-column prop="certifierUserName" label="证明人">
<template slot-scope="{row}">
{{row.certifierUserName}}({{row.certifierLoginName}})
@@ -69,7 +69,7 @@ layout("/layouts/platform.html"){
</dict-tag>
</template>
</el-table-column>
<el-table-column prop="reimburseProject" label="报销项目">
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
<template slot-scope="{row}">
<dict-tag :options="dict.type.UNION_REIMBURSE_PROJECT"
:value="row.reimburseProject">
@@ -77,7 +77,7 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
<el-table-column prop="money" label="金额"></el-table-column>
<el-table-column prop="createTime" label="申请时间"></el-table-column>
<el-table-column prop="createTime" label="申请时间" sortable="custom"></el-table-column>
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
<el-table-column prop="instanceState" label="流程状态">
<template slot-scope="{row}">
@@ -151,6 +151,11 @@ layout("/layouts/platform.html"){
}
}
,
computed: {
isAdmin() {
return this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])
}
},
methods: {
onView(row) {
this.$refs.guava.edit(() => {
@@ -214,10 +219,10 @@ layout("/layouts/platform.html"){
},
created() {
this.pageData()
//工会查询
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
//单位查询
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
if (this.isAdmin) {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
}
}
})
</script>
@@ -12,7 +12,7 @@ layout("/layouts/platform.html"){
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<search-item label="所属工会" v-if="isAdmin">
<el-select v-model="pageForm.unionId" @change="doSearch" style="width: 100%"
placeholder="请选择所属工会" clearable>
<el-option v-for="item in unionOptions"
@@ -22,7 +22,7 @@ layout("/layouts/platform.html"){
></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<search-item label="所属单位" v-if="isAdmin">
<el-select v-model="pageForm.unitId" @change="doSearch" style="width: 100%"
placeholder="请选择所属单位" clearable>
<el-option v-for="item in unitOptions"
@@ -51,12 +51,12 @@ layout("/layouts/platform.html"){
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
<el-table-column prop="loginName" label="经办人工号"></el-table-column>
<el-table-column prop="loginName" label="经办人工号" sortable="custom"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="unionName" label="所属工会"></el-table-column>
<el-table-column prop="unitName" label="所属单位"></el-table-column>
<el-table-column prop="createTime" label="申请时间"></el-table-column>
<el-table-column prop="reimburseProject" label="报销项目">
<el-table-column prop="unionName" label="所属工会" sortable="custom"></el-table-column>
<el-table-column prop="unitName" label="所属单位" sortable="custom"></el-table-column>
<el-table-column prop="createTime" label="申请时间" sortable="custom"></el-table-column>
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
<template slot-scope="{row}">
<span v-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">慰问</span>
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
@@ -85,7 +85,7 @@ layout("/layouts/platform.html"){
<el-table-column label="操作" fixed="right" width="350px">
<template slot-scope="{row}">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="openEdit(row)" size="mini" type="primary">实际金额</el-button>
<el-button v-if="isAdmin" @click="openEdit(row)" size="mini" type="primary">实际金额</el-button>
<el-button v-if="row.stateId == 3" @click="doPrint(row)" size="mini" type="primary">打印</el-button>
<el-button v-if="$auth.hasRole('SYSADMIN')" @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
</template>
@@ -144,6 +144,11 @@ layout("/layouts/platform.html"){
}
}
,
computed: {
isAdmin() {
return this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])
}
},
methods: {
onView(row) {
this.$refs.guava.edit(()=>{
@@ -174,30 +179,32 @@ layout("/layouts/platform.html"){
// 弹窗关闭时的处理
handleDialogClose() {
this.$refs.editForm.resetFields();
if (this.$refs.editForm) {
this.$refs.editForm.resetFields();
}
},
// 保存实际报销金额
saveFinallyMoney() {
this.$refs.editForm.validate(async (valid) => {
this.$refs.editForm.validate((valid) => {
if (valid) {
const resp = await this.$axios.post("/platform/unionReimburse/collect/updateActuallyAmount", {
id: this.editFormData.id,
realMoney: this.editFormData.realMoney
}).then((res) => {
if (res.code === 0) {
this.$message.success('保存成功');
this.editDialogVisible = false;
this.$refs.editForm.resetFields();
this.pageData();
}
})
this.$axios.post("/platform/unionReimburse/collect/updateActuallyAmount", {
id: this.editFormData.id,
realMoney: this.editFormData.realMoney
}).then((res) => {
if (res.code === 0) {
this.$message.success('保存成功');
this.editDialogVisible = false;
this.$refs.editForm.resetFields();
this.pageData();
}
})
}
});
},
exportSkr() {
const {year = '', unionId = '', unitId = '', reimburseProject = ''} = this.pageForm
window.open('/platform/unionReimburse/collect/exportSkr?year=' + year + "&unionId=" + unionId + '&unitId=' + unitId + "&reiItemId=" + reimburseProject)
window.open('/platform/unionReimburse/collect/exportSkr?year=' + year + "&unionId=" + unionId + '&unitId=' + unitId + "&reimburseProject=" + reimburseProject)
},
doPrint(row) {
if (row.reimburseProject != "UNION_REIMBURSE_PROJECT_1") {
@@ -212,10 +219,10 @@ layout("/layouts/platform.html"){
},
created() {
this.pageData()
//工会查询
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
//单位查询
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
if (this.isAdmin) {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
}
}
})
</script>
@@ -12,7 +12,7 @@ layout("/layouts/platform.html"){
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<search-item label="所属工会" v-if="isAdmin">
<el-select v-model="pageForm.unionId" @change="doSearch" style="width: 100%"
placeholder="请选择所属工会" clearable>
<el-option v-for="item in unionOptions"
@@ -22,7 +22,7 @@ layout("/layouts/platform.html"){
></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<search-item label="所属单位" v-if="isAdmin">
<el-select v-model="pageForm.unitId" @change="doSearch" style="width: 100%"
placeholder="请选择所属单位" clearable>
<el-option v-for="item in unitOptions"
@@ -48,12 +48,12 @@ layout("/layouts/platform.html"){
<table-tool></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
<el-table-column prop="loginName" label="经办人工号"></el-table-column>
<el-table-column prop="loginName" label="经办人工号" sortable="custom"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="unionName" label="所属工会"></el-table-column>
<el-table-column prop="unitName" label="所属单位"></el-table-column>
<el-table-column prop="createTime" label="申请时间"></el-table-column>
<el-table-column prop="reimburseProject" label="报销项目">
<el-table-column prop="unionName" label="所属工会" sortable="custom"></el-table-column>
<el-table-column prop="unitName" label="所属单位" sortable="custom"></el-table-column>
<el-table-column prop="createTime" label="申请时间" sortable="custom"></el-table-column>
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
<template slot-scope="{row}">
<span v-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">慰问</span>
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
@@ -119,6 +119,11 @@ layout("/layouts/platform.html"){
}
}
,
computed: {
isAdmin() {
return this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])
}
},
methods: {
onView(row) {
this.$refs.guava.view(() => {
@@ -177,10 +182,10 @@ layout("/layouts/platform.html"){
},
created() {
this.pageData()
//工会查询
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
//单位查询
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
if (this.isAdmin) {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
}
}
})
</script>
@@ -12,7 +12,7 @@ layout("/layouts/platform.html"){
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<search-item label="所属工会" v-if="isAdmin">
<el-select v-model="pageForm.unionId" @change="doSearch" style="width: 100%"
placeholder="请选择所属工会" clearable>
<el-option v-for="item in unionOptions"
@@ -22,7 +22,7 @@ layout("/layouts/platform.html"){
></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<search-item label="所属单位" v-if="isAdmin">
<el-select v-model="pageForm.unitId" @change="doSearch" style="width: 100%"
placeholder="请选择所属单位" clearable>
<el-option v-for="item in unitOptions"
@@ -46,7 +46,7 @@ layout("/layouts/platform.html"){
</el-card>
<el-card shadow="never">
<table-tool>
<el-button @click="AllReview" size="medium" type="primary">一键审核</el-button>
<el-button @click="AllReview" size="small" type="primary">一键审核</el-button>
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
<el-radio-button :label="true">已审核</el-radio-button>
<el-radio-button :label="false">未审核</el-radio-button>
@@ -54,12 +54,12 @@ layout("/layouts/platform.html"){
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
<el-table-column prop="loginName" label="经办人工号"></el-table-column>
<el-table-column prop="loginName" label="经办人工号" sortable="custom"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="unionName" label="所属工会"></el-table-column>
<el-table-column prop="unitName" label="所属单位"></el-table-column>
<el-table-column prop="createTime" label="申请时间"></el-table-column>
<el-table-column prop="reimburseProject" label="报销项目">
<el-table-column prop="unionName" label="所属工会" sortable="custom"></el-table-column>
<el-table-column prop="unitName" label="所属单位" sortable="custom"></el-table-column>
<el-table-column prop="createTime" label="申请时间" sortable="custom"></el-table-column>
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
<template slot-scope="{row}">
<span v-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">慰问</span>
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
@@ -70,8 +70,9 @@ layout("/layouts/platform.html"){
</el-table-column>
<el-table-column label="备注">
<template slot-scope="{row}">
<span v-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
被慰问人:{{ row.condolenceUserName }}</span>
<span v-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
被慰问人:{{ row.condolenceUserName }}
</span>
<span v-else>活动名称:{{ row.activityName }}</span>
</template>
</el-table-column>
@@ -88,8 +89,7 @@ layout("/layouts/platform.html"){
<el-table-column label="操作" fixed="right" width="300px">
<template slot-scope="{row}">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.stateId == 2" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.stateId == 2" @click="openAudit(row)" size="mini" type="primary">审核</el-button>
</template>
</el-table-column>
</el-table>
@@ -125,14 +125,13 @@ layout("/layouts/platform.html"){
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../info.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["UNION_REIMBURSE_TYPE", "UNION_REIMBURSE_PROJECT"],
//分页数据
// 分页数据
mixins: [initTableMixins],
components: {
"union-reimburse-info": unionReimburseInfo
@@ -148,8 +147,12 @@ layout("/layouts/platform.html"){
unionOptions: [],
unitOptions: []
}
}
,
},
computed: {
isAdmin() {
return this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])
}
},
methods: {
onView(row) {
this.$refs.guava.edit(() => {
@@ -159,7 +162,7 @@ layout("/layouts/platform.html"){
},
AllReview() {
this.$confirm('确定所申请都通过线下审核了吗?', '提示', {
this.$confirm('确定所申请都通过线下审核了吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
@@ -168,9 +171,9 @@ layout("/layouts/platform.html"){
if (resp && resp.code === 0) {
this.pageForm.approval = true
this.pageData();
this.$message.success(resp.msg || '一键审核成功');
this.$message.success(resp.msg || '一键审核成功')
} else {
this.$message.error(resp.msg || '一键审核失败');
this.$message.error(resp.msg || '一键审核失败')
}
}).catch(() => {
// 用户取消操作
@@ -209,16 +212,14 @@ layout("/layouts/platform.html"){
})
}
})
},
}
},
created() {
this.pageData()
//工会查询
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
//单位查询
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
if (this.isAdmin) {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
}
}
})
</script>
@@ -12,7 +12,7 @@ layout("/layouts/platform.html"){
<search-item label="姓名/工号">
<el-input placeholder="请输入慰问对象姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<search-item label="所属工会" v-if="isAdmin">
<el-select v-model="pageForm.unionId" @change="doSearch" style="width: 100%"
placeholder="请选择所属工会" clearable>
<el-option v-for="item in unionOptions"
@@ -80,15 +80,15 @@ layout("/layouts/platform.html"){
<span>{{scope.$index+(pageForm.pageNumber - 1) * pageForm.pageSize + 1}} </span>
</template>
</el-table-column>
<el-table-column prop="condolenceLoginName" label="被慰问人工号"></el-table-column>
<el-table-column prop="condolenceLoginName" label="被慰问人工号" sortable="custom"></el-table-column>
<el-table-column prop="condolenceUserName" label="姓名"></el-table-column>
<el-table-column prop="condolenceUnionCode" label="分工会代码"></el-table-column>
<el-table-column prop="condolenceUnionName" label="分工会名称"></el-table-column>
<el-table-column prop="condolenceUnionName" label="分工会名称" sortable="custom"></el-table-column>
<el-table-column prop="typeName" label="慰问类型"></el-table-column>
<el-table-column prop="way" label="慰问方式"></el-table-column>
<el-table-column prop="condolenceMoney" label="慰问金额"></el-table-column>
<el-table-column prop="newCreateTime" label="慰问时间"></el-table-column>
<el-table-column prop="newCondolenceTime" label="录入时间"></el-table-column>
<el-table-column prop="newCreateTime" label="慰问时间" sortable="custom"></el-table-column>
<el-table-column prop="newCondolenceTime" label="录入时间" sortable="custom"></el-table-column>
<el-table-column label="申请状态">
<template slot-scope="{row}">
<span v-if="row.stateId == 1" style="color: #409eff;">待提交</span>
@@ -170,6 +170,11 @@ layout("/layouts/platform.html"){
}
}
,
computed: {
isAdmin() {
return this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])
}
},
methods: {
onView(row) {
this.$refs.guava.edit(()=>{
@@ -294,10 +299,10 @@ layout("/layouts/platform.html"){
created() {
this.pageData()
this.queryCondolenceType()
//工会查询
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
//单位查询
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
if (this.isAdmin) {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
}
this.$nextTick(() => {
setTimeout(() => {
this.getCondolencesType()
@@ -232,7 +232,7 @@ layout("/layouts/platform.html"){
return masterUnitNames || slaveUnitNames
}
if (row.caseFilingResult === "CONFIRM_FILING") {
return [masterUnitNames ? "主办:" + masterUnitNames : "", slaveUnitNames ? "协办:" + slaveUnitNames : ""].filter(function(item) {
return [masterUnitNames ? "主办:" + masterUnitNames : "", slaveUnitNames ? "协办:" + slaveUnitNames : ""].filter(function (item) {
return item
}).join("")
}
@@ -243,7 +243,7 @@ layout("/layouts/platform.html"){
return ""
}
if (Array.isArray(unitNames)) {
return unitNames.filter(function(item) {
return unitNames.filter(function (item) {
return item
}).join("")
}
@@ -363,6 +363,10 @@ layout("/layouts/platform.html"){
})
.then((res) => {
if (res.code === 0) {
res.data.list.map((item) => {
item.brief = removeHTMLTag(item.brief)
item.measures = removeHTMLTag(item.measures)
})
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
@@ -25,9 +25,56 @@ layout("/layouts/platform.html"){
.dimension-pills {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
}
.analysis-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
}
.analysis-toolbar-main {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 12px 18px;
flex: 1;
min-width: 0;
}
.analysis-field {
display: flex;
align-items: center;
gap: 8px;
min-width: 330px;
}
.analysis-field-label {
flex: 0 0 auto;
color: #4b617f;
font-size: 13px;
font-weight: 600;
}
.analysis-field-select {
width: 240px;
}
.analysis-dimension-box {
display: flex;
align-items: center;
gap: 10px;
min-width: 420px;
}
.analysis-view-switch {
flex: 0 0 auto;
}
.dimension-pill {
padding: 3px 10px;
border-radius: 999px;
@@ -36,6 +83,14 @@ layout("/layouts/platform.html"){
background: #edf4ff;
border: 1px solid #cfe1ff;
line-height: 1.4;
cursor: pointer;
transition: all 0.2s;
}
.dimension-pill.is-active {
color: #ffffff;
background: #2f7df6;
border-color: #2f7df6;
}
.analysis-tip {
@@ -112,15 +167,28 @@ layout("/layouts/platform.html"){
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;">
<search @search="doSearch" style="flex:1;">
<search-item label="教代会届次">
<el-select @change="doSearch" clearable filterable placeholder="请选择教代会届次" v-model="pageForm.sessionId">
<div class="analysis-toolbar">
<div class="analysis-toolbar-main">
<div class="analysis-field">
<span class="analysis-field-label">教代会届次</span>
<el-select class="analysis-field-select" @change="doSearch" clearable filterable placeholder="请选择教代会届次" v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
</search>
<el-button size="mini" type="primary" @click="toggleChartView">
</div>
<div class="analysis-dimension-box">
<span class="analysis-field-label">统计维度</span>
<div class="dimension-pills">
<span
class="dimension-pill"
:class="{'is-active': pageForm.dimension === item.value}"
@click="toggleDimension(item.value)"
v-for="item in dimensionOptions"
:key="item.value"
>{{ item.label }}</span>
</div>
</div>
</div>
<el-button class="analysis-view-switch" size="mini" type="primary" @click="toggleChartView">
{{ showChart ? '切换表格展示' : '切换图形化展示' }}
</el-button>
</div>
@@ -133,17 +201,10 @@ layout("/layouts/platform.html"){
<span class="page-title-accent"></span>
<span class="page-title-text">统计数据</span>
</div>
<div class="dimension-pills mt10">
<span class="dimension-pill">提案人单位</span>
<span class="dimension-pill">提案类型</span>
<span class="dimension-pill">代表团</span>
<span class="dimension-pill">立案结果</span>
<span class="dimension-pill">满意度</span>
</div>
</div>
<el-button size="mini" type="primary" @click="exportStatistics">导出统计数据</el-button>
</div>
<el-table :data="statisticsRows" border stripe style="width: 100%">
<el-table :data="statisticsRows" border stripe style="width: 100%" v-loading="tableLoading">
<el-table-column prop="dimension" label="统计维度" width="180"></el-table-column>
<el-table-column prop="itemName" label="分类项" min-width="260" show-overflow-tooltip></el-table-column>
<el-table-column prop="count" label="数量" width="120"></el-table-column>
@@ -159,7 +220,7 @@ layout("/layouts/platform.html"){
</div>
<el-button size="mini" type="primary" @click="exportAnalysis">导出分析数据</el-button>
</div>
<el-table :data="analysisRows" border stripe style="width: 100%">
<el-table :data="analysisRows" border stripe style="width: 100%" v-loading="tableLoading">
<el-table-column prop="dimension" label="统计维度" width="160"></el-table-column>
<el-table-column prop="total" label="总量" width="100"></el-table-column>
<el-table-column prop="categoryCount" label="分类数量" width="120"></el-table-column>
@@ -177,13 +238,6 @@ layout("/layouts/platform.html"){
<span class="page-title-accent"></span>
<span class="page-title-text">图形化统计展示(混合图)</span>
</div>
<div class="mt10">
<span class="keyword-tag">提案人单位</span>
<span class="keyword-tag">提案类型</span>
<span class="keyword-tag">代表团</span>
<span class="keyword-tag">立案结果</span>
<span class="keyword-tag">满意度</span>
</div>
</div>
<div>
<el-button size="mini" type="primary" @click="exportStatistics">导出统计数据</el-button>
@@ -228,11 +282,20 @@ layout("/layouts/platform.html"){
data() {
return {
pageForm: {
sessionId: ""
sessionId: "",
dimension: ""
},
dimensionOptions: [
{label: "提案人单位", value: "提案人单位"},
{label: "提案类型", value: "提案类型"},
{label: "代表团", value: "代表团"},
{label: "立案结果", value: "立案结果"},
{label: "满意度", value: "满意度"}
],
sessionOptions: [],
statisticsRows: [],
analysisRows: [],
tableLoading: false,
showChart: false,
chartMap: {}
}
@@ -276,6 +339,10 @@ layout("/layouts/platform.html"){
isPieDimension(dimension) {
return ["立案结果", "满意度"].includes(dimension)
},
toggleDimension(dimension) {
this.pageForm.dimension = this.pageForm.dimension === dimension ? "" : dimension
this.doSearch()
},
renderCharts() {
this.destroyCharts()
this.chartGroups.forEach(group => {
@@ -343,18 +410,24 @@ layout("/layouts/platform.html"){
this.destroyCharts()
return
}
this.$axios.post(loc() + "/statisticsData", this.pageForm).then((res) => {
if (res.code === 0) {
this.statisticsRows = res.data || []
this.tableLoading = true
Promise.all([
this.$axios.post(loc() + "/statisticsData", this.pageForm),
this.$axios.post(loc() + "/analysisData", this.pageForm)
]).then((resList) => {
const statisticsRes = resList[0]
const analysisRes = resList[1]
if (statisticsRes.code === 0) {
this.statisticsRows = statisticsRes.data || []
if (this.showChart) {
this.$nextTick(() => this.renderCharts())
}
}
})
this.$axios.post(loc() + "/analysisData", this.pageForm).then((res) => {
if (res.code === 0) {
this.analysisRows = res.data || []
if (analysisRes.code === 0) {
this.analysisRows = analysisRes.data || []
}
}).finally(() => {
this.tableLoading = false
})
},
exportStatistics() {
@@ -376,4 +449,4 @@ layout("/layouts/platform.html"){
</script>
<!--#
}
#-->
#-->
@@ -368,7 +368,7 @@ layout("/layouts/platform.html"){
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession", {
orderBy: "asc"
orderBy: "desc"
}).then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
@@ -15,6 +15,11 @@ layout("/layouts/platform.html"){
<el-option :key="item.code" :label="item.name" :value="item.id" v-for="item in underTakeOptions"></el-option>
</el-select>
</search-item>
<search-item label="立案结果">
<el-select clearable filterable placeholder="立案结果" v-model="pageForm.caseFilingResult">
<el-option :key="item.code" :label="item.label" :value="item.code" v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT"></el-option>
</el-select>
</search-item>
</search>
</el-card>
@@ -42,6 +47,7 @@ layout("/layouts/platform.html"){
new Vue({
el: "#app",
dicts: ["PROPOSAL_CASE_FILING_RESULT"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
@@ -12,6 +12,18 @@ layout("/layouts/platform.html"){
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" v-model="pageForm.unionId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -149,11 +161,14 @@ layout("/layouts/platform.html"){
showApprovalForm: false,
replyUnitOptions: [],
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
}
},
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
},
methods: {
openView(row) {
@@ -179,10 +194,40 @@ layout("/layouts/platform.html"){
this.$refs.proposalInfoRef.onOpen(row)
})
},
// 教代会
async meetingChange(val) {
/**
* 教代会切换后需要同步刷新代表团下拉,避免上一届次代表团条件残留。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 根据当前教代会加载代表团筛选项,没有选教代会时代表团下拉置空。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
@@ -190,8 +235,8 @@ layout("/layouts/platform.html"){
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
this.pageData()
}
}
})
@@ -13,6 +13,18 @@ layout("/layouts/platform.html"){
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" v-model="pageForm.unionId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -53,7 +65,7 @@ layout("/layouts/platform.html"){
<el-radio-button :label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" ref="tableRef" row-key="id" style="width: 100%">
<el-table :data="tableData" @sort-change="pageOrder" ref="tableRef" row-key="id" style="width: 100%" v-loading="tableLoading">
<el-table-column type="selection" width="50" fixed="left" v-if="!pageForm.approval"></el-table-column>
<el-table-column label="序号" width="50" type="index" :index="indexMethod"
fixed="left"></el-table-column>
@@ -164,7 +176,7 @@ layout("/layouts/platform.html"){
</template>
<template #public>
<merge ref="mergeRef" @close="$refs.guava.index()"></merge>
<merge ref="mergeRef" @close="handleMergeClose"></merge>
</template>
</guava>
</div>
@@ -210,6 +222,7 @@ layout("/layouts/platform.html"){
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
underTakeOptions: []
}
},
@@ -316,6 +329,22 @@ layout("/layouts/platform.html"){
})
},
/**
* 并案审核完成后由父页面统一收口处理:
* 1. 关闭弹层
* 2. 清空左侧勾选框
* 3. 刷新父列表,避免仍显示审核前数据
*/
handleMergeClose() {
this.$refs.guava.index()
this.$nextTick(() => {
if (this.$refs.tableRef) {
this.$refs.tableRef.clearSelection()
}
})
this.doSearch()
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
@@ -332,11 +361,42 @@ layout("/layouts/platform.html"){
})
},
// 教代会
async meetingChange(val) {
/**
* 教代会切换后重新加载当前届次代表团,并清空旧的代表团筛选条件,
* 避免跨届次继续沿用旧代表团数据。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 代表团下拉按教代会联动查询,没有选教代会时保持空列表。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
@@ -344,6 +404,7 @@ layout("/layouts/platform.html"){
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
@@ -362,6 +423,7 @@ layout("/layouts/platform.html"){
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
this.listUnderTake()
}
})
@@ -180,7 +180,6 @@ const merge = {
if (res.code === 0) {
this.$emit('close')
this.$message.success(res.msg)
this.doSearch()
}
}).finally(() => {
loading.close()
@@ -13,6 +13,18 @@ layout("/layouts/platform.html"){
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" v-model="pageForm.unionId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -205,6 +217,7 @@ layout("/layouts/platform.html"){
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
underTakeOptions: [],
}
},
@@ -373,11 +386,42 @@ layout("/layouts/platform.html"){
})
},
// 教代会
async meetingChange(val) {
/**
* 教代会变更后,按当前届次联动刷新代表团下拉并清空旧值,
* 避免查询条件串到其他届次。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 根据教代会查询代表团列表,未选教代会时不加载代表团数据。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
@@ -385,6 +429,7 @@ layout("/layouts/platform.html"){
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
@@ -403,6 +448,7 @@ layout("/layouts/platform.html"){
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
this.listUnderTake()
}
})
@@ -12,6 +12,18 @@ layout("/layouts/platform.html"){
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" v-model="pageForm.unionId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -109,12 +121,16 @@ layout("/layouts/platform.html"){
pageForm: {
approval: false
},
showApprovalForm: false
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
unionOptions: []
}
},
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
},
methods: {
openView(row) {
@@ -143,12 +159,49 @@ layout("/layouts/platform.html"){
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
/**
* 根据当前教代会加载代表团下拉,切换教代会时同步清空已选代表团,
* 避免把上一届教代会的代表团条件带到当前查询里。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 教代会切换后,先联动刷新代表团下拉,再按新的筛选条件重新查询列表。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (!valid) return
@@ -13,6 +13,18 @@ layout("/layouts/platform.html"){
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" v-model="pageForm.unionId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -147,6 +159,7 @@ layout("/layouts/platform.html"){
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
}
},
methods: {
@@ -242,11 +255,42 @@ layout("/layouts/platform.html"){
})
},
// 教代会
async meetingChange(val) {
/**
* 教代会切换时重新联动查询代表团,并清空上一届次已选代表团,
* 保证列表始终按当前教代会范围查询。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 代表团下拉只展示当前教代会下的数据,未选教代会时保持空列表。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
@@ -254,6 +298,7 @@ layout("/layouts/platform.html"){
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
@@ -263,6 +308,7 @@ layout("/layouts/platform.html"){
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
}
})
</script>
@@ -28,7 +28,8 @@ layout("/layouts/platform.html"){
</el-radio-group>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column label="序号" width="50" type="index" :index="indexMethod"
fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
@@ -54,10 +55,11 @@ layout("/layouts/platform.html"){
<el-table-column label="操作" fixed="right" width="300px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10 || row.count <= 0" @click="openAudit(row)" size="mini" type="primary">附议
<el-button v-if="showSecondAction(row)"
@click="openAudit(row)" size="mini" type="primary">附议
</el-button>
<!-- <el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回-->
<!-- </el-button>-->
<!-- <el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回-->
<!-- </el-button>-->
</template>
</el-table-column>
</el-table>
@@ -68,7 +70,8 @@ layout("/layouts/platform.html"){
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
<!-- {{formData.taskName}}-->
提案附议
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
@@ -77,16 +80,16 @@ layout("/layouts/platform.html"){
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end" v-if="row.taskKey ==='second'">
<el-row type="flex" justify="end" v-if="row.curTaskCode ==='second'">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(20)" size="small" type="danger">不同意</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button>
</el-row>
<el-row type="flex" justify="end" v-else>
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="updateSecond(2)" size="small" type="danger">不同意</el-button>
<el-button @click="updateSecond(1)" size="small" type="primary">同意</el-button>
</el-row>
<el-row type="flex" justify="end" v-else>
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="updateSecond(2)" size="small" type="danger">不同意</el-button>
<el-button @click="updateSecond(1)" size="small" type="primary">同意</el-button>
</el-row>
</div>
</proposal-info>
</template>
@@ -124,6 +127,12 @@ layout("/layouts/platform.html"){
}
},
methods: {
// 附议按钮显示规则:
// 1. 当前任务进行中(taskState=10)时显示
// 2. 当前任务已废弃(taskState=99)时,仅 invite、second、delegation、committee 节点显示
showSecondAction(row) {
return row.taskState === 10 || (row.taskState === 99 && ["invite", "second", "delegation", "preAudit", "committee"].includes(row.taskKey))
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
@@ -131,11 +140,13 @@ layout("/layouts/platform.html"){
})
},
openAudit(row) {
this.row = row
this.row = row
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
proposalId: row.id,
taskActorUserId: row.taskActorUserId,
taskName: row.curTaskName,
tf_opinion: "同意该提案"
}
@@ -151,7 +162,7 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
this.$axios.post("/platform/proposal/seconded/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
@@ -161,27 +172,34 @@ layout("/layouts/platform.html"){
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
this.updateSecond(val, false)
}
})
})
})
},
updateSecond(submitType, flag = true) {
this.$axios.post("/platform/proposal/seconded/updateInfo", {
proposalId: this.row.id,
taskActorUserId: this.row.taskActorUserId,
opinion: this.formData.tf_opinion,
submitType: submitType,
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
if(flag) this.$message.success(res.msg)
this.doSearch()
}
})
},
updateSecond(submitType) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/proposal/seconded/updateInfo", {
proposalId: this.row.id,
taskId: this.row.taskId,
taskActorUserId: this.row.taskActorUserId,
opinion: this.formData.tf_opinion,
submitType: submitType,
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
@@ -144,7 +144,7 @@ layout("/layouts/platform.html"){
</el-button>
<!--历史答复内容只允许超级管理员修改,且只在已审核数据中开放入口。-->
<el-button v-if="pageForm.approval && row.taskState === 20 && $auth.hasRole('SYSADMIN')"
@click="openReplyEdit(row)" size="mini" type="warning">编辑答复
@click="openReplyEdit(row)" size="mini" type="primary">编辑答复
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
@@ -30,7 +30,7 @@ const write = {
<div class="info-box" :class="{ hidden: !isSelected }">
<div class="info-content">
<i class="fa fa-info-circle info-icon"></i>
<!-- <i class="fa fa-info-circle info-icon"></i>-->
<div class="info-text">
<h2 class="info-title" style="font-size: 18px;">推选信息</h2>
<p class="info-desc">您已被预选为{{ sessionName }}代表</p>
@@ -484,7 +484,11 @@ const write = {
}
.header-x .header-right {
display: flex;
align-items: center;
gap: 8px;
color: #64748b;
margin-top: 8px;
}
.notice-panel {
@@ -334,7 +334,7 @@ layout("/layouts/platform.html"){
officialCapacity: [{required: true, message: '请填写职称', trigger: ['blur', 'change']}],
subsidyStandards: [{required: true, message: '请选择困难类型', trigger: ['blur', 'change']}],
reason: [{required: true, message: '请填写申请原因', trigger: ['blur', 'change']}],
// sign: [{required: true, message: '请签字', trigger: ['blur', 'change']}]
sign: [{required: true, message: '请签字', trigger: ['blur', 'change']}]
},
// 替他人申请相关
@@ -49,7 +49,9 @@ layout("/layouts/platform.html"){
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
@selection-change="handleSelectionChange"
ref="table" row-key="id" style="width: 100%">
<el-table-column type="selection" width="45"></el-table-column>
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
@@ -137,7 +139,8 @@ layout("/layouts/platform.html"){
units: [],
formData: {},
showApprovalForm: false
showApprovalForm: false,
selectData: []
}
},
components: {
@@ -160,13 +163,18 @@ layout("/layouts/platform.html"){
this.$message.warning('没有待审核的数据!');
return;
}
const message = '确定要一键审核这 ' + this.tableData.length + ' 条记录吗?';
if (this.selectData.length === 0) {
this.$message.warning('请勾选待审核数据!');
return;
}
const message = '确定要一键审核这 ' + this.selectData.length + ' 条记录吗?';
this.$confirm(message, '批量审核确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.batchApprove(this.tableData);
this.batchApprove(this.selectData);
}).catch(() => {
});
@@ -284,6 +292,9 @@ layout("/layouts/platform.html"){
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
handleSelectionChange: function (val) {
this.selectData = val
},
},
async created() {
this.pageData()
@@ -100,13 +100,14 @@ layout("/layouts/platform.html"){
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "受助人工号", sortable: true },
{ prop: "loginName", label: "受助人工号", sortable: true, width: "125" },
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "proxyUserName", label: "申请人", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "mobile", label: "联系方式", sortable: true },
{ prop: "subsidyStandards", label: "困难类型", sortable: true },
{ prop: "money", label: "实际帮扶金额", sortable: true, width: "135"},
{ prop: "applyTime", label: "申请时间", sortable: true },
{ prop: "applyCount", label: "申请次数", sortable: true },
{ prop: "taskName", label: "当前节点" },
@@ -9,6 +9,10 @@ const APPLY_INFO = {
<el-descriptions-item label="工号">{{viewData.loginname}}</el-descriptions-item>
<el-descriptions-item label="联系方式">{{viewData.mobile}}</el-descriptions-item>
<el-descriptions-item label="性别">{{viewData.sex}}</el-descriptions-item>
<el-descriptions-item label="基金会员类型">
<dict-tag :options="dict.type.AIDFUND_MEMBER_USER_TYPE"
:value="viewData.aidFundMemberUserType"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="入校时间">{{$moment(viewData.arrivalAtSchoolDate).format('YYYY-MM-DD')}}
</el-descriptions-item>
<el-descriptions-item label="所在单位">{{viewData.unitName}}</el-descriptions-item>
@@ -60,6 +60,16 @@ layout("/layouts/platform.html"){
<el-card shadow="never" class="mt10">
<table-tool label="申请记录">
<el-button @click="openBatchAudit"
:disabled="pageForm.approval===true||pageForm.approval==='true'"
size="small"
type="primary">批量审核
</el-button>
<el-button @click="exportApplyRecord"
icon="el-icon-download"
size="small"
type="primary">导出
</el-button>
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.approval">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
@@ -68,6 +78,11 @@ layout("/layouts/platform.html"){
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column
:reserve-selection="true"
type="selection"
width="55">
</el-table-column>
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
@@ -90,19 +105,8 @@ layout("/layouts/platform.html"){
:value="row.aidFundMemberUserType"></dict-tag>
</template>
<template scope="{row}" v-else-if="column.prop=='changeType'">
<template v-if="row.changeType==='AIDFUND_MEMBER_CHANGE_TYPE_ONE'">
<el-tag type="success">
<dict-tag :options="dict.type.AIDFUND_MEMBER_CHANGE_TYPE"
:value="row.changeType"></dict-tag>
</el-tag>
</template>
<template v-else>
<el-tag type="danger">
<dict-tag :options="dict.type.AIDFUND_MEMBER_CHANGE_TYPE"
:value="row.changeType"></dict-tag>
</el-tag>
</template>
<dict-tag :options="dict.type.AIDFUND_MEMBER_CHANGE_TYPE"
:value="row.changeType"></dict-tag>
</template>
<template scope="{row}" v-else-if="column.prop=='money'">
<template v-if="row.changeType==='AIDFUND_MEMBER_CHANGE_TYPE_ONE'">
@@ -124,6 +128,43 @@ layout("/layouts/platform.html"){
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog
:visible.sync="batchAuditVisible"
title="批量审核"
width="40%">
<el-form :model="batchForm" :rules="batchFormRules" label-width="100px" ref="batchFormRef">
<el-form-item label="审核状态" prop="submitType">
<el-radio-group v-model="batchForm.submitType">
<el-radio-button :label="2">拒绝</el-radio-button>
<el-radio-button :label="1">通过</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="审核名单">
<el-table :data="batchAuditTableData" row-key="id" style="width: 100%" max-height="300">
<el-table-column label="姓名" prop="userName" min-width="100"></el-table-column>
<el-table-column label="工号" prop="loginName" min-width="120"></el-table-column>
<el-table-column label="单位" prop="unitName" min-width="140" show-overflow-tooltip></el-table-column>
<el-table-column label="入校时间" prop="arrivalAtSchoolDate" min-width="110"></el-table-column>
<el-table-column label="缴费金额" prop="money" min-width="100"></el-table-column>
</el-table>
</el-form-item>
<el-alert
:closable="false"
class="mb10"
title="批量通过时,将按人员当前入校时间自动提交;缺少入校时间的记录会审核失败。"
type="warning"
v-if="batchForm.submitType===1">
</el-alert>
<el-form-item label="审批意见" prop="tf_opinion">
<user-opinion-textarea v-model="batchForm.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<span class="dialog-footer" slot="footer">
<el-button @click="batchAuditVisible = false">取 消</el-button>
<el-button @click="submitBatchAudit" type="primary">提 交</el-button>
</span>
</el-dialog>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
@@ -202,12 +243,27 @@ layout("/layouts/platform.html"){
{prop: "unitName", label: "所属单位"},
{prop: "unionName", label: "所属工会"},
{prop: "aidFundMemberUserType", label: "基金会员类型"},
{prop: "money", label: "缴费金额"},
{prop: "changeType", label: "变更类型"},
{prop: "applyTime", label: "申请日期"},
{prop: "curTaskName", label: "当前节点"},
{prop: "instanceState", label: "流程状态"}
],
showApprovalForm: false,
batchAuditVisible: false,
batchAuditTableData: [],
batchForm: {
submitType: 1,
tf_opinion: ""
},
batchFormRules: {
submitType: [
{required: true, message: "必填", trigger: ["change", "blur"]}
],
tf_opinion: [
{required: true, message: "必填", trigger: ["change", "blur"]}
]
},
unionOptions: [],
unitOptions: [],
pickerOptions: {
@@ -221,6 +277,91 @@ layout("/layouts/platform.html"){
'info': APPLY_INFO,
},
methods: {
openBatchAudit() {
const selection = this.$refs.table.selection
if (!selection || selection.length === 0) {
this.$message.warning("请先勾选需要审核的记录")
return
}
this.$set(this, "batchForm", {
submitType: 1,
tf_opinion: ""
})
this.$set(this, "batchAuditTableData", selection.map(row => {
return {
id: row.id,
userName: row.userName,
loginName: row.loginName,
unitName: row.unitName,
arrivalAtSchoolDate: row.arrivalAtSchoolDate,
money: row.money
}
}))
this.$set(this, "batchAuditVisible", true)
this.$nextTick(() => {
if (this.$refs.batchFormRef) {
this.$refs.batchFormRef.clearValidate()
}
})
},
submitBatchAudit() {
const selection = this.$refs.table.selection
if (!selection || selection.length === 0) {
this.$message.warning("请先勾选需要审核的记录")
return
}
this.$refs.batchFormRef.validate((valid) => {
if (!valid) {
return
}
let message = "确定要审核这 " + selection.length + " 条记录吗?"
const joinCount = selection.filter(row => row.changeType === "AIDFUND_MEMBER_CHANGE_TYPE_ONE").length
if (this.batchForm.submitType === 1 && joinCount > 0) {
message = "确定要批量通过这 " + selection.length + " 条记录吗?其中有 " + joinCount + " 条加入基金记录将按当前人员入校时间自动审核。"
}
this.$confirm(message, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
const ids = selection.map(row => row.id)
const loading = this.$loading({
lock: true,
text: "正在批量审核...",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
})
this.$axios.post("/platform/medicalMutualAid/aidFund/foundationAudit/batchExecuteTask", {
ids: JSON.stringify(ids),
data: JSON.stringify(this.batchForm)
}).then((res) => {
if (res.code === 0) {
const result = res.data || {}
const successCount = result.successCount || 0
const failCount = result.failCount || 0
const failMessages = result.failMessages || []
if (failCount > 0) {
let failText = failMessages.slice(0, 3).join("")
if (failMessages.length > 3) {
failText = failText + ";其余记录请查看列表后重试"
}
this.$message.warning("批量审核完成:成功 " + successCount + " 条,失败 " + failCount + " 条。" + failText)
} else {
this.$message.success("批量审核完成:成功 " + successCount + " 条")
}
this.$set(this, "batchAuditVisible", false)
this.doSearch()
this.$refs.table.clearSelection()
}
}).finally(() => {
loading.close()
})
})
})
},
exportApplyRecord() {
this.$downLoad("/platform/medicalMutualAid/aidFund/foundationAudit/exportApplyRecord", this.pageForm)
},
getPayMoney() {
this.$axios.post('/platform/medicalMutualAid/aidFund/foundationAudit/getPayMoney', {
arrivalAtSchoolDate: this.formData.arrivalAtSchoolDate,
@@ -56,6 +56,11 @@ layout("/layouts/platform.html"){
批量变更
</el-button>
<el-button @click="exportMemberList" icon="el-icon-download" size="small" type="primary"
v-if="$auth.hasPermission('medicalMutualAid.aidFund.manage')">
导出会员名单
</el-button>
<el-button @click="exportNewMember" icon="el-icon-download" size="small" type="primary"
v-if="$auth.hasPermission('medicalMutualAid.aidFund.manage.exportNewMember')" class="mr10">
导出{{new
@@ -448,6 +453,9 @@ layout("/layouts/platform.html"){
exportNewMember() {
this.$downLoad(loc() + "/exportNewMember")
},
exportMemberList() {
this.$downLoad(loc() + "/exportMemberList", this.pageForm)
},
getYearOptions() {
let year = new Date().getFullYear();
let arr = []
@@ -534,6 +534,7 @@ layout("/layouts/platform.html"){
} else {
await this.createRemoteMethod(this.$store.state.user.id)
this.$set(this.formData, 'sex', this.$store.state.user.sex)
this.$set(this.formData, 'userName', this.$store.state.user.username)
if (this.$store.state.user.birthday) {
this.$set(this.formData, 'age', this.$moment().diff(this.$store.state.user.birthday, 'years'))
}
@@ -216,6 +216,7 @@ layout("/layouts/platform.html"){
}
},
computed: {
//申请费用总额
applyLoveSum() {
const {applySum, loveSubsidyMoney} = this.calcData
@@ -244,6 +245,16 @@ layout("/layouts/platform.html"){
},
},
methods: {
async grantOrIntoChange(key, val) {
if (val === '') {
if (key === 'grants') {
this.calcData.schoolGrants = 0
} else if (key === 'into') {
this.calcData.unionInto = 0
}
}
const resp = await this.$axios.post(loc() + '/setGrantsOrUnionInto', {keys: key, value: val})
},
getSummaries(param) {
const {columns, data} = param
const sums = []
@@ -0,0 +1,418 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.medical-dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: 180px 1fr 1fr;
gap: 20px;
width: 100%;
min-height: calc(100vh - 126px);
box-sizing: border-box;
}
.dashboard-card {
background: #ffffff;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
border: 1px solid #eef1f6;
}
.dashboard-title {
padding: 16px 20px 8px;
font-size: 16px;
font-weight: 600;
color: #333333;
border-bottom: 1px solid #f0f2f5;
flex-shrink: 0;
}
.overview-card {
padding: 20px;
box-sizing: border-box;
justify-content: space-between;
}
.overview-label {
font-size: 14px;
color: #7a7f87;
line-height: 1;
}
.overview-value {
font-size: 34px;
font-weight: 700;
color: #1f6f5f;
line-height: 1.2;
margin-top: 18px;
}
.overview-sub {
font-size: 13px;
color: #949aa3;
line-height: 1.6;
margin-top: auto;
}
.wide-panel {
grid-column: span 2;
min-height: 0;
}
.full-panel {
grid-column: 1 / -1;
min-height: 0;
}
.chart-panel {
min-height: 0;
}
.table-panel {
min-height: 0;
}
.panel-body {
flex: 1;
min-height: 0;
padding: 12px 16px 16px;
}
.chart-box {
width: 100%;
height: 100%;
min-height: 260px;
}
.money-text {
color: #cf6a32;
}
@media (max-width: 1400px) {
.medical-dashboard {
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 180px) auto auto auto;
}
.wide-panel {
grid-column: span 2;
}
.full-panel {
grid-column: 1 / -1;
}
}
@media (max-width: 768px) {
.medical-dashboard {
grid-template-columns: 1fr;
grid-template-rows: repeat(4, 160px) auto auto auto;
gap: 15px;
}
.wide-panel {
grid-column: span 1;
}
.full-panel {
grid-column: span 1;
}
.overview-value {
font-size: 28px;
}
.chart-box {
min-height: 220px;
}
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<div class="medical-dashboard">
<div class="dashboard-card overview-card" v-loading="loading.overview">
<div class="overview-label">基金会员总数</div>
<div class="overview-value">{{ overview.fundMemberCount || 0 }}</div>
<div class="overview-sub">
本年度申请数:{{ overview.currentYearApplyCount || 0 }}
</div>
</div>
<div class="dashboard-card overview-card" v-loading="loading.overview">
<div class="overview-label">重疾 / 普疾申请数</div>
<div class="overview-value">{{ overview.majorDiseaseApplyCount || 0 }} / {{ overview.commonDiseaseApplyCount || 0 }}</div>
<div class="overview-sub">
统计口径:流程已办结
</div>
</div>
<div class="dashboard-card overview-card" v-loading="loading.overview">
<div class="overview-label">补助金额合计</div>
<div class="overview-value money-text">{{ formatMoney(overview.totalSubsidyMoney) }}</div>
<div class="overview-sub">
单位:元
</div>
</div>
<div class="dashboard-card overview-card" v-loading="loading.overview">
<div class="overview-label">爱心基金合计</div>
<div class="overview-value money-text">{{ formatMoney(overview.totalLoveSubsidyMoney) }}</div>
<div class="overview-sub">
单位:元
</div>
</div>
<div class="dashboard-card wide-panel table-panel">
<div class="dashboard-title">各工会医疗互助统计表</div>
<div class="panel-body" v-loading="loading.unionStat">
<el-table
:data="unionTableData"
:header-cell-style="{background:'#FAFAFA'}"
height="100%"
style="width: 100%">
<el-table-column type="index" label="序号" width="70" align="center"></el-table-column>
<el-table-column prop="unionName" label="工会名称" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="applyCount" label="申请数" width="100" align="center"></el-table-column>
<el-table-column label="补助金额" min-width="140" align="right">
<template slot-scope="{row}">
{{ formatMoney(row.subsidyMoney) }}
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="dashboard-card wide-panel chart-panel">
<div class="dashboard-title">在职状态分布</div>
<div class="panel-body" v-loading="loading.userStateStat">
<div id="userStateChart" class="chart-box"></div>
</div>
</div>
<div class="dashboard-card full-panel chart-panel">
<div class="dashboard-title">人员类型统计</div>
<div class="panel-body" v-loading="loading.personTypeStat">
<div id="personTypeChart" class="chart-box"></div>
</div>
</div>
<div class="dashboard-card full-panel">
<div class="dashboard-title">疾病类型统计</div>
<div class="panel-body" v-loading="loading.diseaseTypeStat">
<div id="diseaseTypeChart" class="chart-box"></div>
</div>
</div>
</div>
</guava>
</div>
<script nonce="${cspNonce!}">
const chartMap = {
userStateChart: null,
personTypeChart: null,
diseaseTypeChart: null
}
new Vue({
el: "#app",
data() {
return {
loading: {
overview: false,
unionStat: false,
userStateStat: false,
personTypeStat: false,
diseaseTypeStat: false
},
overview: {
fundMemberCount: 0,
currentYearApplyCount: 0,
majorDiseaseApplyCount: 0,
commonDiseaseApplyCount: 0,
totalSubsidyMoney: 0,
totalLoveSubsidyMoney: 0
},
unionTableData: [],
userStateData: [],
personTypeData: [],
diseaseTypeData: []
}
},
methods: {
formatMoney(value) {
if (value === null || value === undefined || value === "") {
return "0.00"
}
const num = Number(value)
if (isNaN(num)) {
return "0.00"
}
return num.toFixed(2)
},
getOverview() {
this.$set(this.loading, "overview", true)
this.$axios.post("/platform/medicalMutualAid/medical/dashboard/overview").then((res) => {
this.$set(this.loading, "overview", false)
if (res.code === 0) {
this.$set(this, "overview", res.data || {})
} else {
this.$message.warning(res.msg)
}
})
},
getUnionStat() {
this.$set(this.loading, "unionStat", true)
this.$axios.post("/platform/medicalMutualAid/medical/dashboard/unionStat").then((res) => {
this.$set(this.loading, "unionStat", false)
if (res.code === 0) {
const tableData = res.data && res.data.tableData ? res.data.tableData : []
this.$set(this, "unionTableData", tableData)
} else {
this.$message.warning(res.msg)
}
})
},
getUserStateStat() {
this.$set(this.loading, "userStateStat", true)
this.$axios.post("/platform/medicalMutualAid/medical/dashboard/userStateStat").then((res) => {
this.$set(this.loading, "userStateStat", false)
if (res.code === 0) {
this.$set(this, "userStateData", res.data || [])
this.renderUserStateChart()
} else {
this.$message.warning(res.msg)
}
})
},
getPersonTypeStat() {
this.$set(this.loading, "personTypeStat", true)
this.$axios.post("/platform/medicalMutualAid/medical/dashboard/personTypeStat").then((res) => {
this.$set(this.loading, "personTypeStat", false)
if (res.code === 0) {
this.$set(this, "personTypeData", res.data || [])
this.renderPersonTypeChart()
} else {
this.$message.warning(res.msg)
}
})
},
getDiseaseTypeStat() {
this.$set(this.loading, "diseaseTypeStat", true)
this.$axios.post("/platform/medicalMutualAid/medical/dashboard/diseaseTypeStat").then((res) => {
this.$set(this.loading, "diseaseTypeStat", false)
if (res.code === 0) {
this.$set(this, "diseaseTypeData", res.data || [])
this.renderDiseaseTypeChart()
} else {
this.$message.warning(res.msg)
}
})
},
renderUserStateChart() {
if (chartMap.userStateChart) {
chartMap.userStateChart.destroy()
}
chartMap.userStateChart = new G2Plot.Pie("userStateChart", {
data: this.userStateData,
angleField: "applyCount",
colorField: "name",
radius: 0.85,
label: {
type: "outer",
content: "{name} {percentage}"
},
legend: {
position: "bottom"
},
color: ["#1f6f5f", "#f59f45", "#5b8ff9", "#9270ca"]
})
chartMap.userStateChart.render()
},
renderPersonTypeChart() {
if (chartMap.personTypeChart) {
chartMap.personTypeChart.destroy()
}
chartMap.personTypeChart = new G2Plot.Column("personTypeChart", {
data: this.personTypeData,
autoFit: true,
xField: "name",
yField: "applyCount",
color: "#4e8f81",
columnStyle: {
radius: [6, 6, 0, 0]
},
label: {
position: "top",
style: {
fill: "#1f2d3d"
}
},
xAxis: {
label: {
autoHide: true,
autoRotate: false
}
},
meta: {
name: {
alias: "人员类型"
},
applyCount: {
alias: "申请数"
}
}
})
chartMap.personTypeChart.render()
},
renderDiseaseTypeChart() {
if (chartMap.diseaseTypeChart) {
chartMap.diseaseTypeChart.destroy()
}
chartMap.diseaseTypeChart = new G2Plot.Bar("diseaseTypeChart", {
data: this.diseaseTypeData,
autoFit: true,
xField: "applyCount",
yField: "name",
legend: false,
color: "#cf6a32",
barStyle: {
radius: [0, 6, 6, 0]
},
label: {
position: "right",
style: {
fill: "#1f2d3d"
}
},
meta: {
name: {
alias: "疾病类型"
},
applyCount: {
alias: "申请数"
}
}
})
chartMap.diseaseTypeChart.render()
},
initData() {
this.getOverview()
this.getUnionStat()
this.getUserStateStat()
this.getPersonTypeStat()
this.getDiseaseTypeStat()
}
},
mounted() {
this.initData()
}
})
</script>
<!--#
}
#-->
@@ -189,7 +189,7 @@ const MEMBER_CHANGE = {
<!-- <el-descriptions-item></el-descriptions-item>-->
</template>
<el-descriptions-item label="会员状态" :span="1.5">
<el-descriptions-item label="会员状态" >
<el-form-item prop="member">
<el-radio-group v-model="formData.member" size="small">
<el-radio border :label="true">会员</el-radio>
@@ -198,7 +198,7 @@ const MEMBER_CHANGE = {
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="福利会员状态" :span="1.5">
<el-descriptions-item label="福利会员状态">
<el-form-item prop="welfareMember">
<el-radio-group v-model="formData.welfareMember" size="small">
<el-radio border :label="true">福利会员</el-radio>
@@ -206,7 +206,17 @@ const MEMBER_CHANGE = {
</el-radio-group>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="入校时间">
<el-form-item>
<el-date-picker v-model="formData.arrivalAtSchoolDate"
type="date"
placeholder="请选择入校时间"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<template v-if="formData.loginname == $store.state.user.loginname">
<el-descriptions-item label="家庭主要成员" :span="3">
<el-form-item prop="families">
@@ -457,7 +467,8 @@ const MEMBER_CHANGE = {
mobile,
email,
families,
personalData
personalData,
arrivalAtSchoolDate
} = this.user
this.$set(this.formData, "userId", id)
@@ -488,6 +499,7 @@ const MEMBER_CHANGE = {
this.$set(this.formData, "email", email)
this.$set(this.formData, "families", families ? families : [])
this.$set(this.formData, "personalData", personalData)
this.$set(this.formData, "arrivalAtSchoolDate", arrivalAtSchoolDate)
}
}
},
@@ -573,8 +573,8 @@ layout("/layouts/platform.html"){
],
changeTypeData: [],
checkedFields: []
checkedFields: [],
allowChangeFields: []
},
components: {
"member-info": MEMBER_INFO,
@@ -657,6 +657,7 @@ layout("/layouts/platform.html"){
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.changeTypeData = await this.$businessTool.getEnumOptions("MemberChangeType")
this.allowChangeFields = await this.$businessTool.getDictOptions("ALLOW_CHANGE_FIELDS")
},
async flushUnits() {
this.$set(this.pageForm, "unitId", null)
@@ -827,7 +828,7 @@ layout("/layouts/platform.html"){
this.$message.error(resp.msg)
}
this.batchEditLoading = false
}
},
},
computed: {
showColumns() {
@@ -255,7 +255,27 @@
"USER_STATE", "USER_PREPARED_BY_TYPE", "USER_PERSON_TYPE", "USER_MARRIAGE","AIDFUND_MEMBER_USER_TYPE","USER_ATTRIBUTE"],
data() {
return {
formData: {
formData: {},
formRules: {
loginname: [{ required: true, message: '请输入工号', trigger: 'blur' }],
username: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
sex: [{ required: true, message: '请选择性别', trigger: 'change' }],
idCard: [{ required: true, message: '请输入身份证号码', trigger: 'blur' }],
mobile: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
unitId: [{ required: true, message: '请选择工作单位', trigger: 'change' }],
unionId: [{ required: true, message: '请选择所属工会', trigger: 'change' }],
userState: [{ required: true, message: '请选择在职状态', trigger: 'change' }]
},
units: [],
unions: [],
submitLoading: false
}
},
methods: {
getDefaultFormData() {
return {
id: '',
recordId: '',
loginname: '',
username: '',
sex: '男',
@@ -282,23 +302,26 @@
specialty: '',
member: false,
welfareMember: false
},
formRules: {
loginname: [{ required: true, message: '请输入工号', trigger: 'blur' }],
username: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
sex: [{ required: true, message: '请选择性别', trigger: 'change' }],
idCard: [{ required: true, message: '请输入身份证号码', trigger: 'blur' }],
mobile: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
unitId: [{ required: true, message: '请选择工作单位', trigger: 'change' }],
unionId: [{ required: true, message: '请选择所属工会', trigger: 'change' }],
userState: [{ required: true, message: '请选择在职状态', trigger: 'change' }]
},
units: [],
unions: [],
submitLoading: false
}
},
methods: {
}
},
onOpen(params) {
this.formData = this.getDefaultFormData()
if (this.$refs.formRef) {
this.$refs.formRef.resetFields()
}
if (params && params.recordId && params.userId) {
// 编辑时回填当前补录记录,继续复用新增表单。
$.post('/platform/member/info/input/findOne', params).then(res => {
if (res.code === 0 && res.data) {
this.formData = Object.assign(this.getDefaultFormData(), res.data)
this.formData.families = this.formData.families || []
}
})
}
this.$nextTick(() => {
this.$refs.formRef && this.$refs.formRef.clearValidate()
})
},
async initUnits() {
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
this.units = await this.$businessTool.listUnit()
@@ -325,10 +348,10 @@
type: "warning"
}).then(() => {
const loading = createLoading()
this.$axios.post('/platform/member/info/input/add', this.formData).then(res => {
const submitUrl = this.formData.recordId ? '/platform/member/info/input/update' : '/platform/member/info/input/add'
this.$axios.post(submitUrl, this.formData).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
commonUtil.pjaxPush("/platform/member/info/input")
}
}).finally(() => {
loading.close()
@@ -338,11 +361,12 @@
},
handleCancel() {
this.$refs.formRef.resetFields()
this.formData.families = []
this.formData = this.getDefaultFormData()
this.$parent.$parent.close()
}
},
created() {
this.formData = this.getDefaultFormData()
this.initUnits()
}
}
@@ -19,9 +19,9 @@ layout("/layouts/platform.html"){
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="模糊查询">
<member-cnd @cnd="(v)=>pageForm={...pageForm,...v}"></member-cnd>
</search-item>
<!-- <search-item label="模糊查询">-->
<!-- <member-cnd @cnd="(v)=>pageForm={...pageForm,...v}"></member-cnd>-->
<!-- </search-item>-->
<search-item label="所属工会">
<el-select
@change="flushUnits"
@@ -78,9 +78,10 @@ layout("/layouts/platform.html"){
:prop="column.prop"
:sortable="column.sortable"
></el-table-column>
<el-table-column label="操作" width="150px">
<el-table-column label="操作" width="220px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini">查看</el-button>
<el-button @click="openEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="doDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
@@ -111,7 +112,7 @@ layout("/layouts/platform.html"){
data() {
return {
pageForm: {
year: new Date().getFullYear() - 1 + "",
year: new Date().getFullYear() + "",
memberSearchName: "",
memberSearchKeyWord: ""
},
@@ -140,7 +141,15 @@ layout("/layouts/platform.html"){
methods: {
openAdd() {
this.$refs.guava.edit(() => {
// 可以在这里初始化表单数据
this.$refs.memberAddFormRef.onOpen()
})
},
openEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.memberAddFormRef.onOpen({
recordId: row.id,
userId: row.userId
})
})
},
handleAddSuccess() {
@@ -48,10 +48,10 @@ layout("/layouts/platform.html"){
<dict-select v-model="pageForm.personType" placeholder="教职工类别" @change="doSearch"
code="USER_PERSON_TYPE"></dict-select>
</search-item>
<search-item label="编制类别">
<dict-select v-model="pageForm.preparedBy" placeholder="编制类别" @change="doSearch"
code="USER_PREPARED_BY_TYPE"></dict-select>
</search-item>
<!-- <search-item label="编制类别">-->
<!-- <dict-select v-model="pageForm.preparedBy" placeholder="编制类别" @change="doSearch"-->
<!-- code="USER_PREPARED_BY_TYPE"></dict-select>-->
<!-- </search-item>-->
<!-- <search-item label="变更类型">-->
<!-- <dict-select v-model="pageForm.changeType" placeholder="变更类型" @change="doSearch"-->
<!-- code="MEMBER_CHANGE_TYPE"></dict-select>-->
@@ -200,7 +200,7 @@ layout("/layouts/platform.html"){
{ prop: "sex", label: "性别", sortable: true, width: "100px" },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "personType", label: "教职工类别", sortable: true },
{ prop: "preparedBy", label: "编制类别", sortable: true },
// { prop: "preparedBy", label: "编制类别", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "changeTypes", label: "变更类型", sortable: true },
@@ -8,7 +8,7 @@ let ADDRESS_DIALOG = {
title="收货地址"
width="30%">
<el-form :model="formData" label-position="right" label-suffix="" label-width="120px" ref="addForm">
<el-form :model="formData" label-position="right" label-suffix="" label-width="120px" ref="addForm" :rules="contactRules">
<el-form-item :rules="{required:true,message: '请选择地址信息', trigger: 'blur'}"
label="地址信息"
prop="addressList">
@@ -41,7 +41,6 @@ let ADDRESS_DIALOG = {
v-model="formData.userName"></el-input>
</el-form-item>
<el-form-item
:rules="{required:true,message: '请填写手机号码', trigger: 'blur'}"
label="手机号码"
prop="tel">
<el-input maxlength="11" placeholder="请填写手机号码"
@@ -60,7 +59,17 @@ let ADDRESS_DIALOG = {
data() {
return {
dzOptions: chengShiList,
dialogVisible: false
dialogVisible: false,
contactRules: {
tel: [
{required: true, message: "请输入联系电话", trigger: "blur"},
{
pattern: /^1[3456789]\d{9}$/,
message: "请输入正确的手机号码",
trigger: "blur"
}
]
},
}
},
methods: {
@@ -88,19 +97,22 @@ let ADDRESS_DIALOG = {
},
doSaveUserAddress() {
this.$refs["addForm"].validate(async (valid) => {
this.$refs["addForm"].validate((valid) => {
if (valid) {
const resp = await this.$axios.post("/platform/welfare/addressManage/doSaveUserAddress", { data: JSON.stringify(this.formData) })
if (resp.code === 0) {
this.$message({
message: resp.msg,
type: "success"
})
this.$emit("select_user_address")
this.dialogVisible = false
} else {
this.$message.error(resp.msg)
}
const savedAddress = Object.assign({}, this.formData)
this.$axios.post("/platform/welfare/addressManage/doSaveUserAddress", { data: JSON.stringify(this.formData) }).then((resp) => {
if (resp.code === 0) {
this.$message({
message: resp.msg,
type: "success"
})
// 保存成功后把最新地址信息回传给父组件,便于父组件刷新后自动选中。
this.$emit("select_user_address", savedAddress)
this.dialogVisible = false
} else {
this.$message.error(resp.msg)
}
})
}
})
},
@@ -375,6 +375,25 @@ const optionSelect = {
}
}
},
// 统一带出地址、收货人和联系电话,避免多个入口重复拼装地址逻辑。
applyAddressSelection(selectedAddress) {
if (!selectedAddress) {
return
}
const addressValue = selectedAddress.province + selectedAddress.city + selectedAddress.county + selectedAddress.addressDetail
this.$set(this.contactForm, "receiveAddress", addressValue)
this.onAddressChange(addressValue)
},
// 首次确认选择时,如果存在默认地址,则自动带出默认地址及联系人信息。
applyDefaultAddressIfNeeded() {
if (this.hasSubmittedBefore || this.contactForm.receiveAddress || !this.addressOptions || this.addressOptions.length === 0) {
return
}
const defaultAddress = this.addressOptions.find((item) => item.isDefault)
if (defaultAddress) {
this.applyAddressSelection(defaultAddress)
}
},
openAddress() {
this.$refs.addressDialog.dialogVisible = true
this.$refs.addressDialog.formData = {userId: this.userId}
@@ -387,7 +406,9 @@ const optionSelect = {
this.selectedRadioId = null
this.contactForm = {
mobile: "",
receiveAddress: ""
receiveAddress: "",
userName: "",
userSign: ""
}
this.getProjectInfo()
@@ -448,6 +469,10 @@ const optionSelect = {
}
})
}
// 首次确认选择且没有历史记录时,尝试自动带出默认收货地址。
if (this.projectInfo.provideMode === 3) {
this.applyDefaultAddressIfNeeded()
}
}
// 地址回显
@@ -606,11 +631,32 @@ const optionSelect = {
},
// 获取收货地址
async getAddress() {
const resp = await this.$axios.post("/platform/welfare/addressManage/selectUserAddress",{userId:this.userId})
if (resp.code === 0) {
this.addressOptions = resp.data
}
getAddress(savedAddress) {
const hasAddressOptions = this.addressOptions && this.addressOptions.length > 0
this.$axios.post("/platform/welfare/addressManage/selectUserAddress", {userId: this.userId}).then((resp) => {
if (resp.code === 0) {
this.addressOptions = resp.data
// 新增地址后,如果原来没有地址或当前未选择地址,则默认带入最新地址并自动回填联系人信息。
if (savedAddress && (!hasAddressOptions || !this.contactForm.receiveAddress)) {
const selectedAddress = this.addressOptions.find((item) => {
return item.id === savedAddress.id ||
(item.province === savedAddress.province &&
item.city === savedAddress.city &&
item.county === savedAddress.county &&
item.addressDetail === savedAddress.addressDetail &&
item.userName === savedAddress.userName &&
item.tel === savedAddress.tel)
})
if (selectedAddress) {
this.applyAddressSelection(selectedAddress)
}
} else {
this.applyDefaultAddressIfNeeded()
}
} else {
this.$message.error(resp.msg)
}
})
},
selectNumChange(index, newValue) {
const option = this.projectInfo.options[index];
@@ -245,6 +245,14 @@ layout("/layouts/platform_h5.html"){
return
}
const selectedOptionIds = subject.userSelectOptionIds || []
const hasSelected = selectedOptionIds.includes(optionId)
// 多选题达到最大可选数量后禁止继续勾选,但允许取消已选项。
if (subject.type === "checkbox" && !hasSelected && subject.maxMulti && subject.maxMulti > 0 && selectedOptionIds.length >= subject.maxMulti) {
this.$toast("本题最多选择" + subject.maxMulti + "项")
return
}
if (subject.type === "radio") {
this.$refs["subject" + subject.id][0].toggleAll(false)
}
@@ -11,7 +11,7 @@ layout("/layouts/platform_h5.html"){
@search="doSearch"
input-align="left"
placeholder="请输入经办人搜索"
v-model="pageForm.userName"
v-model="pageForm.searchKeyword"
></van-search>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
@@ -39,21 +39,24 @@ layout("/layouts/platform_h5.html"){
</dict-tag>
</table-column>
<table-column label="金额(元)">{{row.money}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</table-column>
<table-column label="申请状态">
<span v-if="row.stateId == 1" style="color: #409eff;">待提交</span>
<span v-else-if="row.stateId == 2" style="color: #409eff;">待审核确认</span>
<span v-else-if="row.stateId == 3" style="color: #67c23a;">报销成功</span>
<span v-else-if="row.stateId == 4" style="color: #f56c6c;">拒绝</span>
<span v-else-if="row.stateId == 5" style="color: #409eff;">退回</span>
<span v-else>{{row.stateId}}</span>
</table-column>
</template>
<template #actions="{index,row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" v-if="row.taskState === 10" @click="onAudit(row)">
<div class="action-btn" v-if="row.stateId == 2" @click="onAudit(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
@@ -67,10 +70,10 @@ layout("/layouts/platform_h5.html"){
<van-cell-group title="审批意见">
<van-field label=""
:rules="[{ required: true,message:'请填审批意见' }]"
v-model="formData.tf_opinion"
v-model="formData.reviewOpinion"
required
type="textarea"
name="tf_opinion"
name="reviewOpinion"
rows="4"
autosize
class="more-text"
@@ -78,17 +81,16 @@ layout("/layouts/platform_h5.html"){
</van-cell-group>
<van-cell-group title="电子签名" class="form-section">
<van-field class="more-text" name="tf_userSign" label="" required
v-model="formData.tf_opinion" :rules="[{ required: true,message:'请签名' }]">
v-model="formData.reviewOpinion" :rules="[{ required: true,message:'请签名' }]">
<template #input>
<h5-signature v-model="formData.tf_userSign" slot="input"></h5-signature>
</template>
</van-field>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button type="danger" @click="handleTaskAction(6)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(2)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(1)">同意申请</van-button>
<van-button type="danger" @click="handleTaskAction(5)">退回到发起人</van-button>
<van-button type="danger" @click="handleTaskAction(4)">拒绝申请</van-button>
<van-button type="primary" @click="handleTaskAction(3)">同意申请</van-button>
</div>
</van-form>
</div>
@@ -122,33 +124,18 @@ layout("/layouts/platform_h5.html"){
}
},
methods: {
onRevoke(row) {
this.$dialog.confirm({
title: "温馨提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.taskId }).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.doSearch()
this.infoShow = false
}
})
}).catch(() => {
// on cancel
})
},
handleTaskAction(val) {
this.$refs.formRef.validate().then(() => {
this.$dialog.confirm({
title: "温馨提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
this.$axios.post("/platform/unionReimburse/review/reviewTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
id: this.formData.id,
reviewOpinion: this.formData.reviewOpinion
}),
submitType: val
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
@@ -157,7 +144,6 @@ layout("/layouts/platform_h5.html"){
}
})
}).catch(() => {
// on cancel
})
}).catch()
},
@@ -168,10 +154,9 @@ layout("/layouts/platform_h5.html"){
onAudit(row) {
this.showApprovalForm = true
this.formData = {
tf_opinion: null,
tf_userSign: null,
processTaskId: row.taskId,
taskName: row.curTaskName
id: row.id,
reviewOpinion: null,
tf_userSign: null
}
this.$refs.unionReimburseInfoRef.onOpen(row)
},
@@ -38,20 +38,21 @@ layout("/layouts/platform_h5.html"){
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)">
<div class="action-btn" v-if="showSecondAction(row)" @click="onApproval(row)">
<i class="fa fa-edit"></i>
<span>附议</span>
</div>
<!-- <div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">-->
<!-- <i class="fa fa-reply"></i>-->
<!-- <span>撤回</span>-->
<!-- </div>-->
<!-- <div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">-->
<!-- <i class="fa fa-reply"></i>-->
<!-- <span>撤回</span>-->
<!-- </div>-->
</template>
</table-list>
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<div class="process-title">提案附议</div>
<!-- <div class="process-title">{{formData.taskName}}</div>-->
<van-form ref="formRef">
<van-field
v-model="formData.tf_opinion"
@@ -67,10 +68,15 @@ layout("/layouts/platform_h5.html"){
<!-- <h5-signature v-model="formData.approvalSignature" slot="input"></h5-signature>-->
<!-- </van-field>-->
</van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<div v-if="row && row.curTaskCode === 'second'"
style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(20)">不同意</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
</div>
<div v-else style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="updateSecond(2)">不同意</van-button>
<van-button type="primary" block @click="updateSecond(1)">同意</van-button>
</div>
</div>
</proposal-info>
@@ -94,6 +100,7 @@ layout("/layouts/platform_h5.html"){
},
sessionOptions: [],
row: null,
formData: {},
showApprovalForm: false,
rules: {
@@ -105,6 +112,12 @@ layout("/layouts/platform_h5.html"){
"proposal-info": PROPOSAL_INFO
},
methods: {
// 附议按钮显示规则:
// 1. 当前任务进行中(taskState=10)时显示
// 2. 当前任务已废弃(taskState=99)时,仅 invite、second、delegation、committee 节点显示
showSecondAction(row) {
return row.taskState === 10 || (row.taskState === 99 && ["invite", "second", "preAudit", "delegation", "committee"].includes(row.taskKey))
},
onReady() {
this.listSession()
},
@@ -131,10 +144,14 @@ layout("/layouts/platform_h5.html"){
},
onApproval(row) {
this.row = row
this.showApprovalForm = true
this.$refs.proposalInfoRef.onOpen(row)
this.formData = {
processTaskId: row.taskId,
taskId: row.taskId,
proposalId: row.id,
taskActorUserId: row.taskActorUserId,
taskName: row.curTaskName,
tf_opinion: "同意该提案"
}
@@ -147,7 +164,7 @@ layout("/layouts/platform_h5.html"){
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
this.$axios.post("/platform/proposal/seconded/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
@@ -167,6 +184,29 @@ layout("/layouts/platform_h5.html"){
}
},
updateSecond(submitType) {
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/platform/proposal/seconded/updateInfo", {
proposalId: this.formData.proposalId,
taskId: this.formData.taskId,
taskActorUserId: this.formData.taskActorUserId,
opinion: this.formData.tf_opinion,
submitType: submitType,
}).then((res) => {
if (res.code === 0) {
this.$refs.proposalInfoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
@@ -225,7 +225,7 @@ layout("/layouts/platform_h5.html"){
></van-picker>
</van-popup>
<van-field
<!-- <van-field
:value="formData.suggestUnits.length > 0 ? formData.suggestUnits.join(', ') : ''"
is-link
readonly
@@ -235,7 +235,7 @@ layout("/layouts/platform_h5.html"){
@click="showSuggestionUnitPicker = true"
:rules="[{ required: true, message: '请选择建议承办单位' }]"
required
></van-field>
></van-field>-->
<van-popup v-model="showSuggestionUnitPicker" position="bottom" :style="{ height: '70%' }">
<div class="suggestion-unit-picker">
<!-- 头部工具栏 -->
@@ -719,6 +719,8 @@ layout("/layouts/platform_h5.html"){
if (this.bizId) {
this.$axios.post("/platform/proposal/write/detail", {id: this.bizId}).then((res) => {
if (res.code === 0) {
res.data.brief=removeHTMLTag(res.data.brief)
res.data.measures=removeHTMLTag(res.data.measures)
this.formData = res.data;
this.listOpenSession(true);
}
@@ -0,0 +1,235 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app">
<van-sticky>
<van-nav-bar title="帮扶二级党组织审核" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<van-search
v-model="pageForm.searchKeyword"
placeholder="请输入工号或者姓名进行查询"
show-action
:reverse-color="false"
input-align="left"
@search="doSearch">
<template #action>
<div @click="doSearch">搜索</div>
</template>
</van-search>
<van-dropdown-menu
v-if="$auth.hasRoleOr('SYSADMIN,SCHOOL_UNION_ADMIN,BRANCH_UNION_CHAIRMAN')"
:close-on-click-outside="false"
:close-on-click-overlay="false"
>
<van-dropdown-item :options="unionList" @change="unionChange" v-model="pageForm.unionId"></van-dropdown-item>
<van-dropdown-item :options="unitList" @change="doSearch" v-model="pageForm.unitId"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.audit = val==='1';this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/difficultHelp/unionLeaderApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="userName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="受助人">{{row.userName + '(' + row.loginName + ')'}}</table-column>
<table-column label="所属工会">{{row.unionName}}</table-column>
<table-column label="工作单位">{{row.unitName}}</table-column>
<table-column label="困难类型">{{row.subsidyStandards}}</table-column>
<table-column label="填报时间">{{row.applyTime}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</table-column>
</template>
<template #actions="{index,row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)">
<i class="fa fa-check"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">{{formData.taskName}}</div>
<van-form ref="formRef">
<el-form-item label="级别" prop="level" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<search-item>
<dict-select v-model="formData.level" code="DIFFICULT_LEVEL" style="width: 100%" placeholder="请选择级别"></dict-select>
</search-item>
</el-form-item>
<el-form-item label="审核金额" prop="money" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number placeholder="请输入金额" v-model="formData.money" style="width: 100%" :precision="2"
:min="0" ></el-input-number>
</el-form-item>
<van-field
v-model="formData.tf_opinion"
name="tf_opinion"
label="审批意见"
placeholder="请输入审批意见"
:rules="[{ required: true, message: '请填写审批意见' }]"
required
maxlength="100"
show-word-limit
></van-field>
</van-form>
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
<van-button type="danger" block @click="handleTaskAction(2)">拒绝</van-button>
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
</div>
</div>
</info>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
new Vue({
el: '#app',
store,
data() {
return {
pageForm: {
pageNo: 1,
pageSize: 10,
searchKeyword: '',
unionId: '',
unitId: '',
approvalText: "0",
audit: false
},
unionList: [],
unitList: [],
formData: {},
showApprovalForm: false
}
},
components: {
"info": INFO
},
methods: {
historyBack,
onReady() {
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
// 查看详情
onView(row) {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
},
onApproval(row) {
this.showApprovalForm = true
this.$refs.infoRef.onOpen(row)
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
},
async handleTaskAction(val) {
try {
await this.$refs.formRef.validate();
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.infoRef.onClose()
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
} catch (error) {
}
},
// 撤回
onRevoke(row) {
debugger
this.$dialog.confirm({
title: '提示',
message: '您确定要撤回吗?',
}).then(() => {
this.$axios.post('/flow/common/revokeTask', {taskId: row.taskId}).then(res => {
if (res.code === 0) {
this.$toast.success('撤回成功');
this.doSearch();
}
})
}).catch(() => {
});
},
unionChange() {
this.$set(this.pageForm, "unitId", null)
this.flushUnits()
this.doSearch()
},
async initUnion() {
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
const unionId = hasAdmin ? null : this.$store.state.user.union.id
this.unionList = await this.$businessTool.listUnion(unionId)
this.unionList.forEach((v) => {
v.text = v.name
v.value = v.id
})
if (hasAdmin) {
this.unionList.unshift({ text: "全部工会", value: null })
}
if (this.unionList && this.unionList.length > 0) {
this.$set(this.pageForm, "unionId", this.unionList[0].value)
}
},
async flushUnits() {
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
const unionId = hasAdmin ? this.pageForm.unionId : this.$store.state.user.union.id
this.unitList = await this.$businessTool.listUnit(unionId)
this.unitList.forEach((v) => {
v.text = v.name
v.value = v.id
})
this.unitList.unshift({ text: "全部单位", value: null })
if (this.unitList && this.unitList.length > 0) {
this.$set(this.pageForm, "unitId", this.unitList[0].value)
}
},
},
async created() {
await this.initUnion()
await this.flushUnits()
}
})
</script>
<!--#
}
#-->
@@ -29,7 +29,7 @@ layout("/layouts/platform_h5.html"){
<i class="fa fa-mail-forward"></i>
<span>提交</span>
</div>
<div class="action-btn delete" @click="onDelete(row)"
<div class="action-btn delete" @click="onDelete(row.id)"
v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>