# Conflicts:
#	src/main/resources/views/platform/zhgh/staffbenefit/excellentRecuperation/activityList/basicForm.js
This commit is contained in:
2025-09-04 09:46:18 +08:00
336 changed files with 28657 additions and 24235 deletions
@@ -254,7 +254,8 @@ layout("/layouts/v4/baseLayout.html"){
<el-card shadow="never" class="filter-section">
<el-form :inline="true" :model="pageForm" class="search-form">
<el-form-item>
<el-input v-model="pageForm.searchKeyword" placeholder="请输入关键词搜索" prefix-icon="el-icon-search"
<el-input v-model="pageForm.searchKeyword" placeholder="请输入关键词搜索"
prefix-icon="el-icon-search"
clearable></el-input>
</el-form-item>
<el-form-item>
@@ -478,13 +479,13 @@ layout("/layouts/v4/baseLayout.html"){
// 处理任务
async openView(task) {
const {taskId, taskState, instanceId, businessNo} = task
// if (taskState === this.taskStateEnum.DOING) {
// window.open("/flow/common/approval/form?instanceId=" + instanceId + "&taskId=" + taskId + "&businessId=" + businessNo)
// } else {
// window.open("/flow/common/approval/form?instanceId=" + instanceId + "&businessId=" + businessNo)
// }
this.$message.error("功能开发中...")
console.log(task)
const {taskId, taskKey, taskState, instanceId, businessNo, formKey} = task
if (!formKey) {
this.$message.warning("当前流程没有配置地址")
return
}
window.open(formKey + "?taskId=" + taskId + "bizId=" + businessNo + "taskKey=" + taskKey)
},
// 获取空状态文本
@@ -141,6 +141,7 @@
<file-upload :value.sync="formData.files"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
@@ -188,6 +189,12 @@
handleTaskAction(val) {
this.$refs.formRef.validate((valid) => {
if (valid) {
if (this.formData.planDate && this.formData.planDate.length > 0) {
this.formData.planStartTime = this.formData.planDate[0]
this.formData.planEndTime = this.formData.planDate[1]
}
if (!this.instanceId) {
this.handleApply(val)
} else {
@@ -306,6 +313,7 @@
this.findOne(this.businessId)
} else {
const user = this.$store.state.user
this.$set(this.formData, "userId", user.id)
this.$set(this.formData, "userName", user.username)
this.$set(this.formData, "loginName", user.loginname)
this.$set(this.formData, "mobile", user.mobile)
@@ -1,104 +1,179 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-descriptions-item__label.is-bordered-label {
width: 15% !important;
}
.el-descriptions-item__label {
width: 15% !important;
}
</style>
<div id="app">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<snaker-start slot="header" label="活动申报" define_key="HDSB"></snaker-start>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix="" class="flow-task-form">
<el-descriptions :column="2" border>
<el-descriptions-item label="活动名称">
<el-form-item prop="activityName">
<el-input placeholder="请输入内容" style="width: 100%" v-model="formData.activityName">
</el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动类型">
<el-form-item prop="activityType">
<el-select @change="activityTypeChange" placeholder="请选择活动类型"
style="width: 100%" v-model="formData.activityType">
<el-option
:key="item.name"
:label="item.typeName"
:value="item.name"
v-for="item in activityDeclareReimbursementList">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, CLUB_MANAGER, CLUB_PRESIDENT')">
<search-item label="所属协会">
<el-select clearable filterable placeholder="所属协会"
style="width: 100%;" v-model="pageForm.clubId">
<el-option :label="item.clubName" :value="item.id"
v-for="item in clubs"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申报记录">
<el-button size="small" type="primary" @click="onApply">活动申报</el-button>
</table-tool>
<el-descriptions-item label="申请人姓名">
<el-form-item prop="userName">
<el-input disabled type="text" v-model="formData.userName"></el-input>
</el-form-item>
</el-descriptions-item>
<template v-if="formData.activityType == 'CLUB'">
<el-descriptions-item label="申请协会">
<el-form-item prop="clubId" label="申请协会">
<el-select v-model="formData.clubId" placeholder="请选择协会"
@change="setDeclareUnitName" style="width: 100%">
<el-option
v-for="item in clubList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
</template>
<template v-else>
<el-descriptions-item label="申请单位">
<el-form-item prop="declareUnitName">
<el-input readonly v-model="formData.declareUnitName" type="text" placeholder="请选择项目类型,自动填充"></el-input>
</el-form-item>
</el-descriptions-item>
</template>
<el-descriptions-item label="联系方式">
<el-form-item prop="mobile">
<el-input type="text" v-model="formData.mobile" placeholder="请输入联系方式" maxlength="11"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="申请时间">
<el-form-item prop="applyTime">
<el-input disabled type="text" v-model="formData.applyTime"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动计划时间">
<el-form-item prop="planDate">
<el-date-picker
start-placeholder="开始日期"
range-separator="-"
end-placeholder="结束日期"
style="width: 100%"
type="daterange"
v-model="formData.planDate"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动人数">
<el-form-item prop="activityNumber">
<el-input-number v-model="formData.activityNumber" placeholder="请输入活动人数"></el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动地址" :span="2">
<el-form-item prop="activityAddress">
<el-input maxlength="150" placeholder="请填写活动地址" type="text"
v-model="formData.activityAddress"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动预算费用" :span="2">
<el-form-item prop="budgets">
<el-table :data="formData.budgets" border max-height="500" size="mini" style="width: 95%">
<el-table-column label="序号" sortable type="index" width="100"></el-table-column>
<el-table-column label="费用项目名称" prop="name">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.name'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="row.name" maxlength="50"
placeholder="请输入费用项目名称"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="预算费用" prop="budgetPrice">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.budgetPrice'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number placeholder="预算费用" v-model="row.budgetPrice" :precision="2"
style="width: 100%" :min="1"></el-input-number>
</el-form-item>
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作" width="150px">
<template slot="header" slot-scope="scope">
<el-button @click="formData.budgets.push({})" icon="el-icon-plus" type="primary"
size="mini">添加
</el-button>
</template>
<template slot-scope="scope">
<el-button :disabled="formData.budgets.length==1"
@click="formData.budgets.splice(scope.$index,1)"
size="mini"
icon="el-icon-delete"
type="danger"></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动方案及简介" :span="2">
<el-form-item prop="activityContent">
<text-editor v-model="formData.activityContent"></text-editor>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="2">
<el-form-item prop="files">
<file-upload :value.sync="formData.files"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="2">
<el-form-item prop="sign">
<pc-signature v-model="formData.sign"></pc-signature>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220" fixed="right">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">
查看
</el-button>
<el-button v-if="row.taskKey === 'startTask'" @click="onEdit(row)" size="mini" type="primary">
编辑
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">
撤回
</el-button>
<el-button @click="onDelete(row.id)" size="mini" type="danger">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-row type="flex" justify="end" class="mt20">
<el-button type="primary" plain @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" @click="onFinishTask" v-else>提交1</el-button>
</el-row>
</el-card>
</div>
<script>
@@ -108,90 +183,140 @@ layout("/layouts/platform.html"){
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formData: {
id: GetQueryString("businessId"),
planDate: []
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
unions: [],
units: [],
clubs: []
formRules: {
activityName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
activityType: [{required: true, message: '必填', trigger: ['blur', 'change']}],
fundsUnitName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
declareUnitName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
planDate: [{required: true, message: '必填', trigger: ['blur', 'change']}],
budgets: [{required: true, message: '必填', trigger: ['blur', 'change']}],
clubId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
mobile: [{required: true, message: '必填', trigger: ['blur', 'change']}],
sign: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
activityDeclareReimbursementList: [],
clubList: [],
}
},
methods: {
onApply() {
window.open("/flow/common/approval/form?defineKey=HDSB")
},
openView(row) {
window.open("/flow/common/approval/form?instanceId=" + (row.instanceId || "") + "&businessId=" + row.id + "&defineKey=HDSB")
},
onEdit(row) {
window.open(
"/flow/common/approval/form?taskId=" +
(row.taskId || "") +
"&instanceId=" +
(row.instanceId || "") +
"&businessId=" +
row.id +
"&defineKey=HYRH"
)
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
// 保存
onSave() {
this.$confirm("您确定保存吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((resp) => {
this.$message.success(resp.msg)
this.pageData()
})
})
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/activityDeclare/apply/onDelete", { id }).then((res) => {
if (this.formData.planDate && this.formData.planDate.length > 0) {
this.formData.planStartTime = this.formData.planDate[0]
this.formData.planEndTime = this.formData.planDate[1]
}
this.$axios.post('/platform/activityDeclare/apply/save', {data: JSON.stringify(this.formData)}).then(res => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
this.$message.success("保存成功")
window.location.href = '/platform/activityDeclare/mine'
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
// 提交
onSubmit() {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
if (this.formData.planDate && this.formData.planDate.length > 0) {
this.formData.planStartTime = this.formData.planDate[0]
this.formData.planEndTime = this.formData.planDate[1]
}
this.$axios.post('/platform/activityDeclare/apply/submit', {
data: JSON.stringify(this.formData)
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
window.location.href = '/platform/activityDeclare/mine'
}
})
})
},
onFinishTask() {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
if (this.formData.planDate && this.formData.planDate.length > 0) {
this.formData.planStartTime = this.formData.planDate[0]
this.formData.planEndTime = this.formData.planDate[1]
}
this.$axios.post('/platform/activityDeclare/apply/submitAgain', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
window.location.href = '/platform/activityDeclare/mine'
}
})
})
},
// 设置申报主体名称
setDeclareUnitName(val){
const club = this.clubList.find(v => v.id === val)
this.$set(this.formData, "declareUnitName", club ? club.clubName : null)
},
// 申请类型选中
activityTypeChange(val) {
if (val === "SCHOOL_UNION") {
this.$set(this.formData, "declareUnitName", "校工会")
} else if (val === "BRANCH_UNION") {
this.$set(this.formData, "declareUnitName", this.$store.state.user.union.name)
this.$set(this.formData, "unionId", this.$store.state.user.union.id)
}
},
findOne(id) {
this.$axios.post("/platform/activityDeclare/mine/findOne", { id })
.then((res) => {
if (res.code === 0) {
this.formData = res.data
if (res.data.clubId) {
this.setDeclareUnitName(res.data.clubId)
}
if (res.data.planStartTime && res.data.planEndTime) {
this.$set(this.formData, "planDate", [res.data.planStartTime, res.data.planEndTime])
}
} else {
this.$message.error(res.msg)
}
})
},
async init() {
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
if (this.bizId) {
this.findOne(this.bizId)
} else {
const user = this.$store.state.user
this.$set(this.formData, "userId", user.id)
this.$set(this.formData, "userName", user.username)
this.$set(this.formData, "loginName", user.loginname)
this.$set(this.formData, "mobile", user.mobile)
this.$set(this.formData, "applyTime", this.$moment().format("YYYY-MM-DD"))
this.$set(this.formData, "budgets", [])
}
}
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
this.clubs = await this.$businessTool.listClub()
} else {
if (this.$auth.hasRoleOr('CLUB_MANAGER, CLUB_PRESIDENT')) {
this.clubs = await this.$businessTool.listClub()
}
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.init()
}
})
</script>
@@ -0,0 +1,134 @@
<div id="activity_declare_view">
<el-descriptions :column="2" border>
<el-descriptions-item label="活动名称">{{ viewData.activityName }}</el-descriptions-item>
<el-descriptions-item label="活动类型">{{ getActivityTypeName(viewData.activityType) }}</el-descriptions-item>
<el-descriptions-item label="申请人">{{ viewData.userName + '(' + viewData.loginName + ')' }}</el-descriptions-item>
<el-descriptions-item :label="viewData.activityType == 'CLUB' ? '申请协会' : '申请单位'">{{ viewData.declareUnitName }}</el-descriptions-item>
<el-descriptions-item label="联系方式">{{ viewData.mobile }}</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ viewData.applyTime }}</el-descriptions-item>
<el-descriptions-item label="活动计划时间">{{ viewData.planStartTime + ' ~ ' + viewData.planEndTime }}</el-descriptions-item>
<el-descriptions-item label="活动人数">{{ viewData.activityNumber }}</el-descriptions-item>
<el-descriptions-item label="活动地址" :span="2">{{ viewData.activityAddress }}</el-descriptions-item>
<el-descriptions-item label="活动预算费用" :span="2">
<el-table :data="viewData.budgets" border max-height="500" size="mini" style="width: calc(1200px - 150px - 15%)">
<el-table-column label="序号" sortable type="index" width="100"></el-table-column>
<el-table-column label="费用项目名称" prop="name"></el-table-column>
<el-table-column label="预算费用" prop="budgetPrice"></el-table-column>
</el-table>
</el-descriptions-item>
<el-descriptions-item label="活动方案及简介" :span="2">
<div v-html="viewData.activityContent"></div>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="2">
<file-preview v-if="viewData.files && viewData.files.length > 0" :files="viewData.files" complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="2">
<el-image v-if="viewData.sign"
:src="viewData.sign"
class="signature-image"></el-image>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
<div class="task-panel mt10">
<div class="task-panel-header">{{ 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="办理意见" :span="3" v-if="!task.ext.isFirstTaskNode">{{ task.taskFormData.opinion }}</el-descriptions-item>
</el-descriptions>
</div>
</template>
</div>
<script>
new Vue({
el: "#activity_declare_view",
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
businessId: GetQueryString("businessId"),
instanceId: GetQueryString("instanceId"),
viewData: {},
doneTasks: [],
activityDeclareReimbursementList: []
}
},
methods: {
info() {
this.$axios.post("/platform/activityDeclare/mine/findOne", { id: this.businessId }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
// if (res.data.budgets) {
// this.viewData.budgets = JSON.parse(res.data.budgets)
// }
}
})
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", { instanceId: this.instanceId }).then((res) => {
debugger
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.info()
this.getDoneTasks()
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<style>
.task-panel {
background: white;
border-radius: 4px;
overflow: hidden;
}
.task-panel-header {
background: rgb(250, 250, 250);
border: 1px solid rgb(228, 231, 237);
border-bottom: none;
padding: 12px 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
.el-descriptions-item__label.is-bordered-label {
width: 15% !important;
}
.el-descriptions-item__label {
width: 15% !important;
}
</style>
@@ -0,0 +1,49 @@
<div id="activity_declare_branch_union_approval_form">
<el-form :model="formData" ref="formRef" label-width="0" label-suffix="" class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_declare_branch_union_approval_form",
data() {
return {
businessId: GetQueryString("businessId"),
formData: {
tf_opinion: ""
},
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
...this.formData
})
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
}
})
},
handleCancel(val) {
console.log(val)
},
}
})
</script>
@@ -0,0 +1,233 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
activityDeclareReimbursementList: [],
unions: [],
units: [],
clubs: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,49 @@
<div id="activity_declare_club_principal_approval_form">
<el-form :model="formData" ref="formRef" label-width="0" label-suffix="" class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_declare_club_principal_approval_form",
data() {
return {
businessId: GetQueryString("businessId"),
formData: {
tf_opinion: ""
},
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
...this.formData
})
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
}
})
},
handleCancel(val) {
console.log(val)
},
}
})
</script>
@@ -0,0 +1,212 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属协会">
<el-select clearable filterable placeholder="所属协会"
style="width: 100%;" v-model="pageForm.clubId">
<el-option :label="item.clubName" :value="item.id"
v-for="item in clubs"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
activityDeclareReimbursementList: [],
unions: [],
units: [],
clubs: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.clubs = await this.$businessTool.listClub()
} else {
this.clubs = await this.$businessTool.listClub()
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,149 @@
const INFO = {
template: /*language=HTML*/ `
<div>
<div class="process-title">申请信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="活动名称">{{ viewData.activityName }}</el-descriptions-item>
<el-descriptions-item label="活动类型">{{ getActivityTypeName(viewData.activityType) }}
</el-descriptions-item>
<el-descriptions-item label="申请人">{{ viewData.userName + '(' + viewData.loginName + ')' }}
</el-descriptions-item>
<el-descriptions-item :label="viewData.activityType == 'CLUB' ? '申请协会' : '申请单位'">{{
viewData.declareUnitName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">{{ viewData.mobile }}</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ viewData.applyTime }}</el-descriptions-item>
<el-descriptions-item label="活动计划时间">{{ $moment(viewData.planStartTime).format('YYYY-MM-DD') + ' ~ ' + $moment(viewData.planEndTime).format('YYYY-MM-DD') }}
</el-descriptions-item>
<el-descriptions-item label="活动人数">{{ viewData.activityNumber }}</el-descriptions-item>
<el-descriptions-item label="活动地址" :span="2">{{ viewData.activityAddress }}</el-descriptions-item>
<el-descriptions-item label="活动预算费用" :span="2">
<el-table :data="viewData.budgets" border max-height="500" size="mini"
style="width: 95%">
<el-table-column label="序号" sortable type="index" width="100"></el-table-column>
<el-table-column label="费用项目名称" prop="name"></el-table-column>
<el-table-column label="预算费用" prop="budgetPrice"></el-table-column>
</el-table>
</el-descriptions-item>
<el-descriptions-item label="活动方案及简介" :span="2">
<div v-html="viewData.activityContent"></div>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="2">
<file-preview v-if="viewData.files && viewData.files.length > 0" :files="viewData.files"
complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="2">
<el-image v-if="viewData.sign"
:src="viewData.sign"
class="signature-image"></el-image>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
<div class="task-panel 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="办理意见" :span="3" v-if="!task.ext.isFirstTaskNode">{{
task.taskFormData.opinion }}
</el-descriptions-item>
</el-descriptions>
</div>
</template>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
store,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
viewData: {},
doneTasks: [],
row: null,
activityDeclareReimbursementList: []
}
},
methods: {
// 打开
onOpen(row) {
this.row = row
this.info()
this.getDoneTasks()
},
// 获取申请信息
info() {
this.$axios.post("/platform/activityDeclare/mine/findOne", { id: this.row.id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 获取已办任务审批记录
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)
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
},
style: /*language=CSS*/ `
.el-descriptions-item__label.is-bordered-label {
width: 15% !important;
}
.el-descriptions-item__label {
width: 15% !important;
}
`
}
@@ -0,0 +1,217 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, CLUB_MANAGER, CLUB_PRESIDENT')">
<search-item label="所属协会">
<el-select clearable filterable placeholder="所属协会"
style="width: 100%;" v-model="pageForm.clubId">
<el-option :label="item.clubName" :value="item.id"
v-for="item in clubs"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申报记录">
<el-button size="small" type="primary" @click="onApply">活动申报</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<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.taskKey === 'startTask' || !row.instanceId" @click="onEdit(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.taskKey === 'startTask' || !row.instanceId" @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
<el-button v-if="row.instanceState === 20" @click="doExportDeclare(row)" size="mini" type="primary">申请表导出</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
unions: [],
units: [],
clubs: [],
activityDeclareReimbursementList: []
}
},
components: {
'info': INFO
},
methods: {
doExportDeclare(row){
this.$downLoad('/platform/activityDeclare/mine/doExportDeclare?id=' + row.id)
},
onApply() {
window.location.href = '/platform/activityDeclare/apply'
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onEdit(row) {
window.location.href = '/platform/activityDeclare/apply?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((resp) => {
this.$message.success(resp.msg)
this.pageData()
})
})
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/activityDeclare/mine/onDelete", { id }).then((res) => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
console.log(this.$store.state.user)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
this.clubs = await this.$businessTool.listClub()
} else {
if (this.$auth.hasRoleOr('CLUB_MANAGER, CLUB_PRESIDENT')) {
this.clubs = await this.$businessTool.listClub()
}
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,49 @@
<div id="activity_declare_school_principal_approval_form">
<el-form :model="formData" ref="formRef" label-width="0" label-suffix="" class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_declare_school_principal_approval_form",
data() {
return {
businessId: GetQueryString("businessId"),
formData: {
tf_opinion: ""
},
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
...this.formData
})
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
}
})
},
handleCancel(val) {
console.log(val)
},
}
})
</script>
@@ -0,0 +1,233 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
activityDeclareReimbursementList: [],
unions: [],
units: [],
clubs: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,49 @@
<div id="activity_declare_school_union_approval_form">
<el-form :model="formData" ref="formRef" label-width="0" label-suffix="" class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_declare_school_union_approval_form",
data() {
return {
businessId: GetQueryString("businessId"),
formData: {
tf_opinion: ""
},
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
...this.formData
})
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
}
})
},
handleCancel(val) {
console.log(val)
},
}
})
</script>
@@ -0,0 +1,233 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
activityDeclareReimbursementList: [],
unions: [],
units: [],
clubs: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,326 @@
<div id="activity_reimbursement_apply">
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix="" class="flow-task-form">
<el-descriptions :column="2" border>
<el-descriptions-item label="活动名称">
<el-form-item prop="id">
<el-select v-model="formData.id"
style="width: 100%;"
@change="activityChange(formData.id)"
filterable placeholder="请选择活动">
<el-option
v-for="item in activityOptions"
:key="item.id"
:label="item.activityName + '(' + item.declareUnitName + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="相关数据">
<el-button size="small" type="primary">查看申报信息</el-button>
</el-descriptions-item>
<el-descriptions-item label="实际活动时间" :span="2">
<el-form-item prop="activityTime">
<el-date-picker
start-placeholder="开始日期"
range-separator="-"
end-placeholder="结束日期"
style="width: 100%"
type="daterange"
v-model="formData.activityTime"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动预算费用" :span="2">
<el-form-item prop="budgets">
<el-table :data="formData.budgets" border max-height="500" size="mini" style="width: 100%">
<el-table-column label="序号" sortable fixed type="index" width="60"></el-table-column>
<el-table-column label="费用项目名称" fixed prop="name" width="200">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.name'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="row.name" style="width: 100%" maxlength="50"
placeholder="请输入费用项目名称"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="预算费用" prop="budgetPrice" width="250">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.budgetPrice'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number placeholder="预算费用" v-model="row.budgetPrice"
:precision="2" style="width: 100%"
:min="1"></el-input-number>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="实际费用" prop="actualPrice" width="250">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.actualPrice'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number placeholder="请填写实际费用" v-model="row.actualPrice"
:precision="2" style="width: 100%"
:min="0"></el-input-number>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="收款人" prop="payeeId" width="200">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.payeeId'">
<el-input v-model="row.username" maxlength="50"
@input="getCardNumberByPayeeId(row)"
placeholder="请输入收款人"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="支行名称" prop="bankName" width="300">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.bankName'">
<el-input v-model="row.bankName" maxlength="80"
placeholder="请输入支行名称"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="报销卡号" prop="bankCardNum" width="250">
<template scope="{row,$index}">
<el-form-item label-width="0">
<el-input type="number" v-model="row.bankCardNum"
maxlength="50"
placeholder="请输入报销卡号"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" width="400">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.remark'">
<el-input v-model="row.remark" maxlength="200"
placeholder="请输入备注"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column fixed="right" header-align="center" label="操作" width="100">
<template slot="header" slot-scope="scope">
<el-button @click="formData.budgets.push({})" type="primary" size="mini">添加</el-button>
</template>
<template slot-scope="scope">
<el-button :disabled="formData.budgets.length==1"
@click="formData.budgets.splice(scope.$index,1)"
size="mini"
icon="el-icon-delete"
type="danger"></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="发票" :span="2">
<el-form-item prop="billFiles">
<file-upload :value.sync="formData.billFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动报道照片/总结/链接" :span="2">
<el-form-item prop="photoFiles">
<file-upload :value.sync="formData.photoFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="奖品/纪念品/服装/道具等活动人员名单" :span="2">
<el-form-item prop="otherFiles">
<file-upload :value.sync="formData.otherFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="2">
<el-form-item prop="sign">
<pc-signature v-model="formData.sign"></pc-signature>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @save-draft="handleSaveDraft"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_reimbursement_apply",
store,
data() {
return {
businessId: GetQueryString("businessId"),
instanceId: GetQueryString("instanceId"),
formData: {
id: GetQueryString("businessId"),
activityTime: []
},
formRules: {
id: [{required: true, message: "必填", trigger: ['change', 'blur']}]
},
activityOptions: []
}
},
methods: {
// 提交
handleTaskAction(val) {
if (!this.formData.id) {
this.$message.warning("请选择活动后才能保存")
}
this.$refs.formRef.validate((valid) => {
if (valid) {
if (this.formData.activityTime && this.formData.activityTime.length > 0) {
this.formData.startTime = this.formData.activityTime[0]
this.formData.endTime = this.formData.activityTime[1]
}
if (!this.instanceId) {
this.handleApply(val)
} else {
this.handleReApply(val)
}
}
})
},
// 提交申请
handleApply(val) {
this.$confirm("您确定要提交吗?", "提示", { type: "warning" })
.then(() => {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios
.post("/flow/common/startInstanceAndExecute", {
...val,
bizData: JSON.stringify(this.formData)
})
.then((res) => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete"
})
}
})
}
})
})
},
// 重新提交申请
handleReApply(val) {
this.$confirm("您确定要提交吗?", "提示", { type: "warning" })
.then(() => {
this.$axios
.post("/flow/common/executeTask", {
data: JSON.stringify({
processTaskId: val.taskId,
processInstanceId: val.instanceId,
submitType: val.submitType,
f_data: JSON.stringify(this.formData)
})
})
.then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
window.GlobalBroadcastChannel.postMessage({
type: "task-complete"
})
}
})
})
},
// 保存
handleSaveDraft(val) {
this.$confirm("您确定要保存吗?", "提示", { type: "warning" })
.then(() => {
this.$axios
.post("/flow/common/startInstance", {
...val,
bizData: JSON.stringify(this.formData)
})
.then((res) => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.parent.postMessage(
{
type: "task-complete"
},
"*"
)
}
})
})
},
// 取消
handleCancel() {
},
async getCardNumberByPayeeId(row) {
const resp = await $.get('/platform/activityReimbursement/apply/getCardNumberByPayeeId', {username:row.username})
if (resp.code === 0) {
if (resp.data) {
this.$set(row, "bankCardNum", resp.data.bankCardNum)
this.$set(row, "bankName", resp.data.bankName)
}
}
},
async activityChange(id) {
const {code, data} = await $.get('/platform/activityDeclare/mine/findOne', {id: id})
if (code === 0) {
this.formData = {
...this.formData,
...data
}
if (data.planStartTime && data.planEndTime) {
this.formData.activityTime = [
new Date(data.planStartTime),
new Date(data.planEndTime)
]
}
}
},
async getActivityReimbursementByUser() {
const {code, data} = await $.get('/platform/activityReimbursement/apply/getActivityReimbursementByUser');
if (code === 0) {
this.activityOptions = data
}
},
},
async created() {
await this.getActivityReimbursementByUser()
},
})
</script>
<style>
.el-descriptions-item__label {
width: 15% !important;
}
</style>
@@ -0,0 +1,376 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-descriptions-item__label {
width: 15% !important;
}
</style>
<div id="app">
<div>
<el-card shadow="never">
<snaker-start slot="header" label="活动报销" define_key="HDBX"></snaker-start>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix="" class="flow-task-form">
<el-descriptions :column="2" border>
<el-descriptions-item label="活动名称">
<el-form-item prop="declareId">
<el-select v-model="formData.declareId"
style="width: 100%;"
@change="activityChange"
filterable placeholder="请选择活动">
<el-option
v-for="item in activityOptions"
:key="item.id"
:label="item.activityName + '(' + item.declareUnitName + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<template v-if="formData.declareId">
<el-descriptions-item label="相关数据">
<el-button size="small" type="primary" @click="viewDeclare">查看申报信息</el-button>
</el-descriptions-item>
</template>
<template v-else>
<el-descriptions-item></el-descriptions-item>
</template>
<el-descriptions-item label="实际活动时间">
<el-form-item prop="activityTime">
<el-date-picker
start-placeholder="开始日期"
range-separator="-"
end-placeholder="结束日期"
style="width: 100%"
type="daterange"
v-model="formData.activityTime"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动计划时间">
<el-form-item prop="planDate">
<el-date-picker
readonly
start-placeholder="开始日期"
range-separator="-"
end-placeholder="结束日期"
style="width: 100%"
type="daterange"
v-model="formData.planDate"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动预算费用" :span="2">
<el-form-item prop="budgets">
<el-table :data="formData.budgets" border max-height="500" size="mini" style="width: 100%">
<el-table-column label="序号" sortable fixed type="index" width="60"></el-table-column>
<el-table-column label="费用项目名称" fixed prop="name" width="200">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.name'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="row.name" style="width: 100%" maxlength="50"
placeholder="请输入费用项目名称"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="预算费用" prop="budgetPrice" width="250">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.budgetPrice'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number placeholder="预算费用" v-model="row.budgetPrice"
:precision="2" style="width: 100%"
:min="1"></el-input-number>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="实际费用" prop="actualPrice" width="250">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.actualPrice'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number placeholder="请填写实际费用" v-model="row.actualPrice"
:precision="2" style="width: 100%"
:min="0"></el-input-number>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="收款人" prop="payeeId" width="200">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.payeeId'">
<el-input v-model="row.username" maxlength="50"
@input="getCardNumberByPayeeId(row)"
placeholder="请输入收款人"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="支行名称" prop="bankName" width="300">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.bankName'">
<el-input v-model="row.bankName" maxlength="80"
placeholder="请输入支行名称"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="报销卡号" prop="bankCardNum" width="250">
<template scope="{row,$index}">
<el-form-item label-width="0">
<el-input type="number" v-model="row.bankCardNum"
maxlength="50"
placeholder="请输入报销卡号"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" width="400">
<template scope="{row,$index}">
<el-form-item label-width="0"
:prop="'budgets.'+$index+'.remark'">
<el-input v-model="row.remark" maxlength="200"
placeholder="请输入备注"></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column fixed="right" header-align="center" label="操作" width="100">
<template slot="header" slot-scope="scope">
<el-button @click="formData.budgets.push({})" type="primary" size="mini">添加</el-button>
</template>
<template slot-scope="scope">
<el-button :disabled="formData.budgets.length==1"
@click="formData.budgets.splice(scope.$index,1)"
size="mini"
icon="el-icon-delete"
type="danger"></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="发票" :span="2">
<el-form-item prop="billFiles">
<file-upload :value.sync="formData.billFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="活动报道照片/总结/链接" :span="2">
<el-form-item prop="photoFiles">
<file-upload :value.sync="formData.photoFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="奖品/纪念品/服装/道具等活动人员名单" :span="2">
<el-form-item prop="otherFiles">
<file-upload :value.sync="formData.otherFiles"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
accept=".doc, .docx, .xls, .xlsx, .pdf, .ppt, .jpg, .jpeg, .png"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="2">
<el-form-item prop="sign">
<pc-signature v-model="formData.sign"></pc-signature>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<el-row type="flex" justify="end" class="mt20">
<el-button type="primary" plain @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" @click="onFinishTask" v-else>提交1</el-button>
</el-row>
</el-card>
<el-dialog title="申报数据" :visible.sync="declareDialogVisible" width="60%">
<div style="max-height: 68vh;overflow-y: auto">
<info ref="infoRef"></info>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="declareDialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</div>
<script>
<!--#include("../../declare/common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formData: {
id: GetQueryString("businessId"),
activityTime: [],
budgets: [],
planDate: [],
},
formRules: {
id: [{required: true, message: "必填", trigger: ['change', 'blur']}]
},
activityOptions: [],
declareDialogVisible: false
}
},
components: {
"info": INFO,
},
methods: {
// 保存
onSave() {
this.$confirm("您确定保存吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
if (this.formData.activityTime && this.formData.activityTime.length > 0) {
this.formData.startTime = this.formData.activityTime[0]
this.formData.endTime = this.formData.activityTime[1]
}
this.$axios.post('/platform/activityReimbursement/apply/save', {data: JSON.stringify(this.formData)}).then(res => {
if (res.code === 0) {
this.$message.success("保存成功")
window.location.href = '/platform/activityReimbursement/mine'
}
})
})
},
// 提交
onSubmit() {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
if (this.formData.activityTime && this.formData.activityTime.length > 0) {
this.formData.startTime = this.formData.activityTime[0]
this.formData.endTime = this.formData.activityTime[1]
}
this.$axios.post('/platform/activityReimbursement/apply/submit', {
data: JSON.stringify(this.formData)
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
window.location.href = '/platform/activityReimbursement/mine'
}
})
})
},
onFinishTask() {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
if (this.formData.activityTime && this.formData.activityTime.length > 0) {
this.formData.startTime = this.formData.activityTime[0]
this.formData.endTime = this.formData.activityTime[1]
}
this.$axios.post('/platform/activityReimbursement/apply/submitAgain', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
window.location.href = '/platform/activityReimbursement/mine'
}
})
})
},
// 查看申报数据
viewDeclare() {
this.declareDialogVisible = true
this.$nextTick(() => {
this.$refs.infoRef.onOpen({id: this.formData.declareId})
})
},
async getCardNumberByPayeeId(row) {
const resp = await this.$axios.post('/platform/activityReimbursement/apply/getCardNumberByPayeeId', {username:row.username})
if (resp.code === 0) {
if (resp.data) {
this.$set(row, "bankCardNum", resp.data.bankCardNum)
this.$set(row, "bankName", resp.data.bankName)
}
}
},
async activityChange(id) {
const {code, data} = await this.$axios.post('/platform/activityDeclare/mine/findOne', {id: id})
if (code === 0) {
this.formData = {
...this.formData,
...data
}
this.formData.id = this.bizId ? this.bizId : null
if (data.planStartTime && data.planEndTime) {
this.formData.planDate = [data.planStartTime, data.planEndTime]
}
}
},
async getActivityReimbursementByUser(id) {
const {code, data} = await this.$axios.post('/platform/activityReimbursement/apply/getActivityReimbursementByUser',{id});
if (code === 0) {
this.activityOptions = data
}
},
findOne(){
this.$axios.post('/platform/activityReimbursement/mine/findOne', {id: this.bizId})
.then(res => {
if (res.code === 0) {
this.formData = res.data
if (res.data.planStartTime && res.data.planEndTime) {
this.formData.planDate = [res.data.planStartTime, res.data.planEndTime]
}
if (res.data.startTime && res.data.endTime) {
this.formData.activityTime = [res.data.startTime, res.data.endTime]
}
// this.activityChange(res.data.activityId)
}
})
},
},
async created() {
await this.getActivityReimbursementByUser(this.bizId)
if (this.bizId) {
this.findOne()
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,152 @@
<div id="activity_declare_view">
<el-descriptions :column="2" border>
<el-descriptions-item label="活动名称">{{ viewData.activityName }}</el-descriptions-item>
<el-descriptions-item label="活动类型">{{ getActivityTypeName(viewData.activityType) }}</el-descriptions-item>
<el-descriptions-item label="申请人">{{ viewData.userName + '(' + viewData.loginName + ')' }}</el-descriptions-item>
<el-descriptions-item :label="viewData.activityType == 'CLUB' ? '申请协会' : '申请单位'">{{ viewData.declareUnitName }}</el-descriptions-item>
<el-descriptions-item label="联系方式">{{ viewData.mobile }}</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ viewData.applyTime }}</el-descriptions-item>
<el-descriptions-item label="活动计划时间">{{ (viewData.planStartTime ? viewData.planStartTime : '未填写') + ' ~ ' + (viewData.planEndTime ? viewData.planEndTime : '未填写') }}</el-descriptions-item>
<el-descriptions-item label="活动人数">{{ viewData.activityNumber }}</el-descriptions-item>
<el-descriptions-item label="实际活动时间" :span="2">{{ (viewData.startTime ? viewData.startTime : '未填写') + ' ~ ' + (viewData.endTime ? viewData.endTime : '未填写') }}</el-descriptions-item>
<el-descriptions-item label="活动地址" :span="2">{{ viewData.activityAddress }}</el-descriptions-item>
<el-descriptions-item label="活动预算费用" :span="2">
<el-table :data="viewData.budgets" border max-height="500" size="mini" style="width: calc(1200px - 150px - 15%)">
<el-table-column label="序号" sortable type="index" fixed></el-table-column>
<el-table-column label="费用项目名称" fixed prop="name" fixed></el-table-column>
<el-table-column label="预算费用" prop="budgetPrice"></el-table-column>
<el-table-column label="实际费用" prop="actualPrice"></el-table-column>
<el-table-column label="收款人" prop="username"></el-table-column>
<el-table-column label="支行名称" prop="bankName"></el-table-column>
<el-table-column label="报销卡号" prop="bankCardNum"></el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
</el-table>
</el-descriptions-item>
<el-descriptions-item label="活动方案及简介" :span="2">
<div v-html="viewData.activityContent"></div>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="2">
<file-preview v-if="viewData.files && viewData.files.length > 0" :files="viewData.files" complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="发票" :span="2">
<file-preview v-if="viewData.billFiles && viewData.billFiles.length > 0" :files="viewData.billFiles" complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="活动报道照片/总结/链接" :span="2">
<file-preview v-if="viewData.photoFiles && viewData.photoFiles.length > 0" :files="viewData.photoFiles" complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="奖品/纪念品/服装/道具等活动人员名单" :span="2">
<file-preview v-if="viewData.otherFiles && viewData.otherFiles.length > 0" :files="viewData.otherFiles" complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="2">
<el-image v-if="viewData.sign"
:src="viewData.sign"
class="signature-image"></el-image>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
<div class="task-panel mt10">
<div class="task-panel-header">{{ 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="办理意见" :span="3" v-if="!task.ext.isFirstTaskNode">{{ task.taskFormData.opinion }}</el-descriptions-item>
</el-descriptions>
</div>
</template>
</div>
<script>
new Vue({
el: "#activity_declare_view",
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
businessId: GetQueryString("businessId"),
instanceId: GetQueryString("instanceId"),
viewData: {},
doneTasks: [],
activityDeclareReimbursementList: []
}
},
methods: {
info() {
this.$axios.post("/platform/activityReimbursement/apply/findOne", { id: this.businessId }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", { instanceId: this.instanceId }).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.info()
this.getDoneTasks()
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<style>
.task-panel {
background: white;
border-radius: 4px;
overflow: hidden;
}
.task-panel-header {
background: rgb(250, 250, 250);
border: 1px solid rgb(228, 231, 237);
border-bottom: none;
padding: 12px 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
.el-descriptions-item__label.is-bordered-label {
width: 15% !important;
}
.el-descriptions-item__label {
width: 15% !important;
}
</style>
@@ -0,0 +1,572 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.top_block {
width: 100%;
padding: 20px 80px;
border-bottom: 10px solid rgb(240, 240, 240);
}
.top_title {
font-size: 14px;
color: #808492;
height: 30px;
line-height: 30px;
margin-bottom: 5px;
}
.top_num {
font-size: 26px;
}
.cut-off-line {
width: 1px;
height: 70%;
position: absolute;
right: 0;
top: 0;
bottom: 0;
margin: auto;
background-color: rgb(230, 230, 230);
}
.year input {
text-align: center;
}
.chartTitle {
font-size: 14px;
color: #808492;
margin-bottom: 20px;
}
</style>
<div id="app" v-cloak>
<div class="p10">
<el-card shadow="never">
<div class="top_block" v-loading="top_block_loading">
<el-row :gutter="60">
<div style="position: absolute;top: -35px;right: -8px">
<el-date-picker
class="year"
style="width: 120px;"
size="mini"
v-model="numForm.startYear"
type="year" :clearable="false"
value-format="yyyy"
@change="getNumData()"
placeholder="选择年">
</el-date-picker>
-
<el-date-picker
class="year"
style="width: 120px;"
size="mini"
v-model="numForm.endYear"
type="year" :clearable="false"
value-format="yyyy"
@change="getNumData()"
placeholder="选择年">
</el-date-picker>
</div>
<el-col :span="4" style="position: relative">
<div class="top_title">校工会活动总人数</div>
<div class="top_num">{{numData.schoolSignNum?numData.schoolSignNum:'0'}}</div>
<div class="cut-off-line"></div>
</el-col>
<el-col :span="4" style="position: relative">
<div class="top_title">分工会活动总人数</div>
<div class="top_num">{{numData.unionSignNum?numData.unionSignNum:'0'}}</div>
<div class="cut-off-line"></div>
</el-col>
<el-col :span="4" style="position: relative">
<div class="top_title">协会活动总人数</div>
<div class="top_num">{{numData.clubSignNum?numData.clubSignNum:'0'}}</div>
<div class="cut-off-line"></div>
</el-col>
<el-col :span="4" style="position: relative">
<div class="top_title">校工会活动报销费用(元)
</div>
<div class="top_num">{{numData.schoolActivityMoney?numData.schoolActivityMoney:'0'}}</div>
<div class="cut-off-line"></div>
</el-col>
<el-col :span="4" style="position: relative">
<div class="top_title">分工会活动报销费用(元)
</div>
<div class="top_num">{{numData.unionActivityMoney?numData.unionActivityMoney:'0'}}</div>
<div class="cut-off-line"></div>
</el-col>
<el-col :span="4">
<div class="top_title">社团活动报销费用(元)
</div>
<div class="top_num">{{numData.clubActivityMoney?numData.clubActivityMoney:'0'}}</div>
</el-col>
</el-row>
</div>
<el-row style="padding: 30px 0;border-bottom: 10px solid rgb(240, 240, 240)">
<div style="position: absolute;top: 25px;right: 40px;z-index: 200">
<el-date-picker
class="year"
style="width: 120px;"
size="mini"
v-model="activityTypeForm.startYear"
type="year" :clearable="false"
value-format="yyyy"
@change="getActivityTypeChart();getActivityTypePieNum();"
placeholder="选择年">
</el-date-picker>
-
<el-date-picker
class="year"
style="width: 120px;"
size="mini"
v-model="activityTypeForm.endYear"
type="year" :clearable="false"
value-format="yyyy"
@change="getActivityTypeChart();getActivityTypePieNum();"
placeholder="选择年">
</el-date-picker>
</div>
<el-col :span="12" style="padding: 0 20px;"
v-loading="activity_type_loading">
<div class="chartTitle">活动类型</div>
<div id="activityTypeChart" style="width: 100%;height: 330px;"></div>
</el-col>
<el-col :span="12" style="padding: 0 20px;position: relative"
v-loading="activity_type_pie_loading">
<div class="chartTitle">活动类型占比</div>
<div id="activityTypePieChart" style="width: 100%;height: 330px;"></div>
</el-col>
</el-row>
<el-row style="padding: 30px 0;border-bottom: 10px solid rgb(240, 240, 240)">
<div style="position: absolute;top: 25px;right: 40px;z-index: 2000">
<el-date-picker
class="year"
style="width: 120px;"
size="mini"
v-model="activityJfForm.startYear"
type="year" :clearable="false"
value-format="yyyy"
@change="getActivityJfPieNum();getActivityJfChart()"
placeholder="选择年">
</el-date-picker>
-
<el-date-picker
class="year"
style="width: 120px;"
size="mini"
v-model="activityJfForm.endYear"
type="year" :clearable="false"
value-format="yyyy"
@change="getActivityJfPieNum();getActivityJfChart();"
placeholder="选择年">
</el-date-picker>
</div>
<el-col :span="12" style="padding: 0 20px;"
v-loading="activity_jf_loading">
<div class="chartTitle">活动报销费用</div>
<div id="activityJfChart" style="width: 100%;height: 330px;"></div>
</el-col>
<el-col :span="12" style="padding: 0 20px;position: relative"
v-loading="activity_jf_pie_loading">
<div class="chartTitle">活动报销费用占比</div>
<div id="activityJfPieChart" style="width: 100%;height: 330px;"></div>
</el-col>
</el-row>
<el-row style="padding: 30px 0;border-bottom: 10px solid rgb(240, 240, 240)">
<div style="position: absolute;top: 25px;right: 40px;z-index: 999">
<el-date-picker
class="year"
style="width: 120px;"
size="mini"
v-model="allUnionYear"
type="year" :clearable="false"
value-format="yyyy" @change="allUnionActivityAndJf"
placeholder="选择年">
</el-date-picker>
</div>
<el-col :span="24" style="padding: 0 20px"
v-loading="all_union_loading">
<div class="chartTitle" style="margin-bottom: 50px">{{allUnionYear}}年工会报销费用及活动情况
<el-tooltip class="item" effect="dark" :content="'点击切换为' + unionTip " placement="top">
<el-button type="text" icon="el-icon-sort" @click="doUnionSwitch"></el-button>
</el-tooltip>
</div>
<div id="allUnionChart" style="width: 100%;height: 300px;"></div>
</el-col>
</el-row>
<el-row style="padding: 30px 0;border-bottom: 10px solid rgb(240, 240, 240)">
<div style="position: absolute;top: 25px;right: 40px;z-index: 999">
<el-date-picker
class="year"
style="width: 120px;"
size="mini"
v-model="allClubYear"
type="year" :clearable="false"
value-format="yyyy" @change="allClubActivityAndJf"
placeholder="选择年">
</el-date-picker>
</div>
<el-col :span="24" style="padding: 0 20px"
v-loading="all_club_loading">
<div class="chartTitle" style="margin-bottom: 50px">{{allClubYear}}年社团报销费用及活动情况
<el-tooltip class="item" effect="dark" :content="'点击切换为' + clubTip " placement="top">
<el-button type="text" icon="el-icon-sort" @click="doClubSwitch"></el-button>
</el-tooltip>
</div>
<div id="allClubChart" style="width: 100%;height: 300px;"></div>
</el-col>
</el-row>
</el-card>
</div>
</div>
<script>
const vue = new Vue({
el: '#app',
data() {
return {
top_block_loading: false,
numForm: {
startYear: new Date().getFullYear() - 2 + '',
endYear: new Date().getFullYear() + '',
},
numData: {},
activity_type_loading: false,
activity_type_pie_loading: false,
activityTypePieChart: null,
activityTypeForm: {
startYear: new Date().getFullYear() - 2 + '',
endYear: new Date().getFullYear() + '',
},
activity_jf_loading: false,
activity_jf_pie_loading: false,
activityJfPieChart: null,
activityJfForm: {
startYear: new Date().getFullYear() - 2 + '',
endYear: new Date().getFullYear() + '',
},
all_union_loading: false,
unionTip:'分工会活动数',
allUnionYear: moment().format('YYYY'),
isUnionJf:true,
all_club_loading: false,
clubTip:'协会活动数',
allClubYear: moment().format('YYYY'),
isClubJf:true,
}
},
methods: {
async getNumData() {
this.top_block_loading = true
const resp = await this.$axios.post("/platform/activityReimbursement/board/getNumData", this.numForm)
if (resp.code === 0) {
this.numData = resp.data
}
this.top_block_loading = false
},
async getActivityTypeChart() {
this.activity_type_loading = true
const resp = await this.$axios.post("/platform/activityReimbursement/board/getActivityTypeChart", this.activityTypeForm)
if (resp.code === 0) {
let {data} = resp
document.getElementById("activityTypeChart").innerHTML = ''
const config = {
isGroup: true,
"legend": {
"position": "top-right",
"flipPage": false
},
"autoFit": false,
"width": $('#activityTypeChart').width(),
"height": $('#activityTypeChart').height(),
"xField": "year",
"yField": "num",
"seriesField": "type",
}
const plot = new G2Plot.Column(document.getElementById("activityTypeChart"), {
data,
...config,
});
plot.render();
}
this.activity_type_loading = false
},
async getActivityTypePieNum() {
this.activity_type_pie_loading = true
// 销毁旧的图表实例(如果存在)
if (this.activityTypePieChart) {
this.activityTypePieChart.destroy();
}
const resp = await this.$axios.post("/platform/activityReimbursement/board/getActivityTypePieNum", this.activityTypeForm)
if (resp.code === 0) {
let {data} = resp
const config = {
"legend": {
"flipPage": false
},
"label": {
"type": "spider",
"offset": 50
},
"width": $('#activityTypePieChart').width(),
"height": $('#activityTypePieChart').height(),
"forceFit": false,
"radius": 1,
"colorField": "type",
"angleField": "num",
meta: {
type: {
alias: '类别',
},
num: {
alias: '数量',
}
},
}
this.activityTypePieChart = new G2Plot.Pie(document.getElementById("activityTypePieChart"), {
data,
...config,
});
this.activityTypePieChart.render();
}
this.activity_type_pie_loading = false
},
async getActivityJfChart() {
this.activity_type_loading = true
const resp = await this.$axios.post("/platform/activityReimbursement/board/getActivityMoneyChart", this.activityJfForm)
if (resp.code === 0) {
let {data} = resp
document.getElementById("activityJfChart").innerHTML = ''
const config = {
isGroup: true,
"legend": {
"position": "top-right",
"flipPage": false
},
"autoFit": false,
"width": $('#activityJfChart').width(),
"height": $('#activityJfChart').height(),
"xField": "year",
"yField": "num",
"seriesField": "type",
}
const plot = new G2Plot.Column(document.getElementById("activityJfChart"), {
data,
...config,
});
plot.render();
}
this.activity_type_loading = false
},
async getActivityJfPieNum() {
this.activity_jf_pie_loading = true
// 销毁旧的图表实例(如果存在)
if (this.activityJfPieChart) {
this.activityJfPieChart.destroy();
}
const resp = await this.$axios.post("/platform/activityReimbursement/board/getActivityMoneyPieNum", this.activityJfForm)
if (resp.code === 0) {
let {data} = resp
const config = {
"legend": {
"flipPage": false
},
"label": {
"type": "spider",
"offset": 50
},
"width": $('#activityJfPieChart').width(),
"height": $('#activityJfPieChart').height(),
"forceFit": false,
"radius": 1,
"colorField": "type",
"angleField": "num",
meta: {
type: {
alias: '类别',
},
num: {
alias: '数量',
}
},
}
this.activityJfPieChart = new G2Plot.Pie(document.getElementById("activityJfPieChart"), {
data,
...config,
});
this.activityJfPieChart.render();
}
this.activity_jf_pie_loading = false
},
async doUnionSwitch(){
this.isUnionJf = !this.isUnionJf
this.unionTip = this.isUnionJf ? '分工会活动数' : '分工会经费详情'
await this.allUnionActivityAndJf();
},
async allUnionActivityAndJf() {
this.all_union_loading = true
const resp = await this.$axios.post("/platform/activityReimbursement/board/allUnionActivityAndMoney",{
year:this.allUnionYear,
isUnionMoney:this.isUnionJf
})
if (resp.code === 0) {
let {data} = resp
document.getElementById("allUnionChart").innerHTML = ''
const config = {
isStack: true,
"legend": {
"position": "top-right",
"flipPage": false
},
autoFit: true,
title: {
visible: true,
text: this.allUnionYear + '年工会经费及活动详情',
},
description: {
visible: true,
text: '单位(元)',
},
xField: 'unionname',
yField: 'money',
stackField: 'type',
color: ["#5B8FF9", "#5AD8A6"],
"xAxis": {
label: {
formatter: (v) => {
if (data.length > 30 && v.length > 3) {
return v.substr(0, 2) + '...'
} else if (data.length > 20 && v.length > 4) {
return v.substr(0, 3) + '...'
} else if (data.length > 10 && v.length > 6) {
return v.substr(0, 5) + '...'
}
return v
}
}
},
"yAxis": {},
meta: {
unionname: {
alias: '工会',
},
money: {
alias: this.isUnionJf?'金额':'活动数',
}
},
connectedArea: {
visible: true,
triggerOn: false,
},
}
const plot = new G2Plot.Column(document.getElementById("allUnionChart"), {
data,
...config,
});
plot.render();
}
this.all_union_loading = false
},
async doClubSwitch(){
this.isClubJf = !this.isClubJf
this.clubTip = this.isClubJf ? '协会活动数' : '协会经费详情'
await this.allClubActivityAndJf();
},
async allClubActivityAndJf(){
this.all_club_loading = true
const resp = await this.$axios.post("/platform/activityReimbursement/board/allClubActivityAndMoney",{
year:this.allClubYear,
isClubMoney:this.isClubJf
})
if (resp.code === 0) {
let {data} = resp
document.getElementById("allClubChart").innerHTML = ''
const config = {
isStack: true,
"legend": {
"position": "top-right",
"flipPage": false
},
autoFit: true,
title: {
visible: true,
text: this.allClubYear + '年工会经费及活动详情',
},
description: {
visible: true,
text: '单位(元)',
},
xField: 'clubName',
yField: 'money',
stackField: 'type',
color: ["#5B8FF9", "#5AD8A6"],
"xAxis": {
label: {
formatter: (v) => {
if (data.length > 30 && v.length > 3) {
return v.substr(0, 2) + '...'
} else if (data.length > 20 && v.length > 4) {
return v.substr(0, 3) + '...'
} else if (data.length > 10 && v.length > 6) {
return v.substr(0, 5) + '...'
}
return v
}
}
},
"yAxis": {},
meta: {
clubName: {
alias: '协会',
},
money: {
alias: this.isClubJf?'金额':'活动数',
}
},
connectedArea: {
visible: true,
triggerOn: false,
},
}
const plot = new G2Plot.Column(document.getElementById("allClubChart"), {
data,
...config,
});
plot.render();
}
this.all_club_loading = false
},
},
async created() {
await this.getNumData()
},
async mounted() {
await this.getActivityJfChart()
await this.getActivityTypeChart()
await this.getActivityTypePieNum()
await this.getActivityJfPieNum()
await this.allUnionActivityAndJf()
await this.allClubActivityAndJf()
},
});
</script>
<!--#
}
#-->
@@ -0,0 +1,49 @@
<div id="activity_reimbursement_branch_union_approval_form">
<el-form :model="formData" ref="formRef" label-width="0" label-suffix="" class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_reimbursement_branch_union_approval_form",
data() {
return {
businessId: GetQueryString("businessId"),
formData: {
tf_opinion: ""
},
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
...this.formData
})
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
}
})
},
handleCancel(val) {
console.log(val)
},
}
})
</script>
@@ -0,0 +1,233 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
activityDeclareReimbursementList: [],
unions: [],
units: [],
clubs: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,49 @@
<div id="activity_reimbursement_club_principal_approval_form">
<el-form :model="formData" ref="formRef" label-width="0" label-suffix="" class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_reimbursement_club_principal_approval_form",
data() {
return {
businessId: GetQueryString("businessId"),
formData: {
tf_opinion: ""
},
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
...this.formData
})
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
}
})
},
handleCancel(val) {
console.log(val)
},
}
})
</script>
@@ -0,0 +1,212 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属协会">
<el-select clearable filterable placeholder="所属协会"
style="width: 100%;" v-model="pageForm.clubId">
<el-option :label="item.clubName" :value="item.id"
v-for="item in clubs"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
activityDeclareReimbursementList: [],
unions: [],
units: [],
clubs: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.clubs = await this.$businessTool.listClub()
} else {
this.clubs = await this.$businessTool.listClub()
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,177 @@
const INFO = {
template: /*language=HTML*/ `
<div>
<div class="process-title">申请信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="活动名称">{{ viewData.activityName }}</el-descriptions-item>
<el-descriptions-item label="活动类型">{{ getActivityTypeName(viewData.activityType) }}
</el-descriptions-item>
<el-descriptions-item label="申请人">{{ viewData.userName + '(' + viewData.loginName + ')' }}
</el-descriptions-item>
<el-descriptions-item :label="viewData.activityType == 'CLUB' ? '申请协会' : '申请单位'">{{
viewData.declareUnitName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">{{ viewData.mobile }}</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ viewData.applyTime }}</el-descriptions-item>
<el-descriptions-item label="活动计划时间">{{ (viewData.planStartTime ? viewData.planStartTime : '未填写')
+ ' ~ ' + (viewData.planEndTime ? viewData.planEndTime : '未填写') }}
</el-descriptions-item>
<el-descriptions-item label="活动人数">{{ viewData.activityNumber }}</el-descriptions-item>
<el-descriptions-item label="实际活动时间" :span="2">{{ (viewData.startTime ? viewData.startTime :
'未填写') + ' ~ ' + (viewData.endTime ? viewData.endTime : '未填写') }}
</el-descriptions-item>
<el-descriptions-item label="活动地址" :span="2">{{ viewData.activityAddress }}</el-descriptions-item>
<el-descriptions-item label="活动预算费用" :span="2">
<el-table :data="viewData.budgets" border max-height="500" size="mini"
style="width: calc(1200px - 150px - 15%)">
<el-table-column label="序号" sortable type="index" fixed></el-table-column>
<el-table-column label="费用项目名称" fixed prop="name" fixed></el-table-column>
<el-table-column label="预算费用" prop="budgetPrice"></el-table-column>
<el-table-column label="实际费用" prop="actualPrice"></el-table-column>
<el-table-column label="收款人" prop="username"></el-table-column>
<el-table-column label="支行名称" prop="bankName"></el-table-column>
<el-table-column label="报销卡号" prop="bankCardNum"></el-table-column>
<el-table-column label="备注" prop="remark"></el-table-column>
</el-table>
</el-descriptions-item>
<el-descriptions-item label="活动方案及简介" :span="2">
<div v-html="viewData.activityContent"></div>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="2">
<file-preview v-if="viewData.files && viewData.files.length > 0" :files="viewData.files"
complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="发票" :span="2">
<file-preview v-if="viewData.billFiles && viewData.billFiles.length > 0" :files="viewData.billFiles"
complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="活动报道照片/总结/链接" :span="2">
<file-preview v-if="viewData.photoFiles && viewData.photoFiles.length > 0"
:files="viewData.photoFiles" complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="奖品/纪念品/服装/道具等活动人员名单" :span="2">
<file-preview v-if="viewData.otherFiles && viewData.otherFiles.length > 0"
:files="viewData.otherFiles" complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="2">
<el-image v-if="viewData.sign"
:src="viewData.sign"
class="signature-image"></el-image>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
<div class="task-panel 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="办理意见" :span="3" v-if="!task.ext.isFirstTaskNode">{{
task.taskFormData.opinion }}
</el-descriptions-item>
</el-descriptions>
</div>
</template>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
store,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
viewData: {},
doneTasks: [],
row: null,
activityDeclareReimbursementList: []
}
},
methods: {
// 打开
onOpen(row) {
this.row = row
this.info()
this.getDoneTasks()
},
// 获取申请信息
info() {
this.$axios.post("/platform/activityReimbursement/mine/findOne", { id: this.row.id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 获取已办任务审批记录
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)
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
},
style: /*language=CSS*/ `
.el-descriptions-item__label.is-bordered-label {
width: 15% !important;
}
.el-descriptions-item__label {
width: 15% !important;
}
`
}
@@ -0,0 +1,221 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, CLUB_MANAGER, CLUB_PRESIDENT')">
<search-item label="所属协会">
<el-select clearable filterable placeholder="所属协会"
style="width: 100%;" v-model="pageForm.clubId">
<el-option :label="item.clubName" :value="item.id"
v-for="item in clubs"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申报记录">
<el-button size="small" type="primary" @click="onApply">活动申报</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="350px" fixed="right">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onEdit(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.taskKey === 'startTask' || !row.instanceId" @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
<el-button @click="doExportDeclare(row)" size="mini" type="primary">申请表导出</el-button>
<el-button v-if="row.instanceState === 20" @click="doExportReimbursement(row)" size="mini" type="primary">报销凭证导出</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
unions: [],
units: [],
clubs: [],
activityDeclareReimbursementList: []
}
},
components: {
'info': INFO
},
methods: {
// 导出示例
doExportDeclare(row){
this.$downLoad('/platform/activityDeclare/mine/doExportDeclare?id=' + row.declareId)
},
// 导出报销凭证
doExportReimbursement(row){
this.$downLoad('/platform/activityReimbursement/mine/doExportReimbursement?id=' + row.id)
},
onApply() {
window.location.href = '/platform/activityReimbursement/apply'
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onEdit(row) {
window.location.href = '/platform/activityReimbursement/apply?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((resp) => {
this.$message.success(resp.msg)
this.pageData()
})
})
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/activityReimbursement/mine/onDelete", { id }).then((res) => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
this.clubs = await this.$businessTool.listClub()
} else {
if (this.$auth.hasRoleOr('CLUB_MANAGER, CLUB_PRESIDENT')) {
this.clubs = await this.$businessTool.listClub()
}
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,49 @@
<div id="activity_reimbursement_school_principal_approval_form">
<el-form :model="formData" ref="formRef" label-width="0" label-suffix="" class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_reimbursement_school_principal_approval_form",
data() {
return {
businessId: GetQueryString("businessId"),
formData: {
tf_opinion: ""
},
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
...this.formData
})
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
}
})
},
handleCancel(val) {
console.log(val)
},
}
})
</script>
@@ -0,0 +1,233 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
activityDeclareReimbursementList: [],
unions: [],
units: [],
clubs: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,49 @@
<div id="activity_reimbursement_school_union_approval_form">
<el-form :model="formData" ref="formRef" label-width="0" label-suffix="" class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#activity_reimbursement_school_union_approval_form",
data() {
return {
businessId: GetQueryString("businessId"),
formData: {
tf_opinion: ""
},
}
},
methods: {
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
...this.formData
})
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
}
})
},
handleCancel(val) {
console.log(val)
},
}
})
</script>
@@ -0,0 +1,233 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="申请人">
<el-input placeholder="请输入申请人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_ADMIN')">
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</template>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginName'">
<span>{{row.userName + '(' + row.loginName + ')' }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='activityType'">
<span>{{ getActivityTypeName(row.activityType) }}</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "申报人", sortable: true },
{ prop: "mobile", label: "联系方式"},
{ prop: "activityName", label: "活动名称"},
{ prop: "activityType", label: "活动类型"},
{ prop: "declareUnitName", label: "申报单位/协会", sortable: true },
{ prop: "activityNumber", label: "活动人数", sortable: true },
{ prop: "applyTime", label: "申报时间", sortable: true },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
activityDeclareReimbursementList: [],
unions: [],
units: [],
clubs: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
getActivityTypeName(type) {
const data = this.activityDeclareReimbursementList.find(item => item.name === type)
return data ? data.typeName : ""
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
this.activityDeclareReimbursementList = await this.$businessTool.getEnumOptions("ActivityDeclareReimbursement")
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,121 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
placeholder="选择年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
@change="doSearch"
></el-date-picker>
</search-item>
<search-item label="活动状态:" style="width: 340px">
<el-radio-group v-model="pageForm.activityType" @change="doSearch">
<el-radio-button :label="1">全部</el-radio-button>
<el-radio-button :label="2">报名中</el-radio-button>
<el-radio-button :label="3">已结束</el-radio-button>
</el-radio-group>
</search-item>
</search>
</el-card>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="活动列表"></table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{row}" v-if="column.prop=='activitySignUpStartTime'">
<span>{{$moment(row.activitySignUpStartTime).format('MM/DD HH:mm')}}</span>
<span></span>
<span>{{$moment(row.activitySignUpEndTime).format('MM/DD HH:mm')}}</span>
</template>
<template v-slot="{row}" v-else-if="column.prop=='activityStartTime'">
<span>{{$moment(row.activityStartTime).format('MM/DD HH:mm')}}</span>
<span></span>
<span>{{$moment(row.activityEndTime).format('MM/DD HH:mm')}}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="{row}">
<el-button @click="onOpen(row)" size="mini" type="primary">去报名</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('info.js'){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"info": info,
},
data() {
return {
pageForm: {
year: this.$moment().format("YYYY"),
activityType: "2"
},
tableColumns: [
{ label: "活动名称", prop: "activityName", width: 600},
{ label: "活动性质", prop: "literacyType"},
{ label: "报名时间", prop: "activitySignUpStartTime"},
{ label: "活动时间", prop: "activityStartTime"},
],
}
},
methods: {
onOpen(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
pageData() {
this.$axios.post("/platform/literacy/manage/apply/activityData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
},
async created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,306 @@
<!--#include('signForm.js'){}#-->
const info = {
template: /*language=HTML*/ `
<div>
<el-row :gutter="20">
<!--<el-col :span="5">
<div class="glow-box">
<img :src="activity.cover"/>
<div class="title">{{ activity.activityName }}</div>
<div v-html="activity.introduce"></div>
</div>
</el-col>-->
<el-col :span="24">
<el-row class="query-row">
<el-col class="query-title hidden-xs-only">类&emsp;&emsp;型:</el-col>
<el-col class="query-content">
<el-select
v-model="pageForm.courseTypeId"
placeholder="请选择类型"
filterable
clearable
style="width: 200px"
@change="doSearch"
>
<el-option v-for="item in courseTypeList" :key="item.id" :label="item.typeName" :value="item.id"></el-option>
</el-select>
</el-col>
</el-row>
<el-row class="query-row" v-if="assortList && assortList.length > 0">
<el-col class="query-title hidden-xs-only">分类标识:</el-col>
<el-col class="query-content">
<el-tag
:effect="pageForm.assortTypes.includes(item) ? 'dark' : 'plain'"
:key="item"
:type="item"
@click="tagClick('assortTypes', item)"
style="margin-right: 10px; cursor: pointer"
v-for="item in assortList"
>
{{ item }}
</el-tag>
</el-col>
</el-row>
<el-table :data="tableData" class="mt10">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{row}" v-if="column.prop=='courseLocationCoordinates'">
<el-button style="padding: 0" @click="openViewMap(row.courseLocationCoordinates)" type="text">
{{row.courseLocation}}
</el-button>
</template>
<template v-slot="{row}" v-else-if="column.prop=='courseTime'">
<el-button style="padding: 0" @click="openViewCourseTime(row.id)" type="text">点击查看时间</el-button>
</template>
<template v-slot="{row}" v-else-if="column.prop=='applyNum'">
<span v-html="calcSignUpCount(row)"></span>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="{row}">
<el-button v-if="!row.isSign" type="primary" size="mini" @click="onSign(row)">我要报名</el-button>
<el-button v-else type="danger" size="mini" @click="onCancel(row)">取消报名</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-col>
</el-row>
<el-dialog :visible.sync="courseTimeListDialog" title="时间信息" width="60%" append-to-body>
<el-table :data="courseTimeList">
<el-table-column label="日期" prop="courseDate">
<template v-slot="{row}">{{$moment(row.courseDate).format('YYYY-MM-DD')}}</template>
</el-table-column>
<el-table-column label="开始时间" prop="courseStartTime">
<template v-slot="{row}">{{$moment(row.courseStartTime).format('HH:mm')}}</template>
</el-table-column>
<el-table-column label="结束时间" prop="courseEndTime">
<template v-slot="{row}">{{$moment(row.courseEndTime).format('HH:mm')}}</template>
</el-table-column>
</el-table>
<el-row class="mt20" justify="end" type="flex">
<el-button @click="courseTimeListDialog = false">取 消</el-button>
</el-row>
</el-dialog>
<el-dialog :visible.sync="viewMapDialog" title="地点" width="60%" append-to-body>
<div id="viewMap" style="width: 100%; height: 500px"></div>
<el-row class="mt20" justify="end" type="flex">
<el-button @click="viewMapDialog = false">取 消</el-button>
</el-row>
</el-dialog>
<sign-form ref="signFormRef" @refresh="doSearch"></sign-form>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
mixins: [initTableMixins],
components: {
"sign-form": signForm,
},
data() {
return {
pageForm: {
assortTypes: [],
},
assortList: [],
courseTimeListDialog: false,
viewMapDialog: false,
courseTimeList: [],
tableColumns: [
{ prop: "courseName", label: "名称" },
{ prop: "typeName", label: "类型", width: 130},
{ prop: "courseLocationCoordinates", label: "地点", width: 200 },
{ prop: "courseInstructor", label: "联系人", width: 100 },
{ prop: "courseTime", label: "时间", width: 200 },
{ prop: "applyNum", label: "已报名人数", width: 200 }
],
activity: {},
courseTypeList: [],
literacyType: '',
}
},
methods: {
tagClick(key, val) {
let idx = this.pageForm[key].indexOf(val)
if (idx !== -1) {
this.pageForm[key].splice(idx, 1)
} else {
this.pageForm[key].push(val)
}
this.doSearch()
},
async onOpen(row) {
this.activity = row
this.$set(this.pageForm, 'activityId', row.id)
await this.pageData()
await this.getCourseTypeList()
this.queryCourseAssort()
},
onSign(row) {
const course = this.courseTypeList.find((v) => v.id === row.courseType)
this.$axios.post("/platform/mobile/literacyActivity/validateSignUp", {courseId: row.id})
.then((res) => {
if (res.code !== 0) {
this.$alert(res.msg, "提示", {
confirmButtonText: "确定",
type: "warning"
})
} else {
let lave = row.coursePeopleNumber - (row.hasRegisterNum + row.courseReservedNumber)
if(row.reserveMode === 2 && lave <= 0) {
this.$alert('您当前的报名为候补报名状态', "提示", {
confirmButtonText: "确定",
type: "warning"
})
}
this.$refs.signFormRef.onOpen(row, course)
}
})
},
onCancel(row) {
this.$confirm("您确定要取消吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(async () => {
const resp = await this.$axios.post("/platform/mobile/literacyActivity/cancelSignUp", {
activityId: row.activityId,
courseId: row.id
})
if (resp.code === 0) {
await this.pageData()
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
})
},
async getCourseTypeList() {
const resp = await this.$axios.post("/platform/literacy/manage/type/getAllType")
if (resp.code === 0) {
this.courseTypeList = resp.data
}
},
async openViewCourseTime(id) {
const resp = await this.$axios.post(loc() + "/getCourseTime", { id: id })
this.courseTimeList = resp.data
this.courseTimeListDialog = true
},
openViewMap(point) {
if (!Array.isArray(point)) {
this.$message.warning("没有设置点位,无法通过地图查看")
return
}
this.viewMapDialog = true
this.$nextTick(() => {
const viewMap = new AMap.Map("viewMap", {
resizeEnable: true,
center: point,
zoom: 16
})
if (viewMarker) {
viewMap.remove(viewMarker)
}
viewMarker = new AMap.Marker({
position: point,
offset: new AMap.Pixel(-13, -30)
})
viewMap.add(viewMarker)
viewMap.setFitView(null, false, [150, 60, 100, 60])
})
},
calcSignUpCount(o) {
let lave = o.coursePeopleNumber - (o.hasRegisterNum + o.courseReservedNumber)
if(o.reserveMode === 2) {
let lave2 = o.waitingNum - o.hasWaitingNum
return "<span style='color: red'>余" + lave +"</span>/" + o.coursePeopleNumber + "人"
+ "<span style='color: red'>候补余" + lave2 + "</span>/" + o.waitingNum + "人"
} else {
return "<span style='color: red'>余" + lave +"</span>/" + o.coursePeopleNumber + "人"
}
},
async pageData() {
const pageForm = clone({...this.pageForm})
pageForm.assortTypes = JSON.stringify(pageForm.assortTypes)
const resp = await this.$axios.post(loc() + "/pageData", pageForm)
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
} else {
this.$message.warning(resp.msg)
}
},
queryCourseAssort() {
console.log(this.activity)
this.$axios.post(loc() + "/queryCourseAssort", {activityId: this.activity.id})
.then((resp) => {
this.assortList = resp.data
})
},
},
created() {
},
style: /*language=CSS*/ `
.glow-box {
min-height: calc(100vh - 56px - 40px - 50px - 80px);
max-height: calc(100vh - 56px - 40px - 50px - 80px);
overflow-y: auto;
background: #F0F2F5;
}
img {
width: 100%;
height: 180px;
}
.title {
background: white;
height: 20px;
}
.query-row {
display: flex;
align-items: center;
padding: 6px 0;
}
.query-row:not(:last-child) {
border-bottom: 1px dashed rgb(230, 230, 230);
}
.query-row > .query-title {
width: 100px;
max-width: 100px;
min-width: 100px;
overflow: hidden;
}
.query-row > .query-content {
min-width: 200px;
overflow: hidden;
}
.query-row > .query-content > .el-tag {
margin-bottom: 5px;
margin-top: 5px;
}
@media screen and (max-width: 992px) {
.query-row:nth-child(4) .query-content .el-col:not(:last-child) {
margin-bottom: 5px;
}
.query-title {
display: none;
}
}
`
}
@@ -0,0 +1,216 @@
const signForm = {
template: /*language=HTML*/ `
<div>
<el-dialog :close-on-click-modal="false" :visible.sync="signDialog" title="信息填写" width="50%" append-to-body>
<el-form :model="formData" ref="form" label-width="120px">
<el-row>
<el-col :span="24">
<el-form-item label="姓名" prop="username">
<el-input readonly v-model="formData.username"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="工号" prop="loginname">
<el-input readonly v-model="formData.loginname"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="所在单位" prop="unitName">
<el-input readonly v-model="formData.unitName"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="所属工会" prop="unionName">
<el-input readonly v-model="formData.unionName"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="性别" prop="sex">
<el-input readonly v-model="formData.sex"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="联系方式" prop="mobile">
<el-input v-model="formData.mobile"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="courseRow.courseIsLimitApply">
<el-col :span="24">
<el-form-item label="报名时段" prop="activityCourseId"
:rules="{ required: true, message: '请选择报名时段', trigger: 'blur'}">
<el-select style="width: 100%" v-model="formData.activityCourseId" placeholder="请选择报名时段">
<el-option v-for="item in courseTimeSelectList"
:label="item.text.substring(0, 12)"
:value="item.value"
:key="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item
v-for="(column, index) in formData.literacyMobileSignColumnList"
:prop="'literacyMobileSignColumnList.' + index + '.columnValue'"
:label="column.columnName"
:key="column.columnCode"
:rules="{ required: column.isRequired,
message: (['SELECT', 'FILE'].includes(column.columnFormType) ? '请选择' : '请填写') + column.columnName,
trigger: 'blur'}"
>
<!--文本框-->
<template v-if="!['SELECT'].includes(column.columnFormType) && ['VARCHAR','TEXT','INT'].includes(column.columnType)">
<el-input
v-model="column.columnValue"
:placeholder="'请填写' + column.columnName"
:type="['INT'].includes(column.columnType) ? 'number' : ''"
></el-input>
</template>
<!--选择框-->
<template v-else-if="['SELECT'].includes(column.columnFormType) && ['VARCHAR','TEXT','INT'].includes(column.columnType)">
<el-select v-model="column.columnValue" :placeholder="'请选择' + column.columnName" style="width: 100%">
<el-option v-for="item in column.selectValues" :key="item" :label="item" :value="item"></el-option>
</el-select>
</template>
<!--时间框-->
<template v-else-if="['DATE', 'DATETIME'].includes(column.columnType)">
<el-date-picker
style="width: 100%"
v-model="column.columnValue"
:type="column.columnType === 'DATE' ? 'date' : 'datetime'"
:placeholder="'请选择' + column.columnName"
:value-format="column.columnType === 'DATE' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'"
></el-date-picker>
</template>
<!--文件-->
<template v-else-if="['JSON'].includes(column.columnType)">
<file-upload :upload_number="column.fileNumber" :value.sync="column.columnValue"
:accept="column.fileType ? column.fileType.join(',') : ''"
upload_result_type="url"
complete_result upload_mode="drag"
upload_result_category="array"></file-upload>
</template>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-row class="mt20" justify="end" type="flex">
<el-button @click="signDialog = false">取 消</el-button>
<el-button @click="onSubmit" type="primary">提 交</el-button>
</el-row>
</el-dialog>
</div>
`,
store,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
return {
signDialog: false,
formData: {},
courseRow: {},
courseTimeSelectList: [],
}
},
methods: {
async getCourseTimeSelectList(o) {
const resp = await $.post('/platform/mobile/literacyActivity/getCourseTimeSelectList',{ courseId: o.id })
if (resp.code === 0) {
this.courseTimeSelectList = resp.data
} else {
this.$message.warning('获取时段信息失败,请联系管理员')
}
},
async onOpen(row, course) {
this.initData(row, course)
if (row.courseIsLimitApply) {
await this.getCourseTimeSelectList(row)
}
this.courseRow = row
this.signDialog = true
},
async onSubmit() {
//获取家属是多少人
let per = 0
this.formData.literacyMobileSignColumnList.forEach((item) => {
if (item.columnCode === "xdqsrs") {
per += Number(item.columnValue)
}
})
const res = await this.$axios.post("/platform/mobile/literacyActivity/validateSignUp", {
courseId: this.formData.courseId,
currentFamilyNumber: per
})
if (res.code !== 0) {
this.$message.warning(res.msg)
return
}
this.$refs["form"].validate(async (valid) => {
if (valid) {
if (this.courseRow.courseIsLimitApply) {
const resp = await this.$axios.post('/platform/mobile/literacyActivity/validateSourceSignUp', {
activityCourseId: this.formData.activityCourseId,
courseId: this.courseRow.id
})
if (resp.code !== 0) {
this.$message.warning(res.msg)
return
}
}
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const mobileColumnsValue = this.formData.literacyMobileSignColumnList.map((v) => {
return {
columnName: v.columnName,
columnValue: v.columnValue,
columnCode: v.columnCode,
columnFormType: v.columnFormType
}
})
this.formData.mobileColumnsValue = JSON.stringify(mobileColumnsValue)
const resp = await this.$axios.post("/platform/mobile/literacyActivity/doSignUp", this.formData)
if (resp.code === 0) {
this.signDialog = false
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
initData(row, course) {
this.formData = {
activityId: row.activityId,
courseId: row.id,
username: this.$store.state.user.username,
loginname: this.$store.state.user.loginname,
unionName: this.$store.state.user.union.name,
unitName: this.$store.state.user.unit.name,
sex: this.$store.state.user.sex,
mobile: this.$store.state.user.mobile,
literacyMobileSignColumnList: course.literacyMobileSignColumnList
}
this.formData.literacyMobileSignColumnList.forEach((item) => {
item.columnValue = ""
})
this.$nextTick(() => {
this.$refs.form.clearValidate()
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,593 @@
<!--#include('courseTime.js'){}#-->
<!--#include('customForm.js'){}#-->
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" label-width="110px" ref="form">
<div v-show="step === 1">
<el-row :gutter="20" type="flex" v-if="!formData.id">
<el-col :span="12">
<el-form-item label="沿用活动" prop="useHistory">
<el-radio-group v-model="formData.useHistory" size="small">
<el-radio :label="true" border>沿用之前活动</el-radio>
<el-radio :label="false" border>不沿用之前活动</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="formData.useHistory">
<el-form-item label="往期活动" prop="historicalAct">
<el-select v-model="formData.historicalAct" placeholder="请选择往期活动" style="width: 100%" @change="historicalActChange">
<el-option v-for="item in historicalActList" :key="item.id" :label="item.activityName" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item :rules="{required:true,message: '请输入活动名称', trigger: 'blur'}" label="活动名称" prop="activityName">
<el-input maxlength="50" v-model="formData.activityName" placeholder="请输入活动名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="literacyType + '通知'" prop="notice">
<el-radio-group v-model="formData.notice" size="small">
<el-radio :label="true" border>通知</el-radio>
<el-radio :label="false" border>不通知</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item :rules="{required:true,message: '请选择活动时间', trigger: 'blur'}" label="活动时间" prop="activityTime">
<el-date-picker
:picker-options="pickerOptions"
end-placeholder="请选择活动结束日期"
range-separator="至"
start-placeholder="请选择活动开始日期"
style="width: 100%"
type="datetimerange"
v-model="formData.activityTime"
value-format="yyyy-MM-dd HH:mm"
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :rules="{required:true,message: '请选择报名时间', trigger: 'blur'}" label="报名时间" prop="activitySignTime">
<el-date-picker
:disabled="false"
end-placeholder="请选择报名结束日期"
range-separator="至"
start-placeholder="请选择报名开始日期"
style="width: 100%"
type="datetimerange"
v-model="formData.activitySignTime"
value-format="yyyy-MM-dd HH:mm"
></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item label="面向对象" prop="joinCnd">
<div style="display: flex; justify-content: space-between">
<div style="width: 99%">
<el-select
@change="changeActivity"
clearable
filterable
placeholder="请选择可报名人员范围"
style="width: 99%"
v-model="formData.activityGroupId"
>
<el-option
:key="item.groupId"
:label="item.groupName"
:value="item.groupId"
v-for="item in activityGroupList"
></el-option>
</el-select>
</div>
<div>
<el-button @click="$refs.drawerUserScope.userScopeDialog = true" type="primary">设置</el-button>
</div>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="活动类型" prop="literacyType" :rules="{required:true,message: '请选择活动类型', trigger: 'blur'}">
<el-select @change="typeChange" filterable placeholder="请选择活动类型" style="width: 100%" v-model="formData.literacyType">
<el-option :label="item.name" :value="item.code" :key="item.code" v-for="item in dict.type.LITERACY_SIGNUP_TYPE"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item :rules="{required:true,message: '请输入活动介绍', trigger: 'blur'}" label="活动介绍" prop="introduce">
<text-editor v-model="formData.introduce"></text-editor>
</el-form-item>
<el-form-item label="封面图片" prop="cover" :rules="{required:true,message: '请上传活动移动端封面图片', trigger: 'blur'}">
<el-col :span="12">
<file-upload
:upload_number="1"
:value.sync="formData.cover"
accept=".jpg,.jpeg,.png"
complete_result
upload_mode="image"
upload_result_category="interval"
></file-upload>
</el-col>
<el-col :span="12">
<el-form-item label="微信群二维码" prop="wechat">
<file-upload
:upload_number="1"
:value.sync="formData.wechat"
accept=".jpg,.jpeg,.png"
complete_result
upload_mode="image"
upload_result_category="interval"
></file-upload>
</el-form-item>
</el-col>
</el-form-item>
</div>
<div v-show="step === 2">
<div class="left-span-label" style="display: flex; justify-content: space-between; align-items: center">
<div>{{literacyType + '信息(温馨提示:如不需要人数限制,下方人数框填写0或者不填)'}}</div>
<div>
<el-button @click="addCourse" size="mini" type="primary">添加{{ literacyType }}</el-button>
</div>
</div>
<el-table :data="formData.courseList">
<el-table-column label="序号" prop="orderNum" width="100px">
<template v-slot="{row}">
<el-input-number
v-model="row.orderNum"
@change="courseOrderNumChange"
:min="1"
:max="formData.courseList.length"
:step="1"
step-strictly
:precision="0"
controls-position="right"
style="width: 76px"
size="small"
label="序号"
></el-input-number>
</template>
</el-table-column>
<el-table-column :label="literacyType + '名称'" prop="courseName">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseName" :placeholder="'请输入' + literacyType + '名称'"></el-input>
</template>
</el-table-column>
<el-table-column label="类型" prop="courseType" sortable>
<template v-slot="{row}">
<el-select size="small" v-model="row.courseType" @change="(val) => {courseTypeChange(val, row)}">
<el-option :label="c.typeName" :value="c.id" :key="c.id" v-for="c in courseTypeList"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column :label="literacyType + '人数'" prop="coursePeopleNumber" width="110px">
<template v-slot="{row}">
<el-input-number
:controls="false"
:max="9999"
size="small"
:min="0"
:precision="0"
step-strictly
style="max-width: 80px"
@change="(c, o) => validNumber(row, null)"
v-model="row.coursePeopleNumber"
placeholder="请输入人数"
></el-input-number>
</template>
</el-table-column>
<el-table-column label="预留名额" prop="courseReservedNumber" width="110px">
<template v-slot="{row}">
<el-input-number
:controls="false"
:max="1000"
:min="0"
size="small"
:precision="0"
step-strictly
style="max-width: 80px"
@change="(c, o) => validNumber(row, o)"
v-model="row.courseReservedNumber"
placeholder="请输入预留名额"
></el-input-number>
</template>
</el-table-column>
<el-table-column label="校区" prop="campus">
<template v-slot="{row}">
<el-select size="small" v-model="row.campus" style="width: 100%">
<el-option :label="item.name" :value="item.name" :key="item.code" v-for="item in dict.type.CAMPUS"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column :label="literacyType + '地点'" prop="courseLocation">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseLocation" :placeholder="'请输入' + literacyType + '地点'"></el-input>
</template>
</el-table-column>
<el-table-column :label="literacyType + '负责人'" prop="courseInstructor">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseInstructor" :placeholder="'请输入' + literacyType + '负责人'"></el-input>
</template>
</el-table-column>
<el-table-column label="分类标识" prop="assort">
<template v-slot="{row}">
<el-input size="small" v-model="row.assort" placeholder="请输入分类标识"></el-input>
</template>
</el-table-column>
<el-table-column :label="literacyType + '时间'">
<template v-slot="scope">
<el-button @click="openSetUpCourseTime(scope.$index)" type="text">设置{{ literacyType }}时间</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template v-slot="scope">
<el-button @click="openMoreInfo(scope, scope.$index)" size="mini" type="primary">自定义设置</el-button>
<el-button @click="removeTableCourse(scope.$index)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="left-span-label" style="margin-top: 20px">个人报名数量限制</div>
<el-form-item label="报名数量限制" prop="cover">
<el-radio-group v-model="formData.restrictLimit" size="small">
<el-radio border :label="1">无限制</el-radio>
<el-radio border :label="2">按类型限制</el-radio>
<el-radio border :label="3">按活动限制</el-radio>
</el-radio-group>
<div calss="limit_div">
<div v-if="formData.restrictLimit === 1" style="color: #c64120; font-size: 12px">注:无限制指对报名的个数不做任何限制</div>
<div v-if="formData.restrictLimit === 2" style="color: #c64120; font-size: 12px">
<div>
<el-button @click="setSignUpCondition" size="mini" type="primary">设置报名限制</el-button>
<span style="color: #c64120; font-size: 12px">注:按类型限制指对每个类型下的个数进行限制</span>
</div>
</div>
<div v-if="formData.restrictLimit === 3">
<div>
<el-input-number v-model="formData.limitNum" :min="1" :max="100" size="mini" label="限制报名个数"></el-input-number>
<span style="color: #c64120; font-size: 12px">注:按活动限制指只能报{{formData.limitNum}}个,不与类型关联</span>
</div>
</div>
</div>
</el-form-item>
</div>
</el-form>
<div style="float: right; margin: 20px 0">
<el-button @click="$emit('back')">取消</el-button>
<el-button v-if="step === 2" type="primary" @click="step = 1">上一步</el-button>
<el-button v-if="step === 1" type="primary" @click="step = 2">下一步</el-button>
<el-button type="primary" @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit">提交</el-button>
</div>
<el-dialog :close-on-click-modal="false" :visible.sync="signUpDialog" title="设置报名限制" append-to-body>
<el-table :data="formData.typeLimits">
<el-table-column prop="code" label="类型编码"></el-table-column>
<el-table-column prop="typeName" label="类型名称"></el-table-column>
<el-table-column label="限制个数" width="500">
<template v-slot="{row}">
<el-input-number size="small" v-model="row.limitNum" :min="0"></el-input-number>
<span style="color: #c64120; font-size: 12px">注:值为空或者为0则表示此类型不限制报名个数</span>
</template>
</el-table-column>
</el-table>
<el-row class="mt20" justify="end" type="flex">
<el-button @click="signUpDialog = false">取消</el-button>
<el-button @click="doLimitNum" type="primary">确定</el-button>
</el-row>
</el-dialog>
<drawer-user-scope
@group_change="getActivityGroup"
ref="drawerUserScope"
:group_id.sync="formData.activityGroupId">
</drawer-user-scope>
<course-time ref="courseTimeRef"></course-time>
<custom-form ref="customFormRef"></custom-form>
</div>
`,
dicts: ["CAMPUS", "LITERACY_SIGNUP_TYPE"],
data() {
return {
signUpDialog: false,
step: 1,
formData: {
notice: false,
courseList: [
{ orderNum: 1, courseName: "", courseTimeList: [], isMobileSign: false, isReceiveGift: false, reserveMode: 1, courseIsLimitApply: false },
],
conditionStructure: {
method: "AND",
conditions: [{}]
},
restrictLimit: 1,
limitNum: 1,
typeLimits: []
},
historicalActList: [],
literacyTypeList: [],
literacyType: "培训班",
activityGroupList: [],
pickerOptions: {
disabledDate(time) {
return time.getTime() < Date.now() - 24 * 60 * 60 * 1000
}
},
campusList: [],
courseTypeList: [],
}
},
components: {
"drawer-user-scope": httpVueLoader("/components/module/activity/DrawerUserScope.vue"),
"course-time": courseTime,
"custom-form": customForm,
},
methods: {
async validNumber(row, old) {
if (GetQueryString("id") === "") {
if (row.courseReservedNumber > row.coursePeopleNumber && row.reserveMode === 1) {
this.$alert("预留人数不能大于" + this.literacyType + "人数!", "提示", {
confirmButtonText: "确定"
})
row.courseReservedNumber = 0
}
} else {
const registerUserCount = await this.getRegisterUserCount(row.id)
if (row.courseReservedNumber + registerUserCount > row.coursePeopleNumber) {
if (row.reserveMode === 1) {
let num = row.coursePeopleNumber - registerUserCount
let str =
"您设置的" +
this.literacyType +
"人数为" +
row.coursePeopleNumber +
"人,当前报名人数为" +
registerUserCount +
"人,预留名额上限为" +
num +
"人!"
this.$alert(str, "提示", {
confirmButtonText: "确定"
})
row.courseReservedNumber = 0
}
}
}
},
async getRegisterUserCount(courseId) {
const resp = await this.$axios.post("/platform/literacy/manage/activity/getRegisterUserCount", { courseId })
return resp.code === 0 ? resp.data : 0
},
courseTypeChange(val, row) {
row.reserveMode = 1
},
setSignUpCondition() {
if (this.formData.courseList !== undefined && this.formData.courseList.length > 0) {
const courseValid = this.formData.courseList.some((item, index) => {
if (item.courseType === undefined) {
this.$message.warning("请在" + (index + 1) + "行" + this.literacyType + "信息中选择类型!")
return true
}
return false
})
if (courseValid) {
return
}
const array = [...new Set(this.formData.courseList.map((o) => o.courseType))]
const typeArray = clone([...this.courseTypeList].filter((x) => array.some((y) => x.id === y)))
const arr = []
typeArray.forEach((item) => {
const t = this.formData.typeLimits.find(o => o.typeId === item.id)
if (t) {
const type = this.courseTypeList.find(o => o.id === t.typeId)
t.code = type.code
t.typeName = type.typeName
arr.push(t)
} else {
arr.push({
code: item.code,
typeName: item.typeName,
typeId: item.id,
limitNum: 0
})
}
})
this.formData.typeLimits = arr
this.signUpDialog = true
} else {
this.$message.warning("请在" + this.literacyType + "信息中选择类型!")
}
},
doLimitNum() {
this.signUpDialog = false
},
openMoreInfo(row, index) {
this.$refs.customFormRef.onOpen(this.formData, row, index)
},
async removeTableCourse(index) {
const confirm = await this.$confirm(
"请确认是否删除此" + this.literacyType + "?如果该" + this.literacyType + "已有报名人员,会随之一起删除!确定吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
)
if (confirm) {
this.formData.courseList.splice(index, 1)
}
},
openSetUpCourseTime(index) {
this.$refs.courseTimeRef.onOpen(this.formData, index)
},
courseOrderNumChange() {
this.formData.courseList = this.formData.courseList.sort((a, b) => a.orderNum - b.orderNum)
},
addCourse() {
this.formData.courseList.push({ courseTimeList: [], isMobileSign: false, isReceiveGift: false, reserveMode: 1, courseIsLimitApply: false })
},
async historicalActChange(val) {
const resp = await this.$axios.post("/platform/literacy/manage/activity/findOne", {id: val})
if (resp.code === 0) {
this.formData = resp.data
this.typeChange(this.formData.literacyType)
this.formData.id = ""
}
},
typeChange(val) {
const type = this.dict.type.LITERACY_SIGNUP_TYPE.find(o => o.code === val)
this.literacyType = type?.name || "培训班"
},
changeActivity(val) {
if (val) {
const group = this.activityGroupList.find(v => v.groupId === val)
this.$set(this.formData, "activityGroupName", group.groupName)
} else {
this.$set(this.formData, "activityGroupName", "全部教职工")
}
},
async getActivityGroup() {
const { data } = await this.$axios.post("/platform/activity/basic/scope/getActivityUserScopeGroup")
return data
},
async getHistoricalActList() {
const resp = await this.$axios.post("/platform/literacy/manage/activity/getHistoricalActList", {})
return resp.data
},
async onSave() {
let valid = false
this.$refs.form.validateField("activityName", (errMsg) => {
valid = errMsg === ""
})
if (!valid) {
this.$message.warning("请输入活动名称")
return
}
await this.doHandle('保存')
},
onSubmit() {
this.$refs["form"].validate(async (valid, errMsg) => {
if (valid) {
const courseValid = this.formData.courseList.some((v, i) => {
const basicValid = v.courseName && v.coursePeopleNumber && v.courseLocation && v.courseInstructor && v.courseType
const timeValid =
v.courseTimeList.length > 0 &&
v.courseTimeList.every((x) => {
return x.courseStartTime && x.courseEndTime && x.courseStartTime < x.courseEndTime
})
if (!timeValid) {
this.$message.warning("第" + (i + 1) + "行时间填写有误,请核查")
return true
}
if (!basicValid) {
this.$message.warning("第" + (i + 1) + "行信息填写有误,请核查")
return true
}
if (v.isMobileSign === true && v.signType === 3 && (v.courseLocationCoordinates === undefined || v.courseLocationCoordinates.length < 2)) {
this.$message.warning("第" + (i + 1) + "行地点坐标填写有误,请核查")
return true
}
if (v.isMobileSign === true && v.signType === 3 && (v.signType === "" || v.signType === undefined)) {
this.$message.warning("第" + (i + 1) + "行签到方式填写有误,请核查")
return true
}
return false
})
if (courseValid) return
if (this.formData.restrictLimit === 2 && this.formData.typeLimits.length === 0) {
this.$message.warning("请设置报名限制")
return
}
this.formData.isDisabled = false
await this.doHandle('提交')
} else {
if(Object.keys(errMsg).length > 0) {
this.$message.warning(errMsg[Object.keys(errMsg)[0]][0].message)
return
}
this.$message.warning("存在必填项未填写")
}
})
},
async doHandle(type) {
const cloneData = clone(this.formData)
cloneData.activitySignUpStartTime = cloneData.activitySignTime !== undefined ? cloneData.activitySignTime[0] : null
cloneData.activitySignUpEndTime = cloneData.activitySignTime !== undefined ? cloneData.activitySignTime[1] : null
cloneData.activityStartTime = cloneData.activityTime !== undefined ? cloneData.activityTime[0] : null
cloneData.activityEndTime = cloneData.activityTime !== undefined ? cloneData.activityTime[1] : null
if (cloneData.activityStartTime !== undefined && cloneData.activityStartTime !== null) {
cloneData.year = new Date(cloneData.activityStartTime).getFullYear()
}
cloneData.typeLimits = JSON.stringify(this.formData.typeLimits)
cloneData.courseList = JSON.stringify(cloneData.courseList)
const confirm = await this.$confirm("您确定要" + type + "吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
if (confirm !== "confirm") return
const resp = await this.$axios.post("/platform/literacy/manage/activity/doHandle", cloneData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.step = 1
this.$emit('refresh')
this.$emit('back')
} else {
this.$message.warning(resp.msg)
}
},
async getAllType() {
const resp = await this.$axios.post("/platform/literacy/manage/type/getAllType", {})
return resp.data
},
async init(row) {
if (row && row.id) {
const resp = await this.$axios.post("/platform/literacy/manage/activity/findOne", {id: row.id})
if (resp.code === 0) {
this.formData = resp.data
this.typeChange(this.formData.literacyType)
}
}
},
async initData(row) {
this.activityGroupList = await this.getActivityGroup()
this.historicalActList = await this.getHistoricalActList()
this.courseTypeList = await this.getAllType()
await this.init(row)
},
},
watch: {
'formData.restrictLimit'(val) {
if (!this.formData.id) {
this.formData.limitNum = val === 3 ? 1 : ''
}
},
'formData.activityGroupId': {
async handler(newVal, oldVal) {
this.activityGroupList = await this.getActivityGroup()
this.userScopeDialog = false
},
deep: true
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,215 @@
const courseTime = {
template: /*language=HTML*/ `
<div>
<el-dialog :close-on-click-modal="false" :visible.sync="setUpCourseDialog" title="设置时间" width="60%" append-to-body>
<div style="color: red; margin-bottom: 10px">温馨提示:有人员报名后,禁止修改下列时间,如有修改,请联系管理员</div>
<div class="left-span-label">选择日期</div>
<el-date-picker
v-if="formData.courseList && formData.courseList[courseIndex]"
:picker-options="setUpCoursePickerOptions"
@change="setUpCourseDataChange"
placeholder="选择一个或多个日期"
style="width: 100%"
type="dates"
v-model="formData.courseList[courseIndex].setUpCourseData"
value-format="yyyy-MM-dd"
></el-date-picker>
<div class="left-span-label">设置时间</div>
<el-row style="margin-bottom: 10px">
<el-time-select
:picker-options="{
start: '08:30',
step: '00:05',
end: '23:30'
}"
placeholder="开始时间"
size="mini"
v-model="courseTimeOneKeySet.startTime"
></el-time-select>
<el-time-select
:picker-options="{
start: '08:30',
step: '00:05',
end: '23:30'
}"
placeholder="结束时间"
size="mini"
v-model="courseTimeOneKeySet.endTime"
></el-time-select>
<el-button @click="oneKeySetStartEndTime" size="mini" type="primary">一键设置开始/结束时间</el-button>
<span style="color: #ac3111">报名人数是否限制:</span>
<el-radio-group size="mini" v-model="formData.courseList[courseIndex].courseIsLimitApply">
<el-radio-button :label="true">是</el-radio-button>
<el-radio-button :label="false">否</el-radio-button>
</el-radio-group>
</el-row>
<el-table v-if="formData.courseList && formData.courseList[courseIndex]"
:data="formData.courseList[courseIndex].courseTimeList">
<el-table-column label="日期">
<template v-slot="{row}">
<i class="el-icon-time"></i>
{{$moment(row.courseDate).format('YYYY-MM-DD')}}
</template>
</el-table-column>
<el-table-column label="开始时间">
<template v-slot="{row}">
<el-time-select
:picker-options="{
start: '08:30',
step: '00:05',
end: '23:30'
}"
placeholder="开始时间"
style="width: 100%"
v-model="row.courseStartTime"
></el-time-select>
</template>
</el-table-column>
<el-table-column label="结束时间">
<template v-slot="{row}">
<el-time-select
:picker-options="{
start: '08:30',
step: '00:05',
end: '23:30'
}"
placeholder="结束时间"
style="width: 100%"
v-model="row.courseEndTime"
></el-time-select>
</template>
</el-table-column>
<template v-if="formData.courseList[courseIndex].courseIsLimitApply">
<el-table-column label="人数限制">
<template v-slot="{row}">
<el-input-number v-model="row.courseLimitNum" :min="1" :max="1000"
style="width: 100%"
placeholder="限制报名个数"></el-input-number>
</template>
</el-table-column>
</template>
<el-table-column label="操作" width="200">
<template v-slot="{row,$index}">
<el-button
@click="formData.courseList[courseIndex].courseTimeList.splice($index,0,{courseDate:row.courseDate,courseStartTime:'',courseEndTime:''})"
size="small"
>
新增同天时段
</el-button>
<el-button @click="removeSetUpTableCourseRow(row,$index)" size="small" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-row class="mt20" justify="end" type="flex">
<el-button @click="doConfirmSetUpCourse" type="primary">确定</el-button>
</el-row>
</el-dialog>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
const that = this
return {
setUpCourseDialog: false,
courseIndex: 0,
formData: {},
courseTimeOneKeySet: {
startTime: "",
endTime: ""
},
setUpCoursePickerOptions: {
disabledDate(time) {
return (
time.getTime() < Date.parse(that.$moment(that.formData.activityTime[0]).format("YYYY-MM-DD") + " 00:00:00") ||
time.getTime() > Date.parse(that.$moment(that.formData.activityTime[1]).format("YYYY-MM-DD") + " 00:00:00")
)
}
},
}
},
methods: {
removeSetUpTableCourseRow(row, index) {
this.formData.courseList[this.courseIndex].courseTimeList.splice(index, 1)
//培训时间列表日期数组
const courseDateArray = this.formData.courseList[this.courseIndex].courseTimeList.map((v) =>
this.$moment(v.courseDate).format("YYYY-MM-DD")
)
//选择课程日期数组
const scdList = this.formData.courseList[this.courseIndex].setUpCourseData
this.formData.courseList[this.courseIndex].setUpCourseData = scdList.filter((v) => {
return courseDateArray.includes(this.$moment(v).format("YYYY-MM-DD"))
})
},
oneKeySetStartEndTime() {
const { startTime, endTime } = this.courseTimeOneKeySet
this.formData.courseList[this.courseIndex].courseTimeList.forEach((v) => {
this.$set(v, "courseStartTime", startTime)
this.$set(v, "courseEndTime", endTime)
})
this.$forceUpdate()
},
setUpCourseDataChange(val) {
if (!val) {
this.formData.courseList[this.courseIndex].courseTimeList = []
return
}
//培训时间日期Set
if (this.formData.courseList[this.courseIndex].courseTimeList === undefined) {
this.$set(this.formData.courseList[this.courseIndex], "courseTimeList", [])
}
const ctList = new Set(
this.formData.courseList[this.courseIndex].courseTimeList.map((v) => this.$moment(v.courseDate).format("YYYY-MM-DD"))
)
val.forEach((v) => {
if (!ctList.has(v)) {
this.formData.courseList[this.courseIndex].courseTimeList.push({
courseDate: v,
courseTime: null
})
}
})
this.formData.courseList[this.courseIndex].courseTimeList = this.formData.courseList[this.courseIndex].courseTimeList.filter((v) => {
return val.includes(this.$moment(v.courseDate).format("YYYY-MM-DD"))
})
this.formData.courseList[this.courseIndex].courseTimeList.sort((a, b) => {
return Date.parse(a["courseDate"]) - Date.parse(b["courseDate"])
})
},
//设置课程时间确定
doConfirmSetUpCourse() {
const courseTableData = this.formData.courseList[this.courseIndex].courseTimeList
if (courseTableData.length === 0) {
this.$message.warning("请填写时间!")
return
}
if (courseTableData && courseTableData.length > 0) {
const valid = courseTableData.every((v) => v.courseStartTime && v.courseEndTime && v.courseStartTime < v.courseEndTime)
if (!valid) {
this.$message.warning("时间填写不完整或者有误!")
return
}
this.setUpCourseDialog = false
}
},
onOpen(formData, index) {
this.formData = formData
this.courseIndex = index
if (!this.formData.activityTime || this.formData.activityTime.length === 0) {
this.$message.warning("请先设置活动起止时间")
return
}
this.courseIndex = index
this.setUpCourseDialog = true
},
},
created() {
if(!this.formData.courseList) {
this.formData = {courseList: [{unionLimit: []}]}
}
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,211 @@
<!--#include('unionForm.js'){}#-->
const customForm = {
template: /*language=HTML*/ `
<div>
<el-drawer title="自定义设置" size="50%" class="my-drawer" :visible.sync="moreInfoDrawer" append-to-body>
<el-row :gutter="50" type="flex">
<el-col :span="4">
<span>分工会人数限制</span>
</el-col>
<el-col :span="20">
<el-button @click="openSetUpUnionLimit(moreInfoIndex)" type="primary" size="small">
设置分工会人数限制
</el-button>
<span
v-if="formData.courseList[moreInfoIndex].unionLimit && formData.courseList[moreInfoIndex].unionLimit.length > 0"
class="text-success"
>
已设置
</span>
<span v-else class="text-danger">未设置</span>
</el-col>
</el-row>
<el-row :gutter="50" type="flex">
<el-col :span="4">
<span>承办工会</span>
</el-col>
<el-col :span="20">
<el-select v-model="formData.courseList[moreInfoIndex].hostUnionId" placeholder="请选择承办工会"
style="width: 100%" clearable>
<el-option :label="item.name" :value="item.id" :key="item.id"
v-for="item in unionList"></el-option>
</el-select>
</el-col>
</el-row>
<el-row :gutter="50" type="flex">
<el-col :span="4">
<span>对内报名时间</span>
</el-col>
<el-col :span="20">
<el-date-picker
placeholder="请选择对内报名时间"
style="width: 100%"
type="datetime"
v-model="formData.courseList[moreInfoIndex].interTime"
format="yyyy-MM-dd HH:mm"
value-format="yyyy-MM-dd HH:mm"
></el-date-picker>
</el-col>
</el-row>
<el-row :gutter="50" type="flex">
<el-col :span="4">
<span>是否签到</span>
</el-col>
<el-col :span="20">
<el-radio-group v-model="formData.courseList[moreInfoIndex].isMobileSign" size="small">
<el-radio border :label="true">签到</el-radio>
<el-radio border :label="false">不签到</el-radio>
</el-radio-group>
</el-col>
</el-row>
<el-row v-if="formData.courseList[moreInfoIndex].isMobileSign === true" :gutter="50" type="flex">
<el-col :span="4">
<span>签到方式</span>
</el-col>
<el-col :span="20">
<el-radio-group v-model="formData.courseList[moreInfoIndex].signType" size="small">
<el-radio border :label="1">扫描二维码</el-radio>
<el-radio border :label="2">被扫</el-radio>
<el-radio border :label="3">GPS定位签到</el-radio>
</el-radio-group>
</el-col>
</el-row>
<el-row
v-if="formData.courseList[moreInfoIndex].isMobileSign === true
&& formData.courseList[moreInfoIndex].signType == 3"
:gutter="50"
type="flex"
>
<el-col :span="4">
<span>地点坐标</span>
</el-col>
<el-col :span="20">
<el-button @click="openMap(moreInfoIndex)" type="primary" size="small">设置签到点</el-button>
</el-col>
</el-row>
<el-row :gutter="50" type="flex">
<el-col :span="4">
<span>是否领取礼品</span>
</el-col>
<el-col :span="20">
<el-radio-group v-model="formData.courseList[moreInfoIndex].isReceiveGift" size="small">
<el-radio border :label="true">领取</el-radio>
<el-radio border :label="false">不领取</el-radio>
</el-radio-group>
</el-col>
</el-row>
<el-row v-if="formData.courseList[moreInfoIndex].isReceiveGift === true" :gutter="50" type="flex">
<el-col :span="4">
<span>领取方式</span>
</el-col>
<el-col :span="20">
<el-radio-group v-model="formData.courseList[moreInfoIndex].giftType" size="small">
<el-radio border :label="1">扫描二维码</el-radio>
<el-radio border :label="2">面对面确认</el-radio>
</el-radio-group>
</el-col>
</el-row>
<el-row :gutter="50" type="flex">
<el-col :span="4">
<span>报名方式</span>
</el-col>
<el-col :span="20">
<el-radio-group
v-model="formData.courseList[moreInfoIndex].reserveMode"
size="small"
>
<el-radio border :label="1">报名人员减少模式</el-radio>
<el-radio border :label="2">候补模式</el-radio>
</el-radio-group>
</el-col>
</el-row>
<el-row :gutter="50" type="flex" v-if="formData.courseList[moreInfoIndex].reserveMode === 2">
<el-col :span="4">
<span>候补数量</span>
</el-col>
<el-col :span="20">
<el-input-number :controls="false" size="small" style="width: 100%"
:max="100"
:min="0"
:precision="0"
step-strictly
v-model="formData.courseList[moreInfoIndex].waitingNum"></el-input-number>
</el-col>
</el-row>
<div style="text-align: right">
<el-button @click="moreInfoDrawer = false">取 消</el-button>
<el-button type="primary" @click="moreInfoDrawer = false">保 存</el-button>
</div>
</el-drawer>
<el-dialog :close-on-click-modal="false" :visible.sync="mapDialog" title="位置信息" :append-to-body="true">
<map-container v-if="mapDialog" :position.sync="formData.courseList[mapIndex].courseLocationCoordinates"></map-container>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="mapDialog = false">确 定</el-button>
</span>
</el-dialog>
<union-form ref="unionFormRef"></union-form>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
return {
moreInfoDrawer: false,
unionList: [],
formData: {},
moreInfoRow: {},
moreInfoIndex: 0,
mapDialog: false,
mapIndex: 0,
}
},
components: {
"union-form": unionForm,
"map-container": httpVueLoader("/components/plugins/mapContainer/MapContainer.vue?v=1.0.1")
},
methods: {
openMap(index) {
this.mapIndex = index
this.mapDialog = true
},
openSetUpUnionLimit(index) {
this.$refs.unionFormRef.onOpen(this.formData, index)
},
async onOpen(formData, chooseRow, index) {
this.formData = formData
this.moreInfoRow = chooseRow
this.moreInfoIndex = index
this.unionList = await this.$businessTool.listUnion()
this.moreInfoDrawer = true
},
},
created() {
if(!this.formData.courseList) {
this.formData = {courseList: [{unionLimit: []}]}
}
},
style: /*language=CSS*/ `
.my-drawer .el-col-4 {
text-align: right;
}
.my-drawer .el-row {
margin-bottom: 20px;
}
.el-drawer__body {
padding: 20px;
}
.el-row--flex {
align-items: center;
}
`
}
@@ -0,0 +1,201 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
@change="doSearch"
placeholder="请选择年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="活动名称:">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入活动名称"
clearable
style="width: 100%"
v-model="pageForm.activityName"
></el-input>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="活动列表">
<el-button @click="openAdd" size="small" type="primary">
<i class="ti-plus"></i>新建活动
</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:width="column.width"
:sortable="column.sortable"
show-overflow-tooltip
v-for="(column, index) in tableColumns"
:key="index"
>
<template v-slot="{ row }" v-if="column.prop === 'isDisabled'">
<el-switch
:active-value="false"
:inactive-value="true"
@change="(val) => { activityStatusChange(row.notice, val,row.id) }"
active-color="#13ce66"
inactive-color="#ff4949"
v-model="row.isDisabled"
></el-switch>
</template>
<template v-slot="{ row: { createdAt } }" v-else-if="column.prop === 'createdAt'">
{{ $moment(createdAt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'activityTime'">
<span>{{ $moment(row.activityStartTime).format('YYYY/MM/DD') }}</span>
<span></span>
<span>{{ $moment(row.activityEndTime).format('YYYY/MM/DD') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="150px">
<template v-slot="{ row }">
<el-dropdown>
<el-button plain size="mini">
<i class="ti-settings"></i>
<span class="ti-angle-down"></span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="openActivityCode(row.id)">活动二维码</el-dropdown-item>
<el-dropdown-item @click.native="makeCode(row)">签到二维码</el-dropdown-item>
<el-dropdown-item @click.native="onView(row)">查看</el-dropdown-item>
<el-dropdown-item @click.native="openEdit(row)">编辑</el-dropdown-item>
<el-dropdown-item @click.native="onDelete(row)">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<basic-form ref="formRef" @back="back" @refresh="doSearch"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
<make-qrcode ref="codeRef"></make-qrcode>
<el-dialog
title="活动二维码"
:visible.sync="codeDialogVisible"
:close-on-click-modal="false"
width="30%">
<div style=" display: flex;justify-content: center;">
<qrcode :options="{ width: 400 }" :value="activityUrl" ></qrcode>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="codeDialogVisible = false" type="primary">关 闭</el-button>
</span>
</el-dialog>
</guava>
</div>
<script>
<!--#include('info.js'){}#-->
<!--#include('basicForm.js'){}#-->
<!--#include('makeQrcode.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["CAMPUS", "LITERACY_SIGNUP_TYPE"],
mixins: [initTableMixins],
components: {
"info": info,
"basic-form": basicForm,
"make-qrcode": makeQrcode,
},
data() {
return {
pageForm: {
year: new Date().getFullYear() + ''
},
tableColumns: [
{ label: "活动名称", prop: "activityName", width: 600 },
{ label: "活动时间", prop: "activityTime" },
{ label: "是否开启", prop: "isDisabled", width: 100 },
{ label: "创建时间", prop: "createdAt" }
],
codeDialogVisible: false,
activityUrl: '',
}
},
methods: {
back() {
this.$refs.guava.index()
},
openAdd() {
this.$refs.guava.edit(() => {
this.$refs.formRef.initData()
})
},
openEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.formRef.initData(row)
})
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.initData(row.id)
})
},
openActivityCode(id) {
this.activityUrl = location.origin + "/platform/mobile/literacyActivity/activityInfo?activityId="
+ id + '&isMySign=0'
this.codeDialogVisible = true
},
makeCode(row) {
this.$refs.codeRef.initData(row)
},
async activityStatusChange(notice, val, id) {
const resp = await this.$axios.post(loc() + "/activityStatusChange", { notice: notice, isDisabled: val, id })
if (resp.code === 0) {
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
},
async onDelete(row) {
this.$confirm("此操作将永久删除, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post(loc() + "/onDelete", { id: row.id })
this.$message.success(resp.msg)
this.doSearch()
}).catch(() => {})
},
},
async created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,111 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-tabs>
<el-tab-pane label="基础信息">
<el-descriptions :column="2" border class="table_fixed mt20">
<el-descriptions-item :span="2" label="活动名称">{{viewData.activityName}}</el-descriptions-item>
<el-descriptions-item label="年度">{{viewData.year}}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{$moment(viewData.createdAt).format('YYYY-MM-DD HH:mm:ss')}}</el-descriptions-item>
<el-descriptions-item label="活动开始时间">{{viewData.activityStartTime}}</el-descriptions-item>
<el-descriptions-item label="活动结束时间">{{viewData.activityEndTime}}</el-descriptions-item>
<el-descriptions-item label="报名开始时间">{{viewData.activitySignUpStartTime}}</el-descriptions-item>
<el-descriptions-item label="报名结束时间">{{viewData.activitySignUpEndTime}}</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane :label="literacyType + '信息'">
<el-table :data="viewData.courseList" class="mt20">
<el-table-column :label="literacyType + '名称'" prop="courseName"></el-table-column>
<el-table-column label="类型" prop="courseTypeName"></el-table-column>
<el-table-column label="人数" prop="coursePeopleNumber"></el-table-column>
<el-table-column label="预留名额" prop="courseReservedNumber"></el-table-column>
<el-table-column label="地点" prop="courseLocation">
<template v-slot="{row}">
<el-button @click="openViewMap(row.courseLocationCoordinates)" type="text">{{row.courseLocation}}</el-button>
</template>
</el-table-column>
<el-table-column label="校区" prop="campus"></el-table-column>
<el-table-column label="负责人" prop="courseInstructor"></el-table-column>
<el-table-column label="上课时间" prop="courseTimeList" width="200px">
<template v-slot="{ row }">
<el-button @click="openViewCourseTime(row.courseTimeList)" type="text">点击查看课程时间</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<el-dialog :visible.sync="courseTimeListDialog" :title="literacyType + '时间'" width="60%" append-to-body>
<el-table :data="courseTimeList">
<el-table-column label="日期" prop="courseDate">
<template v-slot="{row}">{{$moment(row.courseDate).format('YYYY-MM-DD')}}</template>
</el-table-column>
<el-table-column label="开始时间" prop="courseStartTime"></el-table-column>
<el-table-column label="结束时间" prop="courseEndTime"></el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="courseTimeListDialog = false" type="primary">关 闭</el-button>
</span>
</el-dialog>
<el-dialog :visible.sync="viewMapDialog" title="地点" width="60%">
<div id="viewMap" style="width: 100%; height: 500px"></div>
</el-dialog>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
return {
literacyType: '',
viewData: {},
courseTimeListDialog: false,
courseTimeList: [],
viewMapDialog: false,
}
},
methods: {
initData(id) {
this.$axios.post(loc() + "/findOne", { id: id })
.then((resp) => {
if (resp.code === 0) {
this.viewData = resp.data
const type = this.dict.type.LITERACY_SIGNUP_TYPE.find((o) => o.code === resp.data.literacyType)
this.literacyType = type?.name || "培训班"
}
})
},
openViewCourseTime(courseTimeList) {
this.courseTimeList = courseTimeList
this.courseTimeListDialog = true
},
openViewMap(point) {
if (!Array.isArray(point)) {
this.$message.warning("没有设置点位,无法通过地图查看")
return
}
this.viewMapDialog = true
this.$nextTick(() => {
viewMap = new AMap.Map("viewMap", {
resizeEnable: true,
center: point,
zoom: 16
})
if (viewMarker) {
viewMap.remove(viewMarker)
}
viewMarker = new AMap.Marker({
position: point,
offset: new AMap.Pixel(-13, -30)
})
viewMap.add(viewMarker)
viewMap.setFitView(null, false, [150, 60, 100, 60])
})
},
},
style: /*language=CSS*/ `
.el-button--text {
padding: 0;
}
`
}
@@ -0,0 +1,82 @@
const makeQrcode = {
template: /*language=HTML*/ `
<div>
<el-dialog :close-on-click-modal="false" :visible.sync="courseDialog"
append-to-body :title="literacyType + '列表'" width="60%">
<el-table :data="courseList">
<el-table-column :label="literacyType + '名称'" prop="courseName"></el-table-column>
<el-table-column label="校区" prop="campus"></el-table-column>
<el-table-column label="是否签到" prop="isMobileSign">
<template v-slot="{row}">
<span v-if="row.isMobileSign === true">签到</span>
<span v-else>不签到</span>
</template>
</el-table-column>
<el-table-column label="签到方式" prop="signType">
<template v-slot="{row}">
<span v-if="row.signType === 1">扫描二维码</span>
<span v-else-if="row.signType === 2">被扫</span>
<span v-else-if="row.signType === 3">GPS定位签到</span>
<span v-else>暂无签到方式</span>
</template>
</el-table-column>
<el-table-column label="是否领取礼品" prop="isReceiveGift">
<template v-slot="{row}">
<span v-if="row.isReceiveGift === true">领取</span>
<span v-else>不领取</span>
</template>
</el-table-column>
<el-table-column label="领取方式" prop="giftType">
<template v-slot="{row}">
<span v-if="row.giftType === 1">扫描二维码</span>
<span v-else-if="row.giftType === 2">面对面确认</span>
<span v-else>暂无领取方式</span>
</template>
</el-table-column>
<el-table-column label="操作" width="260">
<template v-slot="{row}">
<el-button v-if="row.signType === 1"
@click="makeCourseCode(row)"
size="mini" type="primary">
生成二维码
</el-button>
<el-button v-else size="mini" type="text">该{{literacyType}}的签到方式不支持生成二维码</el-button>
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="courseDialog = false" type="primary">关 闭</el-button>
</span>
</el-dialog>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
return {
courseDialog: false,
literacyType: "",
courseList: [],
}
},
methods: {
initData(row) {
this.courseList = row.courseList
const type = this.dict.type.LITERACY_SIGNUP_TYPE.find((o) => o.code === row.literacyType)
this.literacyType = type?.name || "培训班"
this.courseDialog = true
},
makeCourseCode(row) {
const o = {courseId: row.id}
const content = jrQrcode.getQrBase64(JSON.stringify(o))
let image = new Image()
image.src = content
let viewer = new Viewer(image, {
zIndex: 99999999,
})
viewer.show()
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,221 @@
const unionForm = {
template: /*language=HTML*/ `
<div>
<el-dialog :close-on-click-modal="false" :visible.sync="setUpUnionLimitDialog" title="分工会人数限制" top="50px" append-to-body>
<div class="left-span-label" style="display: flex; justify-content: space-between; align-items: center">
<div>分段设置</div>
<div>
<el-button size="small" type="primary" @click="unionLimitQuickSetting">应用分段设置</el-button>
</div>
</div>
<el-row v-for="(item,index) in unionUserNumCalc" :key="index" :gutter="20" class="mb5">
<el-col :span="7">
<el-input-number
v-model="item.startNum"
:precision="0"
:step="1"
:min="1"
placeholder="请输入最小人数"
style="width: 100%"
></el-input-number>
</el-col>
<el-col :span="7">
<el-input-number
v-model="item.endNum"
:precision="0"
:step="1"
:min="1"
placeholder="请输入最大人数"
style="width: 100%"
></el-input-number>
</el-col>
<el-col :span="6">
<el-input-number
v-model="item.resultNum"
:precision="0"
:step="1"
:min="1"
placeholder="请输入限制人数"
style="width: 100%"
></el-input-number>
</el-col>
<el-col :span="4" class="text-right">
<el-button icon="el-icon-plus" @click="unionUserNumCalc.push({})"></el-button>
<el-button icon="el-icon-minus" @click="unionUserNumCalc.splice(index,1)" :disabled="unionUserNumCalc.length===1"></el-button>
</el-col>
</el-row>
<el-row class="mt10">
<div v-for="(item,index) in unionUserNumCalcTips" class="text-danger">
<span class="mr10">({{index+1}}).</span>
{{item}}
</div>
</el-row>
<div class="left-span-label" style="display: flex; justify-content: space-between; align-items: center">
<div>比例设置</div>
<div>
一键比例:
<el-input-number
v-model="unionUserNumOneKeyRatio"
:precision="0"
:step="1"
:min="0"
placeholder="请输入一键比例"
size="small"
:max="100"
></el-input-number>
<el-button size="small" type="primary" @click="applyScaleSettings" class="ml5">应用比例设置</el-button>
</div>
</div>
<el-table :data="formData.courseList[unionLimitIndex].unionLimit" max-height="500px">
<el-table-column prop="name" label="分工会"></el-table-column>
<el-table-column prop="teacherCount" label="人数"></el-table-column>
<el-table-column prop="ratio" label="比例(%)">
<template v-slot="{row}">
<el-input-number v-model="row.ratio" :precision="0" :step="1" :min="0" :max="100"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="limitCount" label="限制人数">
<template v-slot="{row}">
<el-input-number
v-model="row.limitCount"
:precision="0"
:step="1"
:min="0"
:max="row.teacherCount"
@change="calSummaryCount"
></el-input-number>
</template>
</el-table-column>
</el-table>
<el-row class="mt20" justify="end" type="flex">
<div class="text-danger" style="width: 100%; font-size: 18px; display: flex; align-items: center; font-weight: bold">
限制总人数:{{summaryCount}}人
</div>
<el-button @click="clearUnionLimit" type="danger">清空分工会人数限制</el-button>
<el-button @click="setUpUnionLimitDialog=false">取消</el-button>
<el-button @click="doConfirmSetUpUnionLimit" type="primary">确定</el-button>
</el-row>
</el-dialog>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
return {
formData: {},
unionLimitIndex: 0,
setUpUnionLimitDialog: false,
unionList: [],
unionUserNumCalc: [{}],
unionUserNumOneKeyRatio: null,
summaryCount: 0,
}
},
computed: {
unionUserNumCalcTips() {
return this.unionUserNumCalc.map((v) => {
return (
(v.startNum ? v.startNum : "?") +
"-" +
(v.endNum ? v.endNum : "?") +
"人的分工会,限报" +
(v.resultNum ? v.resultNum : "?") +
"人"
)
})
}
},
methods: {
calSummaryCount() {
const array = this.formData.courseList[this.unionLimitIndex].unionLimit
if (array) {
this.summaryCount = array.reduce((prev, curr) => {
const value = Number(curr.limitCount)
if (!isNaN(value)) {
return prev + curr.limitCount
} else {
return prev
}
}, 0)
}
},
async onOpen(formData, index) {
this.unionList = await this.$businessTool.listUnion()
this.formData = formData
this.unionLimitIndex = index
this.setUpUnionLimitDialog = true
if (
!this.formData.courseList[this.unionLimitIndex].unionLimit ||
this.formData.courseList[this.unionLimitIndex].unionLimit.length === 0
) {
const resp = await this.$axios.get("/platform/literacy/manage/activity/getUnionLimit", {
activityScopeId: this.formData.activityGroupId
})
if (resp.code === 0) {
this.$set(this.formData.courseList[this.unionLimitIndex], "unionLimit", resp.data)
}
}
this.summaryCount = this.formData.courseList[this.unionLimitIndex].unionLimit.reduce((prev, curr) => {
const value = Number(curr.limitCount)
if (!isNaN(value)) {
return prev + curr.limitCount
} else {
return prev
}
}, 0)
},
unionLimitQuickSetting() {
this.unionUserNumCalc.forEach((v, i) => {
const startNum = v.startNum
const endNum = v.endNum
const resultNum = v.resultNum
if (startNum > endNum) {
this.$message.warning("第" + (i + 1) + "行设置错误")
} else {
this.formData.courseList[this.unionLimitIndex].unionLimit.forEach((x) => {
if (x.teacherCount >= startNum && x.teacherCount <= endNum) {
x.limitCount = resultNum
}
})
this.calSummaryCount()
}
})
},
doConfirmSetUpUnionLimit() {
this.setUpUnionLimitDialog = false
},
//应用比例设置
applyScaleSettings() {
this.formData.courseList[this.unionLimitIndex].unionLimit.forEach((v) => {
v.limitCount = parseFloat(((v.teacherCount * this.unionUserNumOneKeyRatio) / 100).toFixed(0))
if (v.ratio) {
v.limitCount = parseFloat(((v.teacherCount * v.ratio) / 100).toFixed(0))
}
})
this.calSummaryCount()
},
async clearUnionLimit() {
const confirm = await this.$confirm("确定要清空分工会人数限制吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
if ("confirm" === confirm) {
this.formData.courseList[this.unionLimitIndex].unionLimit = []
this.unionUserNumOneKeyRatio = null
this.unionUserNumCalc = [{}]
this.setUpUnionLimitDialog = false
}
},
},
created() {
if(!this.formData.courseList) {
this.formData = {courseList: [{unionLimit: []}]}
}
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,156 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-icon-arrow-left,
.el-icon-arrow-right {
font-size: 28px;
font-weight: bolder;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
placeholder="请选择年度"
type="year"
style="width: 100%"
@change="yearChange"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="活动名称:">
<el-select @change="activityChange" style="width: 100%" v-model="pageForm.activityId">
<el-option :label="item.activityName" :value="item.id" v-for="item in activityList" :key="item.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool :label="literacyType">
<el-button type="primary" size="small" @click="exportSignUser" :disabled="!pageForm.activityId">导出报名人员</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column :label="literacyType" prop="courseName" show-overflow-tooltip></el-table-column>
<el-table-column label="类型" prop="courseType" sortable show-overflow-tooltip></el-table-column>
<el-table-column :label="literacyType + '地点'" prop="courseLocation" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="负责人" prop="courseInstructor" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="最多报名人数" prop="coursePeopleNumber" sortable align="center" header-align="center" show-overflow-tooltip>
<template v-slot="{row}">
<span v-if="row.reserveMode === 1">
{{row.coursePeopleNumber}}
</span>
<span v-if="row.reserveMode === 2">
{{(row.coursePeopleNumber + row.waitingNum) + '(候补占' + row.waitingNum + ''}}
</span>
</template>
</el-table-column>
<el-table-column label="预留人数" prop="courseReservedNumber" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="已报名人数" prop="registerNum" sortable show-overflow-tooltip>
<template v-slot="{row}">
<el-link @click="openView(row)" type="primary">
{{row.registerNum}}
</el-link>
</template>
</el-table-column>
<el-table-column label="操作" width="200px">
<template v-slot="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="openSign(row)" size="mini" v-if="row.interTime" :type="row.openOtherUnion === true ? 'danger' : 'primary'">
{{row.openOtherUnion === true ? '关闭报名' : '开放报名'}}
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('info.js'){}#-->
new Vue({
el: "#app",
dicts: ["LITERACY_SIGNUP_TYPE"],
mixins: [initTableMixins],
components: {
"info": info,
},
data() {
return {
activityList: [],
pageForm: {
year: new Date().getFullYear().toString(),
activityId: null
},
tableColumns: [
{ label: "培训班", prop: "courseName" },
{ label: "类型", prop: "courseType", sortable: true },
{ label: "地点", prop: "courseLocation" },
{ label: "教师", prop: "courseInstructor", sortable: true },
{ label: "最多报名人数", prop: "coursePeopleNumber", sortable: true },
{ label: "已报名人数", prop: "registerNum", sortable: true }
],
literacyType: "培训班",
}
},
methods: {
async openSign(row) {
const resp = await this.$axios.post(loc() + "/signChange", { courseId: row.id, openOtherUnion: !row.openOtherUnion })
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
},
activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.LITERACY_SIGNUP_TYPE.find(o => o.code === activity.literacyType)
this.literacyType = type?.name || "培训班"
},
exportSignUser() {
this.$downLoad(loc() + "/exportSignUser", { activityId: this.pageForm.activityId })
},
async yearChange() {
this.pageForm.activityId = null
await this.getActivityList()
await this.doSearch()
},
async getActivityList() {
const resp = await this.$axios.post(loc() + "/activityList", { year: this.pageForm.year })
this.activityList = resp.data
if (this.activityList && this.activityList.length > 0) {
this.pageForm.activityId = this.activityList[0].id
this.activityChange(this.activityList[0].id)
}
},
async initData() {
await this.getActivityList()
},
async openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
}
},
async created() {
await this.initData()
await this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,98 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-tabs>
<el-tab-pane label="报名人员">
<el-table :data="registerUserTableData" class="mt20">
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="(column, index) in registerUserTableColumns"
:key="index"
>
<template v-slot="{row}" v-if="column.prop === 'state'">
<span class="text-success" v-if="row.state === 1">正常报名</span>
<span class="text-warning" v-else-if="row.state === 2">候补报名</span>
<span class="text-success" v-else-if="row.state === 3">正常报名(候补)</span>
<span class="text-info" v-else-if="row.state === 4">无效报名(缺席)</span>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="签到情况" v-if="clickRow.isMobileSign === true && Object.keys(userSignInfo).length > 0">
<el-tabs style="height: 600px" tab-position="left" class="mt20">
<el-tab-pane v-for="(item, key) in userSignInfo" :key="key">
<span slot="label">
<i class="el-icon-date"></i>
{{key}}
</span>
<el-table :data="item" style="max-height: 600px; overflow-y: auto">
<el-table-column label="姓名" prop="username"></el-table-column>
<el-table-column label="工号" prop="loginname"></el-table-column>
<el-table-column label="是否签到" prop="isAttend">
<template v-slot="{row}">
<template v-if="Date.now() < Date.parse(row.courseStartTime)">
<span class="text-default">未开始</span>
</template>
<template v-else>
<span class="text-success" v-if="row.isAttend">已签到</span>
<span class="text-warning" v-else>未签到</span>
</template>
</template>
</el-table-column>
<el-table-column label="签到时间" prop="attendTime"></el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-tab-pane>
</el-tabs>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
return {
registerUserTableData: [],
registerUserTableColumns: [
{ label: "姓名", prop: "username" },
{ label: "工号", prop: "loginname" },
{ label: "单位", prop: "unitName" },
{ label: "分工会", prop: "unionName" },
{ label: "联系方式", prop: "mobile" },
{ label: "报名时间", prop: "signUpTime" },
{ label: "报名状态", prop: "state" }
],
cloneTableColumns: [
{label: '姓名', prop: 'username'},
{label: '工号', prop: 'loginname'},
{label: '单位', prop: 'unitName'},
{label: '分工会', prop: 'unionName'},
{label: '联系方式', prop: 'mobile'},
{label: '报名时间', prop: 'signUpTime'},
{label: '报名状态', prop: 'state'},
],
userSignInfo: {},
clickRow: {}
}
},
methods: {
async onOpen(row) {
this.clickRow = row
const resp_register = await this.$axios.post(loc() + "/registerUserList", {courseId: row.id})
this.registerUserTableData = resp_register.data
const resp_signInfo = await this.$axios.post(loc() + "/getSignInfo", {courseId: row.id})
this.userSignInfo = resp_signInfo.data
const resp_columnInfo = await $.get(loc() + '/getTaleColumnInfo', {courseId: row.id})
if (resp_columnInfo.data) {
this.registerUserTableColumns = []
this.registerUserTableColumns = this.cloneTableColumns.concat(resp_columnInfo.data)
}
}
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,350 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form label-width="120px" :model="formData" ref="addForm" :rules="rules">
<el-form-item prop="code" label="类型编码">
<el-input v-model="formData.code" placeholder="请输入类型编码"></el-input>
</el-form-item>
<el-form-item prop="typeName" label="类型名称">
<el-input v-model="formData.typeName" placeholder="请输入类型名称"></el-input>
</el-form-item>
<el-form-item prop="isBringFamily" label="是否携带家属">
<el-radio-group v-model="formData.isBringFamily" @input="isBringFamilyInput">
<el-radio :label="true" border>携带</el-radio>
<el-radio :label="false" border>不携带</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="formData.isBringFamily === true" prop="isAddFamily" label="家属纳入总人数">
<el-radio-group v-model="formData.isAddFamily">
<el-radio :label="true" border>纳入</el-radio>
<el-radio :label="false" border>不纳入</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="formData.isBringFamily === true" prop="selfAddFamily" label="本人纳入总人数">
<el-radio-group v-model="formData.selfAddFamily">
<el-radio :label="true" border>纳入</el-radio>
<el-radio :label="false" border>不纳入</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div class="left-span-label" style="display: flex; justify-content: space-between; align-items: center">
<div>
报名填写字段
<span style="color: #c64120; margin-left: 10px">
注:移动端报名时字段的显示顺序会按照下面表格中的序号进行排列、字段编码不能重复
</span>
</div>
<div>
<el-button
@click="formData.literacyMobileSignColumnList.push({isRequired: false})"
size="small"
type="primary"
style="margin-left: 10px"
>
<i class="ti-plus"></i>
添加
</el-button>
</div>
</div>
<el-table :data="formData.literacyMobileSignColumnList">
<el-table-column label="序号" prop="columnIndex">
<template v-slot="{row}">
<el-input-number v-model="row.columnIndex" placeholder="请输入序号"></el-input-number>
</template>
</el-table-column>
<el-table-column label="字段名称" prop="columnName">
<template v-slot="{row}">
<el-input v-model="row.columnName" placeholder="请输入字段名称"></el-input>
</template>
</el-table-column>
<el-table-column label="字段编码" prop="columnCode">
<template v-slot="{row}">
<el-input
v-model="row.columnCode"
placeholder="请输入字段编码"
:disabled="formData.isBringFamily === true && row.columnCode === 'xdqsrs'"
></el-input>
</template>
</el-table-column>
<el-table-column label="控件类型" prop="columnFormType">
<template v-slot="{row, $index}">
<el-select
filterable
v-model="row.columnFormType"
@change="(val) => {columnFormTypeChange(val, $index)}"
placeholder="请选择控件类型"
>
<el-option v-for="item in columnFormTypeList" :label="item.description" :value="item.code" :key="item.code"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="字段类型" prop="columnType">
<template v-slot="{row}">
<el-select
filterable
placeholder="请选择字段类型"
v-model="row.columnType"
>
<el-option v-for="item in columnTypeOptions" :label="item" :value="item" :key="item"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column label="是否必填" prop="isRequired" sortable>
<template v-slot="{row}">
<el-switch
v-model="row.isRequired"
active-color="#13ce66"
inactive-color="#ff4949"
:active-value="true"
:inactive-value="false"
active-text="是"
inactive-text="否"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作">
<template v-slot="{row, $index}">
<el-button
@click="openDetailedParams(row, $index)"
:disabled="!['SELECT', 'RADIO', 'FILE'].includes(row.columnFormType)"
size="mini"
type="primary"
>
设置详细参数
</el-button>
<el-button
@click="formData.literacyMobileSignColumnList.splice($index, 1)"
:disabled="formData.isBringFamily === true && row.columnCode === 'xdqsrs'"
size="mini"
type="danger"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div style="float: right; margin: 20px 0">
<el-button @click="$emit('refresh')">取 消</el-button>
<el-button type="primary" @click="doHandle">确 定</el-button>
</div>
<el-drawer append-to-body :visible.sync="detailedParamsVisible" size="40%">
<template #title>
<div class="left-span-label">设置详细参数</div>
</template>
<el-form class="mt20" ref="paramForm" :rules="paramFormRules" :model="clickRow" label-width="80px">
<template v-if="['SELECT'].includes(clickRow.columnFormType)">
<el-form-item label="选项列表" prop="selectValues">
<el-select
v-model="clickRow.selectValues"
multiple
style="width: 100%"
filterable
allow-create
default-first-option
placeholder="请选择选项列表(如无数据时,需手动输入选项进行添加)"
>
<el-option v-for="item in clickRow.columnOptions" :label="item" :value="item" :key="item"></el-option>
</el-select>
</el-form-item>
</template>
<template v-if="['RADIO'].includes(clickRow.columnFormType)">
<el-form-item label="选项列表" prop="selectValues">
<el-select
v-model="clickRow.selectValues"
multiple
style="width: 100%"
filterable
allow-create
default-first-option
placeholder="请选择选项列表(如无数据时,需手动输入选项进行添加)"
>
<el-option v-for="item in clickRow.columnOptions" :label="item" :value="item" :key="item"></el-option>
</el-select>
</el-form-item>
</template>
<template v-if="['FILE'].includes(clickRow.columnFormType)">
<el-form-item label="文件类型" prop="fileType">
<el-select v-model="clickRow.fileType" multiple style="width: 100%" filterable placeholder="请选择文件类型">
<el-option label="jpg" value="jpg"></el-option>
<el-option label="png" value="png"></el-option>
<el-option label="jpeg" value="jpeg"></el-option>
<el-option label="doc" value="doc"></el-option>
<el-option label="docx" value="docx"></el-option>
<el-option label="xlsx" value="xlsx"></el-option>
<el-option label="pdf" value="pdf"></el-option>
<el-option label="mp3" value="mp3"></el-option>
<el-option label="mp4" value="mp4"></el-option>
</el-select>
</el-form-item>
<el-form-item label="文件个数" prop="fileNumber">
<el-input-number v-model="clickRow.fileNumber" :min="1" :max="10" placeholder="请输入文件个数" style="width: 100%"></el-input-number>
</el-form-item>
</template>
</el-form>
<div style="float: right; margin: 20px 0">
<el-button @click="detailedParamsVisible = false">取 消</el-button>
<el-button type="primary" @click="doDetailParams">确 定</el-button>
</div>
</el-drawer>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
return {
formData: {
literacyMobileSignColumnList: [{ isRequired: false }],
isBringFamily: false,
isAddFamily: false,
selfAddFamily: true,
},
rules: {
typeName: [{ required: true, message: "请输入类型名称", trigger: ["change", "blur"] }],
code: [{ required: true, message: "请输入类型编码", trigger: ["change", "blur"] }],
isBringFamily: [{ required: true, message: "请选择是否携带家属", trigger: ["blur", "change"] }],
isAddFamily: [{ required: true, message: "请选择家属是否纳入总人数", trigger: ["blur", "change"] }]
},
columnTypeOptions: [],
columnFormTypeList: [],
clickRow: {},
paramFormRules: {
selectValues: [{ required: true, message: "请选择选项列表", trigger: ["blur"] }],
fileType: [{ required: true, message: "请选择文件类型", trigger: ["blur"] }],
fileNumber: [{ required: true, message: "请输入文件个数", trigger: ["blur", "change"] }]
},
detailedParamsVisible: false,
}
},
methods: {
isBringFamilyInput(o) {
this.$set(this.formData, "isAddFamily", o === true ? false : null)
if (o === true) {
this.formData.literacyMobileSignColumnList.unshift({
columnName: "携带亲属人数",
columnCode: "xdqsrs",
columnFormType: "INPUT",
columnType: "INT",
isRequired: true
})
} else {
this.formData.literacyMobileSignColumnList.forEach((item, index) => {
if (item.columnCode === "xdqsrs" && this.formData.isBringFamily === false) {
this.formData.literacyMobileSignColumnList.splice(index, 1)
}
})
}
},
columnFormTypeChange(val, index) {
if (val === "FILE") {
this.formData.literacyMobileSignColumnList[index].columnType = "JSON"
this.formData.literacyMobileSignColumnList[index].isDisabled = true
} else {
this.formData.literacyMobileSignColumnList[index].columnType = ""
this.formData.literacyMobileSignColumnList[index].isDisabled = false
}
},
doHandle() {
if (this.formData.id) {
this.doEdit()
} else {
this.doAdd()
}
},
async doDetailParams() {
const isValid = await this.$refs["paramForm"].validate()
if (isValid) {
this.detailedParamsVisible = false
}
},
openDetailedParams(row, index) {
this.clickRow = row
this.detailedParamsVisible = true
if (this.$refs["paramForm"]) this.$refs["paramForm"].clearValidate()
},
doAdd() {
this.$refs["addForm"].validate((valid) => {
if (valid) {
const newListLength = new Set(this.formData.literacyMobileSignColumnList.map((item) => item.columnCode)).size
const listLength = this.formData.literacyMobileSignColumnList.length
if (listLength > newListLength) {
this.$message.warning('字段编码不能重复')
return
}
const cloneData = clone(this.formData)
this.$axios.post(loc() + "/doAdd", { data: JSON.stringify(cloneData) }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.$emit('refresh')
} else {
this.$message.error(res.msg)
}
})
}
})
},
doEdit() {
this.$refs["addForm"].validate((valid) => {
if (valid) {
const newListLength = new Set(this.formData.literacyMobileSignColumnList.map((item) => item.columnCode)).size
const listLength = this.formData.literacyMobileSignColumnList.length
if (listLength > newListLength) {
this.$message.warning('字段编码不能重复')
return
}
const cloneData = clone(this.formData)
cloneData.literacyMobileSignColumnList = JSON.stringify(cloneData.literacyMobileSignColumnList)
this.$axios.post(loc() + "/doEdit", cloneData).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.$emit('refresh')
} else {
this.$message.error(res.msg)
}
})
}
})
},
async getColTypeOptions() {
const resp = await this.$axios.get(loc() + "/getColumnType")
this.columnTypeOptions = resp.data
},
async getEnumOptions() {
const resp = await this.$axios.post("/open/common/dictEnumOptions", { name: "ColumnFormTypeEnum" })
return resp.data
},
initData(row) {
if(row && row.id) {
this.formData = JSON.parse(JSON.stringify(row))
this.formData.literacyMobileSignColumnList.forEach((item) => {
item.isDisabled = item.columnFormType === "FILE"
})
} else {
this.formData = {
literacyMobileSignColumnList: [{ isRequired: false }],
isBringFamily: false,
isAddFamily: false,
selfAddFamily: true,
}
if (this.$refs["addForm"]) this.$refs["addForm"].resetFields()
}
},
},
async created() {
await this.getColTypeOptions()
this.columnFormTypeList = await this.getEnumOptions()
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,120 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-row--flex.is-justify-space-between {
justify-content: left;
}
.el-drawer__body {
padding: 0 30px 0 10px;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="类型名称:">
<el-input clearable placeholder="请输入类型名称" v-model="pageForm.typeName"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="申请列表">
<el-button type="primary" size="small" @click="openAdd">
<i class="ti-plus"></i>
新增类型
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<el-table-column label="序号" width="70" type="index">
<template v-slot="scope">
<span>{{scope.$index+(pageForm.pageNumber - 1) * pageForm.pageSize + 1}}</span>
</template>
</el-table-column>
<el-table-column label="类型编码" prop="code" sortable></el-table-column>
<el-table-column label="类型名称" prop="typeName"></el-table-column>
<el-table-column label="操作" width="300px">
<template v-slot="{ row }">
<el-button v-if="row.xh!==1" size="mini" type="primary" @click="rowChange(row, false)">上移</el-button>
<el-button v-if="row.xh!==pageForm.totalCount" size="mini" type="primary" @click="rowChange(row, true)">下移</el-button>
<el-button type="primary" size="mini" @click="openEdit(row)">编辑</el-button>
<el-button type="danger" size="mini" @click="doDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="doSearch();$refs.guava.index()"></basic-form>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
},
data() {
return {}
},
methods: {
async rowChange(row, toDown) {
await this.$axios.post(loc() + "/xhChange", { id: row.id, xh: row.xh, toDown }).then((res) => {
if (res.code === 0) {
this.doSearch()
}
})
},
openAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.initData()
})
},
pageData() {
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
openEdit(obj) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.initData(obj)
})
},
doDelete(id) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post(loc() + "/doDelete", { id: id }).then((res) => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
}
})
})
.catch(() => {})
},
},
async created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,144 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
placeholder="请选择年度"
type="year"
style="width: 100%"
@change="yearChange"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="活动名称:">
<el-select @change="activityChange" style="width: 100%" v-model="pageForm.activityId">
<el-option :label="item.activityName" :value="item.id" v-for="item in activityList" :key="item.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="人员调整"></table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column :label="literacyType" prop="courseName" show-overflow-tooltip></el-table-column>
<el-table-column label="类型" prop="courseType" sortable show-overflow-tooltip></el-table-column>
<el-table-column :label="literacyType + '地点'" prop="courseLocation" sortable show-overflow-tooltip></el-table-column>
<el-table-column
:label="literacyType === '培训班' ? '讲师' : '负责人'"
prop="courseInstructor"
sortable
show-overflow-tooltip
></el-table-column>
<el-table-column label="最多报名人数" prop="coursePeopleNumber" sortable show-overflow-tooltip>
<template v-slot="{row}">
<span v-if="row.reserveMode === 1">
{{row.coursePeopleNumber}}
</span>
<span v-if="row.reserveMode === 2">
{{(row.coursePeopleNumber + row.waitingNum) + '(候补占' + row.waitingNum + ''}}
</span>
</template>
</el-table-column>
<el-table-column label="预留人数" prop="courseReservedNumber" sortable show-overflow-tooltip></el-table-column>
<el-table-column label="已报名人数" prop="registerNum" sortable show-overflow-tooltip>
<template v-slot="{row}">
<el-link @click="openView(row)" type="primary">
{{row.registerNum}}
</el-link>
</template>
</el-table-column>
<el-table-column label="操作" width="150px">
<template v-slot="{row}">
<el-button @click="openView(row)" size="mini" type="primary">调整</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<user-info ref="userInfoRef" @refresh="doSearch"></user-info>
</template>
</guava>
</div>
<script>
<!--#include('userInfo.js'){}#-->
new Vue({
el: "#app",
dicts: ["LITERACY_SIGNUP_TYPE"],
mixins: [initTableMixins],
components: {
"user-info": userInfo,
},
data() {
return {
literacyType: "培训班",
activityList: [],
pageForm: {
year: new Date().getFullYear().toString(),
activityId: null
},
tableColumns: [
{ label: "培训班", prop: "courseName" },
{ label: "类型", prop: "courseType", sortable: true },
{ label: "地点", prop: "courseLocation" },
{ label: "教师", prop: "courseInstructor", sortable: true },
{ label: "最多报名人数", prop: "coursePeopleNumber", sortable: true },
{ label: "已报名人数", prop: "registerNum", sortable: true }
],
}
},
methods: {
activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.LITERACY_SIGNUP_TYPE.find(o => o.code === activity.literacyType)
this.literacyType = type?.name || "培训班"
},
async yearChange() {
this.pageForm.activityId = null
await this.getActivityList()
await this.doSearch()
},
async getActivityList() {
const resp = await this.$axios.post(loc() + "/activityList", { year: this.pageForm.year })
this.activityList = resp.data
if (this.activityList && this.activityList.length > 0) {
this.pageForm.activityId = this.activityList[0].id
this.activityChange(this.activityList[0].id)
}
},
async initData() {
await this.getActivityList()
},
async openView(o) {
this.$refs.guava.view(() => {
const activity = this.activityList.find((o) => o.id === this.pageForm.activityId)
this.$refs.userInfoRef.onOpen(o, activity)
})
},
},
async created() {
await this.initData()
await this.pageData()
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,224 @@
const userInfo = {
template: /*language=HTML*/ `
<div>
<div class="left-span-label">{{ registerCourse.courseName + '报名人员' }}</div>
<div>
<search @search="registerSearch">
<search-item label="姓名/工号:">
<el-input v-model="registerForm.searchKeyword" placeholder="请输入内容"></el-input>
</search-item>
<search-item label="所属工会:">
<el-select v-model="registerForm.unionId" clearable filterable placeholder="请选择院级工会" @change="getUnitList()">
<el-option v-for="item in unionList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="所属单位:">
<el-select v-model="registerForm.unitId" clearable filterable placeholder="请选择单位">
<el-option v-for="item in unitList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
</search>
</div>
<el-table :data="registerUserTableData" class="mt15">
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="(column, index) in registerUserTableColumns"
:key="index"
>
<template v-slot="{row}" v-if="column.prop === 'state'">
<span class="text-success" v-if="row.state === 1">正常报名</span>
<span class="text-warning" v-else-if="row.state === 2">候补报名</span>
<span class="text-success" v-else-if="row.state === 3">正常报名(候补)</span>
<span class="text-info" v-else-if="row.state === 4">无效报名(缺席)</span>
</template>
</el-table-column>
<el-table-column label="操作" width="150px">
<template v-slot="{row}">
<el-button v-if="row.state === 1 || row.state === 3" @click="adjust(row)" size="mini" type="primary">修改</el-button>
<el-button @click="deleteSignUser(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog title="人员调整" append-to-body class="adjustDialog" :close-on-click-modal="false" :visible.sync="adjustDialogVisible" width="50%">
<span style="color: #c33714">注:如单选为灰色选择不了,则表示对应的{{ literacyType }}人数已满!候补报名不做调整。</span>
<el-table :data="courseList" class="mt20">
<el-table-column label="单选" width="160">
<template v-slot="{row}">
<el-radio
:label="row.id"
@change.native="getCurrentRow(row)"
:disabled="(row.courseReservedNumber + row.registerNum) >= row.coursePeopleNumber"
v-model="afterAdjustCourse"
></el-radio>
</template>
</el-table-column>
<el-table-column
:label="literacyType + '列表'"
prop="courseName"
align="center"
header-align="center"
show-overflow-tooltip
></el-table-column>
<el-table-column label="最多报名人数" prop="coursePeopleNumber" align="center" header-align="center">
</el-table-column>
<el-table-column label="预留名额" prop="courseReservedNumber" align="center" header-align="center"></el-table-column>
<el-table-column label="已报名人数" prop="registerNum" align="center" header-align="center"></el-table-column>
<el-table-column label="候补人数" prop="hasWaitingNum" align="center" header-align="center"></el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="adjustDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="doAdjust">确 定</el-button>
</span>
</el-dialog>
</div>
`,
dicts: ["LITERACY_SIGNUP_TYPE"],
data() {
return {
afterAdjustCourse: "",
adjustDialogVisible: false,
unionList: [],
unitList: [],
registerForm: {
unionId: "",
unitId: ""
},
registerCourse: {},
courseList: [],
userInfo: {},
chooseRow: {},
registerUserTableData: [],
registerUserTableColumns: [
{ label: "姓名", prop: "username" },
{ label: "工号", prop: "loginname" },
{ label: "单位", prop: "unitName" },
{ label: "分工会", prop: "unionName" },
{ label: "联系方式", prop: "mobile" },
{ label: "报名时间", prop: "signUpTime" },
{ label: "报名状态", prop: "state" }
],
literacyType: '',
activity: {},
}
},
methods: {
async onOpen(row, activity) {
this.registerCourse = row
this.registerForm.courseId = row.id
this.activity = activity
const resp_register = await this.$axios.post(loc() + "/registerUserList", this.registerForm)
this.registerUserTableData = resp_register.data
const type = this.dict.type.LITERACY_SIGNUP_TYPE.find(o => o.code === activity.literacyType)
this.literacyType = type?.name || "培训班"
},
getCurrentRow(row) {
this.chooseRow = row
},
async doAdjust() {
if (!this.afterAdjustCourse) {
this.$message.warning("请选择要调整的" + this.literacyType + "")
return
}
this.$confirm(
"您确定要将" +
"<span style='color: red'>" +
this.userInfo.username +
"</span>" +
"的报名信息调整到" +
"<span style='color: red'>" +
this.chooseRow.courseName +
"</span>" +
"中吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
dangerouslyUseHTMLString: true
}
)
.then(async () => {
const loading = this.$loading({
lock: true,
text: "努力调整中,感谢您的耐心等待。。。",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
})
const resp = await this.$axios.post(loc() + "/adjust", {
activityId: this.activity.id,
oldCourseId: this.registerCourse.id,
newCourseId: this.afterAdjustCourse,
userId: this.userInfo.userId
})
loading.close()
if (resp.code === 0) {
this.$message.success(resp.msg)
this.adjustDialogVisible = false
await this.registerSearch()
this.$emit("refresh", null)
} else {
this.$message.warning(resp.msg)
}
})
.catch(() => {})
},
async adjust(o) {
this.userInfo = o
this.afterAdjustCourse = ""
await this.getCourse(this.activity.id)
this.adjustDialogVisible = true
},
deleteSignUser(o) {
this.$confirm("您确定要删除" + "<span style='color: red'>" + o.username + "</span>" + "的报名信息吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
dangerouslyUseHTMLString: true
})
.then(async () => {
const resp = await this.$axios.post(loc() + "/deleteSignUser", {
activityId: this.activity.id,
courseId: this.registerCourse.id,
userId: o.userId
})
if (resp.code === 0) {
this.$message.success(resp.msg)
await this.registerSearch()
this.$emit("refresh", null)
} else {
this.$message.warning(resp.msg)
}
})
.catch(() => {})
},
async registerSearch() {
this.registerForm.courseId = this.registerCourse.id
const resp_register = await $.get(loc() + "/registerUserList", this.registerForm)
this.registerUserTableData = resp_register.data
},
async getCourse(val) {
const {data} = await this.$axios.post(loc() + "/getCourse", {activityId: val})
this.courseList = data
}
},
async created() {
this.unionList = await this.$businessTool.listUnion()
this.unitList = await this.$businessTool.listUnit(this.registerForm.unionId)
},
style: /*language=CSS*/ `
.adjustDialog .el-radio__label {
display: none;
}
.adjustDialog .el-dialog__body {
max-height: 600px;
overflow-y: auto;
}
`
}
@@ -0,0 +1,235 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
placeholder="选择年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="活动名称:">
<el-select @change="activityChange" style="width: 100%" v-model="pageForm.activityId">
<el-option :label="item.activityName" :value="item.id" v-for="item in activityList" :key="item.id"></el-option>
</el-select>
</search-item>
<search-item :label="literacyType + ''">
<el-select @change="courseChange" :placeholder="'请选择' + literacyType" style="width: 100%" v-model="pageForm.courseId">
<el-option :label="item.courseName" :value="item.id" v-for="item in courseList" :key="item.id"></el-option>
</el-select>
</search-item>
<search-item label="人员信息:">
<el-input clearable placeholder="输入姓名或者工号搜索" v-model="pageForm.userKeyWord"></el-input>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool ref="tool" :label="literacyType + '(温馨提示:如需补充人员,请在上面选择具体的' + literacyType + ''">
<el-button @click="openReserve" type="primary" v-if="reserveMode === 2" size="small">补充人员</el-button>
<el-button @click="exportSignPerson" type="primary" size="small">导出签到名单</el-button>
<el-button @click="exportGiftPerson" type="primary" size="small">导出领取名单</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column
:label="column.prop === 'courseNames' ? literacyType : column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-if="(column.prop !== 'state' && column.prop !== 'absentCount') || (reserveMode === 2 && column.prop === 'state' && column.prop !== 'absentCount')
|| (column.prop === 'absentCount' && course.isMobileSign === true)"
v-for="(column,index) in tableColumns"
:key="index"
>
<template v-slot="{row}" v-if="column.prop==='isDisabled'">
<span class="text-danger" v-if="row.isDisabled"></span>
<span class="text-success" v-else></span>
</template>
<template v-slot="{row}" v-else-if="column.prop==='state'">
<span class="text-success" v-if="row.state === 1">正常报名</span>
<span class="text-warning" v-else-if="row.state === 2">候补报名</span>
<span class="text-success" v-else-if="row.state === 3">正常报名(候补)</span>
<span class="text-info" v-else-if="row.state === 4">无效报名(缺席)</span>
</template>
</el-table-column>
<el-table-column label="操作" width="150px">
<template v-slot="{row}">
<el-button @click="handleUser(row.userId)" size="mini" type="danger" v-if="!row.isDisabled">拉黑</el-button>
<el-button @click="handleUser(row.userId)" size="mini" type="success" v-if="row.isDisabled">解封</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</guava>
<el-dialog title="补充人员" :visible.sync="reserveDialogVisible" width="55%" top="3%">
<vi-title title="以下为候补人员,已为您按照报名时间降序排列"></vi-title>
<el-table :data="reserveTableData" ref="multipleTable" @selection-change="handleSelectionChange">
<el-table-column :selectable="(row, index) => {return row.state === 2}" type="selection" width="55"></el-table-column>
<el-table-column prop="username" label="姓名"></el-table-column>
<el-table-column prop="loginname" label="工号"></el-table-column>
<el-table-column prop="mobile" label="联系方式"></el-table-column>
<el-table-column prop="unitName" label="单位"></el-table-column>
<el-table-column prop="unionName" label="工会"></el-table-column>
<el-table-column prop="signUpTime" label="报名时间"></el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="reserveDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="reserveDo">确 定</el-button>
</span>
</el-dialog>
</div>
<script>
new Vue({
el: "#app",
dicts: ["LITERACY_SIGNUP_TYPE"],
mixins: [initTableMixins],
data() {
return {
reserveDialogVisible: false,
reserveTableData: [],
activityList: [],
pageForm: {
year: new Date().getFullYear().toString(),
activityId: null
},
tableColumns: [
{ label: "姓名", prop: "username" },
{ label: "工号", prop: "loginname" },
{ label: "联系方式", prop: "mobile" },
{ label: "单位", prop: "unitName", sortable: true },
{ label: "分工会", prop: "unionName", sortable: true },
{ label: "课程", prop: "courseNames", sortable: true },
{ label: "缺席次数", prop: "absentCount" },
{ label: "是否黑名单", prop: "isDisabled", sortable: true }
],
literacyType: "培训班",
courseList: [],
course: {},
reserveMode: 1,
multipleSelection: [],
}
},
methods: {
handleSelectionChange(val) {
this.multipleSelection = val
},
async openReserve() {
const activity = this.activityList.find((o) => o.id === this.pageForm.activityId)
if (this.$moment().unix() < this.$moment(activity.activityEndTime).unix()) {
this.$alert("此活动还未结束,无法补充", "提示", {
confirmButtonText: "确定"
})
return
}
const resp = await this.$axios.post("/platform/literacy/userManage/getReserveUser", { courseId: this.course.id })
this.reserveTableData = resp.data
this.reserveDialogVisible = true
},
reserveDo() {
if (this.multipleSelection.length === 0) {
this.$message.warning("请先在左侧多选框中选择要补充的人员")
return
}
this.$confirm("您选择了" + this.multipleSelection.length + "位教职工,确定要进行补充操作吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(async () => {
const ids = this.multipleSelection.map((o) => o.userId)
const resp = await this.$axios.post("/platform/literacy/userManage/reserveSingUp", {
ids: JSON.stringify(ids),
courseId: this.course.id
})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
this.multipleSelection = []
this.$refs.multipleTable.clearSelection()
this.reserveDialogVisible = false
}
})
.catch(() => {})
},
courseChange(val) {
const course = this.courseList.find((o) => o.id === val)
this.course = course
this.reserveMode = course.reserveMode
if (this.reserveMode === 2) {
this.tableColumns.push({ label: "报名状态", prop: "state", sortable: true })
} else {
const o = this.tableColumns.find((o) => o.label === "报名状态")
if (o !== null && o !== undefined) {
this.tableColumns.splice(this.tableColumns.length - 1, 1)
}
}
this.$refs.tool.app = this
this.doSearch()
},
exportSignPerson() {
this.exportPro(loc() + "/exportSignPerson", { activityId: this.pageForm.activityId })
},
exportGiftPerson() {
this.exportPro(loc() + "/exportGiftPerson", { activityId: this.pageForm.activityId })
},
exportPro(url, param) {
if (param.activityId === null) {
this.$message.warning("请选择活动")
return
}
this.$downLoad(url, param)
},
async activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.dict.type.LITERACY_SIGNUP_TYPE.find(o => o.code === activity.literacyType)
this.literacyType = type?.name || "培训班"
const resp = await this.$axios.post(loc() + "/getCourseByActivityId", { activityId: val })
this.courseList = resp.data
this.pageForm.courseId = ""
},
async handleUser(userId) {
const resp = await $.post(loc() + "/doHandleUser", { userId })
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
}
},
async yearChange() {
this.pageForm.activityId = null
await this.getActivityList()
await this.doSearch()
},
async getActivityList() {
const resp = await this.$axios.post("/platform/literacy/statistics/activity/activityList", { year: this.pageForm.year })
this.activityList = resp.data
if (this.activityList && this.activityList.length > 0) {
this.pageForm.activityId = this.activityList[0].id
await this.activityChange(this.activityList[0].id)
}
},
async initData() {
await this.getActivityList()
},
},
async created() {
await this.initData()
await this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -33,7 +33,7 @@ const clubUserJoin = {
{{viewData.unitName}}
</el-descriptions-item>
<el-descriptions-item label="职务">
{{viewData.governmentPosition}}
{{viewData.position}}
</el-descriptions-item>
<el-descriptions-item label="职称" :span="2">
{{viewData.technicalTitle}}
@@ -56,8 +56,8 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="职务">
<el-form-item prop="governmentPosition" label="职务">
<el-input :value="formData.governmentPosition" readonly placeholder="读取信息中心数据"></el-input>
<el-form-item prop="position" label="职务">
<el-input :value="formData.position" readonly placeholder="读取信息中心数据"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="职称" :span="2">
@@ -143,7 +143,7 @@ layout("/layouts/platform.html"){
// birthday: [{ required: true, message: "请填写", trigger: ["blur", "change"] }],
// mobile: [{ required: true, message: "请填写", trigger: ["blur", "change"] }],
// email: [{ required: true, message: "请填写", trigger: ["blur", "change"] }],
governmentPosition: [{ required: false, message: "请填写", trigger: ["blur", "change"] }],
position: [{ required: false, message: "请填写", trigger: ["blur", "change"] }],
technicalTitle: [{ required: false, message: "请填写", trigger: ["blur", "change"] }],
education: [{ required: false, message: "请填写", trigger: ["blur", "change"] }],
academicDegree: [{ required: false, message: "请填写", trigger: ["blur", "change"] }],
@@ -251,7 +251,8 @@ layout("/layouts/platform.html"){
this.$set(this.formData, "political", user.political)
this.$set(this.formData, "education", user.education)
this.$set(this.formData, "technicalTitle", user.technicalTitle)
this.$set(this.formData, "governmentPosition", user.governmentPosition)
this.$set(this.formData, "position", user.position)
this.$set(this.formData, "academicDegree", user.academicDegree)
}
}
},
@@ -10,7 +10,8 @@ const CLUB_FORM_TEMPLATE = {
</el-col>
<el-col :span="12">
<el-form-item label="协会编码" prop="clubCode">
<el-input placeholder="请输入协会编码" v-model="formData.clubCode" disabled></el-input>
<el-input v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')" placeholder="请输入协会编码" v-model="formData.clubCode"></el-input>
<el-input v-else placeholder="请输入协会编码" v-model="formData.clubCode" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
@@ -104,13 +104,13 @@ layout("/layouts/platform.html"){
let formData = {}
try {
let hz = this.$refs.clubManagerRef.managePerson.filter((o) => o.roleCode === CLUB_ROLE_CONSTANT.CLUB_PRESIDENT)
if (hz.length > 1) {
this.$message.warning({ title: "警告", message: "会长只能有1人" })
if (hz.length !== 1) {
this.$message.warning({ title: "警告", message: "会长需要1人" })
return
}
let msz = this.$refs.clubManagerRef.managePerson.filter((o) => o.roleCode === CLUB_ROLE_CONSTANT.CLUB_SECRETARY)
if (msz.length > 1) {
this.$message.warning({ title: "警告", message: "秘书长只能有1人" })
if (msz.length !== 1) {
this.$message.warning({ title: "警告", message: "秘书长需要1人" })
return
}
formData.sponsor = this.$refs.clubSponsorRef.sponsorData
@@ -7,7 +7,14 @@ layout("/layouts/platform.html"){
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy" placeholder="年度" style="width: 100%"></el-date-picker>
<el-date-picker
:clearable="true"
v-model="pageForm.year"
type="year"
value-format="yyyy"
placeholder="年度"
style="width: 100%"
></el-date-picker>
</search-item>
<search-item label="标题">
<el-input v-model="pageForm.title" placeholder="标题" clearable></el-input>
@@ -28,22 +35,20 @@ layout("/layouts/platform.html"){
<el-table-column prop="userName" label="投稿人姓名"></el-table-column>
<el-table-column prop="unitName" label="投稿人单位"></el-table-column>
<el-table-column prop="unionName" label="投稿人工会"></el-table-column>
<el-table-column prop="clubName" label="投稿人协会"></el-table-column>
<el-table-column prop="submitTime" label="投稿时间"></el-table-column>
<el-table-column label="当前节点" prop="processInstanceNodeName" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" fixed="right">
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
<el-table-column prop="instanceState" label="流程状态">
<template slot-scope="{row}">
<el-button @click="onOpen(row.id)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.processInstanceTaskStatus==='ACTIVE'" @click="openApproval(row)" size="mini" type="primary">
审核
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200px" fixed="right">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button
v-if="row.processInstanceTaskStatus==='COMPLETE' && !row.nextTaskIsComplete"
@click="openRevoke(row.processInstanceTaskId)"
size="mini"
type="danger"
>
撤回
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
@@ -51,21 +56,27 @@ layout("/layouts/platform.html"){
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #public>
<info ref="infoRef"></info>
<div v-if="showApprovalForm">
<div class="process-title">{{formData.processInstanceNodeName}}</div>
<el-form :model="formData" ref="approvalFormRef" label-position="left" label-width="80px">
<el-form-item label="审核意见" prop="approvalOpinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.approvalOpinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button plain @click="$refs.guava.index()">取消</el-button>
<el-button type="danger" @click="doApproval('BACK')">退回修改</el-button>
<el-button type="primary" @click="doApproval('PASS')">同意</el-button>
</el-row>
</div>
<template #edit>
<article-info ref="articleInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</article-info>
</template>
</guava>
</div>
@@ -77,53 +88,68 @@ layout("/layouts/platform.html"){
el: "#app",
store,
mixins: [initTableMixins],
components: { info },
components: {
"article-info": ARTICLE_INFO
},
data() {
return {
pageForm: {
approval: false
},
showApprovalForm: false
showApprovalForm: false,
}
},
methods: {
onOpen(id) {
this.$refs.guava.public(() => {
this.$refs.infoRef.onOpen(id)
// 查看
openView(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = false
this.$refs.articleInfoRef.onOpen(row)
})
},
openApproval(row) {
this.$refs.guava.public(() => {
this.$refs.infoRef.onOpen(row.id)
this.formData = row.approvalParam
// 审核
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
})
},
doApproval(approvalType) {
this.formData.bpmTaskApprovalType = approvalType
this.$refs.approvalFormRef.validate((valid) => {
if (valid) {
this.$axios
.post("/platform/article/clubApproval/approval", {
approval: JSON.stringify(this.formData)
})
.then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.articleInfoRef.onOpen(row)
})
},
openRevoke(taskId) {
// 提交
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
// 撤回
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/platform/article/clubApproval/revoke", { taskId }).then((res) => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
@@ -131,6 +157,7 @@ layout("/layouts/platform.html"){
})
})
}
},
created() {
this.pageData()
@@ -56,6 +56,7 @@ const ARTICLE_INFO = {
</div>
`,
store,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
@@ -11,7 +11,7 @@ layout("/layouts/platform.html"){
style="width: 100%"></el-date-picker>
</search-item>
<search-item label="标题">
<el-input v-model="pageForm.title" placeholder="标题" clearable></el-input>
<el-input v-model="pageForm.title" placeholder="请输入标题" clearable></el-input>
</search-item>
</search>
</el-card>
@@ -35,7 +35,7 @@ layout("/layouts/platform.html"){
</el-table-column>
<el-table-column label="操作" fixed="right" width="300px">
<template slot-scope="{row}">
<el-button @click="onOpen(row.id)" size="mini" type="primary">查看</el-button>
<el-button @click="onOpen(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onEdit(row)"
size="mini" type="primary">编辑
</el-button>
@@ -148,7 +148,7 @@ layout("/layouts/platform.html"){
<span>{{ $moment(row.createdAt).format('YYYY-MM-DD') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<el-table-column label="操作" width="160">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="toggleRowTimePeriod(row)" size="mini" type="primary">展开</el-button>
@@ -263,7 +263,7 @@ layout("/layouts/platform.html"){
},
async getRealTimeData() {
this.lastTimeData = clone(this.realTimeData)
const resp = await this.$axios.post(loc() + '/getRealTimeData/' + this.timePeriodId)
const resp = await this.$axios.post('/platform/meeting/online/getRealTimeData/' + this.timePeriodId)
if (resp.code === 0) {
this.lastTimeData = clone(this.realTimeData)
this.$set(this, 'realTimeData', resp.data.countData)
@@ -320,6 +320,19 @@ layout("/layouts/platform.html"){
async created() {
this.queryMeetingType()
this.pageData()
// 监听页面可见性变化
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// 用户切换到其他标签页或最小化浏览器 → 停止轮询
this.stopInterval()
}
})
// 关闭或刷新页面时也停止
window.addEventListener('beforeunload', () => {
this.stopInterval()
})
}
})
</script>
@@ -0,0 +1,147 @@
<!--#
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-date-picker
v-model="pageForm.year"
type="year"
value-format="yyyy"
placeholder="请选择年度"
@change="doSearch"
style="width: 100%"
></el-date-picker>
</search-item>
<search-item label="名称/地点:">
<el-input placeholder="请输入名称或地点查询" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch">
</el-input>
</search-item>
<search-item label="会议类型:">
<el-select v-model="pageForm.type" @change="doSearch" style="width: 100%"
placeholder="请选择慰问类型" filterable clearable>
<el-option v-for="item in typeOptions"
:value="item.id"
:key="item.id"
:label="item.name"
></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="会议列表"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize" ref="meetingTable">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{ row }" v-if="column.prop === 'name'">
<el-link size="mini" type="primary" @click="onInfo(row)">{{ row.name }}</el-link>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'createdAt'">
<span>{{ $moment(row.createdAt).format('YYYY-MM-DD') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template v-slot="{ row }">
<el-button @click="onInfo(row)" size="mini" type="primary">查看会议</el-button>
<el-button @click="onView(row)" size="mini" type="primary">查看人数</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #view>
<periods-info ref="periodsInfoRef"
:type-options="typeOptions"
:union-list="unionList"
:unit-list="unitList"></periods-info>
</template>
<template #public>
<meeting-info ref="infoRef"></meeting-info>
</template>
</guava>
</div>
<script>
<!--#include('../common/meetingInfo.js'){}#-->
<!--#include('periodsInfo.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"meeting-info": meetingInfo,
"periods-info": periodsInfo,
},
data() {
return {
tableColumns: [
{prop: 'name', label: '会议名称'},
{prop: 'typeName', label: '会议类型'},
{prop: 'address', label: '会议地点'},
{prop: 'createdAt', label: '创建时间'},
],
typeOptions: [],
unionList: [],
unitList: [],
}
},
methods: {
onInfo(row) {
this.$refs.guava.public(() => {
this.$refs.infoRef.onOpen(row)
})
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.periodsInfoRef.onOpen(row)
})
},
queryMeetingType() {
this.$axios.post('/platform/meeting/type/queryMeetingType')
.then((resp) => {
this.typeOptions = resp.data
})
},
pageData() {
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
},
async created() {
this.queryMeetingType()
this.unionList = await this.$businessTool.listUnion()
this.unitList = await this.$businessTool.listUnit()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,186 @@
const periodsInfo = {
template: /*language=HTML*/ `
<div>
<el-alert title="可点击表格中的数字查看具体人员名单" type="info" effect="dark" class="mb20" :closable="false" show-icon></el-alert>
<el-table ref="periodsTable" :data="periodsTableData" :size="tableSize" @cell-click="handleCellClick">
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
:class-name="column.className"
v-if="!column.condition || column.condition.includes(typeOptions.find(o => o.id === selectRow.typeId)?.designId)"
v-for="column in periodsTableColumns"
>
<template slot-scope="{ row }">
<el-link v-if="column.className && column.className === 'export-column'"
@click="onUser(row, column.prop)" type="primary">
{{ row[column.prop] }}
</el-link>
<span v-else-if="column.prop === 'proportionNum'">
{{ proportionNum(row.comeCount, row.totalCount) }}
</span>
<span v-else>
{{ row[column.prop] }}
</span>
</template>
</el-table-column>
<el-table-column align="center" fixed="right" header-align="center" label="操作" width="160">
<template slot-scope="{ row }">
<el-button @click="exportUser(row)" size="mini" type="primary">导出人员</el-button>
</template>
</el-table-column>
</el-table>
<el-alert :title="tooltip + '人员名单'" type="info" effect="dark" class="mt20 mb20" :closable="false" show-icon></el-alert>
<div style="padding: 20px; border-radius: 8px; border: 1px solid #ebeef5">
<search @search="doSearch">
<search-item label="姓名/工号:">
<el-input placeholder="请输入姓名或工号查询" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch">
</el-input>
</search-item>
<search-item label="所属工会:">
<el-select v-model="pageForm.unionId" placeholder="请选择所属工会" filterable clearable
@change="doSearch" style="width: 100%">
<el-option
v-for="item in unionList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</search-item>
<search-item label="所属单位:">
<el-select @change="doSearch"
clearable
filterable
placeholder="请选择单位" style="width: 100%" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitList"></el-option>
</el-select>
</search-item>
</search>
</div>
<el-table :data="userTableData" :row-key="(row)=>{row.id}" :size="tableSize" class="mt20">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</div>
`,
props: {
unionList: {
type: Array,
required: true
},
unitList: {
type: Array,
required: true
},
typeOptions: {
type: Array,
required: true
},
},
store,
mixins: [initTableMixins],
data() {
return {
periodsTableData: [],
selectRow: {},
tableColumns: [
{prop: 'loginName', label: '工号'},
{prop: 'userName', label: '姓名'},
{prop: 'sex', label: '性别'},
{prop: 'mobile', label: '联系方式'},
{prop: 'unitName', label: '所属单位'},
{prop: 'unionName', label: '所属工会'},
],
periodsTableColumns: [
{prop: 'periodName', label: '时间段名称'},
{prop: 'startTime', label: '开始时间'},
{prop: 'endTime', label: '结束时间'},
{prop: 'totalCount', label: '应到人数', className: 'export-column', width: 100},
{prop: 'comeCount', label: '实到人数', className: 'export-column', width: 100},
{prop: 'formalRoleCount', label: '正式代表', className: 'export-column', condition: ['JDHHY', 'GHDHY'], width: 100},
{prop: 'attendanceRoleCount', label: '列席代表', className: 'export-column', condition: ['JDHHY', 'GHDHY'], width: 100},
{prop: 'leaveCount', label: '请假人数', className: 'export-column', width: 100},
{prop: 'noComeCount', label: '未到人数', className: 'export-column', width: 100},
{prop: 'proportionNum', label: '人数比例', width: 100},
],
userTableData: [],
tooltip: '',
selectPeriodRow: {},
selectUserType: '',
}
},
methods: {
handleCellClick(row, column, cell, event) {
if (!cell.classList.contains('export-column')) {
return; // 不是目标列,直接返回
}
this.onUser(row, column.property)
this.tooltip = '【' + row.periodName + '-' + column.label + '】'
},
onOpen(row) {
this.selectRow = row
this.$axios.post(loc() + '/view', {meetingId: row.id})
.then((res) => {
this.periodsTableData = res.data
this.$emit("refresh", null)
})
},
doSearch() {
this.pageForm.pageNumber = 1
this.onUser()
},
onUser(row, type) {
this.selectPeriodRow = row || this.selectPeriodRow
this.selectUserType = type || this.selectUserType
this.$set(this.pageForm, 'type', this.selectUserType)
this.$set(this.pageForm, 'meetingId', this.selectPeriodRow.meetingId)
this.$set(this.pageForm, 'periodId', this.selectPeriodRow.id)
this.$axios.post(loc() + "/queryUserTable", this.pageForm).then((res) => {
if (res.code === 0) {
this.userTableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
exportUser(row) {
const exportColumns = this.periodsTableColumns.filter(o => o.className === 'export-column')
const dataColumns = exportColumns.map(o => {return {prop: o.prop, label: o.label}})
this.$downLoad(loc() + '/exportUser', {
periodId: row.id,
meetingId: row.meetingId,
exportColumns: JSON.stringify(dataColumns)
})
},
proportionNum(comeCount, totalCount) {
return ((comeCount ? comeCount : 0) / totalCount * 100).toFixed(2) + "%"
},
},
style: /*language=CSS*/ `
.el-alert__icon {
color: #006DB9;
}
`
}
@@ -175,6 +175,7 @@ const apply = {
this.dialogVisible = true
this.formData = clone(applyRow)
this.$set(this.formData, 'applyTime', this.formData.startTime + '-' + this.formData.endTime)
this.$set(this.formData, 'sex', this.$store.state.user.sex)
await this.queryTimesByDay()
}
},
@@ -164,7 +164,7 @@ const basicForm = {
<el-button size="mini" type="primary" icon="el-icon-plus"
@click="formData.openHours.push({})"></el-button>
</template>
<template v-slot="{ row }">
<template v-slot="scope">
<el-button type="danger" icon="el-icon-delete"
:disabled="formData.openHours.length==0" size="mini"
@click="formData.openHours.splice(scope.$index, 1)"></el-button>
@@ -332,7 +332,7 @@ const basicForm = {
},
oneKeySetStartEndTime() {
if(this.multipleSelection.length === 0) {
this.$message.warning('请选择需要一键设置的时间')
this.$message.warning('请在下面表格多选框中选择需要一键设置的时间')
return
}
const { startTime, endTime } = this.timeOneKeySet
@@ -19,6 +19,12 @@ layout("/layouts/platform.html"){
}
</style>
<div id="app" v-clock>
<el-card shadow="never">
<snaker-start slot="header" label="建家申报" define_key="ZGXJSB"></snaker-start>
</el-card>
<guava ref="guava">
<template>
<el-card shadow="never">
@@ -101,11 +107,6 @@ layout("/layouts/platform.html"){
<el-form-item class="is-required" label="基层工会简况"
prop="basicInformation">
<text-editor v-model="formData.basicInformation"></text-editor>
<div style="text-align: right">
<span style="color: #0a84ff">当前字数:{{ formData.basicInformation ? (dd3s.html2txt(formData.basicInformation).length) : 0 }}</span>
<span>{{ ';最多500字' }}</span>
</div>
<!-- <el-input type="textarea" v-model="formData.basicInformation" maxlength="500" show-word-limit :rows="10"></el-input>-->
</el-form-item>
</el-col>
</el-row>
@@ -132,36 +133,14 @@ layout("/layouts/platform.html"){
el: '#app',
mixins: [initTableMixins],
data() {
const validBasicInformation = (rule, value, callback) => {
if (!this.formData.basicInformation || !dd3s.html2txt(this.formData.basicInformation)) {
callback(new Error('请填写基层工会简况'));
} else if (dd3s.html2txt(this.formData.basicInformation).length > 500) {
console.log(11)
callback(new Error('基层工会简况最多500字'));
} else {
callback();
}
};
return {
id: '',
formData: {},
formRules: {
mobile: [{required: true, message: '手机号不能为空', trigger: 'blur'},
{pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur'}],
basicInformation: [{
required: true,
message: '必填',
trigger: ['blur', 'change']
}],
constructionPlan: [{
required: true,
message: '必填',
trigger: ['blur', 'change']
}],
basicInformation: [{
validator: validBasicInformation,
trigger: ['blur', 'change']
}],
basicInformation: [{required: true, message: '必填', trigger: ['blur', 'change']}],
constructionPlan: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
}
},
@@ -112,12 +112,11 @@ layout("/layouts/platform.html"){
</el-card>
<el-card shadow="never">
<table-tool>
<el-button type="primary" size="small" @click="exportAllProposalAsZip">导出全部提案压缩包</el-button>
<el-button type="primary" size="small" @click="exportAllProposalFeedBackAsZip">
导出全部提案反馈表压缩包
</el-button>
<el-button type="primary" size="small" @click="exportProposalSummaryAsExcel">导出汇总表</el-button>
<el-button type="primary" size="small" @click="exportProposalRegisterSummaryAsExcel">导出立案汇总表
<el-button type="primary" size="small" @click="exportAllProposalAsZip">导出提案压缩包</el-button>
<el-button type="primary" size="small" @click="exportCollectZip">导出提案征集表压缩包</el-button>
<!-- <el-button type="primary" size="small" @click="exportAllProposalFeedBackAsZip">导出反馈表压缩包</el-button>-->
<el-button type="primary" size="small" @click="exportSummaryAsExcel">导出汇总表</el-button>
<!-- <el-button type="primary" size="small" @click="exportProposalRegisterSummaryAsExcel">导出立案汇总表-->
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
@@ -140,10 +139,15 @@ layout("/layouts/platform.html"){
<el-tag size="mini" v-else type="danger"></el-tag>
</template>
</el-table-column>
<el-table-column label="主办单位" prop="masterUnderTakeName" show-overflow-tooltip></el-table-column>
<el-table-column label="协办单位" prop="slaveUnderTakeNames" show-overflow-tooltip></el-table-column>
<el-table-column label="当前节点" prop="processInstanceNodeName"
show-overflow-tooltip></el-table-column>
<el-table-column label="主办单位" prop="masterUnitName" show-overflow-tooltip></el-table-column>
<el-table-column label="协办单位" prop="slaveUnitNames" show-overflow-tooltip></el-table-column>
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
<el-table-column prop="instanceState" label="流程状态">
<template slot-scope="{row}">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
@@ -199,6 +203,11 @@ layout("/layouts/platform.html"){
pageForm: JSON.stringify(this.pageForm)
})
},
exportCollectZip() {
this.$downLoad(loc() + "/exportCollectZip", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportAllProposalFeedBackAsZip() {
this.$downLoad(loc() + "/exportAllProposalFeedBackAsZip", {
pageForm: JSON.stringify(this.pageForm)
@@ -207,8 +216,8 @@ layout("/layouts/platform.html"){
exportDocx(id) {
this.$downLoad("/platform/proposal/common/exportProposalAsDocx", {id})
},
exportProposalSummaryAsExcel() {
this.$downLoad("/platform/proposal/export/comprehensive/exportProposalSummaryAsExcel", {
exportSummaryAsExcel() {
this.$downLoad("/platform/proposal/export/comprehensive/exportSummaryAsExcel", {
pageForm: JSON.stringify(this.pageForm)
})
},
@@ -6,6 +6,13 @@ layout("/layouts/platform.html"){
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" 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-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -32,13 +39,6 @@ layout("/layouts/platform.html"){
style="width: 100%"
></el-input>
</search-item>
<search-item label="教代会">
<el-select @change="meetingChange" 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-card>
@@ -216,18 +216,7 @@ layout("/layouts/platform.html"){
// 教代会
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.delegationOptions = await proposal.getDelegation(val)
this.committeeOptions = await this.getInstitutions(val)
},
// 代表团
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
this.doSearch()
},
// 查询开启的教代会
@@ -238,7 +227,6 @@ layout("/layouts/platform.html"){
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
@@ -6,10 +6,6 @@ layout("/layouts/platform.html"){
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
@@ -17,6 +13,10 @@ layout("/layouts/platform.html"){
v-for="item in sessionOptions"></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>
</search-item>
</search>
</el-card>
@@ -158,16 +158,7 @@ layout("/layouts/platform.html"){
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.listDelegation()
},
// 代表团
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
this.doSearch()
},
// 查询开启的教代会
@@ -6,6 +6,13 @@ layout("/layouts/platform.html"){
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" 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-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -32,13 +39,6 @@ layout("/layouts/platform.html"){
style="width: 100%"
></el-input>
</search-item>
<search-item label="教代会">
<el-select @change="meetingChange" 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-card>
@@ -204,19 +204,7 @@ layout("/layouts/platform.html"){
// 教代会
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.delegationOptions = await proposal.getDelegation(val)
this.committeeOptions = await this.getInstitutions(val)
},
// 代表团
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
this.doSearch()
},
// 查询开启的教代会
@@ -8,14 +8,14 @@ layout("/layouts/platform.html"){
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable style="width: 100%"></el-input>
</search-item>
<search-item label="教代会">
<el-select @change="meetingChange" 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-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable style="width: 100%"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
@@ -123,8 +123,7 @@ layout("/layouts/platform.html"){
//教代会change
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.doSearch()
//this.delegationOptions = await proposal.getDelegation(val)
//this.committeeOptions = await this.getInstitutions(val)
},
@@ -6,6 +6,13 @@ layout("/layouts/platform.html"){
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" 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-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -32,13 +39,6 @@ layout("/layouts/platform.html"){
style="width: 100%"
></el-input>
</search-item>
<search-item label="教代会">
<el-select @change="meetingChange" 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-card>
@@ -187,19 +187,7 @@ layout("/layouts/platform.html"){
// 教代会
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.delegationOptions = await proposal.getDelegation(val)
this.committeeOptions = await this.getInstitutions(val)
},
// 代表团
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
this.doSearch()
},
// 查询开启的教代会
@@ -6,10 +6,6 @@ layout("/layouts/platform.html"){
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
@@ -17,6 +13,10 @@ layout("/layouts/platform.html"){
v-for="item in sessionOptions"></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>
</search-item>
</search>
</el-card>
@@ -160,16 +160,7 @@ layout("/layouts/platform.html"){
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.listDelegation()
},
// 代表团
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
this.doSearch()
},
// 查询开启的教代会
@@ -6,6 +6,13 @@ layout("/layouts/platform.html"){
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" 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-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
@@ -32,13 +39,6 @@ layout("/layouts/platform.html"){
style="width: 100%"
></el-input>
</search-item>
<search-item label="教代会">
<el-select @change="meetingChange" 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-card>
@@ -92,9 +92,12 @@ layout("/layouts/platform.html"){
<el-form-item label="承办单位">
<el-input :value="formData.taskUnitName" disabled></el-input>
</el-form-item>
<!-- <el-form-item label="落实情况" prop="implementState" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">-->
<!-- <dict-select v-model="formData.implementState" code="PROPOSAL_REPLY_IMPLEMENT"></dict-select>-->
<!-- </el-form-item>-->
<el-form-item label="落实情况" prop="tf_implementState"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_implementState" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_REPLY_IMPLEMENT" :label="item.code" border>{{item.label}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="答复内容" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<text-editor v-model="formData.tf_opinion"></text-editor>
@@ -124,7 +127,7 @@ layout("/layouts/platform.html"){
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_CASE_FILING_RESULT"],
dicts: ["PROPOSAL_CASE_FILING_RESULT","PROPOSAL_REPLY_IMPLEMENT"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
@@ -216,19 +219,7 @@ layout("/layouts/platform.html"){
// 教代会
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.delegationOptions = await proposal.getDelegation(val)
this.committeeOptions = await this.getInstitutions(val)
},
// 代表团
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
this.doSearch()
},
// 查询开启的教代会
@@ -99,27 +99,38 @@ layout("/layouts/platform.html"){
</el-col>
</el-row>
<el-form-item label="提案摘要" prop="excerpt">
<span slot="label">
提案摘要
<el-tooltip content="请简述提案内容和依据、改进建议和措施摘要" placement="right">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<!-- <el-form-item label="提案摘要" prop="excerpt">-->
<!-- <span slot="label">-->
<!-- 提案摘要-->
<!-- <el-tooltip content="请简述提案内容和依据、改进建议和措施摘要" placement="right">-->
<!-- <i class="el-icon-question"></i>-->
<!-- </el-tooltip>-->
<!-- </span>-->
<!-- <el-input-->
<!-- v-model="formData.excerpt"-->
<!-- type="textarea"-->
<!-- autosize-->
<!-- :autosize="{ minRows: 4, maxRows: 4}"-->
<!-- placeholder="提案摘要"-->
<!-- ></el-input>-->
<!-- </el-form-item>-->
<el-form-item label="调研情况" prop="researchFindings">
<el-input
v-model="formData.excerpt"
v-model="formData.researchFindings"
type="textarea"
autosize
:autosize="{ minRows: 4, maxRows: 4}"
placeholder="提案摘要"
placeholder="调研情况"
></el-input>
</el-form-item>
<el-form-item label="提案内容和依据" prop="brief">
<text-editor v-model="formData.brief" key="brief" placeholder="提案内容和依据"></text-editor>
<el-form-item label="案由" prop="brief">
<text-editor v-model="formData.brief" key="brief" placeholder="案由"></text-editor>
</el-form-item>
<el-form-item label="改进建议措施" prop="measures">
<el-form-item label="建议措施" prop="measures">
<text-editor v-model="formData.measures" key="measures"
placeholder="改进建议措施"></text-editor>
placeholder="建议措施"></text-editor>
</el-form-item>
<el-form-item label="附件上传" prop="files">
<file-upload
@@ -131,9 +142,9 @@ layout("/layouts/platform.html"){
></file-upload>
</el-form-item>
<el-form-item label="电子签名" prop="signature">
<pc-signature v-model="formData.signature"></pc-signature>
</el-form-item>
<!-- <el-form-item label="电子签名" prop="signature">-->
<!-- <pc-signature v-model="formData.signature"></pc-signature>-->
<!-- </el-form-item>-->
</el-form>
<el-row justify="end" type="flex" v-if="isWriteTime">
<el-button @click="onSave" type="primary">保存</el-button>
@@ -181,6 +192,7 @@ layout("/layouts/platform.html"){
implementUnitId: [{required: false, message: "请选择建以落实部门", trigger: ["blur", "change"]}],
sign: [{required: true, message: "请扫描二维码进行签字", trigger: ["blur", "change"]}],
excerpt: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
researchFindings: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
brief: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
measures: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
unitName: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
@@ -28,7 +28,7 @@ layout("/layouts/platform.html"){
<el-table-column prop="userName" label="投稿人姓名"></el-table-column>
<el-table-column prop="unitName" label="投稿人单位"></el-table-column>
<el-table-column prop="unionName" label="投稿人工会"></el-table-column>
<!-- <el-table-column prop="submitTime" label="投稿时间"></el-table-column>-->
<!-- <el-table-column prop="submitTime" label="投稿时间"></el-table-column>-->
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
<el-table-column prop="instanceState" label="流程状态">
<template slot-scope="{row}">
@@ -39,8 +39,10 @@ layout("/layouts/platform.html"){
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @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.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
@@ -79,7 +81,7 @@ layout("/layouts/platform.html"){
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
mixins: [initTableMixins, flowMixins],
components: {
"suggestion-info": SUGGESTION_INFO
},
@@ -94,13 +96,13 @@ layout("/layouts/platform.html"){
},
methods: {
openView(row) {
this.$refs.guava.edit(()=>{
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.suggestionInfoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(()=>{
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
@@ -0,0 +1,73 @@
const BANNER = {
template: /*language=HTML*/ `
<div class="banner-container">
<el-carousel :interval="5000" arrow="always" height="480px">
<el-carousel-item v-for="(banner, index) in banners" :key="index">
<a :href="banner.link" class="banner-item">
<img :src="banner.image" :alt="banner.title" class="banner-image">
<div class="banner-title">{{ banner.title }}</div>
</a>
</el-carousel-item>
</el-carousel>
</div>
`,
data() {
return {
banners: [
{
id: 1,
title: '618年中大促',
image: 'https://img10.360buyimg.com/babel/s1920x600_jfs/t1/211815/34/8529/107925/6111c8c9E4a1f8d2b/291c9c66391b8c6d.jpg',
link: '#'
},
{
id: 2,
title: '手机5折起',
image: 'https://img10.360buyimg.com/babel/s1920x600_jfs/t1/198372/22/19657/123948/6111c8c9E0d8a5c8d/1c8e6b1c8b5e5b8a.jpg',
link: '#'
},
{
id: 3,
title: '家电清凉一夏',
image: 'https://img10.360buyimg.com/babel/s1920x600_jfs/t1/198372/22/19657/123948/6111c8c9E0d8a5c8d/1c8e6b1c8b5e5b8a.jpg',
link: '#'
}
]
}
},
methods: {
},
style: /*language=CSS*/ `
.banner-container {
margin-bottom: 20px;
}
.banner-item {
position: relative;
display: block;
width: 100%;
height: 100%;
}
.banner-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.banner-title {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
color: white;
font-size: 30px;
font-weight: bold;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
background: rgba(0, 0, 0, 0.3);
padding: 10px 20px;
border-radius: 4px;
}
`
}
@@ -0,0 +1,356 @@
<!--#include("breadcrumbNav.js"){}#-->
const HEADER = {
template: /*language=HTML*/ `
<div>
<div class="header-top">
<div class="container">
<div class="welcome">欢迎来到京东商城</div>
<div class="user-info">
<template v-if="isLogin">
<a href="javascript:void(0)">我的订单</a>
<a href="javascript:void(0)">我的京东</a>
<a href="javascript:void(0)" @click="logout">退出</a>
</template>
<template v-else>
<a href="javascript:void(0)" @click="login">登录</a>
<a href="javascript:void(0)" @click="register">注册</a>
</template>
<a href="javascript:void(0)">我的订单</a>
<a href="javascript:void(0)">我的京东</a>
<a href="javascript:void(0)">企业采购</a>
<el-dropdown @command="handleService">
<span class="el-dropdown-link">
客户服务<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="help">帮助中心</el-dropdown-item>
<el-dropdown-item command="customer">在线客服</el-dropdown-item>
<el-dropdown-item command="after-sales">售后服务</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-dropdown @command="handleApp">
<span class="el-dropdown-link">
手机京东<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="app">京东APP</el-dropdown-item>
<el-dropdown-item command="wechat">微信小程序</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
<div class="header-main">
<div class="container">
<div class="logo">
<a href="/">
<img src="https://img11.360buyimg.com/jdcdh/s150x50_jfs/t1/173705/37/11987/5525/60b3d1c7E56f89c06/899d8b19c09f7d2c.png" alt="京东商城">
</a>
</div>
<div class="search-box">
<el-input
v-model="searchQuery"
placeholder="搜索商品"
@keyup.enter.native="handleSearch">
<el-button slot="append" type="danger" icon="el-icon-search" @click="handleSearch"></el-button>
</el-input>
<div class="hot-keys">
<a href="javascript:void(0)" v-for="(keyword, index) in hotSearch" :key="index">{{ keyword }}</a>
</div>
</div>
<div class="cart-box">
<el-badge :value="cartCount" :max="99">
<el-button type="danger" icon="el-icon-shopping-cart-2" size="medium">我的购物车</el-button>
</el-badge>
<div class="cart-dropdown" v-if="cartCount > 0">
<p>最近加入的商品</p>
<div class="cart-items">
<div class="cart-item" v-for="(item, index) in cartItems" :key="index">
<div class="item-image">
<img :src="item.image" alt="商品图片">
</div>
<div class="item-info">
<div class="item-name">{{ item.name }}</div>
<div class="item-price">¥{{ item.price }} × {{ item.quantity }}</div>
</div>
</div>
</div>
<div class="cart-footer">
<span>共 {{ cartCount }} 件商品</span>
<el-button type="danger" size="small">去购物车</el-button>
</div>
</div>
</div>
</div>
</div>
<div class="header-bottom">
<div class="container">
<nav class="main-nav">
<ul class="nav-list">
<li :class="{ 'active': activeNav === 'home' }">
<a href="/">首页</a>
</li>
<li :class="{ 'active': activeNav === 'electronics' }">
<a href="/category/electronics">手机数码</a>
</li>
<li :class="{ 'active': activeNav === 'home-appliance' }">
<a href="/category/appliance">家用电器</a>
</li>
<li :class="{ 'active': activeNav === 'computer' }">
<a href="/category/computer">电脑办公</a>
</li>
<li :class="{ 'active': activeNav === 'furniture' }">
<a href="/category/furniture">家居家装</a>
</li>
<li :class="{ 'active': activeNav === 'food' }">
<a href="/category/food">食品生鲜</a>
</li>
<li :class="{ 'active': activeNav === 'book' }">
<a href="/category/book">图书</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
`,
data() {
return {
searchQuery: '',
hotSearch: ['手机', '笔记本', '电视', '空调', '洗衣机', '冰箱'],
cartCount: 3,
cartItems: [
{ id: 1, name: 'Apple iPhone 13', price: 5999, quantity: 1, image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 2, name: '华为MateBook X Pro', price: 8999, quantity: 1, image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 3, name: '小米电视6 OLED', price: 5999, quantity: 1, image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' }
],
isLogin: false,
activeNav: 'home'
}
},
methods: {
handleSearch() {
if (this.searchQuery.trim()) {
this.$emit('search', this.searchQuery);
console.log('搜索:', this.searchQuery);
}
},
handleService(command) {
console.log('客户服务:', command);
},
handleApp(command) {
console.log('手机京东:', command);
},
login() {
this.isLogin = true;
console.log('登录');
},
register() {
console.log('注册');
},
logout() {
this.isLogin = false;
console.log('退出');
}
},
created() {
},
style: /*language=CSS*/ `
.site-header {
background: #fff;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.header-top {
background: #f5f5f5;
height: 30px;
line-height: 30px;
font-size: 12px;
color: #999;
}
.container {
width: 1200px;
margin: 0 auto;
display: flex;
justify-content: space-between;
}
.welcome {
float: left;
}
.user-info {
float: right;
}
.user-info a {
color: #999;
margin-left: 15px;
text-decoration: none;
}
.user-info a:hover {
color: #c81623;
}
.el-dropdown-link {
cursor: pointer;
color: #999;
}
.header-main {
padding: 20px 0;
}
.logo {
float: left;
width: 160px;
}
.logo img {
width: 100%;
}
.search-box {
float: left;
width: 550px;
margin: 0 20px;
}
.hot-keys {
margin-top: 8px;
}
.hot-keys a {
color: #999;
font-size: 12px;
margin-right: 10px;
text-decoration: none;
}
.hot-keys a:hover {
color: #c81623;
}
.cart-box {
float: right;
position: relative;
}
.cart-box:hover .cart-dropdown {
display: block;
}
.cart-dropdown {
position: absolute;
right: 0;
width: 300px;
background: #fff;
border: 1px solid #e0e0e0;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 1000;
display: none;
padding: 10px;
}
.cart-items {
max-height: 300px;
overflow-y: auto;
margin: 10px 0;
}
.cart-item {
display: flex;
padding: 10px 0;
border-bottom: 1px solid #eee;
}
.item-image {
width: 60px;
height: 60px;
margin-right: 10px;
}
.item-image img {
width: 100%;
height: 100%;
object-fit: contain;
}
.item-info {
flex: 1;
}
.item-name {
font-size: 13px;
color: #333;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.item-price {
font-size: 12px;
color: #c81623;
}
.cart-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
border-top: 1px solid #eee;
}
.header-bottom {
background: #c81623;
height: 40px;
}
.main-nav {
height: 40px;
line-height: 40px;
}
.nav-list {
display: flex;
list-style: none;
height: 40px;
line-height: 40px;
}
.nav-list li {
margin: 0 15px;
}
.nav-list a {
color: #fff;
text-decoration: none;
font-size: 16px;
font-weight: bold;
}
.nav-list a:hover {
color: #fff;
text-decoration: underline;
}
.nav-list .active a {
color: #fff;
position: relative;
}
.nav-list .active a::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background: #fff;
}
`
}
@@ -0,0 +1,105 @@
const HOT_BRANDS = {
template: /*language=HTML*/ `
<div class="hot-brands">
<div class="section-header">
<h2 class="title">热门品牌</h2>
<div class="more">
<a href="javascript:void(0)">查看全部品牌 <i class="el-icon-arrow-right"></i></a>
</div>
</div>
<div class="brands-content">
<div class="brand-item" v-for="(brand, index) in brands" :key="index">
<a :href="brand.link">
<img :src="brand.logo" :alt="brand.name">
<div class="brand-name">{{ brand.name }}</div>
</a>
</div>
</div>
</div>
`,
data() {
return{
brands: [
{ id: 1, name: 'Apple', logo: 'https://img10.360buyimg.com/uba/s96x32_jfs/t1/17745/33/1524/7225/5c3b6c97E0c4c9e92/44a8b4c0e0c8f8d8.png', link: '#' },
{ id: 2, name: '华为', logo: 'https://img10.360buyimg.com/uba/s96x32_jfs/t1/35476/25/11785/6489/5d1c3e74E1c4c5a5b/0e0b8b6c8d7e8e8e.png', link: '#' },
{ id: 3, name: '小米', logo: 'https://img10.360buyimg.com/uba/s96x32_jfs/t1/18563/13/11786/5790/5d1c3e74E0c4c5a5b/1e0b8b6c8d7e8e8e.png', link: '#' },
{ id: 4, name: '联想', logo: 'https://img10.360buyimg.com/uba/s96x32_jfs/t1/36547/27/11785/5678/5d1c3e74E1c4c5a5b/2e0b8b6c8d7e8e8e.png', link: '#' },
{ id: 5, name: '海尔', logo: 'https://img10.360buyimg.com/uba/s96x32_jfs/t1/37547/29/11785/5890/5d1c3e74E1c4c5a5b/3e0b8b6c8d7e8e8e.png', link: '#' },
{ id: 6, name: '美的', logo: 'https://img10.360buyimg.com/uba/s96x32_jfs/t1/38547/31/11785/5987/5d1c3e74E1c4c5a5b/4e0b8b6c8d7e8e8e.png', link: '#' },
{ id: 7, name: '三星', logo: 'https://img10.360buyimg.com/uba/s96x32_jfs/t1/39547/33/11785/6123/5d1c3e74E1c4c5a5b/5e0b8b6c8d7e8e8e.png', link: '#' },
{ id: 8, name: '索尼', logo: 'https://img10.360buyimg.com/uba/s96x32_jfs/t1/40547/35/11785/6234/5d1c3e74E1c4c5a5b/6e0b8b6c8d7e8e8e.png', link: '#' }
]
}
},
methods: {
},
created() {
},
style: /*language=CSS*/ `
.hot-brands {
background: #fff;
border-radius: 4px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.title {
font-size: 20px;
color: #333;
font-weight: bold;
}
.more a {
color: #666;
font-size: 14px;
text-decoration: none;
}
.more a:hover {
color: #c81623;
}
.brands-content {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 15px;
}
.brand-item {
text-align: center;
padding: 10px 0;
transition: all 0.3s;
}
.brand-item:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transform: translateY(-3px);
border-radius: 4px;
}
.brand-item img {
width: 80%;
height: auto;
max-height: 40px;
object-fit: contain;
}
.brand-name {
margin-top: 8px;
font-size: 14px;
color: #333;
}
`
}
@@ -0,0 +1,855 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.jd-container {
max-width: 1200px;
margin: 0 auto;
background: #fff;
}
/* 顶部导航栏 */
.jd-header {
height: 110px;
background: #c81623;
display: flex;
align-items: center;
padding: 0 20px;
}
.jd-logo {
display: flex;
align-items: center;
color: #fff;
text-decoration: none;
}
.jd-logo img {
height: 60px;
margin-right: 15px;
}
.jd-logo h1 {
font-size: 28px;
font-weight: normal;
}
.jd-logo span {
font-size: 16px;
opacity: 0.9;
}
/* 购物车标题 */
.cart-title {
padding: 20px 20px 10px;
border-bottom: 2px solid #c81623;
}
.cart-title h2 {
font-size: 24px;
color: #c81623;
font-weight: normal;
}
/* 购物车表格 */
.cart-table {
padding: 0 20px;
}
.el-table {
border: 1px solid #e6e6e6;
margin-bottom: 20px;
}
.el-table th {
background-color: #f5f5f5;
padding: 10px 0;
font-weight: normal;
}
.product-cell {
display: flex;
align-items: center;
padding: 15px 0;
}
.product-image {
width: 80px;
height: 80px;
border: 1px solid #eee;
margin-right: 15px;
object-fit: cover;
}
.product-info {
flex: 1;
}
.product-name {
font-size: 14px;
line-height: 1.4;
color: #333;
margin-bottom: 5px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.product-desc {
font-size: 12px;
color: #999;
}
.spec-select {
width: 120px;
margin-top: 5px;
}
.price-cell {
color: #c81623;
font-weight: bold;
font-size: 16px;
}
.quantity-cell {
display: flex;
align-items: center;
}
.el-input-number {
width: 120px;
}
.el-input-number--mini .el-input__inner {
padding-left: 30px;
padding-right: 30px;
height: 30px;
line-height: 30px;
}
.el-input-number--mini .el-input-number__decrease,
.el-input-number--mini .el-input-number__increase {
width: 28px;
height: 28px;
line-height: 28px;
}
.subtotal {
color: #c81623;
font-weight: bold;
}
.delete-btn {
color: #999;
cursor: pointer;
transition: all 0.3s;
}
.delete-btn:hover {
color: #c81623;
}
/* 底部操作栏 */
.cart-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
background: #fff;
border-top: 1px solid #e6e6e6;
position: relative;
}
.footer-left {
display: flex;
align-items: center;
}
.select-all {
margin-right: 20px;
font-size: 14px;
}
.selected-count {
color: #c81623;
font-weight: bold;
margin: 0 5px;
}
.total-price {
font-size: 18px;
color: #c81623;
font-weight: bold;
}
.settlement-btn {
background: #c81623;
border-color: #c81623;
color: #fff;
padding: 0 25px;
height: 36px;
font-size: 16px;
}
.settlement-btn:hover {
background: #a7141f;
border-color: #a7141f;
}
.settlement-btn:disabled {
background: #ccc;
border-color: #ccc;
}
/* 地址选择区域 */
.address-section {
padding: 15px 20px;
background: #f9f9f9;
border-top: 1px dashed #e6e6e6;
}
.address-title {
font-size: 14px;
color: #333;
margin-bottom: 10px;
display: flex;
align-items: center;
}
.address-title i {
margin-right: 5px;
color: #c81623;
}
.address-list {
display: flex;
gap: 15px;
}
.address-card {
border: 1px solid #e6e6e6;
padding: 12px;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
background: #fff;
position: relative;
width: 220px;
}
.address-card:hover {
border-color: #c81623;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.address-card.active {
border-color: #c81623;
background: #fff9f9;
}
.address-card.active::before {
content: '';
position: absolute;
top: 0;
right: 0;
border-width: 0 16px 16px 0;
border-style: solid;
border-color: #c81623 transparent;
}
.address-card.active::after {
content: '';
position: absolute;
top: 2px;
right: 2px;
width: 12px;
height: 6px;
border: 2px solid #fff;
border-top: none;
border-right: none;
transform: rotate(-45deg);
}
.address-name {
font-weight: bold;
margin-bottom: 5px;
}
.address-detail {
font-size: 13px;
color: #666;
line-height: 1.4;
}
.address-actions {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.address-actions .el-button {
padding: 0;
font-size: 13px;
}
/* 空购物车状态 */
.empty-cart {
text-align: center;
padding: 50px 0;
}
.empty-cart img {
width: 180px;
margin-bottom: 20px;
}
.empty-cart p {
color: #999;
margin-bottom: 20px;
}
.continue-shopping {
background: #c81623;
color: #fff;
padding: 8px 25px;
border-radius: 2px;
text-decoration: none;
display: inline-block;
}
.continue-shopping:hover {
background: #a7141f;
}
/* 优惠信息 */
.promotion {
padding: 10px 20px;
background: #fff9f9;
border: 1px solid #ffeaea;
color: #c81623;
font-size: 13px;
}
.promotion i {
margin-right: 5px;
}
/* 响应式调整 */
@media (max-width: 768px) {
.cart-table {
padding: 0 10px;
}
.el-table {
font-size: 13px;
}
.product-name {
font-size: 13px;
}
.cart-footer {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.footer-right {
width: 100%;
display: flex;
justify-content: flex-end;
}
}
</style>
<div id="app">
<div class="jd-container">
<!-- 顶部导航 -->
<header class="jd-header">
<a href="#" class="jd-logo">
<img src="https://img12.360buyimg.com/img/jfs/t1/2022/36/7653/3103/5b9f5f5cE6c40a453/9c4c3d0a0e0d6e0d.png" alt="京东">
<div>
<h1>京东</h1>
<span>品质购物,品质生活</span>
</div>
</a>
</header>
<!-- 购物车标题 -->
<div class="cart-title">
<h2>我的购物车</h2>
</div>
<!-- 购物车内容 -->
<div v-if="cartItems.length > 0">
<div class="cart-table">
<!-- 购物车表格 -->
<el-table :data="cartItems" style="width: 100%" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column label="商品" min-width="400">
<template slot-scope="scope">
<div class="product-cell">
<img :src="scope.row.image" :alt="scope.row.name" class="product-image">
<div class="product-info">
<div class="product-name">{{ scope.row.name }}</div>
<div class="product-desc">{{ scope.row.description }}</div>
<el-select v-model="scope.row.selectedSpec" size="mini" class="spec-select" @change="updateSpec(scope.row)">
<el-option
v-for="spec in scope.row.specs"
:key="spec.value"
:label="spec.label"
:value="spec.value">
</el-option>
</el-select>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="单价" width="120" align="center">
<template slot-scope="scope">
<div class="price-cell">¥{{ scope.row.price.toFixed(2) }}</div>
</template>
</el-table-column>
<el-table-column label="数量" width="150" align="center">
<template slot-scope="scope">
<div class="quantity-cell">
<el-input-number
v-model="scope.row.quantity"
:min="1"
:max="99"
size="mini"
@change="updateQuantity(scope.row)">
</el-input-number>
</div>
</template>
</el-table-column>
<el-table-column label="小计" width="120" align="center">
<template slot-scope="scope">
<div class="subtotal">¥{{ (scope.row.price * scope.row.quantity).toFixed(2) }}</div>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center">
<template slot-scope="scope">
<span class="delete-btn" @click="removeItem(scope.row)">删除</span>
</template>
</el-table-column>
</el-table>
</div>
<!-- 收货地址选择 -->
<div class="address-section">
<div class="address-title">
<i class="el-icon-location-outline"></i>
<span>收货地址</span>
</div>
<div class="address-list">
<div
v-for="(address, index) in addresses"
:key="index"
class="address-card"
:class="{active: selectedAddress === index}"
@click="selectAddress(index)">
<div class="address-name">{{ address.name }} {{ address.phone }}</div>
<div class="address-detail">{{ address.province }} {{ address.city }} {{ address.district }} {{ address.street }}</div>
<div class="address-actions">
<el-button type="text" @click.stop="editAddress(index)">编辑</el-button>
<el-button type="text" @click.stop="removeAddress(index)">删除</el-button>
</div>
</div>
<div class="address-card" @click="addNewAddress">
<div style="text-align: center; padding: 20px 0; color: #c81623;">
<i class="el-icon-plus" style="font-size: 24px; display: block; margin-bottom: 5px;"></i>
<div>添加新地址</div>
</div>
</div>
</div>
</div>
<!-- 底部操作栏 -->
<div class="cart-footer">
<div class="footer-left">
<div class="select-all">
<el-checkbox v-model="selectAll" @change="toggleSelectAll">全选</el-checkbox>
</div>
<div>
已选择 <span class="selected-count">{{ selectedItems.length }}</span> 件商品
</div>
</div>
<div class="footer-right">
<div>
合计:<span class="total-price">¥{{ totalPrice.toFixed(2) }}</span>
<span style="color: #999; font-size: 13px; margin-left: 5px;">(不含运费)</span>
</div>
<el-button
type="danger"
class="settlement-btn"
:disabled="selectedItems.length === 0"
@click="checkout">
去结算
</el-button>
</div>
</div>
</div>
<!-- 空购物车 -->
<div v-else class="empty-cart">
<img src="https://img11.360buyimg.com/imagetools/jfs/t1/186857/25/10011/5375/60d9e586Ee3b46c7a/5a3d5c5b0d3a7a9d.png" alt="空购物车">
<p>您的购物车空空如也,快去挑选心仪的商品吧!</p>
<a href="#" class="continue-shopping">继续购物</a>
</div>
<!-- 地址编辑弹窗 -->
<el-dialog title="编辑收货地址" :visible.sync="addressDialogVisible" width="500px">
<el-form :model="currentAddress" label-width="80px">
<el-form-item label="收货人">
<el-input v-model="currentAddress.name" placeholder="请输入收货人姓名"></el-input>
</el-form-item>
<el-form-item label="手机号码">
<el-input v-model="currentAddress.phone" placeholder="请输入手机号码"></el-input>
</el-form-item>
<el-form-item label="所在地区">
<el-cascader
v-model="currentAddress.region"
:options="regionOptions"
placeholder="请选择省市区"
style="width: 100%;"></el-cascader>
</el-form-item>
<el-form-item label="详细地址">
<el-input
v-model="currentAddress.street"
type="textarea"
:rows="3"
placeholder="请输入详细地址,如街道、门牌号等"></el-input>
</el-form-item>
<el-form-item label="设为默认">
<el-switch v-model="currentAddress.isDefault"></el-switch>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addressDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="saveAddress">确 定</el-button>
</span>
</el-dialog>
</div>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
// 购物车商品数据
cartItems: [
{
id: 1,
name: 'Apple iPhone 13 256GB 国行正品 全网通5G手机',
description: '全新国行,官方正品,全国联保',
image: 'https://img14.360buyimg.com/n1/s200x200_jfs/t1/213334/24/9509/167699/616d8d9aE7c89c58e/3a5d4b9a5b9b1e8c.jpg',
price: 6999.00,
quantity: 1,
specs: [
{ label: '256GB 星光色', value: '256GB-星光色' },
{ label: '256GB 午夜色', value: '256GB-午夜色' },
{ label: '256GB 蓝色', value: '256GB-蓝色' },
{ label: '512GB 星光色', value: '512GB-星光色' }
],
selectedSpec: '256GB 星光色'
},
{
id: 2,
name: '小米电视6 OLED 55英寸 4K超高清 HDR10+ 智能液晶电视机',
description: 'OLED屏幕,极致色彩,智能语音控制',
image: 'https://img10.360buyimg.com/n1/s200x200_jfs/t1/197519/35/11029/141950/616d8d9aE7c89c58e/3a5d4b9a5b9b1e8c.jpg',
price: 4999.00,
quantity: 1,
specs: [
{ label: '55英寸', value: '55英寸' },
{ label: '65英寸', value: '65英寸' }
],
selectedSpec: '55英寸'
},
{
id: 3,
name: '飞利浦电动牙刷HX6730/02 成人声波震动牙刷',
description: '3种清洁模式,智能计时,30天超长续航',
image: 'https://img12.360buyimg.com/n1/s200x200_jfs/t1/199876/28/10998/98765/616d8d9aE7c89c58e/3a5d4b9a5b9b1e8c.jpg',
price: 299.00,
quantity: 2,
specs: [
{ label: '标准版', value: '标准版' },
{ label: '旅行套装', value: '旅行套装' }
],
selectedSpec: '标准版'
}
],
// 选中的商品
selectedItems: [],
// 收货地址
addresses: [
{
name: '张三',
phone: '138****1234',
province: '北京市',
city: '北京市',
district: '海淀区',
street: '中关村大街1号',
isDefault: true
},
{
name: '李四',
phone: '139****5678',
province: '上海市',
city: '上海市',
district: '浦东新区',
street: '张江高科技园区',
isDefault: false
}
],
selectedAddress: 0,
// 地址编辑相关
addressDialogVisible: false,
currentAddress: {
name: '',
phone: '',
region: [],
street: '',
isDefault: false
},
regionOptions: [
{
value: '北京市',
label: '北京市',
children: [
{
value: '北京市',
label: '北京市',
children: [
{ value: '东城区', label: '东城区' },
{ value: '西城区', label: '西城区' },
{ value: '朝阳区', label: '朝阳区' },
{ value: '海淀区', label: '海淀区' },
{ value: '丰台区', label: '丰台区' },
{ value: '石景山区', label: '石景山区' }
]
}
]
},
{
value: '上海市',
label: '上海市',
children: [
{
value: '上海市',
label: '上海市',
children: [
{ value: '黄浦区', label: '黄浦区' },
{ value: '徐汇区', label: '徐汇区' },
{ value: '长宁区', label: '长宁区' },
{ value: '静安区', label: '静安区' },
{ value: '浦东新区', label: '浦东新区' },
{ value: '闵行区', label: '闵行区' }
]
}
]
},
{
value: '广东省',
label: '广东省',
children: [
{
value: '广州市',
label: '广州市',
children: [
{ value: '越秀区', label: '越秀区' },
{ value: '海珠区', label: '海珠区' },
{ value: '天河区', label: '天河区' },
{ value: '白云区', label: '白云区' }
]
},
{
value: '深圳市',
label: '深圳市',
children: [
{ value: '福田区', label: '福田区' },
{ value: '罗湖区', label: '罗湖区' },
{ value: '南山区', label: '南山区' },
{ value: '宝安区', label: '宝安区' }
]
}
]
}
]
}
},
computed: {
// 全选状态
selectAll: {
get() {
return this.selectedItems.length === this.cartItems.length && this.cartItems.length > 0;
},
set(value) {
if (value) {
this.selectedItems = [...this.cartItems];
} else {
this.selectedItems = [];
}
}
},
// 计算总价
totalPrice() {
return this.selectedItems.reduce((total, item) => {
return total + (item.price * item.quantity);
}, 0);
}
},
methods: {
// 选择/取消选择商品
handleSelectionChange(selection) {
this.selectedItems = selection;
},
// 全选/取消全选
toggleSelectAll(value) {
this.selectAll = value;
},
// 更新商品数量
updateQuantity(item) {
const index = this.cartItems.findIndex(i => i.id === item.id);
if (index !== -1) {
this.$set(this.cartItems, index, { ...item });
}
},
// 更新商品规格
updateSpec(item) {
const index = this.cartItems.findIndex(i => i.id === item.id);
if (index !== -1) {
this.$set(this.cartItems, index, { ...item });
}
},
// 删除商品
removeItem(item) {
this.cartItems = this.cartItems.filter(i => i.id !== item.id);
this.selectedItems = this.selectedItems.filter(i => i.id !== item.id);
},
// 选择收货地址
selectAddress(index) {
this.selectedAddress = index;
},
// 编辑地址
editAddress(index) {
const address = this.addresses[index];
this.currentAddress = {
name: address.name,
phone: address.phone,
region: [address.province, address.city, address.district],
street: address.street,
isDefault: address.isDefault
};
this.addressDialogVisible = true;
},
// 删除地址
removeAddress(index) {
if (this.addresses.length <= 1) {
this.$message.warning('至少保留一个收货地址');
return;
}
this.addresses.splice(index, 1);
if (this.selectedAddress >= this.addresses.length) {
this.selectedAddress = this.addresses.length - 1;
}
this.$message.success('地址已删除');
},
// 添加新地址
addNewAddress() {
this.currentAddress = {
name: '',
phone: '',
region: [],
street: '',
isDefault: false
};
this.addressDialogVisible = true;
},
// 保存地址
saveAddress() {
if (!this.currentAddress.name || !this.currentAddress.phone) {
this.$message.error('请填写收货人和手机号');
return;
}
if (this.currentAddress.region.length < 3) {
this.$message.error('请选择完整的省市区');
return;
}
if (!this.currentAddress.street) {
this.$message.error('请填写详细地址');
return;
}
const newAddress = {
name: this.currentAddress.name,
phone: this.currentAddress.phone,
province: this.currentAddress.region[0],
city: this.currentAddress.region[1],
district: this.currentAddress.region[2],
street: this.currentAddress.street,
isDefault: this.currentAddress.isDefault
};
if (this.currentAddress.isDefault) {
// 如果设为默认,取消其他地址的默认状态
this.addresses.forEach(addr => {
addr.isDefault = false;
});
}
this.addresses.push(newAddress);
this.selectedAddress = this.addresses.length - 1;
this.addressDialogVisible = false;
this.$message.success('地址保存成功');
},
// 结算
checkout() {
if (this.selectedItems.length === 0) {
this.$message.warning('请至少选择一件商品');
return;
}
const address = this.addresses[this.selectedAddress];
this.$alert('是否确认订单', '确认订单', {
dangerouslyUseHTMLString: true,
confirmButtonText: '确认提交',
callback: action => {
if (action === 'confirm') {
this.$message.success('订单提交成功!');
// 清空购物车中已选商品
this.cartItems = this.cartItems.filter(item =>
!this.selectedItems.some(selected => selected.id === item.id)
);
this.selectedItems = [];
}
}
});
}
},
mounted() {
// 初始化选中所有商品
this.selectedItems = [...this.cartItems];
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,270 @@
const PRODUCT_SECTION = {
template: /*language=HTML*/ `
<div class="product-section" :style="{ backgroundColor: sectionBg }">
<div class="section-header">
<h2 class="title">{{ sectionTitle }}</h2>
<div class="section-tabs">
<span
v-for="(tab, index) in tabs"
:key="index"
:class="{ active: activeTab === tab }"
@click="activeTab = tab">
{{ tab }}
</span>
</div>
<div class="more">
<a href="javascript:void(0)">更多 <i class="el-icon-arrow-right"></i></a>
</div>
</div>
<div class="product-content">
<div class="product-sidebar" v-if="sidebarProducts && sidebarProducts.length > 0">
<div
v-for="(product, index) in sidebarProducts"
:key="index"
class="sidebar-item"
:class="{ 'big-item': index === 0 }">
<a href="javascript:void(0)">
<img :src="product.image" :alt="product.name">
<div class="info">
<div class="name">{{ product.name }}</div>
<div class="price">¥{{ product.price }}</div>
</div>
</a>
</div>
</div>
<div class="product-list">
<div
v-for="(product, index) in displayedProducts"
:key="index"
class="product-item">
<a href="javascript:void(0)">
<div class="product-image">
<img :src="product.image" :alt="product.name">
</div>
<div class="product-info">
<div class="product-name">{{ product.name }}</div>
<div class="product-price">¥{{ product.price }}</div>
<div class="product-desc">{{ product.desc }}</div>
</div>
</a>
</div>
</div>
</div>
</div>
`,
props: {
sectionTitle: {
type: String,
required: true
},
products: {
type: Array,
required: true
},
sidebarProducts: {
type: Array,
default: () => []
},
sectionBg: {
type: String,
default: '#fff'
}
},
data() {
return {
activeTab: '推荐',
tabs: ['推荐', '热卖', '新品']
}
},
computed: {
displayedProducts() {
// 这里可以根据activeTab筛选不同类别的商品
// 为简化示例,这里只返回前8个商品
return this.products.slice(0, 8);
}
},
style: /*language=CSS*/ `
.product-section {
padding: 20px;
border-radius: 4px;
margin-bottom: 20px;
}
.section-header {
display: flex;
align-items: center;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
.title {
font-size: 20px;
color: #333;
font-weight: bold;
flex: 1;
}
.section-tabs {
display: flex;
margin-right: 20px;
}
.section-tabs span {
margin: 0 10px;
cursor: pointer;
padding: 5px 10px;
border-radius: 15px;
font-size: 14px;
color: #666;
}
.section-tabs span.active {
background: #c81623;
color: #fff;
}
.more a {
color: #666;
font-size: 14px;
text-decoration: none;
}
.more a:hover {
color: #c81623;
}
.product-content {
display: flex;
gap: 20px;
}
.product-sidebar {
width: 200px;
display: flex;
flex-direction: column;
gap: 10px;
}
.sidebar-item {
border-radius: 4px;
overflow: hidden;
transition: all 0.3s;
}
.sidebar-item:hover {
transform: translateY(-3px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.sidebar-item a {
display: block;
color: #333;
text-decoration: none;
}
.sidebar-item img {
width: 100%;
height: 100px;
object-fit: cover;
}
.info {
padding: 10px;
background: #fff;
}
.name {
font-size: 14px;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.price {
color: #c81623;
font-weight: bold;
}
.big-item {
height: 210px;
}
.big-item img {
height: 150px;
}
.product-list {
flex: 1;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.product-item {
background: #fff;
border-radius: 4px;
overflow: hidden;
transition: all 0.3s;
}
.product-item:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-3px);
}
.product-item a {
display: block;
color: #333;
text-decoration: none;
}
.product-image {
width: 100%;
height: 180px;
display: flex;
align-items: center;
justify-content: center;
background: #f9f9f9;
overflow: hidden;
}
.product-image img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.product-info {
padding: 12px;
}
.product-name {
font-size: 14px;
color: #333;
height: 40px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin-bottom: 8px;
}
.product-price {
color: #e4393c;
font-weight: bold;
font-size: 16px;
margin-bottom: 5px;
}
.product-desc {
font-size: 12px;
color: #999;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
`
}
@@ -0,0 +1,312 @@
const SIDEBAR = {
template: /*language=HTML*/ `
<div class="sidebar">
<ul class="category-list">
<li class="category-item"
v-for="category in categories"
:key="category.id"
@mouseenter="showSubCategories(category)"
@mouseleave="hideSubCategories">
<router-link :to="'/category/' + category.id" class="category-link">
<span class="category-name">{{ category.name }}</span>
<i class="el-icon-arrow-right"></i>
</router-link>
<!-- 二级分类面板 -->
<div class="sub-category-panel" v-if="activeCategory && activeCategory.id === category.id">
<div class="sub-category-content">
<div class="sub-category-group" v-for="group in category.children" :key="group.id">
<h3 class="sub-category-title">
<router-link :to="'/category/' + group.id">{{ group.name }}</router-link>
</h3>
<ul class="sub-category-list">
<li v-for="child in group.children" :key="child.id">
<router-link :to="'/category/' + child.id">{{ child.name }}</router-link>
</li>
</ul>
</div>
</div>
</div>
</li>
</ul>
</div>
`,
data() {
return {
categories: [],
activeCategory: null,
loading: false
}
},
methods: {
showSubCategories(category) {
this.activeCategory = category;
},
hideSubCategories() {
setTimeout(() => {
if (!this.$el.matches(':hover') && !this.$el.querySelector('.sub-category-panel:hover')) {
this.activeCategory = null;
}
}, 300);
},
async getCategories() {
this.loading = true;
try {
this.categories = [
{
"id": "1348576427268399553",
"name": "家用电器",
"parentId": "0",
"level": 0,
"sortOrder": 1,
"children": [
{
"id": "1348576427268399567",
"name": "生活电器",
"parentId": "1348576427268399553",
"level": 1,
"sortOrder": 0,
"children": [
{"id": "1348576427268399568", "name": "电风扇", "level": 2},
{"id": "1348576427268399569", "name": "吸尘器", "level": 2},
{"id": "1348576427268399570", "name": "加湿器", "level": 2},
{"id": "1348576427268399571", "name": "净水设备", "level": 2},
{"id": "1348576427268399572", "name": "饮水机", "level": 2}
]
},
{
"id": "1348576427268399580",
"name": "大家电",
"parentId": "1348576427268399553",
"level": 1,
"sortOrder": 1,
"children": [
{"id": "1348576427268399581", "name": "电视", "level": 2},
{"id": "1348576427268399582", "name": "空调", "level": 2},
{"id": "1348576427268399583", "name": "冰箱", "level": 2},
{"id": "1348576427268399584", "name": "洗衣机", "level": 2}
]
}
]
},
{
"id": "1348576427268399600",
"name": "手机通讯",
"parentId": "0",
"level": 0,
"sortOrder": 2,
"children": [
{
"id": "1348576427268399601",
"name": "手机",
"parentId": "1348576427268399600",
"level": 1,
"children": [
{"id": "1348576427268399602", "name": "智能手机", "level": 2},
{"id": "1348576427268399603", "name": "游戏手机", "level": 2},
{"id": "1348576427268399604", "name": "老人手机", "level": 2}
]
},
{
"id": "1348576427268399605",
"name": "运营商",
"parentId": "1348576427268399600",
"level": 1,
"children": [
{"id": "1348576427268399606", "name": "合约机", "level": 2},
{"id": "1348576427268399607", "name": "选号中心", "level": 2}
]
}
]
},
{
"id": "1348576427268399700",
"name": "电脑办公",
"parentId": "0",
"level": 0,
"sortOrder": 3,
"children": [
{
"id": "1348576427268399701",
"name": "笔记本",
"parentId": "1348576427268399700",
"level": 1,
"children": [
{"id": "1348576427268399702", "name": "轻薄本", "level": 2},
{"id": "1348576427268399703", "name": "游戏本", "level": 2},
{"id": "1348576427268399704", "name": "商务本", "level": 2}
]
},
{
"id": "1348576427268399710",
"name": "台式机",
"parentId": "1348576427268399700",
"level": 1,
"children": [
{"id": "1348576427268399711", "name": "游戏台式机", "level": 2},
{"id": "1348576427268399712", "name": "设计师主机", "level": 2}
]
}
]
},
{
"id": "1348576427268399800",
"name": "食品生鲜",
"parentId": "0",
"level": 0,
"sortOrder": 4,
"children": [
{
"id": "1348576427268399801",
"name": "水果",
"parentId": "1348576427268399800",
"level": 1,
"children": [
{"id": "1348576427268399802", "name": "苹果", "level": 2},
{"id": "1348576427268399803", "name": "香蕉", "level": 2},
{"id": "1348576427268399804", "name": "橙子", "level": 2}
]
},
{
"id": "1348576427268399810",
"name": "肉禽蛋",
"parentId": "1348576427268399800",
"level": 1,
"children": [
{"id": "1348576427268399811", "name": "猪肉", "level": 2},
{"id": "1348576427268399812", "name": "牛肉", "level": 2},
{"id": "1348576427268399813", "name": "鸡蛋", "level": 2}
]
}
]
}
]
} catch (error) {
console.error('获取分类失败:', error);
this.$message.error('获取分类数据失败');
} finally {
this.loading = false;
}
}
},
async created() {
await this.getCategories()
},
style: /*language=CSS*/ `
.sidebar {
width: 210px;
background: #222;
border-radius: 4px;
overflow: hidden;
}
.category-list {
list-style: none;
}
.category-item {
position: relative;
border-bottom: 1px solid #333;
}
.category-link {
display: block;
padding: 12px 15px;
color: #fff;
text-decoration: none;
font-size: 14px;
transition: all 0.3s;
position: relative;
}
.category-link:hover {
background: #c81623;
padding-left: 20px;
}
.category-link:hover .el-icon-arrow-right {
opacity: 1;
}
.category-name {
display: inline-block;
max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
.el-icon-arrow-right {
position: absolute;
right: 15px;
opacity: 0;
transition: opacity 0.3s;
}
.sub-category-panel {
position: absolute;
left: 210px;
top: 0;
width: 700px;
min-height: 400px;
background: #fff;
border: 1px solid #e0e0e0;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 1000;
padding: 20px;
border-radius: 0 4px 4px 0;
}
.sub-category-content {
display: flex;
flex-wrap: wrap;
}
.sub-category-group {
width: 230px;
margin-right: 20px;
margin-bottom: 15px;
}
.sub-category-title {
font-size: 16px;
color: #333;
margin-bottom: 10px;
}
.sub-category-title a {
color: #333;
font-weight: bold;
text-decoration: none;
}
.sub-category-title a:hover {
color: #c81623;
}
.sub-category-list {
list-style: none;
}
.sub-category-list li {
padding: 5px 0;
}
.sub-category-list li a {
color: #666;
text-decoration: none;
font-size: 14px;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: color 0.2s;
}
.sub-category-list li a:hover {
color: #c81623;
padding-left: 5px;
}
`
}
@@ -0,0 +1,255 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.home-page {
background-color: #f5f5f5;
}
.main-content {
padding: 20px 0;
}
.container {
width: 1200px;
margin: 0 auto;
}
.content-wrapper {
display: flex;
gap: 20px;
}
.content-area {
flex: 1;
}
</style>
<div id="app">
<div class="home-page">
<!-- 顶部导航 -->
<header-component></header-component>
<!-- 主内容区域 -->
<div class="main-content">
<div class="container">
<div class="content-wrapper">
<!-- 左侧分类导航 -->
<category-nav :categories="categoryData"
@category-selected="handleCategorySelect"></category-nav>
<!-- 右侧内容区域 -->
<div class="content-area">
<!-- 轮播图 -->
<banner :banners="banners"></banner>
<!-- 热门品牌 -->
<hot-brands :brands="hotBrands"></hot-brands>
<!-- 家用电器专区 -->
<product-section
section-title="家用电器"
:products="applianceProducts"
:sidebar-products="applianceSidebar"
section-bg="#f9f9f9"></product-section>
<!-- 手机数码专区 -->
<product-section
section-title="手机数码"
:products="digitalProducts"
:sidebar-products="digitalSidebar"
section-bg="#fff"></product-section>
<!-- 电脑办公专区 -->
<product-section
section-title="电脑办公"
:products="computerProducts"
:sidebar-products="computerSidebar"
section-bg="#f9f9f9"></product-section>
<!-- 食品生鲜专区 -->
<product-section
section-title="食品生鲜"
:products="foodProducts"
:sidebar-products="foodSidebar"
section-bg="#fff"></product-section>
</div>
</div>
</div>
</div>
<!-- 页脚 -->
<footer-component></footer-component>
</div>
</div>
<script>
new Vue({
el: '#app',
data() {
return{
// 分类数据(简化版,实际应用中从API获取)
categoryData: [
{
"id": "1348576427268399553",
"name": "家用电器",
"parentId": "0",
"level": 0,
"children": [
{
"id": "1348576427268399567",
"name": "生活电器",
"parentId": "1348576427268399553",
"level": 1,
"children": [
{"id": "1348576427268399568", "name": "电风扇", "level": 2},
{"id": "1348576427268399569", "name": "吸尘器", "level": 2},
{"id": "1348576427268399570", "name": "加湿器", "level": 2},
{"id": "1348576427268399571", "name": "净水设备", "level": 2}
]
},
{
"id": "1348576427268399580",
"name": "大家电",
"parentId": "1348576427268399553",
"level": 1,
"children": [
{"id": "1348576427268399581", "name": "电视", "level": 2},
{"id": "1348576427268399582", "name": "空调", "level": 2},
{"id": "1348576427268399583", "name": "冰箱", "level": 2},
{"id": "1348576427268399584", "name": "洗衣机", "level": 2}
]
}
]
},
{
"id": "1348576427268399600",
"name": "手机通讯",
"parentId": "0",
"level": 0,
"children": [
{
"id": "1348576427268399601",
"name": "手机",
"parentId": "1348576427268399600",
"level": 1,
"children": [
{"id": "1348576427268399602", "name": "智能手机", "level": 2},
{"id": "1348576427268399603", "name": "游戏手机", "level": 2},
{"id": "1348576427268399604", "name": "老人手机", "level": 2}
]
}
]
},
{
"id": "1348576427268399700",
"name": "电脑办公",
"parentId": "0",
"level": 0,
"children": [
{
"id": "1348576427268399701",
"name": "笔记本",
"parentId": "1348576427268399700",
"level": 1,
"children": [
{"id": "1348576427268399702", "name": "轻薄本", "level": 2},
{"id": "1348576427268399703", "name": "游戏本", "level": 2}
]
}
]
}
],
// 轮播图数据
banners: [
{ id: 1, image: 'https://img10.360buyimg.com/cms/jfs/t1/206882/36/9500/185895/613f845aE6f4c0d13/7b8c6a5a5e9b6e3a.jpg', url: '#' },
{ id: 2, image: 'https://img14.360buyimg.com/cms/jfs/t1/196395/24/18927/188310/613f845aE3d0e6e57/3d0e8b9b8b8e3a9f.jpg', url: '#' },
{ id: 3, image: 'https://img12.360buyimg.com/cms/jfs/t1/178900/38/20300/177950/613f845aE7e9c9c5f/9d1b4c7b3d7b6e3a.jpg', url: '#' }
],
// 热门品牌
hotBrands: [
{ id: 1, name: 'Apple', logo: 'https://img11.360buyimg.com/vclist/jfs/t1/196565/35/10440/7517/613f845aE7b4d9c5f/7b8c6a5a5e9b6e3a.png' },
{ id: 2, name: '华为', logo: 'https://img11.360buyimg.com/vclist/jfs/t1/196565/35/10440/7517/613f845aE7b4d9c5f/7b8c6a5a5e9b6e3a.png' },
{ id: 3, name: '小米', logo: 'https://img11.360buyimg.com/vclist/jfs/t1/196565/35/10440/7517/613f845aE7b4d9c5f/7b8c6a5a5e9b6e3a.png' },
{ id: 4, name: '格力', logo: 'https://img11.360buyimg.com/vclist/jfs/t1/196565/35/10440/7517/613f845aE7b4d9c5f/7b8c6a5a5e9b6e3a.png' },
{ id: 5, name: '联想', logo: 'https://img11.360buyimg.com/vclist/jfs/t1/196565/35/10440/7517/613f845aE7b4d9c5f/7b8c6a5a5e9b6e3a.png' }
],
// 家用电器商品
applianceProducts: [
{ id: 1, name: '美的电风扇FS40-15HR', price: 199.00, image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg', hot: true },
{ id: 2, name: '戴森V11吸尘器', price: 4999.00, image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg', hot: true },
{ id: 3, name: '小米加湿器2', price: 199.00, image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 4, name: '海尔净水器HRO75H1', price: 1299.00, image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 5, name: '格力冷风扇', price: 599.00, image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 6, name: '飞利浦空气净化器', price: 1599.00, image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' }
],
applianceSidebar: [
{ id: 1, name: '电视', image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 2, name: '空调', image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 3, name: '冰箱', image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' }
],
// 手机数码商品
digitalProducts: [
{ id: 7, name: '华为Mate 50 Pro', price: 6999.00, image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg', hot: true },
{ id: 8, name: '小米13 Ultra', price: 5999.00, image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 9, name: 'iPhone 14 Pro', price: 8999.00, image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg', hot: true },
{ id: 10, name: 'vivo X90 Pro+', price: 4999.00, image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 11, name: 'OPPO Find X6', price: 4499.00, image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 12, name: '荣耀Magic5 Pro', price: 4699.00, image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' }
],
digitalSidebar: [
{ id: 1, name: '手机配件', image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 2, name: '智能手表', image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 3, name: '耳机', image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' }
],
// 电脑办公商品
computerProducts: [
{ id: 13, name: '联想拯救者Y9000P', price: 8999.00, image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg', hot: true },
{ id: 14, name: 'MacBook Pro 14', price: 15999.00, image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg', hot: true },
{ id: 15, name: '华为MateBook X Pro', price: 8999.00, image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 16, name: '戴尔XPS 13', price: 9999.00, image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 17, name: '惠普暗影精灵9', price: 6999.00, image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 18, name: '外星人m16', price: 12999.00, image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' }
],
computerSidebar: [
{ id: 1, name: '台式机', image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 2, name: '平板电脑', image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 3, name: '办公设备', image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' }
],
// 食品生鲜商品
foodProducts: [
{ id: 19, name: '五常大米5kg', price: 69.90, image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 20, name: '进口牛排10片装', price: 199.00, image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg', hot: true },
{ id: 21, name: '智利车厘子5kg', price: 299.00, image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 22, name: '阳澄湖大闸蟹4只装', price: 258.00, image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg', hot: true },
{ id: 23, name: '每日坚果750g', price: 89.90, image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 24, name: '进口橄榄油500ml', price: 79.90, image: 'https://img12.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' }
],
foodSidebar: [
{ id: 1, name: '新鲜水果', image: 'https://img13.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' },
{ id: 2, name: '肉禽蛋品', image: 'https://img14.360buyimg.com/n7/jfs/t1/142701/17/20119/143370/60d4d5a4E9d0a7c96/6a0c6c4e0b7b0b3e.jpg' },
{ id: 3, name: '海鲜水产', image: 'https://img10.360buyimg.com/n7/jfs/t1/159523/33/20120/137983/60d4d5a4E1d0b4c96/5c5a5c4e0b7b0b3e.jpg' }
]
}
},
methods: {
handleCategorySelect(category) {
console.log('Selected category:', category)
// 这里可以添加跳转到分类页面的逻辑
// this.$router.push({ name: 'category', params: { id: category.id } })
}
},
created() {
},
});
</script>
<!--#
}
#-->
@@ -0,0 +1,127 @@
const ADD_GOODS_FIRST = {
template: /*language=HTML*/ `
<div>
<!-- 商品分类 -->
<div class="content-goods-publish">
<div class="goods-category">
<ul v-if="categoryListLevel1.length > 0">
<li
v-for="(item, index) in categoryListLevel1"
:class="{ activeClass: category[0].name === item.name }"
@click="handleSelectCategory(item, index, 1)"
:key="index"
>
<span>{{ item.name }}</span>
<span>&gt;</span>
</li>
</ul>
<ul v-if="categoryListLevel2.length > 0">
<li
v-for="(item, index) in categoryListLevel2"
:class="{ activeClass: category[1].name === item.name }"
@click="handleSelectCategory(item, index, 2)"
:key="index"
>
<span>{{ item.name }}</span>
<span>&gt;</span>
</li>
</ul>
<ul v-if="categoryListLevel3.length > 0">
<li
v-for="(item, index) in categoryListLevel3"
:class="{ activeClass: category[2].name === item.name }"
@click="handleSelectCategory(item, index, 3)"
:key="index"
>
<span>{{ item.name }}</span>
</li>
</ul>
</div>
<p class="current-goods-category">
您当前选择的商品类别是
<span>{{ category[0].name }}</span>
<span v-show="category[1].name">> {{ category[1].name }}</span>
<span v-show="category[2].name">> {{ category[2].name }}</span>
</p>
</div>
<!-- 底部按钮 -->
<div class="footer">
<el-button-group>
<el-button type="primary" @click="next">下一步</el-button>
</el-button-group>
</div>
</div>
`,
data(){
return {
// 商品分类选择数组
category: [
{ name: "", id: "" },
{ name: "", id: "" },
{ name: "", id: "" },
],
// 商品类型
goodsType: "PHYSICAL_GOODS",
/** 1级分类列表*/
categoryListLevel1: [],
/** 2级分类列表*/
categoryListLevel2: [],
/** 3级分类列表*/
categoryListLevel3: [],
}
},
methods: {
/** 选择商城商品分类 */
handleSelectCategory(row, index, level) {
if (level === 1) {
this.category.forEach((cate) => {
(cate.name = ""), (cate.id = "");
});
this.category[0].name = row.name;
this.category[0].id = row.id;
this.categoryListLevel2 = this.categoryListLevel1[index].children;
this.categoryListLevel3 = [];
} else if (level === 2) {
this.category[1].name = row.name;
this.category[1].id = row.id;
this.category[2].name = "";
this.category[2].id = "";
this.categoryListLevel3 = this.categoryListLevel2[index].children;
} else {
this.category[2].name = row.name;
this.category[2].id = row.id;
}
},
/** 查询下一级 商城商品分类*/
getAllCategory() {
this.$axios.post('/platform/mall/category/manage/allChildren').then((res) => {
if (res.code === 0 && res.data) {
this.categoryListLevel1 = res.data;
}
});
},
// 下一步
next() {
window.scrollTo(0, 0);
if (!this.category[0].name) {
this.$message.error("请选择商品分类");
} else if (!this.category[2].name) {
this.$message.error("必须选择到三级分类");
} else if (this.category[2].name) {
let params = {
category: this.category,
goodsType: this.goodsType,
};
this.$emit("change", params);
}
},
},
mounted() {
this.getAllCategory();
},
style: /*language=CSS*/ `
/deep/ .ivu-scroll-container {
height: 450px !important;
}
`,
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
const ADD_GOODS_THIRD = {
template: /*language=HTML*/ `
`,
data(){
return {
}
},
methods: {
},
}
@@ -0,0 +1,67 @@
<!--#
layout("/layouts/platform.html"){
#-->
<link rel="stylesheet" href="${base!}/assets/platform/module/mall/addGoods.css" />
<div id="app">
<div>
<div class="step-list">
<el-steps :active="activestep" align-center finish-status="success">
<el-step title="选择商品品类"></el-step>
<el-step title="填写商品详情"></el-step>
<el-step title="商品发布成功"></el-step>
</el-steps>
</div>
<!-- 第一步 选择分类 -->
<first-step ref='first' v-show="activestep === 0" @change="getFirstData"></first-step>
<!-- 第二步 商品详细信息 -->
<second-step ref='second' :first-data="firstData" v-if="activestep === 1"></second-step>
<!-- 第三步 发布完成 -->
<third-step ref='third' v-if="activestep === 2"></third-step>
</div>
</div>
<script>
<!--#include("addGoodsFirst.js"){}#-->
<!--#include("addGoodsSecond.js"){}#-->
<!--#include("addGoodsThird.js"){}#-->
const vue = new Vue({
el: '#app',
data(){
return {
/** 当前激活步骤*/
activestep: 0,
firstData: {}, // 第一步传递的数据
id: ''
}
},
components: {
'first-step': ADD_GOODS_FIRST,
'second-step': ADD_GOODS_SECOND,
'third-step': ADD_GOODS_THIRD,
},
methods: {
// 选择商品分类回调
getFirstData (item) {
this.firstData = item;
this.activestep = 1;
}
},
created () {
this.id = GetQueryString("id")
},
mounted () {
// 编辑商品、模板
if (this.id) {
this.activestep = 1;
} else {
this.activestep = 0
// this.$refs.first.selectGoodsType = true;
}
}
});
</script>
<!--#
}
#-->
@@ -0,0 +1,411 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<el-card>
<!-- 顶部按钮 -->
<div style="margin-bottom:10px">
<el-button type="primary" icon="el-icon-plus" @click="addParent">
添加一级分类
</el-button>
</div>
<!-- 表格 -->
<el-table
row-key="id"
:data="tableData"
style="width:100%"
lazy
:load="loadChildren"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column label="分类名称" prop="name"></el-table-column>
<el-table-column label="当前层级" prop="level">
<template slot-scope="{ row }">
{{ (row.level + 1) + '级' }}
</template>
</el-table-column>
<!-- 状态列 -->
<el-table-column label="状态" prop="delFlag">
<template slot-scope="{ row }">
<el-tag :type="row.delFlag ? 'danger' : 'success'">
{{ !row.delFlag ? '正常启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<!-- 你的业务列请自行补充 -->
<el-table-column label="操作" width="260">
<template slot-scope="scope">
<!-- 通用操作下拉 -->
<el-dropdown trigger="click" style="margin-right:6px">
<el-button size="mini">
操作<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="edit(scope.row)">
编辑
</el-dropdown-item>
<el-dropdown-item
v-if="scope.row.delFlag == true"
@click.native="enable(scope.row)"
>
启用
</el-dropdown-item>
<el-dropdown-item
v-if="scope.row.delFlag == false"
@click.native="disable(scope.row)"
>
禁用
</el-dropdown-item>
<el-dropdown-item @click.native="remove(scope.row)">
删除
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- 添加子分类(level ≠ 2 时显示) -->
<el-button
v-if="scope.row.level !== 2"
type="primary"
size="mini"
icon="el-icon-plus"
@click="addChildren(scope.row)"
>
添加子分类
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新增/编辑分类弹窗 -->
<el-dialog
:title="modalTitle"
:visible.sync="modalVisible"
width="40%"
:close-on-click-modal="false"
>
<el-form ref="form" :model="formAdd" label-width="100px" :rules="formValidate">
<el-form-item
v-if="showParent"
label="上级分类"
prop="parentId"
style="display:none"
>
<el-input v-model="formAdd.parentId" placeholder="请输入上级分类" clearable></el-input>
</el-form-item>
<el-form-item label="层级" prop="level" style="display:none">
<el-input v-model="formAdd.level" placeholder="请输入层级" clearable></el-input>
</el-form-item>
<el-form-item label="分类名称" prop="name">
<el-input v-model="formAdd.name" placeholder="请输入分类名称" clearable></el-input>
</el-form-item>
<el-form-item v-if="formAdd.level !== 1" label="分类图标" prop="image">
<file-upload
:value.sync="formAdd.image"
:upload_number="1"
upload_mode="image"
upload_result_category="interval"
upload_result_type="url"
></file-upload>
<!--<upload-pic-input
v-model="formAdd.image"
style="width:100%"></upload-pic-input>-->
</el-form-item>
<el-form-item label="排序值" prop="sortOrder">
<el-input-number v-model="formAdd.sortOrder"></el-input-number>
</el-form-item>
<el-form-item label="是否启用" prop="delFlag">
<el-switch
v-model="formAdd.delFlag"
:active-value="false"
:inactive-value="true"
active-text="启用"
inactive-text="禁用"
></el-switch>
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="modalVisible = false">取消</el-button>
<el-button type="primary" :loading="submitLoading" @click="Submit">提交</el-button>
</div>
</el-dialog>
</el-card>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
recordLevel:[], // 记录当前层级
submitLoading: false, //加载状态
categoryList: [], // 分类列表
loading: false, // 加载状态
brands: [], //品牌集合
specifications: [], //规格集合
categoryId: "", // 分类id
categorySpecs: [], //已经选择的规格
modalType: 0, // 添加或编辑标识
modalVisible: false, // 添加或编辑显示
modalBrandVisible: false, //品牌关联编辑显示
modalSpecVisible: false, //品牌关联编辑显示
modalTitle: "", // 添加或编辑标题
showParent: false, // 是否展示上级菜单
parentTitle: "", // 父级菜单名称
modalBrandTitle: "", // 品牌弹窗标题
modalSpecTitle: "", // 规格弹窗标题
formAdd: {
// 添加或编辑表单对象初始化数据
parentId: "",
name: "",
image: "",
sortOrder: 0,
delFlag: 0,
level: 0,
},
brandForm: {
categoryBrands: [],
},
brandWay: "", //请求绑定品牌的信息
specForm: {}, // 规格数据
// 表单验证规则
formValidate: {
name: [{required: true, message: "请输入分类名称", trigger: ["blur", "change"]}],
sortOrder: [{required: true, message: "请输入排序值", trigger: ["blur", "change"]}],
},
tableColumns: [
{label: "分类名称", prop: "name"},
{label: "状态", prop: "delFlag"},
{label: "操作", prop: "action"},
],
tableData: [], // 表格数据
checkedCategoryChildren: "", //选中的分类子级
};
},
methods: {
// 初始化数据
init() {
this.getAllList(0);
},
// 添加子分类
addChildren(v) {
this.modalType = 0;
this.modalTitle = "添加子分类";
this.parentTitle = v.name;
this.formAdd.level = eval(v.level + "+1");
this.formAdd.commissionRate = v.commissionRate;
this.showParent = true;
delete this.formAdd.id;
this.formAdd.parentId = v.id;
this.modalVisible = true;
},
// 编辑分类
edit(v) {
this.modalType = 1;
this.modalTitle = "编辑";
this.formAdd.id = v.id;
this.formAdd.name = v.name;
this.formAdd.level = v.level;
this.formAdd.parentId = v.parentId;
this.formAdd.sortOrder = v.sortOrder;
this.formAdd.commissionRate = v.commissionRate;
this.formAdd.delFlag = v.delFlag;
this.formAdd.image = v.image;
this.showParent = false;
this.modalVisible = true;
},
// 添加一级分类
addParent() {
this.modalType = 0;
this.modalTitle = "添加一级分类";
this.parentTitle = "顶级分类";
this.showParent = true;
// this.$refs.form.resetFields();
delete this.formAdd.id;
this.formAdd.parentId = 0;
this.modalVisible = true;
},
// 提交
Submit() {
this.$refs.form.validate((valid) => {
if (valid) {
this.submitLoading = true;
if (this.modalType === 0) {
// 添加 避免编辑后传入id等数据 记得删除
delete this.formAdd.id;
this.$axios.post("/platform/mall/category/manage/saveCategory", this.formAdd).then((res) => {
this.submitLoading = false;
if (res.code === 0) {
this.$message.success("添加成功");
this.getAllList();
this.modalVisible = false;
// this.$refs.form.resetFields();
} else {
this.$message.error(res.message);
}
});
} else {
// 编辑
this.$axios.post("/platform/mall/category/manage/updateCategory", this.formAdd).then((res) => {
this.submitLoading = false;
if (res.code === 0) {
this.$message.success("修改成功");
this.getAllList();
this.modalVisible = false;
// this.$refs.form.resetFields();
} else {
this.$message.error(res.message);
}
});
}
}
});
},
// 删除分类
remove(v) {
this.$confirm("确定要删除 " + v.name + " ", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/mall/category/manage/delAllByIds", {
id: v.id
}).then((res) => {
if (res.code === 0) {
this.$message.success("操作成功");
this.getAllList();
} else {
this.$message.error(res.message);
}
});
})
},
// 异步手动加载分类名称
loadChildren(row, treeNode, resolve) {
// 记录层级(可选)
this.recordLevel[row.level] = row.id;
if (row.level === 0) {
// 根节点 -> 拿一级子节点
const children = this.categoryList
.find(item => item.id === row.id)
?.children || [];
// 给下一级节点加 hasChildren
children.forEach(child => {
child.hasChildren = !!(child.children && child.children.length);
});
setTimeout(() => resolve(children), 100);
} else {
// 非根节点 -> 用你原来的递归方法
this.deepCategoryChildren(row.id, this.categoryList);
setTimeout(() => {
const list = this.checkedCategoryChildren || [];
list.forEach(item => {
item.hasChildren = !!(item.children && item.children.length);
});
resolve(list);
}, 100);
}
},
// 通过递归children来实现手动加载数据
deepCategoryChildren(id, list) {
if (id != "0" && list.length != 0) {
for (let i = 0; i < list.length; i++) {
let item = list[i];
if (item.id == id) {
this.checkedCategoryChildren = item.children;
return;
} else {
this.deepCategoryChildren(id, item.children);
}
}
}
},
// 获取分类数据
getAllList() {
this.loading = true;
this.$axios.post("/platform/mall/category/manage/allChildren").then((res) => {
this.loading = false;
if (res.code === 0) {
localStorage.setItem("category", JSON.stringify(res.data));
this.categoryList = JSON.parse(JSON.stringify(res.data));
this.tableData = res.data
// this.tableData = res.data.map((item) => {
// if(this.recordLevel[0] && item.id === this.recordLevel[0]) {
// item._showChildren = true
// // 继续判断第二层
// if(this.recordLevel[1] && item.children){
// item.children.map((child)=>{
// if(this.recordLevel[1] && child.id === this.recordLevel[1]){
// child._showChildren = true
// }
// })
// }
// }else{
// if (item.children.length !== 0) {
// item.children = [];
// item._loading = false;
// }
// }
// return item;
// });
}
});
},
// 启用分类
enable(v) {
this.$confirm("您是否要启用当前分类 " + v.name + " 及其子分类?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/mall/category/manage/disable", {
id: v.id,
enableOperations: false
}).then((res) => {
if (res.code === 0) {
this.$message.success("操作成功");
this.getAllList(0);
} else {
this.$message.error(res.message);
}
});
})
},
// 禁用分类
disable(v) {
this.$confirm("您是否要启用当前分类 " + v.name + " 及其子分类?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/mall/category/manage/disable", {
id: v.id,
enableOperations: true
}).then((res) => {
if (res.code === 0) {
this.$message.success("操作成功");
this.getAllList(0);
} else {
this.$message.error(res.message);
}
});
})
},
},
mounted() {
this.init();
},
});
</script>
<!--#
}
#-->
@@ -373,7 +373,7 @@
},
findOne(id) {
this.$axios.post('/platform/difficultyHelp/view/findOne', { id }).then(res => {
this.$axios.post('/platform/difficultHelp/mine/findOne', { id }).then(res => {
if (res.code === 0) {
this.formData = res.data
}
@@ -3,86 +3,229 @@ layout("/layouts/platform.html"){
#-->
<div id="app">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="受助人">
<el-input placeholder="请输入受助人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请记录">
<el-button size="small" type="primary" @click="onApply">帮扶申请</el-button>
</table-tool>
<snaker-start slot="header" label="困难帮扶申请" define_key="KNBF"></snaker-start>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix="" class="flow-task-form">
<el-descriptions :column="3" border>
<el-descriptions-item label="填写人姓名">
<el-form-item prop="proxyUserName">
<el-input readonly v-model="formData.proxyUserName"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="填写人工号">
<el-form-item prop="proxyLoginName">
<el-input readonly v-model="formData.proxyLoginName"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="申请模式">
<el-form-item prop="mode">
<el-select v-model="formData.mode" placeholder="申请模式">
@change="modeChange" style="width: 100%">
<el-option label="本人申请" value="1"></el-option>
<el-option v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN, BRANCH_UNION_CHAIRMAN, BRANCH_UNION_OPERATOR')"
label="替他人申请" value="2"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="受补助人">
<template v-if="formData.mode == 2">
<el-select :remote-method="queryRecipients"
@change="userChange" clearable filterable
placeholder="输入工号或者姓名查找" remote
style="width: 100%" v-model="formData.userId">
<el-option :key="o.id"
:label="o.username+'('+o.loginname+')'"
:value="o.id"
v-for="o in subsidizedList"></el-option>
</el-select>
</template>
<template v-else>
<el-input readonly maxlength="100" type="text"
v-model="formData.userName"></el-input>
</template>
</el-descriptions-item>
<el-descriptions-item label="性别">
<el-form-item prop="sex">
<el-select v-model="formData.sex" placeholder="请选择性别" clearable style="width: 100%">
<el-option v-for="item in ['男性','女性']" :key="item" :label="item" :value="item">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="出生年月">
<el-form-item prop="birthday">
<el-date-picker
clearable
style="width: 100%"
v-model="formData.birthday"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择出生年月">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="所属单位">
<el-form-item prop="unitName">
<el-input maxlength="50" clearable placeholder="所在单位"
readonly v-model="formData.unitName"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="所属工会">
<el-form-item prop="unionName">
<el-input maxlength="50" clearable placeholder="所属工会"
readonly v-model="formData.unionName"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="职务职称">
<el-form-item prop="officialCapacity">
<el-input maxlength="20" clearable placeholder="请填写职务职称"
v-model="formData.officialCapacity"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="手机号码">
<el-form-item prop="mobile">
<el-input maxlength="11" clearable placeholder="请填写手机号码"
v-model="formData.mobile" maxlength="11"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="身份证号" :span="2">
<el-form-item prop="idCard">
<el-input maxlength="20" clearable placeholder="请填写身份证号"
v-model="formData.idCard" maxlength="18"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="本人月收入">
<el-form-item prop="monthlyIncome">
<el-input-number clearable
style="width: 100%"
v-model="formData.monthlyIncome"
:min="0"
:max="9999999"
placeholder="请填写本人月收入">
</el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="收款账户" :span="2">
<el-form-item prop="bankCardNum">
<el-input maxlength="20" clearable placeholder="请填写华夏银行工资卡号"
v-model="formData.bankCardNum"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="困难类型" :span="3">
<el-form-item prop="subsidyStandards">
<el-select v-model="formData.subsidyStandards" style="width: 100%">
<el-option v-for="(item,index) in subsidyStandards" :key="index" :label="item"
:value="item">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="申请原因" :span="3">
<el-form-item prop="reason">
<el-input maxlength="500" :autosize="{ minRows: 5, maxRows: 10}"
placeholder="请简述申请原因"
clearable
show-word-limit
v-model="formData.reason"
type="textarea"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="家庭成员经济收入" :span="3">
<el-form-item prop="familyList">
<el-table :data="formData.familyList" border max-height="500" size="mini" style="width: 100%">
<el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
<el-table-column prop="name" label="姓名">
<template slot-scope="{row,$index}">
<el-form-item label-width="0"
:prop="'familyList.'+$index+'.name'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="row.name" placeholder="请输入姓名" clearable></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="relation" label="年龄(岁)">
<template slot-scope="{row,$index}">
<el-form-item label-width="0"
:prop="'familyList.'+$index+'.age'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number v-model="row.age" placeholder="请输入年龄" :min="1"
:max="100" :step="1" style="width: 100%" clearable></el-input-number>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="relation" label="关系">
<template slot-scope="{row,$index}">
<el-form-item label-width="0"
:prop="'familyList.'+$index+'.relation'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="row.relation" placeholder="请输入关系" clearable></el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column prop="monthlyIncome" label="月收入(元)">
<template slot-scope="{row,$index}">
<el-form-item label-width="0"
:prop="'familyList.'+$index+'.monthlyIncome'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number v-model="row.monthlyIncome" placeholder="请输入月收入"
:min="1" :step="1" style="width: 100%" clearable></el-input-number>
</el-form-item>
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作" width="150px">
<template slot="header" slot-scope="scope">
<el-button @click="formData.familyList.push({})" icon="el-icon-plus" type="primary"
size="mini">添加
</el-button>
</template>
<template slot-scope="scope">
<el-button @click="formData.familyList.splice(scope.$index,1)"
size="mini"
icon="el-icon-delete"
type="danger"></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="3">
<el-form-item prop="files">
<file-upload :value.sync="formData.files"
upload_mode="drag"
:upload_number="10" upload_result_category="array"
complete_result></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="3">
<el-form-item prop="sign">
<pc-signature v-model="formData.sign"></pc-signature>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220" fixed="right">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">
查看
</el-button>
<el-button v-if="row.taskKey === 'startTask'" @click="onEdit(row)" size="mini" type="primary">
编辑
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">
撤回
</el-button>
<el-button @click="onDelete(row.id)" size="mini" type="danger">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
<el-row type="flex" justify="end" class="mt20">
<el-button type="primary" plain @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" @click="onFinishTask" v-else>提交1</el-button>
</el-row>
</el-card>
</div>
<script>
@@ -92,82 +235,265 @@ layout("/layouts/platform.html"){
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formData: {
id: GetQueryString("bizId"),
mode: '1'
},
tableColumns: [
{ prop: "loginName", label: "工号", sortable: true },
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "subsidyStandards", label: "困难类型", sortable: true },
{ prop: "applyTime", label: "申请时间", sortable: true },
{ prop: "taskName", label: "当前节点" },
{ prop: "instanceState", label: "流程状态" }
],
unions: [],
units: []
subsidyStandards: [
'患重大疾病(癌症)',
'本人家庭(仅指代本人及其配偶、子女共同组成的家庭)人均月收入低于1300元或本人配偶、子女患有重大疾病且自付医疗费用超过家庭年收入的80%',
'患精神类疾病',
'长期病休',
'其他特殊情况'
],
formRules: {
proxyUserName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
proxyLoginName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
sex: [{required: true, message: '必填', trigger: ['blur', 'change']}],
unitName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
unionName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
monthlyIncome: [{required: true, message: '必填', trigger: ['blur', 'change']}],
mobile: [{required: true, message: '必填', trigger: ['blur', 'change']}],
idCard: [{required: true, message: '必填', trigger: ['blur', 'change']}],
bankCardNum: [{required: true, message: '必填', trigger: ['blur', 'change']}],
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']}]
},
// 替他人申请相关
subsidizedList: []
}
},
methods: {
onApply() {
window.open("/flow/common/approval/form?defineKey=KNBF")
},
openView(row) {
window.open("/flow/common/approval/form?instanceId=" + (row.instanceId || "") + "&businessId=" + row.id + "&defineKey=KNBF")
},
onEdit(row) {
window.open(
"/flow/common/approval/form?taskId=" +
(row.taskId || "") +
"&instanceId=" +
(row.instanceId || "") +
"&businessId=" +
row.id +
"&defineKey=HYRH"
)
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
// 保存
onSave() {
this.$confirm("您确定保存吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((resp) => {
this.$message.success(resp.msg)
this.pageData()
})
})
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/difficultHelp/apply/onDelete", { id }).then((res) => {
this.$axios.post('/platform/difficultHelp/apply/save', {data: JSON.stringify(this.formData)}).then(res => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
this.$message.success("保存成功")
window.location.href = '/platform/difficultHelp/mine'
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
// 提交
onSubmit() {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/difficultHelp/apply/submit', {
data: JSON.stringify(this.formData)
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
window.location.href = '/platform/difficultHelp/mine'
}
})
})
},
onFinishTask() {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/difficultHelp/apply/submitAgain', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
window.location.href = '/platform/difficultHelp/mine'
}
})
})
},
// 查询受助人
queryRecipients(key) {
this.$axios.get("/platform/difficultHelp/apply/queryRecipients", {
key
}).then(res => {
if (res.code === 0) {
this.subsidizedList = res.data
}
})
},
findOne(id) {
this.$axios.post('/platform/difficultHelp/mine/findOne', { id }).then(res => {
if (res.code === 0) {
this.formData = res.data
}
})
},
async userChange() {
const user = this.subsidizedList.find(item => item.id === this.formData.userId)
if (user) {
this.$set(this.formData, 'userId', user.id)
this.$set(this.formData, 'userName', user.username)
this.$set(this.formData, 'loginName', user.loginname)
this.$set(this.formData, 'sex', user.sex)
this.$set(this.formData, 'unitId', user.unitId)
this.$set(this.formData, 'unitName', user.unitName)
this.$set(this.formData, 'unionId', user.unionId)
this.$set(this.formData, 'unionName', user.unionName)
this.$set(this.formData, 'birthday', user.birthday)
this.$set(this.formData, 'mobile', user.mobile)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
this.$set(this.formData, 'userId', null)
this.$set(this.formData, 'userName', null)
this.$set(this.formData, 'loginName', null)
this.$set(this.formData, 'sex', null)
this.$set(this.formData, 'unitId', null)
this.$set(this.formData, 'unitName', null)
this.$set(this.formData, 'unionId', null)
this.$set(this.formData, 'unionName', null)
this.$set(this.formData, 'birthday', null)
this.$set(this.formData, 'mobile', null)
}
},
// 申请模式
modeChange(val) {
const user = this.$store.state.user
if (val === "1") {
this.$set(this.formData, 'userId', user.id)
this.$set(this.formData, 'userName', user.username)
this.$set(this.formData, 'loginName', user.loginname)
this.$set(this.formData, 'proxyUserId', user.id)
this.$set(this.formData, 'proxyUserName', user.username)
this.$set(this.formData, 'proxyLoginName', user.loginname)
this.$set(this.formData, 'mode', "1")
this.$set(this.formData, 'sex', user.sex)
this.$set(this.formData, 'unitId', user.unit.id)
this.$set(this.formData, 'unitName', user.unit.name)
this.$set(this.formData, 'unionId', user.union.id)
this.$set(this.formData, 'unionName', user.union.name)
this.$set(this.formData, 'monthlyIncome', null)
this.$set(this.formData, 'birthday', user.birthday)
this.$set(this.formData, 'mobile', user.mobile)
this.$set(this.formData, 'homeAddress', user.homeAddress)
this.$set(this.formData, 'subsidyStandards', null)
this.$set(this.formData, 'reason', null)
this.$set(this.formData, 'remarks', null)
this.$set(this.formData, 'familyList', [])
this.$set(this.formData, 'files', [])
this.queryRecipients(user.loginname)
} else {
this.formData = {}
this.$set(this.formData, 'proxyUserId', user.id)
this.$set(this.formData, 'proxyUserName', user.username)
this.$set(this.formData, 'proxyLoginName', user.loginname)
this.$set(this.formData, 'mode', "2")
this.$set(this.formData, 'familyList', [])
this.$set(this.formData, 'files', [])
}
},
/**
* 检验身份证号
* @param idCard
* @returns {{status: number, msg: string}}
*/
isValidIdCard(idCard) {
// 校验18位身份证号
const format18 = /^(((([1][1-5])|([2][1-3])|([3][1-7])|([4][1-6])|([5][0-4])|([6][1-5])|([7][1])|([8][1-2]))\d{4})|(([9](([1][1-5])|([2][1-3])|([3][1-7])|([4][1-6])|([5][0-4])|([6][1-5])|([7][1])|([8][1-2])))\d{3}))(([1][9]\d{2})|([2]\d{3}))(([0][1-9])|([1][0-2]))(([0][1-9])|([1-2][0-9])|([3][0-1]))\d{3}[0-9xX]$/;
// 校验15位身份证号
const format15 = /^\d{15}$/;
// 校验外国人永久居留身份证号
const format15Foreign = /^[a-zA-Z]{3}[0-9]{4}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{2}$/;
// 校验格式
if (!(format18.test(idCard) || format15.test(idCard) || format15Foreign.test(idCard))) {
return { status: 0, msg: '身份证号码格式不正确' };
}
// 校验出生日期
let year, month, day;
if (idCard.length === 18) {
year = idCard.substr(6, 4);
month = idCard.substr(10, 2);
day = idCard.substr(12, 2);
} else if (idCard.length === 15) {
year = '19' + idCard.substr(6, 2);
month = idCard.substr(8, 2);
day = idCard.substr(10, 2);
} else {
return { status: 0, msg: '身份证号码格式不正确' };
}
const date = new Date(year, month - 1, day);
if (date.getFullYear() !== parseInt(year, 10) || date.getMonth() + 1 !== parseInt(month, 10) || date.getDate() !== parseInt(day, 10)) {
return { status: 0, msg: '身份证出生日期不正确' };
}
// 校验18位身份证号的校验码
if (idCard.length === 18) {
const coefficients = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
const checkCodeMap = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
let sum = 0;
for (let i = 0; i < 17; i++) {
sum += parseInt(idCard.charAt(i), 10) * coefficients[i];
}
const checkCode = checkCodeMap[sum % 11];
if (checkCode.toUpperCase() !== idCard.charAt(17).toUpperCase()) {
return { status: 0, msg: '身份证校验码不正确' };
}
}
return { status: 1, msg: '校验通过' };
},
/**
* 校验银行卡号
* @param bankCardNum
* @returns {{status: number, msg: string}}
*/
validateCard(bankCardNum) {
// 移除所有空格
bankCardNum = bankCardNum.replace(/\s+/g, '');
// 检查格式
const cardRegex = /^\d{13,19}$/;
if (!cardRegex.test(bankCardNum)) {
return { status: 0, msg: "银行卡号格式不正确,请输入13到19位数字。" };
}
// 检查Luhn算法
if (!/^\d+$/.test(bankCardNum)) {
return { status: 0, msg: "无效的卡号,请检查后再试。" };
}
let sum = 0;
let shouldDouble = false;
for (let i = bankCardNum.length - 1; i >= 0; i--) {
let digit = parseInt(bankCardNum.charAt(i));
if (shouldDouble) {
digit *= 2;
if (digit > 9) {
digit -= 9;
}
}
sum += digit;
shouldDouble = !shouldDouble;
}
if ((sum % 10) !== 0) {
return { status: 0, msg: "无效的卡号,请检查后再试。" };
}
return { status: 200, msg: "卡号有效。" };
}
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
if (this.bizId) {
this.findOne(this.bizId)
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
this.modeChange("1")
}
}
})
@@ -2,86 +2,113 @@
layout("/layouts/platform.html"){
#-->
<div id="app">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="受助人">
<el-input placeholder="请输入受助人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openApproval(row)" size="mini" type="primary">
审核
</el-button>
<el-button v-if="row.canRevoke" @click="openRevoke(row)" size="mini" type="danger">
撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="受助人">
<el-input placeholder="请输入受助人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
@@ -103,18 +130,68 @@ layout("/layouts/platform.html"){
{ prop: "instanceState", label: "流程状态"}
],
unions: [],
units: []
units: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row) {
window.open("/flow/common/approval/form?instanceId=" + (row.instanceId || "") + "&businessId=" + row.id + "&defineKey=KNBF")
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openApproval(row) {
window.open("/flow/common/approval/form?taskId=" + row.taskId + "&instanceId=" + row.instanceId + "&businessId=" + row.businessNo)
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
openRevoke(row) {
console.log(row)
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
@@ -0,0 +1,134 @@
const INFO = {
template: /*language=HTML*/ `
<div>
<div class="process-title">申请信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="3" border>
<el-descriptions-item label="填写人姓名">{{ viewData.proxyUserName }}</el-descriptions-item>
<el-descriptions-item label="填写人工号">{{ viewData.proxyLoginName }}</el-descriptions-item>
<el-descriptions-item label="申请模式">{{ viewData.mode == 1 ? '本人申请' : '替他人申请' }}
</el-descriptions-item>
<el-descriptions-item label="受助人">{{ viewData.userName + '(' + viewData.loginName + ')' }}
</el-descriptions-item>
<el-descriptions-item label="性别">{{ viewData.sex }}</el-descriptions-item>
<el-descriptions-item label="出生年月">{{ viewData.birthday }}</el-descriptions-item>
<el-descriptions-item label="所属工会">{{ viewData.unionName }}</el-descriptions-item>
<el-descriptions-item label="所属单位">{{ viewData.unitName }}</el-descriptions-item>
<el-descriptions-item label="职务职称">{{ viewData.officialCapacity }}</el-descriptions-item>
<el-descriptions-item label="手机号码">{{ viewData.mobile }}</el-descriptions-item>
<el-descriptions-item label="身份证号" :span="2">{{ viewData.idCard }}</el-descriptions-item>
<el-descriptions-item label="月收入">{{ viewData.monthlyIncome }}</el-descriptions-item>
<el-descriptions-item label="收款账户" :span="2">{{ viewData.bankCardNum }}</el-descriptions-item>
<el-descriptions-item label="困难类型" :span="3">{{ viewData.subsidyStandards }}</el-descriptions-item>
<el-descriptions-item label="申请原因" :span="3">{{ viewData.reason }}</el-descriptions-item>
<el-descriptions-item label="家庭成员经济收入" :span="3">
<el-table :data="viewData.familyList" border style="width: 92%">
<el-table-column label="序号" type="index" width="50"></el-table-column>
<el-table-column label="姓名" prop="name"></el-table-column>
<el-table-column prop="relation" label="年龄(岁)"></el-table-column>
<el-table-column prop="relation" label="关系"></el-table-column>
<el-table-column prop="monthlyIncome" label="月收入(元)"></el-table-column>
</el-table>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="3">
<file-preview v-if="viewData.files && viewData.files.length > 0" :files="viewData.files"
complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="3">
<el-image v-if="viewData.sign"
:src="viewData.sign"
class="signature-image"></el-image>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
<div class="task-panel 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>
<template v-if="task.taskFormData.tf_money">
<el-descriptions-item label="审批金额">{{ '¥' + task.taskFormData.tf_money }}</el-descriptions-item>
</template>
<el-descriptions-item label="办理意见" :span="3" v-if="!task.ext.isFirstTaskNode">{{
task.taskFormData.opinion }}
</el-descriptions-item>
</el-descriptions>
</div>
</template>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
store,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
viewData: {},
doneTasks: [],
row: null,
}
},
methods: {
// 打开
onOpen(row) {
this.row = row
this.info()
this.getDoneTasks()
},
// 获取申请信息
info() {
this.$axios.post("/platform/difficultHelp/mine/findOne", { id: this.row.id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 获取已办任务审批记录
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)
}
},
}
@@ -0,0 +1,179 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="受助人">
<el-input placeholder="请输入受助人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请记录">
<el-button size="small" type="primary" @click="onApply">帮扶申请</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<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.taskKey === 'startTask' || !row.instanceId" @click="onEdit(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.taskKey === 'startTask' || !row.instanceId" @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "工号", sortable: true },
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "subsidyStandards", label: "困难类型", sortable: true },
{ prop: "applyTime", label: "申请时间", sortable: true },
{ prop: "taskName", label: "当前节点" },
{ prop: "instanceState", label: "流程状态" }
],
unions: [],
units: []
}
},
components: {
"info": INFO
},
methods: {
onApply(){
window.location.href = '/platform/difficultHelp/apply'
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onEdit(row) {
window.location.href = '/platform/difficultHelp/apply?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/difficultHelp/mine/onDelete", { id }).then((res) => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,170 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="受助人">
<el-input placeholder="请输入受助人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="数据列表">
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(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>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
store,
data() {
return {
pageForm: {
year: this.$moment().format("YYYY")
},
tableColumns: [
{ prop: "loginName", label: "工号", sortable: true },
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "subsidyStandards", label: "困难类型", sortable: true },
{ prop: "applyTime", label: "申请时间", sortable: true },
{ prop: "taskName", label: "当前节点" },
{ prop: "instanceState", label: "流程状态" }
],
unions: [],
units: []
}
},
components: {
'info': INFO
},
methods: {
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onEdit(row) {
window.location.href = '/platform/difficultHelp/apply?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/difficultHelp/mine/onDelete", { id }).then((res) => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
} else {
this.units = await this.$businessTool.listUnit(this.$store.state.user.union.id)
}
},
},
async created() {
this.pageData()
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
this.unions = await this.$businessTool.listUnion()
} else {
this.unions = await this.$businessTool.listUnion(this.$store.state.user.union.id)
}
}
})
</script>
<!--#
}
#-->
@@ -2,86 +2,114 @@
layout("/layouts/platform.html"){
#-->
<div id="app">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="受助人">
<el-input placeholder="请输入受助人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openApproval(row)" size="mini" type="primary">
审核
</el-button>
<el-button v-if="row.canRevoke" @click="openRevoke(row)" size="mini" type="danger">
撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy">
</el-date-picker>
</search-item>
<search-item label="受助人">
<el-input placeholder="请输入受助人工号或姓名" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属工会">
<el-select @change="flushUnits" @clear="flushUnits" clearable
filterable
placeholder="所属工会"
style="width: 100%;"
v-model="pageForm.unionId">
<el-option :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="所属单位"
style="width: 100%;" v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="审批列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" header-align="center" label="序号"
type="index" width="60px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="100px" label-suffix="">
<el-form-item label="审核金额" prop="tf_money" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number placeholder="请输入金额" v-model="formData.tf_money" style="width: 60%"></el-input-number>
</el-form-item>
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
@@ -103,18 +131,71 @@ layout("/layouts/platform.html"){
{ prop: "instanceState", label: "流程状态"}
],
unions: [],
units: []
units: [],
// 审核相关
formData: {
tf_money: 0,
tf_opinion: "",
},
showApprovalForm: false
}
},
components: {
'info': INFO,
},
methods: {
openView(row) {
window.open("/flow/common/approval/form?instanceId=" + (row.instanceId || "") + "&businessId=" + row.id + "&defineKey=KNBF")
openView(row){
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openApproval(row) {
window.open("/flow/common/approval/form?taskId=" + row.taskId + "&instanceId=" + row.instanceId + "&businessId=" + row.businessNo)
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
openRevoke(row) {
console.log(row)
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async flushUnits(){
this.$set(this.pageForm, "unitId", null)
@@ -76,6 +76,7 @@
<script>
new Vue({
el: "#difficult_help_view",
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
businessId: GetQueryString("businessId"),
@@ -86,14 +87,18 @@
},
methods: {
info() {
this.$axios.post("/platform/difficultHelp/view/findOne", { id: this.businessId }).then((res) => {
this.$axios.post("/platform/difficultHelp/mine/findOne", { id: this.businessId }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", { instanceId: this.instance})
this.$axios.post("/flow/common/doneTasks", { instanceId: this.instanceId }).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
}
},
created() {
@@ -39,10 +39,24 @@ const basicForm = {
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="unionId" label="工会"
:rules="[{required:true,message:'请选择工会',trigger:['change','blur']}]">
<el-select clearable filterable multiple style="width: 100%"
v-model="formData.unionId"
placeholder="请选择活动线路"
@change="onUnionChange">
<el-option :value="item.id"
:key="item.id"
:label="item.name"
v-for="item in unionOptions"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="unionQuotaAllocationList" label="工会名额分配">
<el-table :data="formData.unionQuotaAllocationList" size="medium" max-height="500"
show-summary style="width: 100%">
<el-table :data="filteredUnionQuotaAllocationList" size="medium" height="70vh">
<el-table-column type="index" label="序号"></el-table-column>
<el-table-column label="工会名称" prop="unionName"></el-table-column>
<el-table-column label="会员人数" prop="memberNum"></el-table-column>
@@ -88,13 +102,27 @@ const basicForm = {
</el-row>
</el-card>
</div>
`,
mixins: [initTableMixins],
data() {
return {
lineList: [],
unionOptions: [],
allUnionQuotaAllocationList: [], // 保存所有工会名额分配数据
}
},
computed: {
// 计算属性:根据选择的工会过滤显示的名额分配列表
filteredUnionQuotaAllocationList() {
// 如果没有选择任何工会,显示所有工会
if (!this.formData.unionId || this.formData.unionId.length === 0) {
return this.allUnionQuotaAllocationList;
}
// 如果选择了工会,只显示选中的工会
return this.allUnionQuotaAllocationList.filter(item =>
this.formData.unionId.includes(item.unionId)
);
}
},
methods: {
@@ -108,32 +136,58 @@ const basicForm = {
listUnion() {
this.$axios.post("/platform/excellentRecuperation/activityList/listUnion").then(res => {
if (res.code === 0) {
this.formData.unionQuotaAllocationList = res.data
this.allUnionQuotaAllocationList = res.data; // 保存所有数据
// 如果formData.unionQuotaAllocationList存在,则更新对应数据
if (this.formData.unionQuotaAllocationList) {
this.updateUnionQuotaAllocationList();
}
}
})
},
// 更新名额分配列表数据
updateUnionQuotaAllocationList() {
this.allUnionQuotaAllocationList.forEach(item => {
const existingItem = this.formData.unionQuotaAllocationList.find(
formDataItem => formDataItem.unionId === item.unionId
);
if (existingItem) {
item.allocationNum = existingItem.allocationNum || 0;
}
});
},
// 工会选择变化时的处理
onUnionChange(selectedUnions) {
// 数据会自动根据计算属性更新显示
console.log("Selected unions:", selectedUnions);
},
clearUnionQuotaAllocation() {
this.$confirm("您确定要清空分配名额吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
this.listUnion()
// 清空所有名额分配
this.allUnionQuotaAllocationList.forEach(item => {
this.$set(item, 'allocationNum', 0);
});
})
},
onOpen(id) {
this.formData = {}
this.$refs.formRef.clearValidate()
this.getLineList()
this.listUnion(); // 始终加载所有工会数据
if (id) {
this.$axios.post("/platform/excellentRecuperation/activityList/findOne", {id}).then(res => {
if (res.code === 0) {
this.formData = res.data
this.$set(this.formData, "signUpTime", [res.data.signUpStartTime, res.data.signUpEndTIme])
// 更新名额分配数据
if (this.allUnionQuotaAllocationList.length > 0) {
this.updateUnionQuotaAllocationList();
}
}
})
} else {
this.listUnion()
}
},
onSubmit() {
@@ -147,6 +201,8 @@ const basicForm = {
const formData = clone(this.formData)
formData.signUpStartTime = formData.signUpTime[0]
formData.signUpEndTIme = formData.signUpTime[1]
// 传递过滤后的名额分配列表
formData.unionQuotaAllocationList = this.filteredUnionQuotaAllocationList;
const resp = await this.$axios.post("/platform/excellentRecuperation/activityList/onSubmit", {
data: JSON.stringify(formData)
})
@@ -158,6 +214,9 @@ const basicForm = {
}
})
}
},
created() {
//工会查询
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
}
}
@@ -2,63 +2,92 @@
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginname'">
<el-link @click="openView(row)" type="primary">{{row.loginname}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='sign'">
<el-image v-if="row.sign" :src="row.sign" style="height: 60px"></el-image>
<el-tag type="warning" v-else>暂无</el-tag>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openApproval(row)" size="mini" type="primary">
审核
</el-button>
<el-button v-if="row.canRevoke" @click="openRevoke(row)" size="mini" type="danger">
撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<guava ref="guava">
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginname'">
<el-link @click="openView(row)" type="primary">{{row.loginname}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='sign'">
<el-image v-if="row.sign" :src="row.sign" style="height: 60px"></el-image>
<el-tag type="warning" v-else>暂无</el-tag>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">
查看
</el-button>
<el-button v-if="row.taskState === 10" @click="openApproval(row)" size="mini" type="primary">
审核
</el-button>
<el-button v-if="row.canRevoke" @click="openRevoke(row)" size="mini" type="danger">
撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
<!--#include("../common/commonQuery.js"){}#-->
new Vue({
el: "#app",
@@ -81,33 +110,68 @@ layout("/layouts/platform.html"){
{ prop: "taskName", label: "当前节点" },
{ prop: "instanceState", label: "流程状态" }
],
// 审核相关
showApprovalForm: false,
formData: {
tf_opinion: ""
},
}
},
components: {
'info': INFO,
'common-query': COMMON_QUERY,
},
methods: {
openView(row) {
window.open("/flow/common/approval/form?instanceId=" + (row.instanceId || "") + "&businessId=" + row.id + "&defineKey=HYRH")
this.$refs.guava.edit(()=>{
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openApproval(row) {
window.open("/flow/common/approval/form?taskId=" + row.taskId + "&instanceId=" + row.instanceId + "&businessId=" + row.businessNo)
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
openRevoke(taskId) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
// this.$axios.post("/platform/member/apply/branchUnionAudit/revoke", { taskId }).then((res) => {
// if (res.code === 0) {
// this.$message.success(res.msg)
// this.doSearch()
// } else {
// this.$message.warning(res.msg)
// }
// })
})
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
openRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
search(pageForm){
if (pageForm) {
@@ -0,0 +1,138 @@
const INFO = {
template: /*language=HTML*/ `
<div>
<div class="process-title">
申请信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="3" border>
<el-descriptions-item label="工号">{{ viewData.loginname }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ viewData.username }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ viewData.sex }}</el-descriptions-item>
<el-descriptions-item label="民族">{{ viewData.nation }}</el-descriptions-item>
<el-descriptions-item label="出生日期">{{ $moment(viewData.birthday).format("YYYY年MM月DD日") }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{ viewData.political }}</el-descriptions-item>
<el-descriptions-item label="学历">{{ viewData.education }}</el-descriptions-item>
<el-descriptions-item label="学位">{{ viewData.academicDegree }}</el-descriptions-item>
<el-descriptions-item label="党政职务">{{ viewData.position }}</el-descriptions-item>
<el-descriptions-item label="工作单位">{{ viewData.unitName }}</el-descriptions-item>
<el-descriptions-item label="所属工会">{{ viewData.unionName }}</el-descriptions-item>
<el-descriptions-item label="所属校区">{{ viewData.campus }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ viewData.idCard }}</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.userState }}</el-descriptions-item>
<el-descriptions-item label="人员类型">{{ viewData.personType }}</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item label="家庭主要成员" :span="3">
<el-table v-if="viewData.families&&viewData.families.length"
:data="viewData.families" size="mini" border
:header-cell-style="{background:'#eff3f6'}"
style="width: 100%">
<el-table-column prop="relation" label="与本人关系" align="center" header-align="center">
</el-table-column>
<el-table-column prop="name" label="姓名" align="center" header-align="center">
</el-table-column>
<el-table-column prop="unit" label="单位" align="center" header-align="center">
</el-table-column>
<el-table-column prop="remark" label="备注" align="center" header-align="center">
</el-table-column>
</el-table>
<el-empty v-else :image-size="50" description="暂无家庭成员信息"></el-empty>
</el-descriptions-item>
<el-descriptions-item label="个人简况" :span="3">
<div v-if="viewData.personalData" class="text-left" v-html="viewData.personalData"></div>
<el-tag type="warning" v-else>暂无</el-tag>
</el-descriptions-item>
<el-descriptions-item label="签字信息" :span="3">
<el-image v-if="viewData.sign" :src="viewData.sign"
class="signature-image"></el-image>
<el-tag type="warning" v-else>暂无</el-tag>
</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>
<template v-if="task.taskFormData.tf_allocation_unionId">
<el-descriptions-item label="分配工会" :span="1.5">
{{ task.taskFormData.tf_allocation_unionName }}
</el-descriptions-item>
<el-descriptions-item label="分配前工会" :span="1.5">
{{ task.taskFormData.tf_self_unionName }}
</el-descriptions-item>
</template>
<el-descriptions-item label="办理意见" :span="3" v-if="!task.ext.isFirstTaskNode">{{
task.taskFormData.opinion }}
</el-descriptions-item>
</el-descriptions>
</div>
</template>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
store,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
transmitData: {},
viewData: {},
doneTasks: []
}
},
methods: {
onOpen(transmitData) {
this.transmitData = transmitData
this.info()
this.getDoneTasks()
},
info() {
this.$axios.post("/platform/member/apply/mine/findMemberApplyRecord", { id: this.transmitData.id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", { bizId: this.transmitData.id }).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
// 查看流程图
openChart(){
this.$refs.snakerChartRef.onOpenFull(this.transmitData.instanceProcessDefineId, this.transmitData.instanceId)
}
}
}
@@ -2,154 +2,154 @@
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请列表">
<el-button size="small" type="primary" @click="$store.dispatch('pjaxRoute', '/platform/member/apply/submit')">申请入会</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginname'">
<el-link @click="openView(row)" type="primary">{{row.loginname}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='sign'">
<el-image v-if="row.sign" :src="row.sign"
class="signature-image"></el-image>
<el-tag type="warning" v-else>暂无</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220">
<template slot-scope="{row}">
<el-button @click="openChangeView(row)" size="mini" type="primary">查看</el-button>
<el-button
v-if="[10,40,70].includes(row.processInstanceNodeCode)"
size="mini"
type="primary"
@click="$store.dispatch('pjaxRoute', '/platform/member/apply/submit?id='+row.id)"
>
编辑
</el-button>
<el-button
v-if="[20].includes(row.processInstanceNodeCode) && !row.nextTaskIsComplete"
size="mini"
type="danger"
@click="openRevoke(row)"
>
撤销
</el-button>
<el-button v-if="[10].includes(row.processInstanceNodeCode)" size="mini" type="danger" @click="doDelete(row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #view>
<member-apply-audit-info ref="memberApplyAuditInfoRef"></member-apply-audit-info>
</template>
</guava>
<guava ref="guava">
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请列表">
<el-button size="small" type="primary" @click="onApply">申请入会</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginname'">
<el-link @click="openView(row)" type="primary">{{row.loginname}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='sign'">
<el-image v-if="row.sign" :src="row.sign" style="height: 60px"></el-image>
<el-tag type="warning" v-else>暂无</el-tag>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220" fixed="right">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">
查看
</el-button>
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId"
@click="onEdit(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.taskKey === 'startTask' || !row.instanceId"
@click="onDelete(row.id)" size="mini" type="danger">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<info ref="info"></info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
<!--#include("../common/commonQuery.js"){}#-->
<!--#include("../common/memberApplyAuditInfo.js"){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
data() {
return {
tableColumns: [
{ prop: "loginname", label: "工号", sortable: true },
{ prop: "username", label: "姓名", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "preparedBy", label: "聘用方式", sortable: true },
{ prop: "personType", label: "人员类型", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "sign", label: "签字" },
{ prop: "processInstanceNodeName", label: "当前节点", sortable: true }
],
unions: [],
units: []
}
},
components: {
'common-query': COMMON_QUERY,
'member-apply-audit-info': MEMBER_APPLY_AUDIT_INFO
},
methods: {
openView(row) {
this.$refs.guava.view(() => {
this.$refs.memberApplyAuditInfoRef.onOpen(row.userId)
})
},
openRevoke(row) {
this.$confirm("您确定要撤销申请吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/member/apply/mine/revokeApply", { id: row.id }).then((resp) => {
this.$message.success(resp.msg)
this.doSearch()
})
})
},
doDelete(row) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/member/apply/mine/delete", { id: row.id }).then((resp) => {
this.$message.success(resp.msg)
this.doSearch()
})
})
},
openChangeView(row) {
this.$refs.guava.public(() => {
this.$refs.memberAuditChangeInfoRef.onOpen({ recordId: row.id, userId: row.userId })
})
},
search(pageForm){
if (pageForm) {
this.pageForm = {...this.pageForm, ...pageForm}
}
this.doSearch()
},
},
created() {
this.pageData()
}
})
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
data() {
return {
tableColumns: [
{ prop: "loginName", label: "工号", sortable: true },
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "preparedBy", label: "聘用方式", sortable: true },
{ prop: "personType", label: "人员类型", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "sign", label: "签字" },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
unions: [],
units: []
}
},
components: {
'info': INFO,
'common-query': COMMON_QUERY,
},
methods: {
onApply() {
window.location.href = '/platform/member/apply/submit'
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.info.onOpen(row)
})
},
onEdit(row) {
window.location.href = '/platform/member/apply/submit?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((resp) => {
this.$message.success(resp.msg)
this.pageData()
})
})
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/member/apply/mine/onDelete", { id }).then((res) => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
}
})
})
},
search(pageForm){
if (pageForm) {
this.pageForm = {...this.pageForm, ...pageForm}
}
this.doSearch()
},
},
created() {
this.pageData()
}
})
</script>
<!--#
@@ -2,64 +2,110 @@
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginname'">
<el-link @click="openView(row)" type="primary">{{row.loginname}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='sign'">
<el-image v-if="row.sign" :src="row.sign" style="height: 60px"></el-image>
<el-tag type="warning" v-else>暂无</el-tag>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openApproval(row)" size="mini" type="primary">
审核
</el-button>
<el-button v-if="row.canRevoke" @click="openRevoke(row)" size="mini" type="danger">
撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<guava ref="guava">
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请列表">
<el-radio-group @change="doSearch" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginname'">
<el-link @click="openView(row)" type="primary">{{row.loginname}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='sign'">
<el-image v-if="row.sign" :src="row.sign" style="height: 60px"></el-image>
<el-tag type="warning" v-else>暂无</el-tag>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openApproval(row)" size="mini" type="primary">
审核
</el-button>
<el-button v-if="row.canRevoke" @click="openRevoke(row)" size="mini" type="danger">
撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="130px" label-suffix="">
<el-row :gutter="20" v-if="formData.origin === 'HMC'">
<el-col :span="12">
<el-form-item label="分配工会关系" prop="tf_allocation_unionId"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select clearable filterable placeholder="请选择工会" style="width: 100%;"
@change="assignmentUnionName"
v-model="formData.tf_allocation_unionId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="当前所在工会" prop="tf_self_unionName">
<el-input v-model="formData.tf_self_unionName" readonly></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
<!--#include("../common/commonQuery.js"){}#-->
new Vue({
el: "#app",
@@ -82,17 +128,59 @@ layout("/layouts/platform.html"){
{ prop: "taskName", label: "当前节点" },
{ prop: "instanceState", label: "流程状态" }
],
// 审核相关
showApprovalForm: false,
formData: {
tf_opinion: ""
},
unions: [],
}
},
components: {
'info': INFO,
'common-query': COMMON_QUERY,
},
methods: {
openView(row) {
window.open("/flow/common/approval/form?instanceId=" + (row.instanceId || "") + "&businessId=" + row.id + "&defineKey=HYRH")
this.$refs.guava.edit(()=>{
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openApproval(row) {
window.open("/flow/common/approval/form?taskId=" + row.taskId + "&instanceId=" + row.instanceId + "&businessId=" + row.businessNo)
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
origin: row.origin,
processTaskId: row.taskId,
taskName: row.curTaskName
}
if (row.origin === "HMC") {
this.$set(this.formData, "tf_self_unionName", this.$store.state.user.union.name)
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
openRevoke(taskId) {
this.$confirm("您确定要撤回吗?", "提示", {
@@ -100,7 +188,7 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/platform/member/apply/schoolUnionAudit/revoke", { taskId }).then((res) => {
this.$axios.post("/flow/common/revokeTask", { taskId }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
@@ -114,9 +202,17 @@ layout("/layouts/platform.html"){
}
this.doSearch()
},
// 分配工会名称
assignmentUnionName(val) {
const union = this.unions.find(item => item.id === val)
this.$set(this.formData, "tf_allocation_unionName", union.name)
},
},
created() {
this.pageData()
this.$businessTool.listUnion().then(data => {
this.unions = data
})
}
})
</script>
@@ -1,466 +0,0 @@
<div id="member_apply">
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix="" class="flow-task-form">
<el-descriptions :column="3" border>
<el-descriptions-item label="工号">
<el-form-item prop="loginname">
<el-input v-model="formData.loginname" readonly size="small"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="姓名">
<el-form-item prop="username">
<el-input v-model="formData.username" readonly size="small"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="性别">
<el-form-item prop="sex">
<el-radio-group v-model="formData.sex" size="small">
<el-radio border label="男性"></el-radio>
<el-radio border label="女性"></el-radio>
</el-radio-group>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="民族">
<el-form-item prop="nation">
<dict-select style="width: 100%" placeholder="请选择民族" v-model="formData.nation"
code="USER_NATION"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="出生日期">
<el-form-item prop="birthday">
<el-date-picker v-model="formData.birthday" type="date"
placeholder="请选择出生日期"
value-format="yyyy-MM-dd"
style="width: 100%"></el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="政治面貌">
<el-form-item prop="political">
<dict-select style="width: 100%" placeholder="请选择政治面貌" v-model="formData.political"
code="POLITICAL_STATUS"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="学历">
<el-form-item prop="education">
<dict-select style="width: 100%" placeholder="请选择学历" v-model="formData.education"
code="USER_EDUCATION"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="学位">
<el-form-item prop="academicDegree">
<dict-select style="width: 100%" placeholder="请选择学位" v-model="formData.academicDegree"
code="USER_ACADEMIC_DEGREE"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="党政职务">
<el-form-item prop="position">
<el-input v-model="formData.position" placeholder="请输入党政职务"
maxlength="50"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="工作单位">
<el-form-item prop="unitId">
<el-select clearable filterable placeholder="请选择工作单位" style="width: 100%"
disabled @change="getUnionName(formData.unitId)"
v-model="formData.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="所属工会">
<el-form-item prop="unionName">
<el-input v-model="formData.unionName" disabled placeholder="请输入所属工会"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="所属校区">
<el-form-item prop="campus">
<dict-select style="width: 100%" placeholder="请选择所属校区" v-model="formData.campus"
code="USER_CAMPUS"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="在职状态">
<el-form-item prop="userState">
<dict-select v-model="formData.userState" code="USER_STATE"
disabled style="width: 100%"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="人员类型">
<el-form-item prop="personType">
<dict-select v-model="formData.personType" code="PERSON_TYPE"
disabled style="width: 100%"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item label="身份证号码">
<el-form-item prop="idCard">
<el-input v-model="formData.idCard" disabled placeholder="请输入身份证号码" maxlength="18"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="联系电话">
<el-form-item prop="mobile">
<el-input v-model="formData.mobile" disabled placeholder="请输入联系电话" maxlength="32"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="电子邮箱">
<el-form-item prop="email">
<el-input v-model="formData.email" placeholder="请输入电子邮箱" maxlength="50"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="家庭主要成员" :span="3">
<el-form-item prop="families">
<el-table :data="formData.families" border size="small">
<el-table-column label="关系" prop="relation">
<template slot-scope="{row}">
<el-input v-model="row.relation" maxlength="50"
placeholder="请输入与本人关系"></el-input>
</template>
</el-table-column>
<el-table-column label="姓名" prop="name">
<template slot-scope="{row}">
<el-input v-model="row.name" maxlength="50" placeholder="请输入姓名"></el-input>
</template>
</el-table-column>
<el-table-column label="工作单位" prop="unit">
<template slot-scope="{row}">
<el-input v-model="row.unit" maxlength="100"
placeholder="请输入工作单位"></el-input>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark">
<template slot-scope="{row}">
<el-input v-model="row.remark" maxlength="100" placeholder="请输入备注"></el-input>
</template>
</el-table-column>
<el-table-column width="100px">
<template slot="header" slot-scope="scope">
<el-button type="primary" size="mini"
@click="formData.families.push({})">添加
</el-button>
</template>
<template slot-scope="scope">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="formData.families.length===0"
@click="formData.families.splice(scope.$index,1)"
></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="个人简况" :span="3">
<el-form-item prop="personalData">
<text-editor v-model="formData.personalData"></text-editor>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="入会意愿" :span="3">
<el-form-item prop="isVoluntary">
<el-checkbox
size="medium"
style="width: 95%; color: #F56C6C; display: flex; align-items: center;"
v-model="formData.isVoluntary">
<div>
<span style="flex: 1; word-wrap: break-word; word-break: break-all; white-space: normal;">
我自愿申请加入学校工会,并委托学校按规定代为扣缴工会会员会费。
</span>
</div>
<div>
<span style="flex: 1; word-wrap: break-word; word-break: break-all; white-space: normal;">
我将严格遵守工会章程,认真执行工会决议,积极参与工会活动,主动融入“学校健康幸福家”建设,为营造温暖、和谐、奋进的校园氛围贡献力量,以实际行动助力学校各项事业发展。
</span>
</div>
</el-checkbox>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="3">
<el-form-item prop="sign">
<pc-signature v-model="formData.sign"></pc-signature>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @save-draft="handleSaveDraft"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#member_apply",
store,
data() {
return {
businessId: GetQueryString("businessId"),
instanceId: GetQueryString("instanceId"),
units: [],
formData: {
families: []
},
formRules: {
username: [{required: false, message: "必填", trigger: ["change", "blur"]}],
sex: [{required: false, message: "必填", trigger: ["change", "blur"]}],
isVoluntary: [{required: true, message: "必填", trigger: ["change", "blur"]}],
sign: [{required: true, message: "必填", trigger: ["change", "blur"]}],
email: [
{
validator: (rule, value, callback) => {
if (!value) {
callback();
} else if (/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value)) {
callback();
} else {
callback(new Error("邮箱格式错误"));
}
},
trigger: ["change", "blur"]
}
],
idCard: [
{
validator: (rule, value, callback) => {
if (!value) {
// 如果值为空,直接通过校验
callback();
} else if (/^[1-9]\d{5}(18|19|20)?\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}(\d|[Xx])$/.test(value)) {
// 18位身份证号码格式正确
callback();
} else if (/^[1-9]\d{7}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 15位身份证号码格式正确
callback();
} else if (/^[1-9]\d{5}(18|19|20)?\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 外国人身份证号码格式正确(18位)
callback();
} else if (/^[1-9]\d{7}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 外国人身份证号码格式正确(15位)
callback();
} else {
// 格式错误,返回错误信息
callback(new Error("身份证号码格式错误"));
}
},
trigger: ["change", "blur"]
}
],
mobile: [
{
validator: (rule, value, callback) => {
if (!value) {
// 如果值为空,直接通过校验
callback();
} else if (/^[1][345789][0-9]{9}$/.test(value)) {
// 手机号格式正确
callback();
} else if (/^\d+-\d+$/.test(value) && value.length <= 16) {
// 座机号格式正确
callback();
} else {
// 格式错误,返回错误信息
callback(new Error(value.includes('-') ? '座机号码格式错误' : '手机号码格式错误'));
}
},
trigger: ["change", "blur"]
}
]
},
}
},
methods: {
// 提交
handleTaskAction(val) {
this.$refs.formRef.validate((valid) => {
if (valid) {
if (!this.instanceId) {
this.handleApply(val)
} else {
this.handleReApply(val)
}
}
})
},
// 提交申请
handleApply(val) {
this.$confirm("您确定要提交吗?", "提示", { type: "warning" })
.then(() => {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios
.post("/flow/common/startInstanceAndExecute", {
...val,
bizData: JSON.stringify(this.formData)
})
.then((res) => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete"
})
}
})
}
})
})
},
// 重新提交申请
handleReApply(val) {
this.$confirm("您确定要提交吗?", "提示", { type: "warning" })
.then(() => {
this.$axios
.post("/flow/common/executeTask", {
data: JSON.stringify({
processTaskId: val.taskId,
processInstanceId: val.instanceId,
submitType: val.submitType,
f_data: JSON.stringify(this.formData)
})
})
.then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
window.GlobalBroadcastChannel.postMessage({
type: "task-complete"
})
}
})
})
},
// 保存
handleSaveDraft(val) {
this.$confirm("您确定要保存吗?", "提示", { type: "warning" })
.then(() => {
this.$axios
.post("/flow/common/startInstance", {
...val,
bizData: JSON.stringify(this.formData)
})
.then((res) => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.parent.postMessage(
{
type: "task-complete"
},
"*"
)
}
})
})
},
// 取消
handleCancel() {
},
async validateApply() {
if (this.formData.id) {
return
}
// const resp = await $.post('/platform/member/apply/submit/validateApply')
// if (resp.code === 0 && resp.data > 0) {
// this.$confirm("您有其他入会流程正在进行中,请勿重复申请,如需查看详情,可前往我的申请界面,是否前往?", "提示", { type: "warning" })
// .then(() => {
// this.member = true
// this.$store.dispatch("pjaxRoute", "/platform/member/apply/mine")
// })
// .catch(() => {
// this.member = true
// })
// }
},
async init() {
let user
const resp = await $.post('/platform/member/apply/submit/getSelfUserInfo')
if (resp.code === 0) {
if (!resp.data) {
user = this.$store.state.user
} else {
user = resp.data
}
} else {
user = this.$store.state.user
}
this.member = user.member
if (this.id) {
this.$axios.post("/platform/member/apply/submit/findApplyById", { id: this.id }).then((res) => {
if (res.code === 0) {
this.formData = res.data
}
})
} else {
const {
id,
username,
loginname,
sex,
nation,
birthday,
political,
education,
academicDegree,
position,
unitId,
unitName,
unit,
unionId,
unionName,
union,
campus,
userState,
personType,
idCard,
mobile,
email,
families,
personalData
} = user
this.$set(this.formData, "userId", id)
this.$set(this.formData, "username", username)
this.$set(this.formData, "loginname", loginname)
this.$set(this.formData, "birthday", birthday)
this.$set(this.formData, "sex", sex)
this.$set(this.formData, "idCard", idCard)
this.$set(this.formData, "nation", nation)
this.$set(this.formData, "political", political)
this.$set(this.formData, "position", position)
this.$set(this.formData, "education", education)
this.$set(this.formData, "academicDegree", academicDegree)
this.$set(this.formData, "campus", campus)
this.$set(this.formData, "userState", userState)
this.$set(this.formData, "personType", personType)
this.$set(this.formData, "unitName", unit ? unit.name : unitName)
this.$set(this.formData, "unitId", unit ? unit.id : unitId)
this.$set(this.formData, "unionName", union ? union.name : unionName)
this.$set(this.formData, "unionId", union ? union.id : unionId)
this.$set(this.formData, "mobile", mobile)
this.$set(this.formData, "email", email)
this.$set(this.formData, "families", families ? families : [])
this.$set(this.formData, "personalData", personalData)
}
},
},
async created() {
this.init()
this.units = await this.$businessTool.listUnit()
await this.validateApply()
}
})
</script>
@@ -3,147 +3,421 @@ layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="申请列表">
<el-button size="small" type="primary" @click="onApply">申请入会</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column
:index="indexMethod"
align="center"
header-align="center"
label="序号"
type="index"
width="80px"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template scope="{row}" v-if="column.prop=='loginname'">
<el-link @click="openView(row)" type="primary">{{row.loginname}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='sign'">
<el-image v-if="row.sign" :src="row.sign" style="height: 60px"></el-image>
<el-tag type="warning" v-else>暂无</el-tag>
</template>
<snaker-start slot="header" label="入会申请" define_key="HYRH"></snaker-start>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix="" class="flow-task-form">
<el-descriptions :column="3" border>
<el-descriptions-item label="工号">
<el-form-item prop="loginname">
<el-input v-model="formData.loginname" readonly size="small"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="姓名">
<el-form-item prop="username">
<el-input v-model="formData.username" readonly size="small"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="性别">
<el-form-item prop="sex">
<el-radio-group v-model="formData.sex" size="small">
<el-radio border label="男性"></el-radio>
<el-radio border label="女性"></el-radio>
</el-radio-group>
</el-form-item>
</el-descriptions-item>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220" fixed="right">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">
查看
</el-button>
<el-button v-if="row.taskKey === 'startTask'" @click="onEdit(row)" size="mini" type="primary">
编辑
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">
撤回
</el-button>
<el-button @click="onDelete(row.id)" size="mini" type="danger">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
<el-descriptions-item label="民族">
<el-form-item prop="nation">
<dict-select style="width: 100%" placeholder="请选择民族" v-model="formData.nation"
code="USER_NATION"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="出生日期">
<el-form-item prop="birthday">
<el-date-picker v-model="formData.birthday" type="date"
placeholder="请选择出生日期"
value-format="yyyy-MM-dd"
style="width: 100%"></el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="政治面貌">
<el-form-item prop="political">
<dict-select style="width: 100%" placeholder="请选择政治面貌" v-model="formData.political"
code="USER_POLITICAL"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="学历">
<el-form-item prop="education">
<dict-select style="width: 100%" placeholder="请选择学历" v-model="formData.education"
code="USER_EDUCATION"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="学位">
<el-form-item prop="academicDegree">
<dict-select style="width: 100%" placeholder="请选择学位" v-model="formData.academicDegree"
code="USER_ACADEMIC_DEGREE"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="党政职务">
<el-form-item prop="position">
<el-input v-model="formData.position" placeholder="请输入党政职务"
maxlength="50"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="工作单位">
<el-form-item prop="unitId">
<el-select clearable filterable placeholder="请选择工作单位" style="width: 100%"
disabled @change="getUnionName(formData.unitId)"
v-model="formData.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="所属工会">
<el-form-item prop="unionName">
<el-input v-model="formData.unionName" disabled placeholder="请输入所属工会"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="所属校区">
<el-form-item prop="campus">
<dict-select style="width: 100%" placeholder="请选择所属校区" v-model="formData.campus"
code="USER_CAMPUS"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="在职状态">
<el-form-item prop="userState">
<dict-select v-model="formData.userState" code="USER_STATE"
disabled style="width: 100%"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="人员类型">
<el-form-item prop="personType">
<dict-select v-model="formData.personType" code="PERSON_TYPE"
disabled style="width: 100%"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item label="身份证号码">
<el-form-item prop="idCard">
<el-input v-model="formData.idCard" disabled placeholder="请输入身份证号码" maxlength="18"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="联系电话">
<el-form-item prop="mobile">
<el-input v-model="formData.mobile" disabled placeholder="请输入联系电话" maxlength="32"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="电子邮箱">
<el-form-item prop="email">
<el-input v-model="formData.email" placeholder="请输入电子邮箱" maxlength="50"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="家庭主要成员" :span="3">
<el-form-item prop="families">
<el-table :data="formData.families" border size="small">
<el-table-column label="关系" prop="relation">
<template slot-scope="{row}">
<el-input v-model="row.relation" maxlength="50"
placeholder="请输入与本人关系"></el-input>
</template>
</el-table-column>
<el-table-column label="姓名" prop="name">
<template slot-scope="{row}">
<el-input v-model="row.name" maxlength="50" placeholder="请输入姓名"></el-input>
</template>
</el-table-column>
<el-table-column label="工作单位" prop="unit">
<template slot-scope="{row}">
<el-input v-model="row.unit" maxlength="100"
placeholder="请输入工作单位"></el-input>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark">
<template slot-scope="{row}">
<el-input v-model="row.remark" maxlength="100" placeholder="请输入备注"></el-input>
</template>
</el-table-column>
<el-table-column width="100px">
<template slot="header" slot-scope="scope">
<el-button type="primary" size="mini"
@click="formData.families.push({})">添加
</el-button>
</template>
<template slot-scope="scope">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="formData.families.length===0"
@click="formData.families.splice(scope.$index,1)"
></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="个人简况" :span="3">
<el-form-item prop="personalData">
<text-editor v-model="formData.personalData"></text-editor>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="入会意愿" :span="3">
<el-form-item prop="isVoluntary">
<el-checkbox
size="medium"
style="width: 95%; color: #F56C6C; display: flex; align-items: center;"
v-model="formData.isVoluntary">
<div>
<span style="flex: 1; word-wrap: break-word; word-break: break-all; white-space: normal;">
我自愿申请加入学校工会,并委托学校按规定代为扣缴工会会员会费。
</span>
</div>
<div>
<span style="flex: 1; word-wrap: break-word; word-break: break-all; white-space: normal;">
我将严格遵守工会章程,认真执行工会决议,积极参与工会活动,主动融入“学校健康幸福家”建设,为营造温暖、和谐、奋进的校园氛围贡献力量,以实际行动助力学校各项事业发展。
</span>
</div>
</el-checkbox>
</el-form-item>
</el-descriptions-item>
<!-- <el-descriptions-item label="签字" :span="3">-->
<!-- <el-form-item prop="sign">-->
<!-- <pc-signature v-model="formData.sign"></pc-signature>-->
<!-- </el-form-item>-->
<!-- </el-descriptions-item>-->
</el-descriptions>
</el-form>
<el-row type="flex" justify="end" class="mt20">
<el-button type="primary" plain @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" @click="onFinishTask" v-else>提交1</el-button>
</el-row>
</el-card>
</div>
<script>
<!--#include("../common/commonQuery.js"){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
data() {
return {
tableColumns: [
{ prop: "loginName", label: "工号", sortable: true },
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "preparedBy", label: "聘用方式", sortable: true },
{ prop: "personType", label: "人员类型", sortable: true },
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "sign", label: "签字" },
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
unions: [],
units: []
id: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
units: [],
formData: {
families: []
},
formRules: {
username: [{required: false, message: "必填", trigger: ["change", "blur"]}],
sex: [{required: false, message: "必填", trigger: ["change", "blur"]}],
isVoluntary: [{required: true, message: "必填", trigger: ["change", "blur"]}],
sign: [{required: true, message: "必填", trigger: ["change", "blur"]}],
email: [
{
validator: (rule, value, callback) => {
if (!value) {
callback();
} else if (/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value)) {
callback();
} else {
callback(new Error("邮箱格式错误"));
}
},
trigger: ["change", "blur"]
}
],
idCard: [
{
validator: (rule, value, callback) => {
if (!value) {
// 如果值为空,直接通过校验
callback();
} else if (/^[1-9]\d{5}(18|19|20)?\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}(\d|[Xx])$/.test(value)) {
// 18位身份证号码格式正确
callback();
} else if (/^[1-9]\d{7}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 15位身份证号码格式正确
callback();
} else if (/^[1-9]\d{5}(18|19|20)?\d{2}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 外国人身份证号码格式正确(18位)
callback();
} else if (/^[1-9]\d{7}((0[1-9])|(10|11|12))(([0|1|2][0-9])|10|20|30|31)\d{3}$/.test(value)) {
// 外国人身份证号码格式正确(15位)
callback();
} else {
// 格式错误,返回错误信息
callback(new Error("身份证号码格式错误"));
}
},
trigger: ["change", "blur"]
}
],
mobile: [
{
validator: (rule, value, callback) => {
if (!value) {
// 如果值为空,直接通过校验
callback();
} else if (/^[1][345789][0-9]{9}$/.test(value)) {
// 手机号格式正确
callback();
} else if (/^\d+-\d+$/.test(value) && value.length <= 16) {
// 座机号格式正确
callback();
} else {
// 格式错误,返回错误信息
callback(new Error(value.includes('-') ? '座机号码格式错误' : '手机号码格式错误'));
}
},
trigger: ["change", "blur"]
}
]
},
}
},
components: {
'common-query': COMMON_QUERY,
},
methods: {
onApply() {
window.open("/flow/common/approval/form?defineKey=HYRH")
},
openView(row) {
window.open("/flow/common/approval/form?instanceId=" + (row.instanceId || "") + "&businessId=" + row.id + "&defineKey=HYRH")
},
onEdit(row) {
window.open(
"/flow/common/approval/form?taskId=" +
(row.taskId || "") +
"&instanceId=" +
(row.instanceId || "") +
"&businessId=" +
row.id +
"&defineKey=HYRH"
)
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
onSave() {
this.$confirm("您确定保存吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((resp) => {
this.$message.success(resp.msg)
this.pageData()
})
})
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/member/apply/submit/onDelete", { id }).then((res) => {
this.$axios.post('/platform/member/apply/submit/save', {data: JSON.stringify(this.formData)}).then(res => {
if (res.code === 0) {
this.doSearch()
this.$message.success(res.msg)
window.location.href = '/platform/member/apply/mine'
}
})
})
},
search(pageForm){
if (pageForm) {
this.pageForm = {...this.pageForm, ...pageForm}
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/member/apply/submit/submit', {
data: JSON.stringify(this.formData)
}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
window.location.href = '/platform/member/apply/mine'
}
})
})
}
})
},
onFinishTask() {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/member/apply/submit/submitAgain', {
data: JSON.stringify(this.formData),
taskId: this.taskId,
}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
window.location.href = '/platform/member/apply/mine'
}
})
})
},
async init() {
let user
const resp = await $.post('/platform/member/apply/submit/getSelfUserInfo')
if (resp.code === 0) {
if (!resp.data) {
user = this.$store.state.user
} else {
user = resp.data
}
} else {
user = this.$store.state.user
}
this.member = user.member
if (this.id) {
const res = await this.$axios.post("/platform/member/apply/submit/findApplyById", { id: this.id })
debugger
if (res.code === 0) {
this.formData = res.data
}
} else {
const {
id,
username,
loginname,
sex,
nation,
birthday,
political,
education,
academicDegree,
position,
unitId,
unitName,
unit,
unionId,
unionName,
union,
campus,
userState,
personType,
idCard,
mobile,
email,
families,
personalData
} = user
this.$set(this.formData, "userId", id)
this.$set(this.formData, "username", username)
this.$set(this.formData, "loginname", loginname)
this.$set(this.formData, "birthday", birthday)
this.$set(this.formData, "sex", sex)
this.$set(this.formData, "idCard", idCard)
this.$set(this.formData, "nation", nation)
this.$set(this.formData, "political", political)
this.$set(this.formData, "position", position)
this.$set(this.formData, "education", education)
this.$set(this.formData, "academicDegree", academicDegree)
this.$set(this.formData, "campus", campus)
this.$set(this.formData, "userState", userState)
this.$set(this.formData, "personType", personType)
this.$set(this.formData, "unitName", unit ? unit.name : unitName)
this.$set(this.formData, "unitId", unit ? unit.id : unitId)
this.$set(this.formData, "unionName", union ? union.name : unionName)
this.$set(this.formData, "unionId", union ? union.id : unionId)
this.$set(this.formData, "mobile", mobile)
this.$set(this.formData, "email", email)
this.$set(this.formData, "families", families ? families : [])
this.$set(this.formData, "personalData", personalData)
}
this.doSearch()
},
},
created() {
this.pageData()
this.init()
this.$businessTool.listUnit().then((data) => {
this.units = data
})
}
})
</script>
@@ -100,7 +100,7 @@
},
methods: {
info() {
this.$axios.post("/platform/member/apply/view/findMemberApplyRecord", { id: this.businessId }).then((res) => {
this.$axios.post("/platform/member/apply/mine/findMemberApplyRecord", { id: this.businessId }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
@@ -4,90 +4,80 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="审核列表">
<el-radio-group @change="search" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">审核</el-radio-button>
<el-radio-button label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index" width="80px"></el-table-column>
<el-table-column :label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns">
<template scope="{row}" v-if="column.prop=='loginname'">
<el-link @click="openUserView(row)" type="primary">{{row.loginname}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='changeTypes'">
<el-card shadow="never">
<common-query ref="commonQueryRef" @search="search"></common-query>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="审核列表">
<el-radio-group @change="search" class="mr5" size="small" v-model="pageForm.audit">
<el-radio-button label="true">已审核</el-radio-button>
<el-radio-button label="false">审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index" width="80px"></el-table-column>
<el-table-column :label="column.label"
:prop="column.prop"
:sortable="column.sortable"
:width="column.width"
header-align="center"
min-width="100px"
show-overflow-tooltip
v-for="column in tableColumns">
<template scope="{row}" v-if="column.prop=='changeTypes'">
<span style="color: #0e78c5;cursor: pointer" @click="openView(row)">
{{getChangeTypes(row.changeTypes)}}
</span>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openApproval(row)" size="mini" type="primary">
审核
</el-button>
<el-button
v-if="row.processInstanceTaskStatus==='COMPLETE' && !row.nextTaskIsComplete"
@click="openRevoke(row.processInstanceTaskId)"
size="mini"
type="danger">
撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template scope="{row}" v-else-if="column.prop=='instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
<!-- <template #view>-->
<!-- <member-info ref="memberInfoRef"></member-info>-->
<!-- </template>-->
<!-- -->
<!-- <template #public>-->
<!-- <member-change-audit-info ref="memberChangeAuditInfoRef"></member-change-audit-info>-->
<!-- <div v-if="showApprovalForm">-->
<!-- <el-form :model="formData" ref="approvalFormRef" label-position="left" label-width="80px">-->
<!-- <el-form-item label="审核意见" prop="approvalOpinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">-->
<!-- <user-opinion-textarea v-model="formData.approvalOpinion"></user-opinion-textarea>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="电子签名" prop="approvalSignature" :rules="[{required:false,message:'必填',trigger:['change','blur']}]">-->
<!-- <pc-signature v-model="formData.approvalSignature"></pc-signature>-->
<!-- </el-form-item>-->
<!-- </el-form>-->
<!-- <el-row type="flex" justify="end">-->
<!-- <el-button plain @click="$refs.guava.index()">取消</el-button>-->
<!-- <el-button type="danger" @click="doApproval('BACK')">退回重新填写</el-button>-->
<!-- <el-button type="danger" @click="doApproval('REJECT')">拒绝</el-button>-->
<!-- <el-button type="primary" @click="doApproval('PASS')">同意</el-button>-->
<!-- </el-row>-->
<!-- </div>-->
<!-- </template>-->
</guava>
</div>
<script>
<!--#include("../common/info.js"){}#-->
<!--#include("../common/commonQuery.js"){}#-->
new Vue({
@@ -114,76 +104,70 @@ layout("/layouts/platform.html"){
],
changeTypeData: [],
// 审核相关
formData: {},
showApprovalForm: false
}
},
components: {
'info': INFO,
'common-query': COMMON_QUERY,
},
methods: {
openView(row){
this.$refs.guava.public(() => {
this.$refs.memberInfoRef.onOpen(row.userId)
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
openUserView(row){
this.$refs.guava.view(() => {
this.$refs.memberChangeAuditInfoRef.onOpen(row.userId)
openAudit(row) {
this.$refs.guava.edit(()=>{
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.infoRef.onOpen(row)
})
},
openApproval(row) {
window.open("/flow/common/approval/form?taskId=" + row.taskId + "&instanceId=" + row.instanceId + "&businessId=" + row.businessNo)
// this.$refs.guava.public(() => {
// this.showApprovalForm = true
// this.formData = row.approvalParam
// this.$refs.memberChangeAuditInfoRef.onOpen(data.id)
// })
},
doApproval(approvalType) {
let msg = '确定要同意此条申请吗?'
if (approvalType === 'REJECT') {
msg = '确定要拒绝此教工的入会申请吗?'
} else if (approvalType === 'BACK') {
msg = '确定要退回此条申请吗?'
}
this.$confirm(msg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
this.formData.bpmTaskApprovalType = approvalType
this.$refs.approvalFormRef.validate((valid) => {
if (valid) {
this.$axios
.post(loc() + "/platform/member/change/branchUnion/audit/approval", {
approval: JSON.stringify(this.formData)
})
.then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
} else {
this.$message.error(res.msg)
}
})
}
})
})
},
openRevoke(taskId) {
this.$confirm("您确定要撤回吗?", "提示", {
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/member/change/branchUnion/audit/revoke", { taskId }).then((resp) => {
this.$message.success(resp.msg)
this.doSearch()
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
search(pageForm){
if (pageForm) {
this.pageForm = {...this.pageForm, ...pageForm}
@@ -0,0 +1,176 @@
const INFO = {
template: /*language=HTML*/ `
<div>
<div class="process-title">申请信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-tabs v-model="activeName">
<el-tab-pane label="基础信息" name="basicInfo">
<el-descriptions :column="3" border class="descriptions-form">
<el-descriptions-item label="工号">{{ viewData.loginname }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ viewData.username }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ viewData.sex }}</el-descriptions-item>
<el-descriptions-item label="民族">{{ viewData.nation }}</el-descriptions-item>
<el-descriptions-item label="出生日期">{{ viewData.birthday ?
$moment(viewData.birthday).format("YYYY年MM月DD日") : '暂无' }}
</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{ viewData.political }}</el-descriptions-item>
<el-descriptions-item label="学历">{{ viewData.education }}</el-descriptions-item>
<el-descriptions-item label="学位">{{ viewData.academicDegree }}</el-descriptions-item>
<el-descriptions-item label="党政职务">{{ viewData.position }}</el-descriptions-item>
<el-descriptions-item label="工作单位">{{ viewData.unitname }}</el-descriptions-item>
<el-descriptions-item label="所属工会">{{ viewData.unionname }}</el-descriptions-item>
<el-descriptions-item label="所属校区">{{ viewData.campus }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ viewData.idCard }}</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.userState }}</el-descriptions-item>
<el-descriptions-item label="人员类型">{{ viewData.personType }}</el-descriptions-item>
<el-descriptions-item label="进校时间">{{ viewData.schoolTime }}</el-descriptions-item>
<template v-if="viewData.userState == '退休'">
<el-descriptions-item label="退休日期">{{ viewData.retireDate ?
$moment(viewData.retireDate).format("YYYY-MM-DD") : '暂无' }}
</el-descriptions-item>
<el-descriptions-item label="福利享受截止日期">{{
$moment(viewData.welfareStopDate).format("YYYY-MM-DD") }}
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
</template>
<el-descriptions-item label="会员状态">{{ viewData.member ? '会员' : '非会员' }}
</el-descriptions-item>
<el-descriptions-item label="福利会员状态">{{ viewData.welfareMember ? '福利会员' : '非福利会员'
}}
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item label="家庭主要成员" :span="3">
<el-table v-if="viewData.families&&viewData.families.length"
:data="viewData.families" size="mini" border
:header-cell-style="{background:'#eff3f6'}"
style="width: 100%">
<el-table-column prop="relation" label="与本人关系" align="center"
header-align="center">
</el-table-column>
<el-table-column prop="name" label="姓名" align="center" header-align="center">
</el-table-column>
<el-table-column prop="unit" label="单位" align="center" header-align="center">
</el-table-column>
<el-table-column prop="remark" label="备注" align="center" header-align="center">
</el-table-column>
</el-table>
<el-empty v-else :image-size="50" description="暂无家庭成员信息"></el-empty>
</el-descriptions-item>
<el-descriptions-item label="个人简况" :span="3">
<template slot="label">个人简况</template>
<div v-if="viewData.vita" class="text-left" v-html="viewData.vita"></div>
<span v-else>无数据</span>
</el-descriptions-item>
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="变更信息" name="changeInfo" v-if="viewData.changeInfos">
<el-table :data="viewData.changeInfos" :size="tableSize" @sort-change="pageOrder" ref="table"
row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index" width="80px"></el-table-column>
<el-table-column prop="fieldName" label="变更字段" header-align="center"></el-table-column>
<el-table-column prop="sourceValue" label="原数据" header-align="center">
<template slot-scope="{row}">
<div v-html="row.sourceValue"></div>
</template>
</el-table-column>
<el-table-column prop="newValue" label="新数据" header-align="center">
<template slot-scope="{row}">
<div v-html="row.newValue"></div>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<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>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
store,
mixins: [initTableMixins],
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data(){
return {
viewData: {},
doneTasks: [],
row: null,
activeName: "basicInfo",
}
},
methods: {
// 打开
onOpen(row) {
this.row = row
this.info()
this.getDoneTasks()
},
// 获取申请信息
info() {
this.$axios.post("/platform/member/change/view/findMemberChangeRecord", { id: this.row.id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 获取已办任务审批记录
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)
}
}
}
@@ -8,7 +8,7 @@ const MEMBER_ALL_CHANGE_INFO = {
<el-descriptions-item label="性别">{{ viewData.sex }}</el-descriptions-item>
<el-descriptions-item label="民族">{{ viewData.nation }}</el-descriptions-item>
<el-descriptions-item label="出生日期">{{ moment(viewData.birthday).format("YYYY年MM月DD日") }}</el-descriptions-item>
<el-descriptions-item label="出生日期">{{ $moment(viewData.birthday).format("YYYY年MM月DD日") }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{ viewData.political }}</el-descriptions-item>
<el-descriptions-item label="学历">{{ viewData.education }}</el-descriptions-item>
@@ -28,8 +28,8 @@ const MEMBER_ALL_CHANGE_INFO = {
<el-descriptions-item label="进校时间">{{ viewData.schoolTime }}</el-descriptions-item>
<template v-if="viewData.userState == '退休'">
<el-descriptions-item label="退休日期">{{ viewData.retireDate ? moment(viewData.retireDate).format("YYYY-MM-DD") : '暂无' }}</el-descriptions-item>
<el-descriptions-item label="福利享受截止日期">{{ moment(viewData.welfareStopDate).format("YYYY-MM-DD") }}</el-descriptions-item>
<el-descriptions-item label="退休日期">{{ viewData.retireDate ? $moment(viewData.retireDate).format("YYYY-MM-DD") : '暂无' }}</el-descriptions-item>
<el-descriptions-item label="福利享受截止日期">{{ $moment(viewData.welfareStopDate).format("YYYY-MM-DD") }}</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
</template>
@@ -96,7 +96,7 @@ const MEMBER_ALL_CHANGE_INFO = {
},
methods:{
onOpen(userId){
$.post('/platform/member/change/mange/getAllChangeMemberInfo', {userId})
this.$axios.post('/platform/member/change/manage/getAllChangeMemberInfo', {userId})
.then(resp => {
if (resp.code === 0) {
this.viewData = resp.data
@@ -2,8 +2,8 @@ const MEMBER_CHANGE = {
template: /*language=HTML*/ `
<el-card shadow="never">
<div class="process-title">会员变更</div>
<el-form :model="formData" ref="formRef" label-width="0" :rules="formRules" size="small">
<el-descriptions :column="3" border class="descriptions-form">
<el-form :model="formData" ref="formRef" label-width="0" :rules="formRules" size="small" class="flow-task-form">
<el-descriptions :column="3" border>
<el-descriptions-item label="工号">
<el-form-item prop="loginname">
<el-input v-model="formData.loginname" readonly size="small"></el-input>
@@ -17,8 +17,8 @@ const MEMBER_CHANGE = {
<el-descriptions-item label="性别">
<el-form-item prop="sex">
<el-radio-group :disabled="allowFields('sex')" v-model="formData.sex" size="small">
<el-radio border label="男"></el-radio>
<el-radio border label="女"></el-radio>
<el-radio border label="男"></el-radio>
<el-radio border label="女"></el-radio>
</el-radio-group>
</el-form-item>
</el-descriptions-item>
@@ -515,5 +515,10 @@ const MEMBER_CHANGE = {
},
created(){
this.init()
}
},
style: /*language=CSS*/ `
.el-descriptions-item__label {
width: 15% !important;
}
`
}

Some files were not shown because too many files have changed in this diff Show More