This commit is contained in:
@jyuhsin
2025-07-28 13:40:05 +08:00
parent 9501b015b9
commit 72546696fa
211 changed files with 24954 additions and 3665 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,208 @@
/*!
* FullCalendar v3.6.1 Print Stylesheet
* Docs & License: https://fullcalendar.io/
* (c) 2017 Adam Shaw
*/
/*
* Include this stylesheet on your page to get a more printer-friendly calendar.
* When including this stylesheet, use the media='print' attribute of the <link> tag.
* Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css.
*/
.fc {
max-width: 100% !important;
}
/* Global Event Restyling
--------------------------------------------------------------------------------------------------*/
.fc-event {
background: #fff !important;
color: #000 !important;
page-break-inside: avoid;
}
.fc-event .fc-resizer {
display: none;
}
/* Table & Day-Row Restyling
--------------------------------------------------------------------------------------------------*/
.fc th,
.fc td,
.fc hr,
.fc thead,
.fc tbody,
.fc-row {
border-color: #ccc !important;
background: #fff !important;
}
/* kill the overlaid, absolutely-positioned components */
/* common... */
.fc-bg,
.fc-bgevent-skeleton,
.fc-highlight-skeleton,
.fc-helper-skeleton,
/* for timegrid. within cells within table skeletons... */
.fc-bgevent-container,
.fc-business-container,
.fc-highlight-container,
.fc-helper-container {
display: none;
}
/* don't force a min-height on rows (for DayGrid) */
.fc tbody .fc-row {
height: auto !important; /* undo height that JS set in distributeHeight */
min-height: 0 !important; /* undo the min-height from each view's specific stylesheet */
}
.fc tbody .fc-row .fc-content-skeleton {
position: static; /* undo .fc-rigid */
padding-bottom: 0 !important; /* use a more border-friendly method for this... */
}
.fc tbody .fc-row .fc-content-skeleton tbody tr:last-child td { /* only works in newer browsers */
padding-bottom: 1em; /* ...gives space within the skeleton. also ensures min height in a way */
}
.fc tbody .fc-row .fc-content-skeleton table {
/* provides a min-height for the row, but only effective for IE, which exaggerates this value,
making it look more like 3em. for other browers, it will already be this tall */
height: 1em;
}
/* Undo month-view event limiting. Display all events and hide the "more" links
--------------------------------------------------------------------------------------------------*/
.fc-more-cell,
.fc-more {
display: none !important;
}
.fc tr.fc-limited {
display: table-row !important;
}
.fc td.fc-limited {
display: table-cell !important;
}
.fc-popover {
display: none; /* never display the "more.." popover in print mode */
}
/* TimeGrid Restyling
--------------------------------------------------------------------------------------------------*/
/* undo the min-height 100% trick used to fill the container's height */
.fc-time-grid {
min-height: 0 !important;
}
/* don't display the side axis at all ("all-day" and time cells) */
.fc-agenda-view .fc-axis {
display: none;
}
/* don't display the horizontal lines */
.fc-slats,
.fc-time-grid hr { /* this hr is used when height is underused and needs to be filled */
display: none !important; /* important overrides inline declaration */
}
/* let the container that holds the events be naturally positioned and create real height */
.fc-time-grid .fc-content-skeleton {
position: static;
}
/* in case there are no events, we still want some height */
.fc-time-grid .fc-content-skeleton table {
height: 4em;
}
/* kill the horizontal spacing made by the event container. event margins will be done below */
.fc-time-grid .fc-event-container {
margin: 0 !important;
}
/* TimeGrid *Event* Restyling
--------------------------------------------------------------------------------------------------*/
/* naturally position events, vertically stacking them */
.fc-time-grid .fc-event {
position: static !important;
margin: 3px 2px !important;
}
/* for events that continue to a future day, give the bottom border back */
.fc-time-grid .fc-event.fc-not-end {
border-bottom-width: 1px !important;
}
/* indicate the event continues via "..." text */
.fc-time-grid .fc-event.fc-not-end:after {
content: "...";
}
/* for events that are continuations from previous days, give the top border back */
.fc-time-grid .fc-event.fc-not-start {
border-top-width: 1px !important;
}
/* indicate the event is a continuation via "..." text */
.fc-time-grid .fc-event.fc-not-start:before {
content: "...";
}
/* time */
/* undo a previous declaration and let the time text span to a second line */
.fc-time-grid .fc-event .fc-time {
white-space: normal !important;
}
/* hide the the time that is normally displayed... */
.fc-time-grid .fc-event .fc-time span {
display: none;
}
/* ...replace it with a more verbose version (includes AM/PM) stored in an html attribute */
.fc-time-grid .fc-event .fc-time:after {
content: attr(data-full);
}
/* Vertical Scroller & Containers
--------------------------------------------------------------------------------------------------*/
/* kill the scrollbars and allow natural height */
.fc-scroller,
.fc-day-grid-container, /* these divs might be assigned height, which we need to cleared */
.fc-time-grid-container { /* */
overflow: visible !important;
height: auto !important;
}
/* kill the horizontal border/padding used to compensate for scrollbars */
.fc-row {
border: 0 !important;
margin: 0 !important;
}
/* Button Controls
--------------------------------------------------------------------------------------------------*/
.fc-button-group,
.fc button {
display: none; /* don't display any button-related controls */
}
@@ -9,7 +9,7 @@
<template v-for="column in dynamicData">
<!-- 文本数值时间 -->
<template v-if="['VARCHAR', 'TEXT', 'INT', 'DATE', 'DATETIME'].includes(column.columnType)">
<template v-if="['CHAR', 'VARCHAR', 'TEXT', 'INT', 'DATE', 'DATETIME'].includes(column.columnType)">
<van-field
class="field"
v-model="column.columnValue"
@@ -22,7 +22,11 @@
:rules="[{ required: column.isRequired, message: (['SELECT'].includes(column.columnFormType) ? '请选择' : '请填写') + column.columnName }]"
:required="column.isRequired"
@click="selectFieldClick(column)"
></van-field>
>
<template v-if="['STEPPER'].includes(column.columnFormType)" #input>
<van-stepper v-model="column.columnValue" :max="3" :min="1"/>
</template>
</van-field>
<van-popup
v-if="['SELECT'].includes(column.columnFormType)"
@@ -165,11 +165,10 @@ module.exports = {
handleSaveDraft() {
if (this.actionLoading) return
// 保存草稿时不显示加载状态,因为只是保存业务数据
this.$emit("save-draft", {
submitType: this.actionEnum.APPLY,
defineKey: this.defineKey,
defineId: this.defineId,
businessId: this.businessId,
isDraft: true // 标识这是草稿保存
})
},
@@ -81,6 +81,12 @@ layout("/layouts/platform.html"){
<el-form-item label="基础类型代码" label-width="110px" prop="code">
<el-input maxlength="100" placeholder="请输入基础类型名称" type="text" v-model="formData.code"></el-input>
</el-form-item>
<el-form-item v-if="checkData.id === 'f708d6343c9542b791d32532f860d120'" label="服装项目" label-width="110px" prop="clothing">
<el-radio-group v-model="formData.clothing">
<el-radio-button :label="true"></el-radio-button>
<el-radio-button :label="false"></el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="基础类型备注" label-width="110px" prop="note">
<el-input maxlength="100" placeholder="请输入基础类型备注" type="textarea" v-model="formData.note"></el-input>
</el-form-item>
@@ -192,7 +198,8 @@ layout("/layouts/platform.html"){
id: row.id,
name: row.name,
code: row.code,
note: row.note
note: row.note,
clothing: row.clothing
}
this.basicTypeDialog = true
},
@@ -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: 800},
{ label: "活动性质", prop: "trainType"},
{ label: "报名时间", prop: "activitySignUpStartTime"},
{ label: "活动时间", prop: "activityStartTime"},
],
}
},
methods: {
onOpen(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
pageData() {
this.$axios.post("/platform/family/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,305 @@
<!--#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: ["FAMILY_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: [],
activityType: '',
}
},
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 courseType = this.courseTypeList.find((v) => v.id === row.courseType)
this.$axios.post("/platform/mobile/familyActivity/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, courseType)
}
})
},
onCancel(row) {
this.$confirm("您确定要取消吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(async () => {
const resp = await this.$axios.post("/platform/mobile/familyActivity/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/family/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() {
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,288 @@
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="80px">
<div class="left-span-label">个人信息</div>
<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>
<div class="left-span-label"
style="display: flex; justify-content: space-between; align-items: center">
<div>家属信息</div>
<div>
<el-button type="primary" size="mini" @click="delFamily">
删除家属
</el-button>
<el-button type="primary" size="mini" @click="addFamily">
添加家属
</el-button>
</div>
</div>
<div v-if="formData.mobileColumnsValue && formData.mobileColumnsValue.length > 0">
<el-tabs v-model="active" type="card">
<el-tab-pane v-for="(item, index) in formData.mobileColumnsValue"
:name="index + ''"
:label="'家属' + (index + 1)"
:key="index">
<el-row>
<el-col :span="24">
<el-form-item
v-for="(column, index) in item"
: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-tab-pane>
</el-tabs>
</div>
<div v-if="formData.mobileColumnsValue.length === 0" style="text-align: center">
<span style="font-size: 15px;color: grey">如有家属,请添加家属</span>
</div>
</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: ["FAMILY_SIGNUP_TYPE"],
data() {
return {
signDialog: false,
formData: {
mobileColumnsValue: [],
},
courseRow: {},
courseTypeRow: {},
courseTimeSelectList: [],
active: '',
}
},
methods: {
addFamily() {
if(this.formData.mobileColumnsValue.length >= this.courseTypeRow.familyMaxCount) {
this.$message.warning('家属最多人数为' + this.courseTypeRow.familyMaxCount)
return
}
const list = clone(this.courseTypeRow.familyMobileSignColumnList)
this.formData.mobileColumnsValue.push(list)
},
delFamily() {
this.formData.mobileColumnsValue.splice(this.active, 1)
const ac = (Number(this.active) - 1)
this.active = '' + (ac >= 0 ? ac : 0)
},
validFamilyForm() {
for (let i = 0; i < this.formData.mobileColumnsValue.length; i++) {
const family = this.formData.mobileColumnsValue[i]
for (const familyColumn of family) {
if(familyColumn.isRequired && !familyColumn.columnValue) {
this.$message.error('家属' + (i + 1) + '的' + familyColumn.columnName + '不能为空')
return false
}
}
}
return true
},
async validSignUp() {
//获取家属是多少人
const res = await this.$axios.post("/platform/mobile/familyActivity/validateSignUp", {
courseId: this.formData.courseId,
currentFamilyNumber: this.formData.mobileColumnsValue.length || 0
})
if (res.code !== 0) {
this.$message.warning(res.msg)
return false
}
return true
},
async validateSourceSignUp() {
if (this.courseRow.courseIsLimitApply) {
const resp = await $.post('/platform/mobile/familyActivity/validateSourceSignUp', {activityCourseId: this.formData.activityCourseId})
if (resp.code !== 0) {
this.$message.warning(resp.msg)
return false
}
}
return true
},
async getCourseTimeSelectList(o) {
const resp = await $.post('/platform/mobile/familyActivity/getCourseTimeSelectList', {courseId: o.id})
if (resp.code === 0) {
this.courseTimeSelectList = resp.data
} else {
this.$message.warning('获取时段信息失败,请联系管理员')
}
},
async onOpen(row, courseType) {
this.initData(row, courseType)
if (row.courseIsLimitApply) {
await this.getCourseTimeSelectList(row)
}
if (courseType && courseType.familyMobileSignColumnList.length > 0) {
courseType.familyMobileSignColumnList.forEach(item => {
item.columnValue = ''
})
}
this.courseRow = row
this.courseTypeRow = courseType
this.signDialog = true
},
async onSubmit() {
//验证家属表单
if (!this.validFamilyForm()) return
if (!await this.validSignUp()) return
if (!await this.validateSourceSignUp()) return
this.$refs["form"].validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
let array = []
this.formData.mobileColumnsValue.forEach(item => {
const o = item.map((v) => {
return {
columnName: v.columnName,
columnValue: v.columnValue,
columnCode: v.columnCode,
columnFormType: v.columnFormType
}
})
array.push(o)
})
this.formData.mobileColumnsValue = JSON.stringify(clone(array))
const resp = await this.$axios.post("/platform/mobile/familyActivity/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, courseType) {
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,
mobileColumnsValue: [],
}
this.$nextTick(() => {
this.$refs.form.clearValidate()
})
},
},
style: /*language=CSS*/ `
.el-tabs__header {
margin: 0 0 15px !important;
}
`
}
@@ -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="activityType + '通知'" 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="trainType" :rules="{required:true,message: '请选择活动类型', trigger: 'blur'}">
<el-select @change="typeChange" filterable placeholder="请选择活动类型" style="width: 100%" v-model="formData.trainType">
<el-option :label="item.name" :value="item.code" :key="item.code" v-for="item in dict.type.FAMILY_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>{{activityType + '信息(温馨提示:如不需要人数限制,下方人数框填写0或者不填)'}}</div>
<div>
<el-button @click="addCourse" size="mini" type="primary">添加{{ activityType }}</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="activityType + '名称'" prop="courseName">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseName" :placeholder="'请输入' + activityType + '名称'"></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="activityType + '人数'" 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="activityType + '地点'" prop="courseLocation">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseLocation" :placeholder="'请输入' + activityType + '地点'"></el-input>
</template>
</el-table-column>
<el-table-column :label="activityType + '负责人'" prop="courseInstructor">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseInstructor" :placeholder="'请输入' + activityType + '负责人'"></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="activityType + '时间'">
<template v-slot="scope">
<el-button @click="openSetUpCourseTime(scope.$index)" type="text">设置{{ activityType }}时间</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", "FAMILY_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: [],
trainTypeList: [],
activityType: "子活动",
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.activityType + "人数!", "提示", {
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.activityType +
"人数为" +
row.coursePeopleNumber +
"人,当前报名人数为" +
registerUserCount +
"人,预留名额上限为" +
num +
"人!"
this.$alert(str, "提示", {
confirmButtonText: "确定"
})
row.courseReservedNumber = 0
}
}
}
},
async getRegisterUserCount(courseId) {
const resp = await this.$axios.post("/platform/family/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.activityType + "信息中选择类型!")
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.activityType + "信息中选择类型!")
}
},
doLimitNum() {
this.signUpDialog = false
},
openMoreInfo(row, index) {
this.$refs.customFormRef.onOpen(this.formData, row, index)
},
async removeTableCourse(index) {
const confirm = await this.$confirm(
"请确认是否删除此" + this.activityType + "?如果该" + this.activityType + "已有报名人员,会随之一起删除!确定吗?",
"提示",
{
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/family/manage/activity/findOne", {id: val})
if (resp.code === 0) {
this.formData = resp.data
this.typeChange(this.formData.trainType)
this.formData.id = ""
}
},
typeChange(val) {
const type = this.dict.type.FAMILY_SIGNUP_TYPE.find(o => o.code === val)
this.activityType = 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/family/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/family/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/family/manage/type/getAllType", {})
return resp.data
},
async init(row) {
if (row && row.id) {
const resp = await this.$axios.post("/platform/family/manage/activity/findOne", {id: row.id})
if (resp.code === 0) {
this.formData = resp.data
this.typeChange(this.formData.trainType)
}
}
},
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: ["FAMILY_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: ["FAMILY_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('MM/DD') }}</span>
<span></span>
<span>{{ $moment(row.activityEndTime).format('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", "FAMILY_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: 800 },
{ 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/familyActivity/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="activityType + '信息'">
<el-table :data="viewData.courseList" class="mt20">
<el-table-column :label="activityType + '名称'" 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="activityType + '时间'" 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: ["FAMILY_SIGNUP_TYPE"],
data() {
return {
activityType: '',
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.FAMILY_SIGNUP_TYPE.find((o) => o.code === resp.data.trainType)
this.activityType = 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="activityType + '列表'" width="60%">
<el-table :data="courseList">
<el-table-column :label="activityType + '名称'" 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">该{{activityType}}的签到方式不支持生成二维码</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: ["FAMILY_SIGNUP_TYPE"],
data() {
return {
courseDialog: false,
activityType: "",
courseList: [],
}
},
methods: {
initData(row) {
this.courseList = row.courseList
const type = this.dict.type.FAMILY_SIGNUP_TYPE.find((o) => o.code === row.trainType)
this.activityType = 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: ["FAMILY_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/family/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,155 @@
<!--#
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%"
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="activityType">
<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="activityType" 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="activityType + '地点'" 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: ["FAMILY_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 }
],
activityType: "子活动",
}
},
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.FAMILY_SIGNUP_TYPE.find(o => o.code === activity.activityType)
this.activityType = 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,123 @@
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>
<template v-slot="{ row }" v-else-if="column.prop === 'familyCount'">
<el-link @click="viewFamily(row)" type="primary">
{{row.familyCount}}
</el-link>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="{ row }">
<el-button size="mini" type="primary" @click="viewFamily(row)">查看</el-button>
</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>
<el-dialog title="家属信息" append-to-body :close-on-click-modal="false" :visible.sync="familyVisible" width="50%">
<template v-for="(item,index) in familyRow.mobileColumnsValue" :key="index">
<div class="left-span-label">家属{{ index + 1 }}</div>
<el-descriptions border class="descriptions-form">
<el-descriptions-item v-for="(column, i) in item" :label="column.columnName" :key="i">
<div v-if="column.columnFormType !== 'FILE'">{{ column.columnValue }}</div>
<div v-else>
<file-preview complete_result :files="column.columnValue"></file-preview>
</div>
</el-descriptions-item>
</el-descriptions>
</template>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="familyVisible = false">确 定</el-button>
</span>
</el-dialog>
</div>
`,
dicts: ["FAMILY_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" },
{ label: "家属人数", prop: "familyCount" },
],
userSignInfo: {},
clickRow: {},
familyRow: {},
familyVisible: false,
}
},
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)
}*/
},
viewFamily(row) {
this.familyRow = row
this.familyVisible = true
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,354 @@
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="familyMaxCount" label="家属最多数">
<el-input v-model="formData.familyMaxCount" placeholder="请输入家属最多数" type="number"></el-input>
</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.familyMobileSignColumnList.push({isRequired: false})"
size="small"
type="primary"
style="margin-left: 10px"
>
<i class="ti-plus"></i>
添加
</el-button>
</div>
</div>
<el-table :data="formData.familyMobileSignColumnList">
<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.familyMobileSignColumnList.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: ["FAMILY_SIGNUP_TYPE"],
data() {
return {
formData: {
familyMobileSignColumnList: [{ isRequired: false }],
isBringFamily: true,
isAddFamily: true,
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"] }],
familyMaxCount: [{ 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.familyMobileSignColumnList.unshift({
columnName: "携带亲属人数",
columnCode: "xdqsrs",
columnFormType: "INPUT",
columnType: "INT",
isRequired: true
})
} else {
this.formData.familyMobileSignColumnList.forEach((item, index) => {
if (item.columnCode === "xdqsrs" && this.formData.isBringFamily === false) {
this.formData.familyMobileSignColumnList.splice(index, 1)
}
})
}
},
columnFormTypeChange(val, index) {
if (val === "FILE") {
this.formData.familyMobileSignColumnList[index].columnType = "JSON"
this.formData.familyMobileSignColumnList[index].isDisabled = true
} else {
this.formData.familyMobileSignColumnList[index].columnType = ""
this.formData.familyMobileSignColumnList[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.familyMobileSignColumnList.map((item) => item.columnCode)).size
const listLength = this.formData.familyMobileSignColumnList.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.familyMobileSignColumnList.map((item) => item.columnCode)).size
const listLength = this.formData.familyMobileSignColumnList.length
if (listLength > newListLength) {
this.$message.warning('字段编码不能重复')
return
}
const cloneData = clone(this.formData)
cloneData.familyMobileSignColumnList = JSON.stringify(cloneData.familyMobileSignColumnList)
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.familyMobileSignColumnList.forEach((item) => {
item.isDisabled = item.columnFormType === "FILE"
})
} else {
this.formData = {
familyMobileSignColumnList: [{ isRequired: false }],
isBringFamily: true,
isAddFamily: true,
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,143 @@
<!--#
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%"
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="activityType" 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="activityType + '地点'" 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 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"></user-info>
</template>
</guava>
</div>
<script>
<!--#include('userInfo.js'){}#-->
new Vue({
el: "#app",
dicts: ["FAMILY_SIGNUP_TYPE"],
mixins: [initTableMixins],
components: {
"user-info": userInfo,
},
data() {
return {
activityType: "子活动",
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.FAMILY_SIGNUP_TYPE.find(o => o.code === activity.activityType)
this.activityType = 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">如单选为灰色选择不了则表示对应的{{ activityType }}人数已满候补报名不做调整</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="activityType + '列表'"
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: ["FAMILY_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" }
],
activityType: '',
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.FAMILY_SIGNUP_TYPE.find(o => o.code === activity.activityType)
this.activityType = type?.name || "子活动"
},
getCurrentRow(row) {
this.chooseRow = row
},
async doAdjust() {
if (!this.afterAdjustCourse) {
this.$message.warning("请选择要调整的" + this.activityType + "")
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.pageForm.activityId,
oldCourseId: this.registerCourse.id,
newCourseId: this.afterAdjustCourse,
userId: this.userInfo.userId
})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$refs.guava.index()
this.adjustDialogVisible = false
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
loading.close()
})
.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.pageForm.activityId,
courseId: this.registerCourse.id,
userId: o.userId
})
if (resp.code === 0) {
this.$message.success(resp.msg)
await this.registerSearch()
this.doSearch()
} 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="activityType + ''">
<el-select @change="courseChange" :placeholder="'请选择' + activityType" 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="activityType + '(温馨提示:如需补充人员,请在上面选择具体的' + activityType + ''">
<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' ? activityType : 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: ["FAMILY_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 }
],
activityType: "子活动",
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/family/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/family/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.FAMILY_SIGNUP_TYPE.find(o => o.code === activity.activityType)
this.activityType = 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/family/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>
<!--#
}
#-->
@@ -0,0 +1,147 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item prop="planType" label="计划类型">
<el-select v-model="formData.planType" placeholder="请选择计划类型" filterable clearable
style="width: 100%">
<el-option v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('SCHOOL_UNION_ADMIN')" label="校工会" value="40001"></el-option>
<el-option v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('BRANCH_UNION_CHAIRMAN')" label="分工会" value="40002"></el-option>
<el-option v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('CLUB_PRESIDENT')" label="协会/社团" value="40003"></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="formData.planType === '40002'" prop="tissueId" label="所属工会">
<el-select v-model="formData.tissueId" placeholder="请选择所属工会" filterable clearable
@change="(val) => {formData.tissueName = unionList.find(o => o.id === formData.tissueId).name}"
style="width: 100%">
<el-option
v-for="item in unionList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="formData.planType === '40003'" prop="tissueId" label="所属协会/社团">
<el-select v-model="formData.tissueId" placeholder="请选择所属协会/社团" filterable clearable
@change="(val) => {formData.tissueName = clubList.find(o => o.id === formData.tissueId).clubName}"
style="width: 100%">
<el-option
v-for="item in clubList"
:key="item.id"
:label="item.clubName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="planName" label="计划名称">
<el-input maxlength="50" placeholder="请填写计划名称" v-model="formData.planName"
type="text"></el-input>
</el-form-item>
<el-form-item prop="planTime" label="预计时间">
<el-date-picker
v-model="formData.planTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择预计时间"
style="width: 100%">
</el-date-picker>
</el-form-item>
<el-form-item prop="activityType" label="活动类型">
<el-select v-model="formData.activityType" placeholder="请选择活动类型" filterable clearable
style="width: 100%">
<el-option
v-for="item in activityTypeList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="money" label="预算费用" class="is-required">
<el-input maxlength="50" placeholder="请填写整数或者小数" v-model="formData.money"
type="number"></el-input>
</el-form-item>
<el-form-item prop="content" label="计划内容" class="is-required">
<text-editor v-model="formData.content"></text-editor>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
props: {
unionList: {
type: Array,
required: true
},
clubList: {
type: Array,
required: true
}
},
data() {
return {
activityTypeList: [],
formData: {},
formRules: {
type: [{required: true, message: '必填', trigger: ['blur', 'change']}],
planName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
planTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
money: [{required: true, message: '必填', trigger: ['blur', 'change']}],
activityType: [{required: true, message: '必填', trigger: ['blur']}],
planType: [{required: true, message: '必填', trigger: ['blur']}],
tissueId: [{required: true, message: '必填', trigger: ['blur']}],
},
}
},
methods: {
onOpen(row) {
if(row && row.id) {
this.fetchOne(row.id)
}
},
fetchOne(id) {
this.$axios.post('/platform/yearPlan/manage/fetchOne', { id: id })
.then((resp) => {
this.formData = clone(resp.data)
})
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/yearPlan/manage/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
queryActivityType() {
this.$axios.post('/platform/yearPlan/manage/queryActivityType')
.then((resp) => {
this.activityTypeList = resp.data
})
},
},
created() {
this.queryActivityType()
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,201 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
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="请输入计划名称"
style="width: 100%"
v-model="pageForm.planName"
></el-input>
</search-item>
<search-item v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('BRANCH_UNION_CHAIRMAN')" label="所属工会:">
<el-select v-model="pageForm.tissueIdByUnion" 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 v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('CLUB_PRESIDENT')" label="协会/社团:">
<el-select v-model="pageForm.tissueIdByClub" placeholder="请选择所属协会/社团" filterable clearable
@change="doSearch" style="width: 100%">
<el-option
v-for="item in clubList"
:key="item.id"
:label="item.clubName"
:value="item.id">
</el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="年度计划">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增计划
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<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 === 'planType'">
<span v-if="row.planType === '40001'">校工会</span>
<span v-if="row.planType === '40002'">分工会</span>
<span v-if="row.planType === '40003'">协会/社团</span>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'tissueName'">
{{ row.tissueName || '校工会' }}
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh" :union-list="unionList" :club-list="clubList"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{label: '年度', prop: 'year'},
{label: '计划名称', prop: 'planName'},
{label: '计划类型', prop: 'planType'},
{label: '所属组织', prop: 'tissueName'},
{label: '活动类型', prop: 'activityTypeName'},
{label: '预计时间', prop: 'planTime'},
{label: '预算费用', prop: 'money'},
],
unionList: [],
clubList: [],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/yearPlan/manage/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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
}
})
},
queryUnion() {
this.$axios.post('/platform/yearPlan/manage/queryUnion')
.then((resp) => {
this.unionList = resp.data
})
},
queryClub() {
this.$axios.post('/platform/yearPlan/manage/queryClub')
.then((resp) => {
this.clubList = resp.data
})
},
},
async created() {
this.queryUnion()
this.queryClub()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,45 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="计划类型">
{{ viewData.type == 40001 ? '校工会计划' : viewData.type == 40002 ? '分工会计划' : '协会/社团计划' }}
</el-descriptions-item>
<el-descriptions-item label="计划名称">
{{ viewData.planName }}
</el-descriptions-item>
<el-descriptions-item label="预计时间">
{{ viewData.planTime }}
</el-descriptions-item>
<el-descriptions-item label="所属组织">
{{ viewData.tissueName || '校工会' }}
</el-descriptions-item>
<el-descriptions-item label="活动类型">
{{ viewData.activityTypeName }}
</el-descriptions-item>
<el-descriptions-item label="预算费用">
{{ viewData.money }}
</el-descriptions-item>
<el-descriptions-item label="计划内容" :span="2">
<div v-html="viewData.content"></div>
</el-descriptions-item>
</el-descriptions>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.$axios.post('/platform/yearPlan/manage/fetchOne', { id: row.id })
.then((resp) => {
this.viewData = resp.data
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,118 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="上传人" prop="userName">
<el-input maxlength="50" placeholder="请填写上传人" :value="$store.state.user.username"
type="text"></el-input>
</el-form-item>
<el-form-item prop="summaryFrom" label="上传类型">
<el-select v-model="formData.summaryFrom" placeholder="请选择上传类型" filterable clearable
style="width: 100%">
<el-option v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('SCHOOL_UNION_ADMIN')" label="校工会" value="40001"></el-option>
<el-option v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('BRANCH_UNION_CHAIRMAN')" label="分工会" value="40002"></el-option>
<el-option v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('CLUB_PRESIDENT')" label="协会/社团" value="40003"></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="formData.summaryFrom === '40002'" prop="tissueId" label="所属工会">
<el-select v-model="formData.tissueId" placeholder="请选择所属工会" filterable clearable
@change="(val) => {formData.tissueName = unionList.find(o => o.id === formData.tissueId).name}"
style="width: 100%">
<el-option
v-for="item in unionList"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="formData.summaryFrom === '40003'" prop="tissueId" label="所属协会/社团">
<el-select v-model="formData.tissueId" placeholder="请选择所属协会/社团" filterable clearable
@change="(val) => {formData.tissueName = clubList.find(o => o.id === formData.tissueId).clubName}"
style="width: 100%">
<el-option
v-for="item in clubList"
:key="item.id"
:label="item.clubName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item prop="summaryType" label="总结类型">
<el-select v-model="formData.summaryType" placeholder="请选择总结类型"
clearable style="width: 100%;">
<el-option v-for="item in dict.type.SUMMARY_TYPE" :label="item.name" :value="item.code" :key="item.code"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="files" label="附件">
<file-upload :upload_number="5" :value.sync="formData.files"
upload_result_type="url"
complete_result upload_mode="drag"
upload_result_category="array"></file-upload>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
store,
dicts: ["SUMMARY_TYPE"],
props: {
unionList: {
type: Array,
required: true
},
clubList: {
type: Array,
required: true
}
},
data() {
return {
formData: {},
formRules: {
summaryFrom: [{required: true, message: '必填', trigger: ['blur']}],
summaryType: [{required: true, message: '必填', trigger: ['blur']}],
tissueId: [{required: true, message: '必填', trigger: ['blur']}],
},
}
},
methods: {
onOpen(row) {
if(row && row.id) {
this.fetchOne(row.id)
}
},
fetchOne(id) {
this.$axios.post('/platform/yearSummary/manage/fetchOne', { id: id })
.then((resp) => {
this.formData = clone(resp.data)
})
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
this.formData.files = JSON.stringify(this.formData.files)
const resp = await this.$axios.post("/platform/yearSummary/manage/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,197 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="总结类型:">
<el-select v-model="pageForm.summaryType" placeholder="请选择总结类型"
clearable style="width: 100%;" @change="doSearch">
<el-option v-for="item in dict.type.SUMMARY_TYPE" :label="item.name" :value="item.code" :key="item.code"></el-option>
</el-select>
</search-item>
<search-item v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('BRANCH_UNION_CHAIRMAN')" label="所属工会:">
<el-select v-model="pageForm.tissueIdByUnion" 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 v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('CLUB_PRESIDENT')" label="协会/社团:">
<el-select v-model="pageForm.tissueIdByClub" placeholder="请选择所属协会/社团" filterable clearable
@change="doSearch" style="width: 100%">
<el-option
v-for="item in clubList"
:key="item.id"
:label="item.clubName"
:value="item.id">
</el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="年度总结">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增计划
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<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 === 'planType'">
<span v-if="row.planType === '40001'">校工会</span>
<span v-if="row.planType === '40002'">分工会</span>
<span v-if="row.planType === '40003'">协会/社团</span>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'tissueName'">
{{ row.tissueName || '校工会' }}
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh" :union-list="unionList" :club-list="clubList"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
dicts: ["SUMMARY_TYPE"],
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{label: '年度', prop: 'year'},
{label: '总结类型', prop: 'summaryTypeName'},
{label: '所属组织', prop: 'tissueName'},
{label: '上传人', prop: 'userName'},
{label: '上传时间', prop: 'cTime'},
],
unionList: [],
clubList: [],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/yearSummary/manage/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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
}
})
},
queryUnion() {
this.$axios.post('/platform/yearPlan/manage/queryUnion')
.then((resp) => {
this.unionList = resp.data
})
},
queryClub() {
this.$axios.post('/platform/yearPlan/manage/queryClub')
.then((resp) => {
this.clubList = resp.data
})
},
},
async created() {
this.queryUnion()
this.queryClub()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,43 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="上传人">
{{viewData.userName}}
</el-descriptions-item>
<el-descriptions-item label="上传类型">
{{ viewData.summaryFrom == 40001 ? '校工会计划' : viewData.type == 40002 ? '分工会计划' : '协会/社团计划' }}
</el-descriptions-item>
<el-descriptions-item label="所属组织">
{{ viewData.tissueName || '校工会' }}
</el-descriptions-item>
<el-descriptions-item label="总结类型">
{{viewData.summaryTypeName}}
</el-descriptions-item>
<el-descriptions-item label="上传时间" :span="2">
{{viewData.cTime}}
</el-descriptions-item>
<el-descriptions-item label="附件">
<file-preview v-if="viewData.files.length > 0" :files="viewData.files" complete_result></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.$axios.post('/platform/yearSummary/manage/fetchOne', { id: row.id })
.then((resp) => {
this.viewData = resp.data
})
},
},
style: /*language=CSS*/ `
`
}
@@ -1,633 +0,0 @@
<el-form :model="formData" label-width="130px" ref="form">
<div class="left-span-label">活动信息</div>
<el-row :gutter="20" type="flex" v-if="fromEdit !== 'edit'">
<el-col :span="12">
<el-form-item label="是否沿用之前活动" prop="use">
<el-radio-group v-model="use">
<el-radio :label="true">沿用之前活动</el-radio>
<el-radio :label="false">不沿用之前活动</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="use">
<el-form-item label="往期活动" prop="historicalAct">
<el-select v-model="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="trainType + '通知'" 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-button @click="$refs.joinCnd.open()" icon="el-icon-s-operation" size="small">打开</el-button>-->
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="活动类型" prop="trainType" :rules="{required:true,message: '请选择活动类型', trigger: 'blur'}">
<el-select @change="typeChange" filterable placeholder="请选择活动类型" style="width: 100%" v-model="formData.trainType">
<el-option :label="item.name" :value="item.code" :key="item.code" v-for="item in trainTypeList"></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 class="left-span-label" style="display: flex; justify-content: space-between; align-items: center">
<div>{{trainType + '信息(温馨提示:如不需要人数限制,下方人数框填写0或者不填)'}}</div>
<div>
<el-button @click="addCourse" size="mini" type="primary">添加{{ trainType }}</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="trainType + '名称'" prop="courseName">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseName" :placeholder="'请输入' + trainType + '名称'"></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.lxname" :value="c.id" :key="c.id" v-for="c in courseTypeList"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column :label="trainType + '人数'" 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 campusList"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column :label="trainType + '地点'" prop="courseLocation">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseLocation" :placeholder="'请输入' + trainType + '地点'"></el-input>
</template>
</el-table-column>
<el-table-column :label="trainType + '负责人'" prop="courseInstructor">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseInstructor" :placeholder="'请输入' + trainType + '负责人'"></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="trainType + '时间'">
<template v-slot="scope">
<el-button @click="openSetUpCourseTime(scope.$index)" type="text">设置{{ trainType }}时间</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">个人报名数量限制</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>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button v-if="activityId !== ''" @click="doBack">返回</el-button>
<el-button @click="doHandle(false)" type="primary">保存</el-button>
<el-button @click="doHandle(true)" type="primary">提交</el-button>
</el-row>
<el-dialog :close-on-click-modal="false" :visible.sync="setUpCourseDialog" title="设置时间">
<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">{{'设置' + trainType + '时间'}}</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>
</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>
<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 v-if="fromEdit === 'edit'" @click="cancel">取消</el-button>
<el-button @click="doConfirmSetUpCourse" type="primary">确定</el-button>
</el-row>
</el-dialog>
<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>
<el-dialog :close-on-click-modal="false" :visible.sync="signUpDialog" title="设置报名限制">
<el-table :data="formData.typeLimits">
<el-table-column prop="code" label="类型编码"></el-table-column>
<el-table-column prop="lxname" label="类型名称"></el-table-column>
<el-table-column label="限制个数" width="500">
<template v-slot="scope">
<span>限制个数</span>
<span style="color: #c64120; font-size: 12px">注:值为空或者为0则表示此类型不限制报名个数</span>
</template>
<template v-slot="{row}">
<el-input-number size="small" v-model="row.limitNum" :min="0"></el-input-number>
</template>
</el-table-column>
</el-table>
<el-row class="mt20" justify="end" type="flex">
<el-button @click="cancelLimitNum">取消</el-button>
<el-button @click="doLimitNum" type="primary">确定</el-button>
</el-row>
</el-dialog>
<el-dialog :close-on-click-modal="false" :visible.sync="setUpUnionLimitDialog" title="分工会人数限制" top="50px">
<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>
<el-drawer title="自定义设置" size="50%" class="my-drawer" :visible.sync="moreInfoDrawer">
<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-button @click="openSetUpUserScope(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-select v-model="formData.courseList[moreInfoIndex].hostUnionId" placeholder="请选择承办工会" style="width: 100%">
<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"
:disabled="formData.courseList[moreInfoIndex].isBringFamily === true"
>
<el-radio border :label="1">报名人员减少模式</el-radio>
<el-radio border :label="2">候补模式</el-radio>
</el-radio-group>
<span v-if="formData.courseList[moreInfoIndex].isBringFamily === true" class="text-danger" style="margin-left: 6px">
温馨提醒:{{formData.courseList[moreInfoIndex].courseName}}为携带家属,只支持报名人员减少模式
</span>
</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>
<drawer-user-scope @group_change="getActivityGroup" ref="drawerUserScope" :group_id.sync="formData.activityGroupId"></drawer-user-scope>
@@ -1,663 +0,0 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-row--flex {
align-items: center;
}
.el-drawer__body {
padding: 20px;
}
.my-drawer .el-col-4 {
text-align: right;
}
.my-drawer .el-row {
margin-bottom: 20px;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<!--#include("/platform/zhgh/activity/trainSingUp/add/include_activity_edit.html"){}#-->
</el-card>
</guava>
</div>
<script>
let pointX = "${AppMapCenterPointX!}"
let pointY = "${AppMapCenterPointY!}"
new Vue({
el: "#app",
store,
components: {
"drawer-user-scope": httpVueLoader("/components/module/activity/DrawerUserScope.vue"),
"map-container": httpVueLoader("/components/plugins/mapContainer/MapContainer.vue?v=1.0.1")
},
data() {
const that = this
return {
use: false,
historicalActList: [],
historicalAct: "",
unionList: [],
trainType: "培训班",
trainTypeList: [],
fromEdit: "",
formData: {
notice: false,
courseList: [
{ orderNum: 1, courseName: "", courseTimeList: [], isMobileSign: false, isReceiveGift: false, reserveMode: 1 },
{ orderNum: 2, courseName: "", courseTimeList: [], isMobileSign: false, isReceiveGift: false, reserveMode: 1 }
],
conditionStructure: {
method: "AND",
conditions: [{}]
},
restrictLimit: 1,
limitNum: 1,
typeLimits: []
},
pickerOptions: {
disabledDate(time) {
return time.getTime() < Date.now() - 24 * 60 * 60 * 1000
}
},
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")
)
}
},
courseIndex: 0,
setUpCourseDialog: false,
unionLimitIndex: 0,
setUpUnionLimitDialog: false,
viewMapDialog: false,
mapDialog: false,
courseTypeList: [],
campusList: [],
courseTimeOneKeySet: {
startTime: "",
endTime: ""
},
conditionStructure: {
method: "AND",
conditions: [{}]
},
fields: [],
activityGroupList: [],
signUpDialog: false,
userScopeIndex: 0,
unionUserNumCalc: [{}],
unionUserNumOneKeyRatio: null,
summaryCount: 0,
moreInfoDrawer: false,
moreInfoRow: {},
moreInfoIndex: 0,
placeSearchComponent: null,
addressValue: "",
mapIndex: 0,
activityId: GetQueryString("id")
}
},
computed: {
unionUserNumCalcTips() {
return this.unionUserNumCalc.map((v) => {
return (
(v.startNum ? v.startNum : "?") +
"-" +
(v.endNum ? v.endNum : "?") +
"人的分工会,限报" +
(v.resultNum ? v.resultNum : "?") +
"人"
)
})
}
},
methods: {
courseTypeChange(val, row) {
const courseType = this.courseTypeList.find((o) => o.id === val)
if (courseType.isBringFamily === true) {
this.$set(row, "isBringFamily", true)
} else {
this.$set(row, "isBringFamily", false)
}
row.reserveMode = 1
},
openMoreInfo(row, index) {
this.moreInfoRow = row
this.moreInfoIndex = index
this.moreInfoDrawer = true
},
openSetUpUserScope(index) {
const id = GetQueryString("id")
if (
id &&
this.formData.courseList[index].conditionStructure &&
this.formData.courseList[index].conditionStructure.conditions.length > 0
) {
this.conditionStructure = this.formData.courseList[index].conditionStructure
} else {
this.conditionStructure = {
method: "AND",
conditions: [{}]
}
}
this.userScopeIndex = index
this.$refs.joinCnd.open()
},
cancel() {
this.$store.dispatch("pjaxRoute", "/platform/trainSingUp/manage/activity")
},
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", "全部教职工")
}
},
//添加培训班
addCourse() {
this.formData.courseList.push({ courseTimeList: [], isMobileSign: false, isReceiveGift: false, reserveMode: 1 })
},
//删除培训班
async removeTableCourse(index) {
const confirm = await this.$confirm(
"请确认是否删除此" + this.trainType + "?如果该" + this.trainType + "已有报名人员,会随之一起删除!确定吗?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
)
if (confirm) {
this.formData.courseList.splice(index, 1)
}
},
//培训日期change
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
}
},
//打开设置课程时间
openSetUpCourseTime(index) {
if (!this.formData.activityTime || this.formData.activityTime.length === 0) {
this.$message.warning("请先设置活动起止时间")
return
}
this.courseIndex = index
this.setUpCourseDialog = true
},
//打开设置分工会人数限制
async openSetUpUnionLimit(index) {
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/trainSingUp/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
/*if (this.formData.courseList[this.unionLimitIndex].unionLimit) {
const totalLimit = this.formData.courseList[this.unionLimitIndex].unionLimit.map(v => v.limitCount).reduce((a, b) => a + b)
console.log(totalLimit)
this.formData.courseList[this.unionLimitIndex].coursePeopleNumber = totalLimit
}*/
},
//应用比例设置
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
}
},
openMap(index) {
this.mapIndex = index
this.mapDialog = true
},
//删除一行培训时间记录
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"))
})
},
courseOrderNumChange() {
this.formData.courseList = this.formData.courseList.sort((a, b) => a.orderNum - b.orderNum)
},
//提交
async doHandle(flag) {
if (flag === false) {
let valid = false
this.$refs.form.validateField("activityName", (errMsg) => {
valid = errMsg === ""
})
if (!valid) {
this.$message.warning("请输入活动名称")
return
}
} else {
const valid = await this.$refs["form"].validate()
if (!valid) {
this.$message.warning("存在必填项未填写")
return
}
const courseValid = this.formData.courseList.some((v, i) => {
const basicValid = v.courseName && v.campus && 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) + "行" + this.trainType + "时间填写有误,请核查!")
return true
}
if (!basicValid) {
this.$message.warning("第" + (i + 1) + "行" + this.trainType + "信息填写有误,请核查!")
return true
}
if (
v.isMobileSign === true &&
v.signType === 3 &&
(v.courseLocationCoordinates === undefined || v.courseLocationCoordinates.length < 2)
) {
this.$message.warning("第" + (i + 1) + "行" + this.trainType + "地点坐标填写有误,请核查!")
return true
}
if (v.isMobileSign === true && v.signType === 3 && (v.signType === "" || v.signType === undefined)) {
this.$message.warning("第" + (i + 1) + "行" + this.trainType + "签到方式填写有误,请核查!")
return true
}
if (v.isReceiveGift === true && (v.giftType === "" || v.giftType === undefined)) {
this.$message.warning("第" + (i + 1) + "行" + this.trainType + "领取方式填写有误,请核查!")
return true
}
return false
})
if (courseValid) {
return
}
if (this.formData.restrictLimit === 2) {
if (this.formData.typeLimits.length === 0) {
this.$message.warning("请设置报名限制!")
return
}
}
}
const cloneData = clone(this.formData)
//cloneData.conditionStructure.conditions = cloneData.conditionStructure.conditions.filter(v => v.field && v.fieldObj && v.operational && v.value)
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()
}
/*const limitNumArray = []
this.formData.typeLimits.forEach(item => {
limitNumArray.push({
typeId: item.id,
limitNum: item.limitNum
})
})*/
const limitNumArray = []
this.formData.typeLimits.forEach((item) => {
if (item.typeId === "" || item.typeId === undefined) {
limitNumArray.push({
typeId: item.id,
limitNum: item.limitNum
})
} else {
limitNumArray.push(item)
}
})
cloneData.typeLimits = limitNumArray
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/doHandle", { data: JSON.stringify(cloneData) })
if (resp.code === 0) {
const message = this.$message.success(resp.msg)
setTimeout(() => {
this.$store.dispatch("pjaxRoute", "/platform/trainSingUp/manage/activity")
message.close()
}, 500)
}
},
async initData() {
const id = GetQueryString("id")
if (id) {
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/findOne", { id: id })
if (resp.code === 0) {
this.formData = resp.data
const type = this.trainTypeList.find((o) => o.code === this.formData.trainType)
this.trainType = type ? type.name : "培训班"
this.formData.courseList.forEach((item) => {
const type = this.courseTypeList.find((o) => o.id === item.courseType)
if (type !== null && type !== undefined) {
if (type.isBringFamily === true) {
this.$set(item, "isBringFamily", true)
item.reserveMode = 1
} else {
this.$set(item, "isBringFamily", false)
}
}
})
}
} else {
}
},
oneKeySetStartEndTime() {
const { startTime, endTime } = this.courseTimeOneKeySet
this.formData.courseList[this.courseIndex].courseTimeList.forEach((v) => {
this.$set(v, "courseStartTime", startTime)
this.$set(v, "courseEndTime", endTime)
// if (!v.courseStartTime) {
// v.courseStartTime = startTime
// }
// if (!v.courseEndTime) {
// v.courseEndTime = endTime
// }
})
this.$forceUpdate()
},
doBack() {
if (GetQueryString("id") !== "") {
this.$store.dispatch("pjaxRoute", "/platform/trainSingUp/manage/activity")
}
},
async validNumber(row, old) {
if (GetQueryString("id") === "") {
if (row.courseReservedNumber > row.coursePeopleNumber && row.reserveMode === 1) {
this.$alert("预留人数不能大于" + this.trainType + "人数!", "提示", {
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.trainType +
"人数为" +
row.coursePeopleNumber +
"人,当前报名人数为" +
registerUserCount +
"人,预留名额上限为" +
num +
"人!"
this.$alert(str, "提示", {
confirmButtonText: "确定"
})
row.courseReservedNumber = 0
}
}
}
},
//获取培训班报名人数
async getRegisterUserCount(courseId) {
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/getRegisterUserCount", { courseId })
return resp.code === 0 ? resp.data : 0
},
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.trainType + "信息中选择类型!")
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.lxname = type.lxname
arr.push(t)
} else {
item.limitNum = 0
arr.push(item)
}
})
this.formData.typeLimits = arr
/*if (GetQueryString("id") === '' || this.formData.typeLimits.length === 0) {
const array = [...new Set(this.formData.courseList.map(o => o.courseType))]
this.formData.typeLimits = clone([...this.courseTypeList].filter(x => array.some(y => x.id === y)))
} else {
this.formData.typeLimits.forEach(item => {
const type = this.courseTypeList.find(o => o.id === item.typeId)
item.code = type.code
item.lxname = type.lxname
})
}*/
this.signUpDialog = true
} else {
this.$message.warning("请在" + this.trainType + "信息中选择类型!")
}
},
doLimitNum() {
/* const courseValid = this.formData.typeLimits.some((item, index) => {
if(item.limitNum === 0) {
this.$notify({title: '警告', type: 'warning', message: '第'+ (index + 1) +'行限制个数不能为0'});
return true
}
return false
})
if(courseValid) {
return
}*/
this.signUpDialog = false
},
cancelLimitNum() {
//this.formData.typeLimits.forEach(item => item.limitNum = 0)
this.signUpDialog = false
},
async getAllType() {
const resp = await this.$axios.post("/platform/trainSingUp/manage/type/getAllType", {})
return resp.data
},
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)
}
},
typeChange(val) {
const type = this.trainTypeList.find((o) => o.code === val)
this.trainType = type ? type.name : ""
},
async getHistoricalActList() {
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/getHistoricalActList", {})
return resp.data
},
async historicalActChange(val) {
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/findOne", { id: val })
if (resp.code === 0) {
this.formData = resp.data
const type = this.trainTypeList.find((o) => o.code === this.formData.trainType)
this.trainType = type ? type.name : "培训班"
this.formData.courseList.forEach((item) => {
const type = this.courseTypeList.find((o) => o.id === item.courseType)
if (type.isBringFamily === true) {
this.$set(item, "isBringFamily", true)
item.reserveMode = 1
} else {
this.$set(item, "isBringFamily", false)
}
})
this.formData.id = ""
}
},
async getActivityGroup() {
const { data } = await this.$axios.post("/platform/activity/basic/scope/getActivityUserScopeGroup")
return data
}
},
async created() {
this.unionList = await this.$businessTool.listUnion()
this.courseTypeList = await this.getAllType()
this.$businessTool.getDictOptions("TRAIN_SIGNUP_TYPE").then((data) => {
this.trainTypeList = data
})
await this.initData()
this.activityGroupList = await this.getActivityGroup()
this.$businessTool.getDictOptions("CAMPUS").then((data) => {
this.campusList = data
})
this.historicalActList = await this.getHistoricalActList()
},
watch: {
"formData.restrictLimit"(val) {
if (GetQueryString("id") === "") {
this.formData.limitNum = val === 3 ? 1 : ""
}
},
"formData.activityGroupId": {
async handler(newVal, oldVal) {
this.activityGroupList = await this.getActivityGroup()
this.$refs.drawerUserScope.userScopeDialog = false
},
deep: true
},
conditionStructure(val) {
this.formData.courseList[this.userScopeIndex].conditionStructure = val
}
}
})
</script>
<!--#
}
#-->
@@ -1,108 +1,28 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.text {
font-size: 14px;
}
.e-item {
margin-bottom: 18px;
}
.reserve_btn {
font-size: 15px;
float: right;
padding: 3px 0;
}
.el-carousel__button {
background-color: #c0c4cc;
}
.el-carousel__container {
height: 260px;
}
.el-button--mini.is-circle {
padding: 5px;
font-size: 1px;
}
.slider {
position: relative;
}
.el-slider__marks-text {
min-width: 40px !important;
}
.el-slider__button-wrapper {
display: none !important;
}
input[type="file"] {
display: none;
}
.el-input-number input {
text-align: left !important;
}
.el-input-number__decrease,
.el-input-number__increase {
display: none;
}
.el-transfer-panel {
text-align: left;
width: calc(50% - 91px);
height: 53vh;
}
.el-transfer-panel__list.is-filterable {
height: calc(50vh - 110px);
}
.transfer {
display: flex;
height: 100%;
width: 100%;
align-items: center;
padding: 0 10px;
}
.transfer .el-checkbox {
display: inline-block !important;
margin: 0 10px !important;
}
.activeCard {
border: 1px solid #409eff;
}
.el-table-container {
padding-top: 0;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<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="activityData"
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="activityData">
<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>
@@ -110,485 +30,88 @@ layout("/layouts/platform.html"){
</search-item>
</search>
</el-card>
</el-card>
<el-row class="el-table-container">
<el-carousel v-if="activityList.length > 0" :interval="5000" arrow="always" style="margin: 10px auto">
<el-carousel-item v-for="index in Math.ceil(activityList.length/4)" :key="index">
<el-row :gutter="20">
<el-col v-for="(item, i) in activityList.slice((index-1)*4,index*4)" :key="i" :span="6">
<el-card
@click="openApply(item)"
:class="'box-card '+(item.id===pageForm.activityId?'activeCard':'')"
style="border-radius: 10px"
>
<div slot="header" class="clearfix" style="width: 100%; word-break: break-all; white-space: pre-wrap">
<div>{{item.activityName}}</div>
<!--<el-button @click="openApply(item)" class="reserve_btn" type="text">请选择活动报名</el-button>-->
</div>
<div @click="openApply(item)">
<div class="text e-item" style="display: flex; justify-content: space-between">
<div>
<div class="text e-item">
<span style="color: gray">活动性质:</span>
<span>{{item.trainType}}</span>
</div>
<div class="text e-item">
<span style="color: gray">报名时间:</span>
<span>
{{$moment(item.activitySignUpStartTime) .format('MM/DD HH:mm')}} 至
{{$moment(item.activitySignUpEndTime).format('MM/DD HH:mm')}}
</span>
</div>
<div class="text item">
<span style="color: gray">活动时间:</span>
<span>
{{$moment(item.activityStartTime).format('MM/DD HH:mm')}} 至
{{$moment(item.activityEndTime).format('MM/DD HH:mm')}}
</span>
</div>
</div>
<div>
<!-- <span style="color: gray">活动类型:</span>
<span>{{item.activityMode == 1 ? '校工会' : '分工会'}}</span>-->
<el-tag
type="danger"
effect="dark"
style="border-radius: 50%"
v-if="$moment(item.activitySignUpEndTime).valueOf() < $moment().valueOf()"
>
报名结束
</el-tag>
<el-tag
type="success"
effect="dark"
style="border-radius: 50%"
v-else-if="$moment().valueOf()>$moment(item.activitySignUpStartTime).valueOf()&&$moment().valueOf()<$moment(item.activitySignUpEndTime).valueOf()"
>
报名中
</el-tag>
<el-tag
type="danger"
effect="dark"
style="border-radius: 50%"
v-else-if="$moment().valueOf()<$moment(item.activitySignUpEndTime).valueOf()"
>
报名未开始
</el-tag>
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</el-carousel-item>
</el-carousel>
<el-empty v-else description="暂无数据"></el-empty>
</el-row>
<el-card shadow="never" class="mt10">
<table-tool :label="trainType + '信息'">
<template #label_end>
<div class="search-item-option">
<el-select
v-model="pageForm.courseTypeId"
:placeholder="'请选择' + trainType + '类型'"
filterable
clearable
style="width: 100%; margin-bottom: 5px; margin-left: 10px"
@change="doSearch"
>
<el-option v-for="item in courseTypeList" :key="item.id" :label="item.lxname" :value="item.id"></el-option>
</el-select>
</div>
</template>
</table-tool>
<el-table :data="tableData" row-key="id" @sort-change="pageOrder" v-loading="tableLoading">
<el-table-column type="index" :index="indexMethod" label="序号" width="80px"></el-table-column>
<el-table-column
v-for="(column, index) in tableColumns"
:key="column.prop"
<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
>
<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">点击查看{{trainType}}时间</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 align="center" label="操作" width="150px">
<template v-slot="scope">
<el-button v-if="!scope.row.isSign" type="primary" size="mini" @click="doApply(scope.row)">我要报名</el-button>
<el-button v-else type="danger" size="mini" @click="doCancel(scope.row)">取消报名</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<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>
<el-col :span="24">
<el-form-item
v-for="(column, index) in formData.trainMobileSignColumnList"
:prop="'trainMobileSignColumnList.' + 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 :files.sync="column.columnValue" :max="column.fileNumber" :type="column.fileType"></file-upload>
</template>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-row type="flex" justify="end">
<el-button type="primary" @click="doSubmit">提交</el-button>
</el-row>
</template>
<el-dialog :visible.sync="courseTimeListDialog" :title="trainType + '时间'" 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>
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="开始时间" 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 label="操作" width="100">
<template v-slot="{row}">
<el-button @click="onOpen(row)" size="mini" type="primary">去报名</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :visible.sync="viewMapDialog" title="地点" width="60%">
<div id="viewMap" style="width: 100%; height: 500px"></div>
</el-dialog>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
let viewMarker = null
<!--#include('info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"info": info,
},
data() {
return {
trainSignUpActivity: {},
pageForm: {
year: this.$moment().format("YYYY"),
activityType: "2"
},
activityList: [],
courseTypeList: [],
tableColumns: [
/* {prop: 'name', label: '活动名称'},*/
{ prop: "courseName", label: "名称" },
{ prop: "lxname", label: "类型" },
{ prop: "coursePeopleNumber", label: "总人数" },
{ prop: "courseLocationCoordinates", label: "地点" },
{ prop: "courseInstructor", label: "联系人" },
{ prop: "courseTime", label: "时间" },
{ prop: "applyNum", label: "已报名人数" }
{ label: "活动名称", prop: "activityName", width: 800},
{ label: "活动性质", prop: "trainType"},
{ label: "报名时间", prop: "activitySignUpStartTime"},
{ label: "活动时间", prop: "activityStartTime"},
],
viewMapDialog: false,
courseTimeListDialog: false,
courseTimeList: [],
formData: {},
formRules: {
mobile: [{ required: true, message: "必填", trigger: ["blur", "change"] }]
},
choose: {},
trainType: "培训班"
}
},
methods: {
async doCancel(row) {
this.$confirm("您确定要取消吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(async () => {
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/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)
onOpen(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
pageData() {
this.$axios.post("/platform/trainSingUp/manage/apply/activityData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
calcSignUpCount(o) {
if (o.reserveMode === 2) {
let lave = 0
let lave2 = 0
if (o.hasRegisterNum < o.coursePeopleNumber) {
lave = o.coursePeopleNumber - o.hasRegisterNum
lave2 = o.courseReservedNumber
} else {
lave = 0
lave2 = o.coursePeopleNumber + o.courseReservedNumber - o.hasRegisterNum
}
let str =
"<span style='color: red'>余" +
lave +
"</span>/" +
o.coursePeopleNumber +
"人" +
"<span style='color: red'>候补余" +
lave2 +
"</span>/" +
o.courseReservedNumber +
"人"
return str
} else {
if (o.coursePeopleNumber === 0) {
return "<span style='color: red'>已报" + o.hasRegisterNum + "</span>/不限"
} else {
let lave = o.coursePeopleNumber - (o.hasRegisterNum + o.courseReservedNumber)
return "<span style='color: red'>余" + lave + "</span>/" + o.coursePeopleNumber + "人"
}
}
},
async doSubmit() {
//获取家属是多少人
let per = 0
this.formData.trainMobileSignColumnList.forEach((item) => {
if (item.columnCode === "xdqsrs") {
per += Number(item.columnValue)
}
})
const res = await this.$axios.post("/platform/mobile/trainSignUpActivity/validateSignUp", {
courseId: this.choose.id,
currentFamilyNumber: per
})
if (res.code !== 0) {
this.$message.warning(res.msg)
return
}
this.$refs["form"].validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const mobileColumnsValue = this.formData.trainMobileSignColumnList.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/trainSignUpActivity/doSignUp", this.formData)
if (resp.code === 0) {
await this.pageData()
this.$message.success(resp.msg)
this.$refs.guava.index()
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
async getScopeUser(activityGroupId) {
const resp = await this.$axios.post("/platform/activity/basic/scope/getScopeUser", { activityGroupId: activityGroupId })
return resp.data
},
async doApply(row) {
this.choose = row
const o = this.courseTypeList.find((v) => v.id === row.courseType)
const data = this.trainSignUpActivity
const now = this.$moment().valueOf()
if (now < this.$moment(data.activitySignUpStartTime).valueOf() || now > this.$moment(data.activitySignUpEndTime).valueOf()) {
this.$message.warning("此活动不在报名时间内")
return
}
const scopeUser = await this.getScopeUser(data.activityGroupId)
if (scopeUser === 0) {
this.$message.warning("您不在活动报名范围内")
return
}
const res = await this.$axios.post("/platform/mobile/trainSignUpActivity/validateSignUp", {
courseId: row.id
})
if (res.code !== 0) {
this.$message.warning(res.msg)
if (res.code !== 3) {
return
}
}
this.formData = {
activityId: data.id,
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,
trainMobileSignColumnList: o.trainMobileSignColumnList
}
this.formData.trainMobileSignColumnList.forEach((item) => {
item.columnValue = ""
})
this.$refs.guava.edit()
this.$nextTick(() => {
this.$refs.form.clearValidate()
})
},
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])
})
},
async openApply(item) {
this.trainSignUpActivity = {}
this.trainSignUpActivity = item
this.pageForm.activityId = item.id
this.trainType = item.trainType
await this.pageData()
},
async getCourseTypeList() {
const resp = await this.$axios.post("/platform/trainSingUp/manage/type/getAllType")
if (resp.code === 0) {
this.courseTypeList = resp.data
}
},
async activityData() {
const resp = await this.$axios.post(loc() + "/activityData", this.pageForm)
if (resp.code === 0) {
this.activityList = resp.data
if (this.activityList.length > 0) {
await this.openApply(this.activityList[0])
}
} else {
this.$message.warning(resp.msg)
}
},
async pageData() {
const resp = await this.$axios.post(loc() + "/pageData", this.pageForm)
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
} else {
this.$message.warning(resp.msg)
}
},
async openViewCourseTime(id) {
const resp = await this.$axios.post(loc() + "/getCourseTime", { id: id })
this.courseTimeList = resp.data
this.courseTimeListDialog = true
}
},
async created() {
await this.activityData()
await this.getCourseTypeList()
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: ["TRAIN_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: [],
trainType: '',
}
},
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/trainSignUpActivity/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/trainSignUpActivity/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/trainSingUp/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,213 @@
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="80px">
<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.trainMobileSignColumnList"
:prop="'trainMobileSignColumnList.' + 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: ["TRAIN_SIGNUP_TYPE"],
data() {
return {
signDialog: false,
formData: {},
courseRow: {},
courseTimeSelectList: [],
}
},
methods: {
async getCourseTimeSelectList(o) {
const resp = await $.post('/platform/mobile/trainSignUpActivity/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.trainMobileSignColumnList.forEach((item) => {
if (item.columnCode === "xdqsrs") {
per += Number(item.columnValue)
}
})
const res = await this.$axios.post("/platform/mobile/trainSignUpActivity/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 $.post('/platform/mobile/trainSignUpActivity/validateSourceSignUp', {activityCourseId: this.formData.activityCourseId})
if (resp.code !== 0) {
this.$message.warning(res.msg)
return
}
}
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const mobileColumnsValue = this.formData.trainMobileSignColumnList.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/trainSignUpActivity/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,
trainMobileSignColumnList: course.trainMobileSignColumnList
}
this.formData.trainMobileSignColumnList.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="trainType + '通知'" 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="trainType" :rules="{required:true,message: '请选择活动类型', trigger: 'blur'}">
<el-select @change="typeChange" filterable placeholder="请选择活动类型" style="width: 100%" v-model="formData.trainType">
<el-option :label="item.name" :value="item.code" :key="item.code" v-for="item in dict.type.TRAIN_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>{{trainType + '信息(温馨提示:如不需要人数限制,下方人数框填写0或者不填)'}}</div>
<div>
<el-button @click="addCourse" size="mini" type="primary">添加{{ trainType }}</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="trainType + '名称'" prop="courseName">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseName" :placeholder="'请输入' + trainType + '名称'"></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="trainType + '人数'" 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="trainType + '地点'" prop="courseLocation">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseLocation" :placeholder="'请输入' + trainType + '地点'"></el-input>
</template>
</el-table-column>
<el-table-column :label="trainType + '负责人'" prop="courseInstructor">
<template v-slot="{row}">
<el-input size="small" v-model="row.courseInstructor" :placeholder="'请输入' + trainType + '负责人'"></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="trainType + '时间'">
<template v-slot="scope">
<el-button @click="openSetUpCourseTime(scope.$index)" type="text">设置{{ trainType }}时间</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", "TRAIN_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: [],
trainTypeList: [],
trainType: "培训班",
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.trainType + "人数!", "提示", {
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.trainType +
"人数为" +
row.coursePeopleNumber +
"人,当前报名人数为" +
registerUserCount +
"人,预留名额上限为" +
num +
"人!"
this.$alert(str, "提示", {
confirmButtonText: "确定"
})
row.courseReservedNumber = 0
}
}
}
},
async getRegisterUserCount(courseId) {
const resp = await this.$axios.post("/platform/trainSingUp/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.trainType + "信息中选择类型!")
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.trainType + "信息中选择类型!")
}
},
doLimitNum() {
this.signUpDialog = false
},
openMoreInfo(row, index) {
this.$refs.customFormRef.onOpen(this.formData, row, index)
},
async removeTableCourse(index) {
const confirm = await this.$confirm(
"请确认是否删除此" + this.trainType + "?如果该" + this.trainType + "已有报名人员,会随之一起删除!确定吗?",
"提示",
{
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/trainSingUp/manage/activity/findOne", {id: val})
if (resp.code === 0) {
this.formData = resp.data
this.typeChange(this.formData.trainType)
this.formData.id = ""
}
},
typeChange(val) {
const type = this.dict.type.TRAIN_SIGNUP_TYPE.find(o => o.code === val)
this.trainType = 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/trainSingUp/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/trainSingUp/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/trainSingUp/manage/type/getAllType", {})
return resp.data
},
async init(row) {
if (row && row.id) {
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/findOne", {id: row.id})
if (resp.code === 0) {
this.formData = resp.data
this.typeChange(this.formData.trainType)
}
}
},
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: ["TRAIN_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: ["TRAIN_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;
}
`
}
@@ -1,51 +0,0 @@
<el-tabs>
<el-tab-pane label="基础信息">
<el-descriptions :column="2" border class="table_fixed">
<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="trainType + '信息'">
<el-table :data="viewData.courseList">
<el-table-column :label="trainType + '名称'" 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">
<template v-slot="scope">
<dict-tag :options="dict.type.CAMPUS" :value="scope.row.campus"></dict-tag>
</template>
</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" type="text">点击查看课程时间</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
<el-dialog :visible.sync="courseTimeListDialog" :title="trainType + '时间'" 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>
</el-dialog>
<el-dialog :visible.sync="viewMapDialog" title="地点" width="60%">
<div id="viewMap" style="width: 100%; height: 500px"></div>
</el-dialog>
@@ -1,113 +1,87 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.table_fixed {
table-layout: fixed !important;
}
.map-search {
margin-bottom: 1rem;
border-radius: 0.25rem;
position: absolute;
top: 1rem;
background-color: white;
width: auto;
min-width: 22rem;
border-width: 0;
right: 1rem;
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, 0.5);
}
.map-search .input-item {
position: relative;
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-ms-flex-align: center;
align-items: center;
width: 100%;
height: 3rem;
}
<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%"
v-model="pageForm.year"
value-format="yyyy"
@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"
@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">新建活动</el-button>
<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"
:sortable="column.sortable"
show-overflow-tooltip
v-for="(column, index) in tableColumns"
:key="index"
: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'">
<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"
: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 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==='notice'">
<el-switch
:active-value="true"
:inactive-value="false"
@change="(val)=>{activityNoticeChange(row.isDisabled,val,row.id)}"
active-color="#13ce66"
inactive-color="#ff4949"
v-model="row.notice"
></el-switch>
<template v-slot="{ row }" v-else-if="column.prop === 'activityTime'">
<span>{{ $moment(row.activityStartTime).format('MM/DD') }}</span>
<span></span>
<span>{{ $moment(row.activityEndTime).format('MM/DD') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="150px">
<template v-slot="{row}">
<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="openCode(row.id)">活动二维码</el-dropdown-item>
<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="sendMsg(row)">通知</el-dropdown-item>-->
<el-dropdown-item @click.native="openView(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="deleteDo(row)">删除</el-dropdown-item>
<el-dropdown-item @click.native="onDelete(row)">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
@@ -116,126 +90,87 @@ layout("/layouts/platform.html"){
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<!--#include("/platform/zhgh/activity/trainSingUp/manage/include_activity_view.html"){}#-->
<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>
<el-dialog :close-on-click-modal="false" :visible.sync="courseDialog" :title="trainType + '列表'" top="50px">
<el-table :data="clickRow.courseList">
<el-table-column :label="trainType + '名称'" prop="courseName"></el-table-column>
<el-table-column label="校区" prop="campus">
<template v-slot="scope">
<dict-tag :options="dict.type.CAMPUS" :value="scope.row.campus"></dict-tag>
</template>
</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">该{{trainType}}的签到方式不支持生成二维码</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!--<send-msg ref="sendMsg" :url="url"></send-msg>-->
<!--<open-qr-code ref="openQRCode" :url="url"></open-qr-code>-->
</div>
<script>
let viewMap = null
let viewMarker = null
<!--#include('info.js'){}#-->
<!--#include('basicForm.js'){}#-->
<!--#include('makeQrcode.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["CAMPUS", "TRAIN_SIGNUP_TYPE"],
mixins: [initTableMixins],
dicts: ["CAMPUS"],
components: {
"info": info,
"basic-form": basicForm,
"make-qrcode": makeQrcode,
},
data() {
const that = this
return {
url: "",
courseDialog: false,
trainType: "",
trainTypeList: [],
campusList: [],
pageForm: {
year: new Date().getFullYear() + ''
},
tableColumns: [
{ label: "活动名称", prop: "activityName" },
{ label: "年度", prop: "year" },
{ label: "开始时间", prop: "activityStartTime" },
{ label: "结束时间", prop: "activityEndTime" },
{ label: "是否开启", prop: "isDisabled" },
{ label: "是否通知", prop: "notice" },
{ label: "活动名称", prop: "activityName", width: 800 },
{ label: "活动时间", prop: "activityTime" },
{ label: "是否开启", prop: "isDisabled", width: 100 },
{ label: "创建时间", prop: "createdAt" }
],
viewData: {},
mapDialog: false,
mapIndex: 0,
courseTimeListDialog: false,
courseTimeList: [],
viewMapDialog: false,
clickRow: {}
codeDialogVisible: false,
activityUrl: '',
}
},
components: {
/*"open-qr-code": httpVueLoader("/components/plugins/OpenQRCode.vue"),
"send-msg": httpVueLoader("/components/plugins/SendMsgByGroupId.vue")*/
},
methods: {
sendMsg(row) {
this.url = `<a href="` + (APP_DOMAIN + "/platform/mobile/trainSignUpActivity/trainList") + `">点击参与</a>`
this.$refs.sendMsg.openDialog(row.activityGroupId)
},
openCode(id) {
this.$refs.openQRCode.openCode("/platform/mobile/trainSignUpActivity/trainList")
},
makeCode(row) {
this.clickRow = row
const type = this.trainTypeList.find((o) => o.code === row.trainType)
this.trainType = type ? type.name : "培训班"
this.courseDialog = true
},
makeCourseCode(row) {
const o = {
courseId: row.id
}
// 生成二维码的 base64 编码
const content = jrQrcode.getQrBase64(JSON.stringify(o))
let image = new Image()
image.src = content
let viewer = new Viewer(image)
viewer.show()
back() {
this.$refs.guava.index()
},
openAdd() {
this.$store.dispatch("pjaxRoute", "/platform/trainSingUp/manage/activity/add")
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/trainSignUpActivity/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) {
@@ -244,97 +179,23 @@ layout("/layouts/platform.html"){
this.$message.warning(resp.msg)
}
},
async activityNoticeChange(isDisabled, val, id) {
const resp = await this.$axios.post(loc() + "/activityStatusChange", { isDisabled: isDisabled, notice: val, id })
if (resp.code === 0) {
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
},
async openEdit(row) {
this.$store.dispatch("pjaxRoute", "/platform/trainSingUp/manage/activity/add?id=" + row.id + "&fromEdit=edit")
},
async deleteDo(row) {
const confirm = await this.$confirm("此操作将永久删除, 是否继续?", "提示", {
async onDelete(row) {
this.$confirm("此操作将永久删除, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
if (confirm === "confirm") {
const resp = await this.$axios.post(loc() + "/doDelete", { id: row.id })
}).then(async () => {
const resp = await this.$axios.post(loc() + "/onDelete", { id: row.id })
this.$message.success(resp.msg)
this.doSearch()
}
}).catch(() => {})
},
async openView(row) {
const { id } = row
const resp = await this.$axios.post(loc() + "/findOne", { id: id })
if (resp.code === 0) {
let cloneData = clone(resp.data)
cloneData.campusList = new Set(cloneData.courseList.map((v) => v.campus))
this.viewData = cloneData
const type = this.trainTypeList.find((o) => o.code === cloneData.trainType)
this.trainType = type ? type.name : "培训班"
this.$refs["guava"].view()
}
},
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])
})
},
getAddress(position) {
// if (!geocoder) {
// geocoder = new AMap.Geocoder({
// city: "010", //城市设为北京,默认:“全国”
// radius: 1000 //范围,默认:500
// });
// }
// geocoder.getAddress(position, (status, result) => {
// if (status === 'complete' && result.regeocode) {
// const address = result.regeocode.formattedAddress
// this.formData.courseList[this.mapIndex].location = address
// } else {
// log.error('根据经纬度查询地址失败')
// }
// })
},
openViewCourseTime(courseTimeList) {
this.courseTimeList = courseTimeList
this.courseTimeListDialog = true
}
},
async created() {
this.pageData()
this.$businessTool.getDictOptions("TRAIN_SIGNUP_TYPE").then((data) => {
this.trainTypeList = data
})
this.$businessTool.getDictOptions("CAMPUS").then((data) => {
this.campusList = data
})
}
})
</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="trainType + '信息'">
<el-table :data="viewData.courseList" class="mt20">
<el-table-column :label="trainType + '名称'" 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="trainType + '时间'" 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: ["TRAIN_SIGNUP_TYPE"],
data() {
return {
trainType: '',
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.TRAIN_SIGNUP_TYPE.find((o) => o.code === resp.data.trainType)
this.trainType = 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="trainType + '列表'" width="60%">
<el-table :data="courseList">
<el-table-column :label="trainType + '名称'" 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">{{trainType}}的签到方式不支持生成二维码</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: ["TRAIN_SIGNUP_TYPE"],
data() {
return {
courseDialog: false,
trainType: "",
courseList: [],
}
},
methods: {
initData(row) {
this.courseList = row.courseList
const type = this.dict.type.TRAIN_SIGNUP_TYPE.find((o) => o.code === row.trainType)
this.trainType = 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: ["TRAIN_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/trainSingUp/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*/ `
`
}
@@ -1,65 +0,0 @@
<el-tabs>
<el-tab-pane label="报名人员">
<el-table :data="registerUserTableData" :size="tableSize" 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">
<!-- <el-timeline>-->
<!-- <el-timeline-item-->
<!-- :color="item.length>0 && Date.now() > Date.parse(item[0].courseStartTime) ? '#0bbd87' :''"-->
<!-- :key="key"-->
<!-- :timestamp="key"-->
<!-- placement="top"-->
<!-- v-for="(item, key) in userSignInfo">-->
<!-- <el-table :data="item">-->
<!-- <el-table-column label="姓名" prop="username"></el-table-column>-->
<!-- <el-table-column label="一卡通号" prop="loginname"></el-table-column>-->
<!-- <el-table-column label="是否签到" prop="isAttend"></el-table-column>-->
<!-- <el-table-column label="签到时间" prop="attendTime"></el-table-column>-->
<!-- </el-table>-->
<!-- </el-timeline-item>-->
<!-- </el-timeline>-->
<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>
@@ -42,18 +42,20 @@ layout("/layouts/platform.html"){
<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.courseReservedNumber}}</span>
<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="coursePeopleNumber" sortable show-overflow-tooltip></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 v-if="row.reserveMode === 1" @click="openView(row)" type="primary">
{{row.registerNum + row.courseReservedNumber}}
<el-link @click="openView(row)" type="primary">
{{row.registerNum}}
</el-link>
<el-link v-if="row.reserveMode === 2" @click="openView(row)" type="primary">{{row.registerNum}}</el-link>
</template>
</el-table-column>
<el-table-column label="操作" width="200px">
@@ -69,15 +71,20 @@ layout("/layouts/platform.html"){
</el-card>
<template #view>
<!--#include("/platform/zhgh/activity/trainSingUp/statistics/include_view.html"){}#-->
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('info.js'){}#-->
new Vue({
el: "#app",
dicts: ["TRAIN_SIGNUP_TYPE"],
mixins: [initTableMixins],
components: {
"info": info,
},
data() {
return {
activityList: [],
@@ -93,20 +100,7 @@ layout("/layouts/platform.html"){
{ label: "最多报名人数", prop: "coursePeopleNumber", sortable: true },
{ label: "已报名人数", prop: "registerNum", sortable: true }
],
registerUserTableData: [],
registerUserTableColumns: [
{ label: "姓名", prop: "username" },
{ label: "一卡通号", prop: "loginname" },
{ label: "单位", prop: "unitName" },
{ label: "分工会", prop: "unionName" },
{ label: "联系方式", prop: "mobile" },
{ label: "报名时间", prop: "signUpTime" },
{ label: "报名状态", prop: "state" }
],
userSignInfo: {},
trainType: "培训班",
trainTypeList: [],
clickRow: {}
}
},
methods: {
@@ -121,8 +115,8 @@ layout("/layouts/platform.html"){
},
activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.trainTypeList.find((o) => o.code === activity.trainType)
this.trainType = type ? type.name : "培训班"
const type = this.dict.type.TRAIN_SIGNUP_TYPE.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
},
exportSignUser() {
this.$downLoad(loc() + "/exportSignUser", { activityId: this.pageForm.activityId })
@@ -137,26 +131,19 @@ layout("/layouts/platform.html"){
this.activityList = resp.data
if (this.activityList && this.activityList.length > 0) {
this.pageForm.activityId = this.activityList[0].id
const type = this.trainTypeList.find((o) => o.code === this.activityList[0].trainType)
this.trainType = type ? type.name : "培训班"
this.activityChange(this.activityList[0].id)
}
},
async initData() {
await this.getActivityList()
},
async openView(row) {
this.clickRow = row
this.$refs.guava.view()
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
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
}
},
async created() {
this.$businessTool.getDictOptions("TRAIN_SIGNUP_TYPE").then((data) => {
this.trainTypeList = data
})
await this.initData()
await this.pageData()
}
@@ -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: ["TRAIN_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.trainMobileSignColumnList.push({isRequired: false})"
size="small"
type="primary"
style="margin-left: 10px"
>
<i class="ti-plus"></i>
添加
</el-button>
</div>
</div>
<el-table :data="formData.trainMobileSignColumnList">
<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.trainMobileSignColumnList.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: ["TRAIN_SIGNUP_TYPE"],
data() {
return {
formData: {
trainMobileSignColumnList: [{ 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.trainMobileSignColumnList.unshift({
columnName: "携带亲属人数",
columnCode: "xdqsrs",
columnFormType: "INPUT",
columnType: "INT",
isRequired: true
})
} else {
this.formData.trainMobileSignColumnList.forEach((item, index) => {
if (item.columnCode === "xdqsrs" && this.formData.isBringFamily === false) {
this.formData.trainMobileSignColumnList.splice(index, 1)
}
})
}
},
columnFormTypeChange(val, index) {
if (val === "FILE") {
this.formData.trainMobileSignColumnList[index].columnType = "JSON"
this.formData.trainMobileSignColumnList[index].isDisabled = true
} else {
this.formData.trainMobileSignColumnList[index].columnType = ""
this.formData.trainMobileSignColumnList[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.trainMobileSignColumnList.map((item) => item.columnCode)).size
const listLength = this.formData.trainMobileSignColumnList.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.trainMobileSignColumnList.map((item) => item.columnCode)).size
const listLength = this.formData.trainMobileSignColumnList.length
if (listLength > newListLength) {
this.$message.warning('字段编码不能重复')
return
}
const cloneData = clone(this.formData)
cloneData.trainMobileSignColumnList = JSON.stringify(cloneData.trainMobileSignColumnList)
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.trainMobileSignColumnList.forEach((item) => {
item.isDisabled = item.columnFormType === "FILE"
})
} else {
this.formData = {
trainMobileSignColumnList: [{ 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*/ `
`
}
@@ -1,57 +0,0 @@
<el-form 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>
@@ -7,7 +7,7 @@ layout("/layouts/platform.html"){
justify-content: left;
}
.el-drawer__body {
padding: 0px 30px 0px 10px;
padding: 0 30px 0 10px;
}
</style>
@@ -17,7 +17,7 @@ layout("/layouts/platform.html"){
<el-card shadow="never">
<search @search="doSearch">
<search-item label="类型名称:">
<el-input clearable placeholder="请输入类型名称" v-model="pageForm.lxname"></el-input>
<el-input clearable placeholder="请输入类型名称" v-model="pageForm.typeName"></el-input>
</search-item>
</search>
</el-card>
@@ -36,23 +36,13 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
<el-table-column label="类型编码" prop="code" sortable></el-table-column>
<el-table-column label="类型名称" prop="lxname"></el-table-column>
<el-table-column label="操作" width="150px">
<template v-slot="scope">
<el-dropdown @command="dropdownCommand">
<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 :command="{type:'top',data:scope.row}" v-if="scope.row.xh!==1">上移</el-dropdown-item>
<el-dropdown-item :command="{type:'edit',data:scope.row}">编辑</el-dropdown-item>
<el-dropdown-item :command="{type:'delete',data:scope.row}">删除</el-dropdown-item>
<el-dropdown-item :command="{type:'bottom',data:scope.row}" v-if="scope.row.xh!==pageForm.totalCount">
下移
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<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>
@@ -61,246 +51,23 @@ layout("/layouts/platform.html"){
</template>
<template #edit>
<div class="left-span-label">基础信息</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="lxname" label="类型名称">
<el-input v-model="formData.lxname" 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>
<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.trainMobileSignColumnList.push({isRequired: false})"
size="small"
type="primary"
style="margin-left: 10px"
>
添加
</el-button>
</div>
</div>
<el-table :data="formData.trainMobileSignColumnList">
<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="请输入字段名称"
:disabled="formData.isBringFamily === true && row.columnCode === 'xdqsrs'"
></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)}"
:disabled="formData.isBringFamily === true && row.columnCode === 'xdqsrs'"
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"
:disabled="row.isDisabled || (formData.isBringFamily === true && row.columnCode === 'xdqsrs')"
>
<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"
:disabled="formData.isBringFamily === true && row.columnCode === 'xdqsrs'"
: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.trainMobileSignColumnList.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="$refs.guava.index()">取 消</el-button>
<el-button type="primary" @click="doHandle">确 定</el-button>
</div>
<basic-form ref="basicFormRef" @refresh="doSearch();$refs.guava.index()"></basic-form>
</template>
</guava>
<el-drawer :visible.sync="detailedParamsVisible" size="40%">
<template #title>
<div class="left-span-label">设置详细参数</div>
</template>
<!--#include("/platform/zhgh/activity/trainSingUp/type/include_signUp_edit.html"){}#-->
</el-drawer>
</div>
<script>
<!--#include('basicForm.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
},
data() {
return {
form: {},
detailedParamsVisible: false,
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
lxname: ""
},
formData: {
trainMobileSignColumnList: [{ isRequired: false }],
isBringFamily: false,
isAddFamily: null
},
rules: {
lxname: [{ 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"] }]
},
tableData: [],
columnTypeOptions: [],
columnFormTypeList: [],
clickRow: {},
paramFormRules: {
selectValues: [{ required: true, message: "请选择选项列表", trigger: ["blur"] }],
fileType: [{ required: true, message: "请选择文件类型", trigger: ["blur"] }],
fileNumber: [{ required: true, message: "请输入文件个数", trigger: ["blur", "change"] }]
},
choose: {}
}
return {}
},
methods: {
isBringFamilyInput(o) {
this.$set(this.formData, "isAddFamily", o === true ? false : null)
if (o === true) {
this.formData.trainMobileSignColumnList.unshift({
columnName: "携带亲属人数",
columnCode: "xdqsrs",
columnFormType: "INPUT",
columnType: "INT",
isRequired: true
})
} else {
this.formData.trainMobileSignColumnList.forEach((item, index) => {
if (item.columnCode === "xdqsrs" && this.formData.isBringFamily === false) {
this.formData.trainMobileSignColumnList.splice(index, 1)
}
})
}
},
columnFormTypeChange(val, index) {
if (val === "FILE") {
this.formData.trainMobileSignColumnList[index].columnType = "JSON"
this.formData.trainMobileSignColumnList[index].isDisabled = true
} else {
this.formData.trainMobileSignColumnList[index].columnType = ""
this.formData.trainMobileSignColumnList[index].isDisabled = false
}
},
doHandle() {
if (this.choose.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()
},
dropdownCommand(command) {
const { type, data } = command
if (type == "top") {
this.rowChange(data, false)
} else if (type == "edit") {
this.openEdit(data)
} else if (type == "delete") {
this.doDelete(data.id)
} else if (type == "bottom") {
this.rowChange(data, true)
}
},
async rowChange(row, toDown) {
await this.$axios.post(loc() + "/xhChange", { id: row.id, xh: row.xh, toDown }).then((res) => {
if (res.code === 0) {
@@ -309,34 +76,8 @@ layout("/layouts/platform.html"){
})
},
openAdd() {
this.choose = {}
this.formData = {
trainMobileSignColumnList: [{ isRequired: false }],
isBringFamily: false
}
this.$refs.guava.edit()
if (this.$refs["addForm"]) this.$refs["addForm"].resetFields()
},
async doAdd() {
this.$refs["addForm"].validate((valid) => {
if (valid) {
const newListLength = new Set(this.formData.trainMobileSignColumnList.map((item) => item.columnCode)).size
const listLength = this.formData.trainMobileSignColumnList.length
if (listLength > newListLength) {
this.$notify.warning({ title: "警告", message: "字段编码不能重复!" })
return
}
const cloneData = clone(this.formData)
this.$axios.post(loc() + "/doAdd", { data: JSON.stringify(cloneData) }).then((res) => {
if (res.code === 0) {
this.pageData()
this.$refs.guava.index()
this.$message.success(res.msg)
} else {
this.$message.error(res.msg)
}
})
}
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.initData()
})
},
pageData() {
@@ -347,47 +88,13 @@ layout("/layouts/platform.html"){
}
})
},
doSearch() {
this.pageForm.pageNumber = 1
this.pageData()
},
pageNumberChange(val) {
this.pageForm.pageNumber = val
this.pageData()
},
openEdit(obj) {
this.choose = obj
this.formData = JSON.parse(JSON.stringify(obj))
this.formData.trainMobileSignColumnList.forEach((item) => {
item.isDisabled = item.columnFormType === "FILE"
})
this.$refs.guava.edit()
},
doEdit() {
this.$refs["addForm"].validate((valid) => {
if (valid) {
const newListLength = new Set(this.formData.trainMobileSignColumnList.map((item) => item.columnCode)).size
const listLength = this.formData.trainMobileSignColumnList.length
if (listLength > newListLength) {
this.$notify.warning({ title: "警告", message: "字段编码不能重复!" })
return
}
const cloneData = clone(this.formData)
cloneData.trainMobileSignColumnList = JSON.stringify(cloneData.trainMobileSignColumnList)
this.$axios.post(loc() + "/doEdit", cloneData).then((res) => {
if (res.code === 0) {
this.pageData()
this.$refs.guava.index()
this.$message.success(res.msg)
} else {
this.$message.error(res.msg)
}
})
}
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.initData(obj)
})
},
doDelete(id) {
this.$confirm("此操作将删除类型,确认删除吗?", "提示", {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
@@ -402,18 +109,8 @@ layout("/layouts/platform.html"){
})
.catch(() => {})
},
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
}
},
async created() {
await this.getColTypeOptions()
this.columnFormTypeList = await this.getEnumOptions()
this.pageData()
}
})
@@ -3,14 +3,7 @@ layout("/layouts/platform.html"){
#-->
<style>
.adjustDialog .el-radio__label {
display: none;
}
.adjustDialog .el-dialog__body {
max-height: 600px;
overflow-y: auto;
}
</style>
<div id="app" v-cloak>
@@ -49,18 +42,20 @@ layout("/layouts/platform.html"){
></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.courseReservedNumber}}</span>
<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="coursePeopleNumber" sortable show-overflow-tooltip></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 v-if="row.reserveMode === 1" @click="openView(row)" type="primary">
{{row.registerNum + row.courseReservedNumber}}
<el-link @click="openView(row)" type="primary">
{{row.registerNum}}
</el-link>
<el-link v-if="row.reserveMode === 2" @click="openView(row)" type="primary">{{row.registerNum}}</el-link>
</template>
</el-table-column>
@@ -74,99 +69,24 @@ layout("/layouts/platform.html"){
</el-card>
<template #view>
<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" :size="tableSize" 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 @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>
<user-info ref="userInfoRef"></user-info>
</template>
</guava>
<el-dialog title="人员调整" top="6vh" class="adjustDialog" :close-on-click-modal="false" :visible.sync="adjustDialogVisible" width="40%">
<span style="color: #c33714">注:如单选为灰色选择不了,则表示对应的{{ trainType }}人数已满!</span>
<el-table :data="courseList">
<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="trainType + '列表'"
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>
<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>
<script>
<!--#include('userInfo.js'){}#-->
new Vue({
el: "#app",
dicts: ["TRAIN_SIGNUP_TYPE"],
mixins: [initTableMixins],
components: {
"user-info": userInfo,
},
data() {
return {
trainType: "培训班",
trainTypeList: [],
afterAdjustCourse: "",
adjustDialogVisible: false,
unionList: [],
unitList: [],
registerForm: {
unionId: "",
unitId: ""
},
activityList: [],
pageForm: {
year: new Date().getFullYear().toString(),
@@ -180,116 +100,13 @@ layout("/layouts/platform.html"){
{ label: "最多报名人数", prop: "coursePeopleNumber", sortable: true },
{ label: "已报名人数", prop: "registerNum", sortable: true }
],
registerUserTableData: [],
registerUserTableColumns: [
{ label: "姓名", prop: "username" },
{ label: "一卡通号", prop: "loginname" },
{ label: "单位", prop: "unitName" },
{ label: "分工会", prop: "unionName" },
{ label: "联系方式", prop: "mobile" },
{ label: "报名时间", prop: "signUpTime" },
{ label: "报名状态", prop: "state" }
],
registerCourse: {},
courseList: [],
userInfo: {},
chooseRow: {}
}
},
methods: {
activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.trainTypeList.find((o) => o.code === activity.trainType)
this.trainType = type ? type.name : "培训班"
},
getCurrentRow(row) {
this.chooseRow = row
},
async doAdjust() {
if (!this.afterAdjustCourse) {
this.$message.warning("请选择要调整的" + this.trainType + "")
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.pageForm.activityId,
oldCourseId: this.registerCourse.id,
newCourseId: this.afterAdjustCourse,
userId: this.userInfo.userId
})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$refs.guava.index()
this.adjustDialogVisible = false
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
loading.close()
})
.catch(() => {})
},
adjust(o) {
this.userInfo = o
this.afterAdjustCourse = ""
this.getCourse(this.pageForm.activityId)
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.pageForm.activityId,
courseId: this.registerCourse.id,
userId: o.userId
})
if (resp.code === 0) {
this.$message.success(resp.msg)
await this.registerSearch()
this.doSearch()
} 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 getUnitList() {
this.registerForm.unitId = ""
this.unitList = await this.$businessTool.listUnit(this.registerForm.unionId)
const type = this.dict.type.TRAIN_SIGNUP_TYPE.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
},
async yearChange() {
this.pageForm.activityId = null
@@ -301,38 +118,23 @@ layout("/layouts/platform.html"){
this.activityList = resp.data
if (this.activityList && this.activityList.length > 0) {
this.pageForm.activityId = this.activityList[0].id
const type = this.trainTypeList.find((o) => o.code === this.activityList[0].trainType)
this.trainType = type ? type.name : "培训班"
this.activityChange(this.activityList[0].id)
}
},
async initData() {
await this.getActivityList()
this.unionList = await this.$businessTool.listUnion()
},
async openView(o) {
this.registerCourse = o
this.registerForm.courseId = o.id
this.$refs.guava.view()
const resp_register = await this.$axios.post(loc() + "/registerUserList", this.registerForm)
this.registerUserTableData = resp_register.data
this.$refs.guava.view(() => {
const activity = this.activityList.find((o) => o.id === this.pageForm.activityId)
this.$refs.userInfoRef.onOpen(o, activity)
})
},
async getCourse(val) {
const { data } = await this.$axios.post(loc() + "/getCourse", { activityId: val })
this.courseList = data
}
},
async created() {
this.$businessTool.getDictOptions("TRAIN_SIGNUP_TYPE").then((data) => {
this.trainTypeList = data
})
await this.initData()
await this.pageData()
},
watch: {
"pageForm.activityId"(val) {
this.getCourse(val)
}
}
})
</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">如单选为灰色选择不了则表示对应的{{ trainType }}人数已满候补报名不做调整</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="trainType + '列表'"
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: ["TRAIN_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" }
],
trainType: '',
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.TRAIN_SIGNUP_TYPE.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
},
getCurrentRow(row) {
this.chooseRow = row
},
async doAdjust() {
if (!this.afterAdjustCourse) {
this.$message.warning("请选择要调整的" + this.trainType + "")
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.pageForm.activityId,
oldCourseId: this.registerCourse.id,
newCourseId: this.afterAdjustCourse,
userId: this.userInfo.userId
})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$refs.guava.index()
this.adjustDialogVisible = false
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
loading.close()
})
.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.pageForm.activityId,
courseId: this.registerCourse.id,
userId: o.userId
})
if (resp.code === 0) {
this.$message.success(resp.msg)
await this.registerSearch()
this.doSearch()
} 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;
}
`
}
@@ -70,10 +70,6 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<!--#include("/platform/zhgh/activity/trainSingUp/statistics/include_view.html"){}#-->
</template>
</guava>
<el-dialog title="补充人员" :visible.sync="reserveDialogVisible" width="55%" top="3%">
@@ -97,6 +93,7 @@ layout("/layouts/platform.html"){
<script>
new Vue({
el: "#app",
dicts: ["TRAIN_SIGNUP_TYPE"],
mixins: [initTableMixins],
data() {
return {
@@ -117,25 +114,11 @@ layout("/layouts/platform.html"){
{ label: "缺席次数", prop: "absentCount" },
{ label: "是否黑名单", prop: "isDisabled", sortable: true }
],
registerUserTableData: [],
registerUserTableColumns: [
{ label: "姓名", prop: "username" },
{ label: "工号", prop: "loginname" },
{ label: "联系方式", prop: "mobile" },
{ label: "单位", prop: "unitname" },
{ label: "分工会", prop: "unionname" },
{ label: "课程次数", prop: "tourseTotal" },
{ label: "缺席次数", prop: "absentCount" },
{ label: "是否黑名单", prop: "isDisabled" }
],
userSignInfo: {},
trainType: "培训班",
trainTypeList: [],
courseList: [],
course: {},
reserveMode: 1,
multipleSelection: [],
clickRow: {}
}
},
methods: {
@@ -210,8 +193,8 @@ layout("/layouts/platform.html"){
},
async activityChange(val) {
const activity = this.activityList.find((o) => o.id === val)
const type = this.trainTypeList.find((o) => o.code === activity.trainType)
this.trainType = type ? type.name : "培训班"
const type = this.dict.type.TRAIN_SIGNUP_TYPE.find(o => o.code === activity.trainType)
this.trainType = type?.name || "培训班"
const resp = await this.$axios.post(loc() + "/getCourseByActivityId", { activityId: val })
this.courseList = resp.data
this.pageForm.courseId = ""
@@ -233,26 +216,14 @@ layout("/layouts/platform.html"){
this.activityList = resp.data
if (this.activityList && this.activityList.length > 0) {
this.pageForm.activityId = this.activityList[0].id
const type = this.trainTypeList.find((o) => o.code === this.activityList[0].trainType)
this.trainType = type ? type.name : "培训班"
await this.activityChange(this.activityList[0].id)
}
},
async initData() {
await this.getActivityList()
},
async openView(userId) {
this.$refs.guava.view()
// const resp_register = await $.get(loc() + '/registerUserList', {courseId})
// this.registerUserTableData = resp_register.data
// const resp_signInfo = await $.get(loc() + '/getSignInfo', {courseId})
// this.userSignInfo = resp_signInfo.data
}
},
async created() {
this.$businessTool.getDictOptions("TRAIN_SIGNUP_TYPE").then((data) => {
this.trainTypeList = data
})
await this.initData()
await this.pageData()
}
@@ -0,0 +1,129 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="项目名称:">
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable clearable
@change="doSearch" style="width: 100%">
<el-option
v-for="item in projectList"
:key="item.code"
:label="item.name"
:value="item.code">
</el-option>
</el-select>
</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>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="登记台账"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<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 === 'buyCount'">
<el-link @click="onView(row)" type="primary" :underline="false">{{ row.buyCount }}</el-link>
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="{ row }">
<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>
<user-info ref="userInfoRef"></user-info>
</template>
</guava>
</div>
<script>
<!--#include('../common/userInfo.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"user-info": userInfo,
},
data() {
return {
tableColumns: [
{label: '年度', prop: 'year'},
{label: '项目', prop: 'projectName'},
{label: '工会', prop: 'unionName'},
{label: '登记人', prop: 'userName'},
{label: '购买人数', prop: 'buyCount'},
],
projectList: [],
unionList: [],
}
},
methods: {
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
}
})
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.userInfoRef.initData(row)
})
},
async getBuyClothesProject() {
const {data} = await this.$axios.post('/platform/clothing/apply/getBuyClothesProject')
return data
},
},
async created() {
this.unionList = await this.$businessTool.listUnion()
this.projectList = await this.getBuyClothesProject()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,184 @@
<!--#
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
disabled
placeholder="请选择年度"
type="year"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="项目名称:">
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable
@change="doSearch" style="width: 100%">
<el-option
v-for="item in projectList"
:key="item.code"
:label="item.name"
:value="item.code">
</el-option>
</el-select>
</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-radio-group @change="(val) => doSearch()" v-model="pageForm.isBuy">
<el-radio-button :label="true">已购买</el-radio-button>
<el-radio-button :label="false">未购买</el-radio-button>
</el-radio-group>
</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 @change="doSearch" filterable clearable v-model="pageForm.sex"
placeholder="请选择性别" style="width: 100%">
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="人员列表">
<el-button v-if="!pageForm.isBuy" type="primary" size="small" @click="doHandler">
<i class="ti-plus"></i>
提交名单
</el-button>
<el-button v-else type="danger" size="small" @click="doHandler">
<i class="el-icon-close"></i>
移除名单
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize"
ref="multipleTable" @selection-change="handleSelectionChange"
:row-key="(val) => val.id">
<el-table-column :reserve-selection="true" type="selection" width="55"></el-table-column>
<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"){}#-->
</el-card>
</template>
</guava>
</div>
<script>
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
},
data() {
return {
pageForm: {
year: this.$moment().format('YYYY'),
isBuy: false,
searchName: 'u.username'
},
tableColumns: [
{ prop: "userName", label: "姓名" },
{ prop: "loginName", label: "工号" },
{ prop: "sex", label: "性别" },
{ prop: "unitName", label: "单位" },
{ prop: "unionName", label: "工会" },
{ prop: "mobile", label: "联系方式" },
],
projectList: [],
unionList: [],
multipleSelection: []
}
},
methods: {
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 getBuyClothesProject() {
const {data} = await this.$axios.post('/platform/clothing/apply/getBuyClothesProject')
return data
},
async doHandler() {
if(!this.pageForm.projectId) {
this.$message.warning('请选择项目')
return
}
if(this.multipleSelection.length === 0) {
this.$message.warning('请先选择人员')
return
}
const confirm = await this.$confirm('您选择了' + this.multipleSelection.length + '人, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
if (confirm === "confirm") {
const resp = await this.$axios.post('/platform/clothing/apply/doHandler', {
ids: JSON.stringify(this.multipleSelection),
projectId: this.pageForm.projectId,
year: this.pageForm.year,
isBuy: this.pageForm.isBuy,
})
if(resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
this.multipleSelection = []
this.$refs.multipleTable.clearSelection()
} else {
this.$message.warning(resp.msg)
}
}
},
handleSelectionChange(val) {
this.multipleSelection = val.length > 0 ? val.map(o => o.id) : []
},
},
async created() {
this.unionList = await this.$businessTool.listUnion()
this.projectList = await this.getBuyClothesProject()
if (this.projectList && this.projectList.length > 0) {
this.pageForm.projectId = this.projectList[0].code
}
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,69 @@
const userInfo = {
template: /*language=HTML*/ `
<div>
<div class="left-span-label">购买服装人员名单</div>
<el-table :data="tableData">
<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-column label="操作" width="100">
<template v-slot="{ row }">
<el-button @click="deleteBuyUser(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
`,
mixins: [initTableMixins],
data() {
return {
tableColumns: [
{label: '姓名', prop: 'buyUserName'},
{label: '工号', prop: 'buyUserLoginName'},
{label: '性别', prop: 'sex'},
{label: '单位', prop: 'buyUserUnitName'},
{label: '所属工会', prop: 'buyUserUnionName'},
{label: '联系方式', prop: 'mobile'},
],
}
},
methods: {
initData(row) {
this.$axios.post('/platform/clothing/record/findBuyClothesUser', {
projectId: row.projectId,
userId: row.userId,
year: row.year,
}).then((resp) => {
if (resp.code === 0) {
this.tableData = clone(resp.data)
}
}).catch(() => {})
},
deleteBuyUser(row) {
this.$confirm('此操作将永久删除, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const resp = await this.$axios.post('/platform/clothing/record/deleteBuyUser', {id: row.id})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
}).catch(() => {})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,158 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="项目名称:">
<el-select v-model="pageForm.projectId" placeholder="请选择项目名称" filterable clearable
@change="doSearch" style="width: 100%">
<el-option
v-for="item in projectList"
:key="item.code"
:label="item.name"
:value="item.code">
</el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="登记记录">
<el-button v-if="!pageForm.isBuy" 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="序号" 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 === 'buyCount'">
<el-link @click="onView(row)" type="primary" :underline="false">{{ row.buyCount }}</el-link>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onExport(row)" size="mini" type="primary">导出</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #view>
<user-info ref="userInfoRef"></user-info>
</template>
</guava>
</div>
<script>
<!--#include('../common/userInfo.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"user-info": userInfo,
},
data() {
return {
tableColumns: [
{label: '年度', prop: 'year'},
{label: '项目', prop: 'projectName'},
{label: '工会', prop: 'unionName'},
{label: '登记人', prop: 'userName'},
{label: '购买人数', prop: 'buyCount'},
],
projectList: [],
}
},
methods: {
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
}
})
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.userInfoRef.initData(row)
})
},
openAdd() {
location.href = '/platform/clothing/apply'
},
onDelete(row) {
this.$confirm('此操作将永久删除, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const resp = await this.$axios.post(loc() + '/doDelete', {
projectId: row.projectId,
year: row.year,
userId: row.userId,
})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
}).catch(() => {})
},
onExport(row) {
const params = {
year: row.year,
projectId: row.projectId,
userId: row.userId,
}
this.$downLoad("/platform/clothing/record/doExport", params)
},
async getBuyClothesProject() {
const {data} = await this.$axios.post('/platform/clothing/apply/getBuyClothesProject')
return data
},
},
async created() {
this.projectList = await this.getBuyClothesProject()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,183 @@
<div id="condolence_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="投稿人姓名">{{formData.userName}}</el-descriptions-item>
<el-descriptions-item label="投稿人工号">{{formData.loginName}}</el-descriptions-item>
<el-descriptions-item label="投稿人单位">{{formData.unitName}}</el-descriptions-item>
<el-descriptions-item label="投稿人工会">{{formData.unionName}}</el-descriptions-item>
<el-descriptions-item label="投稿来源" :span="2">
<el-form-item prop="origin" label="投稿来源" label-width="0">
<el-radio-group v-model="formData.origin" size="small">
<el-radio border v-for="item in origins" :label="item.code" :key="item.code">{{item.name}}</el-radio>
</el-radio-group>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="投稿人协会" v-if="formData.origin === 'ARTICLE_ORIGIN_CLUB'">
<el-form-item prop="clubId" label="投稿人协会" v-if="formData.origin === 'ARTICLE_ORIGIN_CLUB'">
<el-select v-model="formData.clubId" placeholder="请选择" style="width: 100%">
<el-option v-for="item in permission?.clubs" :key="item.id" :label="item.clubName" :value="item.id"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="投稿人联系方式" :span="2">
<el-form-item prop="title" label="投稿标题">
<el-input v-model="formData.title" maxlength="100" show-word-limit placeholder="请输入标题"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="投稿人联系方式" :span="2">
<el-form-item prop="mobile" label="投稿人联系方式">
<el-input v-model="formData.mobile" placeholder="请输入投稿人联系方式"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="修改人联系方式" :span="2">
<el-form-item prop="mobile2" label="修改人联系方式">
<el-input v-model="formData.mobile2" placeholder="请输入修改人联系方式"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="投稿说明" :span="2">
<el-form-item prop="excerpt" label="投稿说明">
<el-input v-model="formData.excerpt" type="textarea" maxlength="500" show-word-limit placeholder="请输入投稿说明"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="稿件" :span="2">
<file-upload
:value.sync="formData.files"
:upload_number="5"
upload_result_category="array"
complete_result
upload_mode="drag"
></file-upload>
</el-descriptions-item>
</el-descriptions>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @save-draft="handleSaveDraft" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
<script>
new Vue({
el: "#condolence_apply",
store,
dicts: ["ARTICLE_ORIGIN"],
computed: {
origins() {
if (this.dict?.type?.ARTICLE_ORIGIN && this.permission && this.permission.roles) {
return this.dict.type.ARTICLE_ORIGIN.filter((item) => this.permission && this.permission.roles.includes(item.code))
}
return []
}
},
data() {
return {
id: GetQueryString("businessId"),
taskId: GetQueryString("taskId"),
instanceId: GetQueryString("instanceId"),
formData: {},
formRules: {
title: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
excerpt: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
clubId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
files: [{ required: false, message: "必填", trigger: ["change", "blur"] }],
origin: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
mobile: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
mobile2: [{ required: true, message: "必填", trigger: ["change", "blur"] }]
},
permission: {}
}
},
methods: {
init() {
if (this.id) {
this.$axios.post("/platform/article/write/get", { id: this.id }).then((res) => {
if (res.code === 0) {
this.formData = res.data
}
})
} else {
const { username, loginname, id, unit, union, mobile } = this.$store.state.user
this.formData = {
userName: username,
loginName: loginname,
userId: id,
unitId: unit?.id,
unitName: unit?.name,
unionId: union?.id,
unionName: union?.name,
mobile: mobile,
mobile2: mobile
}
}
},
checkPermission() {
this.$axios.post("/platform/article/write/checkPermission").then((res) => {
if (res.code === 0) {
this.permission = res.data
}
})
},
handleTaskAction(val) {
console.log(val)
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.parent.postMessage(
{
type: "task-complete"
},
"*"
)
}
})
}
})
},
handleSaveDraft(val) {
this.$message.success("保存成功")
this.$refs.formRef.validateField(["title"], (errMsg) => {
if (errMsg) {
this.$message.warning("请填写标题")
return
}
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() {}
},
created() {
this.init()
this.checkPermission()
}
})
</script>
@@ -0,0 +1,56 @@
<div id="condolence_audit">
<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:true,message:'必填',trigger:['change','blur']}]">-->
<!-- <pc-signature v-model="formData.approvalSignature"></pc-signature>-->
<!-- </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: "#condolence_audit",
store,
data() {
return {
id: GetQueryString("businessId"),
taskId: GetQueryString("taskId"),
instanceId: GetQueryString("instanceId"),
formData: {}
}
},
methods: {
handleTaskAction(val) {
console.log(val)
const param = {
...val,
"tf_data": this.formData
}
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify(param)
}).then(res => {
if (res.code === 0) {
this.$message.success("操作成功")
// 发送完成消息
window.parent.postMessage({
type: "task-complete"
}, "*")
}
})
},
handleCancel() {
}
},
created() {
}
})
</script>
@@ -0,0 +1,221 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="项目名称:">
<el-select placeholder="请选择项目名称"
v-model="pageForm.contributionName"
style="width: 100%;"
clearable @change="doSearch"
filterable>
<el-option v-for="item in contributionOptions"
:label="item.contributionName"
:key="item.contributionName"
:value="item.contributionName"></el-option>
</el-select>
</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-item label="捐款方式:">
<el-select placeholder="请选择捐款方式" v-model="pageForm.payMode" style="width: 100%;"
clearable @change="doSearch"
filterable>
<el-option label="微信" value="WeChat"></el-option>
<el-option label="支付宝" value="Alipay"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="捐款列表">
<el-button type="primary" size="small" @click="onExport">
<i class="el-icon-download"></i>
导出
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize"
row-key="id" show-summary :summary-method="getSummaries">
<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 === 'payMode'">
{{ row.payMode === 'WeChat' ? '微信' : '支付宝' }}
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="{ row }">
<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>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="捐款项目">
{{ viewData.contributionName }}
</el-descriptions-item>
<el-descriptions-item label="捐款人工号">
{{ viewData.loginName }}
</el-descriptions-item>
<el-descriptions-item label="姓名">
{{ viewData.userName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">
{{ viewData.mobile }}
</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.money || 0}}元
</el-descriptions-item>
<el-descriptions-item label="捐款方式">
{{ viewData.payMode === 'WeChat' ? '微信' : '支付宝' }}
</el-descriptions-item>
<el-descriptions-item label="捐款时间" :span="2">
{{ viewData.contributionTime }}
</el-descriptions-item>
<el-descriptions-item label="捐款凭证" :span="2">
<file-preview v-if="viewData.contributionFiles" complete_result :files="viewData.contributionFiles"></file-preview>
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
</template>
</guava>
</div>
<script>
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
},
data() {
return {
tableColumns: [
{prop: 'contributionName', label: '捐款项目'},
{prop: 'loginName', label: '捐款人工号'},
{prop: 'userName', label: '姓名'},
{prop: 'mobile', label: '联系方式'},
{prop: 'unionName', label: '所属工会'},
{prop: 'unitName', label: '所属单位'},
{prop: 'money', label: '善款金额'},
{prop: 'payMode', label: '捐款方式'},
{prop: 'contributionTime', label: '捐款时间'},
],
contributionOptions: [],
unionList: [],
unitList: [],
viewData: {},
}
},
methods: {
getSummaries(param) {
const {columns, data} = param
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '总额'
return
}
if (index !== 7) {
sums[index] = null
return
}
const values = data.map(item => Number(item[column.property]))
if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr)
if (!isNaN(value)) {
return Math.floor((prev + curr) * 100) / 100
} else {
return prev
}
}, 0)
sums[index] += ' 元'
} else {
sums[index] = null
}
})
return sums
},
onView(row) {
this.$refs.guava.view(() => {
if(row.contributionFiles) {
row.contributionFiles = JSON.parse(row.contributionFiles)
}
this.viewData = clone(row)
})
},
onExport() {
this.$downLoad("/platform/contribution/detailed/doExport", this.pageForm)
},
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
}
})
},
queryContributionList() {
this.$axios.post('/platform/contribution/list/queryContributionList')
.then((resp) => {
this.contributionOptions = resp.data
})
},
},
async created() {
this.unionList = await this.$businessTool.listUnion()
this.unitList = await this.$businessTool.listUnit()
this.queryContributionList()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,115 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="项目名称" prop="contributionName">
<el-input type="text" v-model="formData.contributionName" maxlength="50"
placeholder="请填写项目名称"></el-input>
</el-form-item>
<el-form-item label="所属捐款专题" prop="contributionTypeCode">
<el-select placeholder="所属捐款专题" v-model="formData.contributionTypeCode"
style="width: 100%;"
clearable
filterable>
<el-option v-for="item in contributionTypeList"
:label="item.typeName + '' + item.typeCode + ''"
:value="item.typeCode"></el-option>
</el-select>
</el-form-item>
<el-form-item label="捐款时间" prop="contributionTime">
<el-date-picker
style="width: 100%;"
v-model="formData.contributionTime"
type="datetimerange"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator="至"
start-placeholder="请选择开始日期"
end-placeholder="请选择结束日期">
</el-date-picker>
</el-form-item>
<el-form-item label="捐款模式" prop="contributionMode">
<el-radio-group v-model="formData.contributionMode">
<el-radio-button :label="1">水滴筹</el-radio-button>
<el-radio-button :label="2">一日捐</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="捐款链接" prop="contributionUrl"
v-if="formData.contributionMode === 1">
<el-input type="text" v-model="formData.contributionUrl" maxlength="50"
placeholder="请填写捐款链接"></el-input>
</el-form-item>
<el-form-item label="是否开启" prop="isContributionEnable">
<el-switch v-model="formData.isContributionEnable" active-color="#13ce66"
inactive-color="#ff4949"></el-switch>
</el-form-item>
<el-form-item label="项目介绍" prop="contributionIntroduce">
<text-editor v-model="formData.contributionIntroduce"></text-editor>
</el-form-item>
<el-form-item label="封面图" prop="contributionFiles">
<file-upload :value.sync="formData.contributionFiles" accept=".jpg,.jpeg,.png"
:upload_number="1" upload_result_category="interval"
complete_result upload_mode="drag"></file-upload>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
data() {
return {
formData: {},
formRules: {
contributionName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
contributionIntroduce: [{required: true, message: '必填', trigger: ['blur', 'change']}],
contributionFiles: [{required: true, message: '必填', trigger: ['blur', 'change']}],
isContributionEnable: [{required: true, message: '必填', trigger: ['blur', 'change']}],
contributionTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
contributionMode: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
contributionTypeList: [],
}
},
methods: {
onOpen(row) {
if(row && row.id) {
this.formData = clone(row)
this.$set(this.formData, 'contributionTime', [this.formData.contributionStartTime, this.formData.contributionEndTime])
}
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
this.$set(this.formData, 'contributionStartTime', this.formData.contributionTime[0])
this.$set(this.formData, 'contributionEndTime', this.formData.contributionTime[1])
const resp = await this.$axios.post("/platform/contribution/list/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
queryContributionType() {
this.$axios.post('/platform/contribution/type/queryContributionType')
.then((resp) => {
this.contributionTypeList = resp.data
})
},
},
created() {
this.queryContributionType()
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,154 @@
<!--#
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-input placeholder="请输入项目名称" clearable v-model="pageForm.contributionName"
@keyup.enter.native="doSearch">
</el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="项目列表">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增项目
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<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 === 'contributionTypeName'">
{{ row.typeName || '暂无' }}
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'isContributionEnable'">
<el-switch @change="switchChange(row)" v-model="row.isContributionEnable"
active-color="#13ce66"
inactive-color="#ff4949"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'contributionName', label: '项目名称'},
{prop: 'contributionTypeName', label: '所属专题'},
{prop: 'contributionCreationDate', label: '创建时间'},
{prop: 'isContributionEnable', label: '是否开启'}
],
}
},
methods: {
switchChange(row) {
this.$axios.post("/platform/contribution/list/onSubmit", row).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
},
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/contribution/list/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,45 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="项目名称">
{{ viewData.contributionName }}
</el-descriptions-item>
<el-descriptions-item label="所属捐款专题">
{{ viewData.typeName }}
</el-descriptions-item>
<el-descriptions-item label="捐款时间">
{{ viewData.contributionStartTime + ' 至 ' + viewData.contributionEndTime }}
</el-descriptions-item>
<el-descriptions-item label="捐款模式">
{{ viewData.contributionMode === 1 ? '水滴筹' : '一日捐' }}
</el-descriptions-item>
<el-descriptions-item label="捐款链接" :span="2">
{{ viewData.contributionUrl || '暂无' }}
</el-descriptions-item>
<el-descriptions-item label="项目介绍" :span="2">
<div v-html="viewData.contributionIntroduce"></div>
</el-descriptions-item>
<el-descriptions-item label="封面图" :span="2">
<img :src="viewData.contributionFiles"
style="height: 100px;width: auto" v-if="viewData.contributionFiles">
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = clone(row)
this.$set(this.formData, 'contributionTime', [this.formData.contributionStartTime, this.formData.contributionEndTime])
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,144 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="项目名称:">
<el-select placeholder="请选择项目名称"
v-model="pageForm.contributionId"
style="width: 100%;"
@change="doSearch"
filterable>
<el-option v-for="item in contributionOptions"
:label="item.contributionName"
:key="item.id"
:value="item.id"></el-option>
</el-select>
</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>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="捐款列表"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize"
row-key="id" show-summary :summary-method="getSummaries"
max-height="600">
<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>
</el-card>
</template>
</guava>
</div>
<script>
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
},
data() {
return {
tableColumns: [
{prop: 'unionCode', label: '工会编码'},
{prop: 'name', label: '工会名称'},
{prop: 'contributionUserNum', label: '捐款人数'},
{prop: 'contributionNum', label: '捐款多少笔'},
{prop: 'money', label: '捐款总额(元)'},
],
contributionOptions: [],
unionList: [],
}
},
methods: {
getSummaries(param) {
const {columns, data} = param
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '总计'
return
}
if (![3, 4, 5].includes(index)) {
sums[index] = null
return
}
const values = data.map(item => Number(item[column.property]))
if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr)
if (!isNaN(value)) {
return Math.floor((prev + curr) * 100) / 100
} else {
return prev
}
}, 0)
if (index === 3) {
sums[index] += ' 人'
} else if (index === 4) {
sums[index] += ' 笔'
} else {
sums[index] += ' 元'
}
} else {
sums[index] = null
}
})
return sums
},
pageData() {
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data
}
})
},
async queryContributionList() {
const resp = await this.$axios.post('/platform/contribution/list/queryContributionList')
this.contributionOptions = resp.data
if (this.contributionOptions && this.contributionOptions.length > 0) {
this.pageForm.contributionId = this.contributionOptions[0].id
}
},
},
async created() {
this.unionList = await this.$businessTool.listUnion()
await this.queryContributionList()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,69 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="专题编号" prop="typeCode">
<el-input type="text" v-model="formData.typeCode" maxlength="50"
placeholder="请填写专题编号"></el-input>
</el-form-item>
<el-form-item label="专题名称" prop="typeName">
<el-input type="text" v-model="formData.typeName" maxlength="50"
placeholder="请填写专题名称"></el-input>
</el-form-item>
<el-form-item label="专题介绍" prop="contributionTypeIntroduce">
<el-input type="textarea" v-model="formData.contributionTypeIntroduce" :rows="4"
placeholder="请填写专题介绍"></el-input>
</el-form-item>
<el-form-item label="封面图" prop="contributionTypeFiles">
<file-upload :value.sync="formData.contributionTypeFiles" accept=".jpg,.jpeg,.png"
:upload_number="1" upload_result_category="interval"
complete_result upload_mode="drag"></file-upload>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
data() {
return {
formData: {},
formRules: {
typeName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
typeCode: [{required: true, message: '必填', trigger: ['blur', 'change']}],
contributionTypeIntroduce: [{required: true, message: '必填', trigger: ['blur', 'change']}],
contributionTypeFiles: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
}
},
methods: {
onOpen(row) {
if(row && row.id) {
this.formData = clone(row)
}
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/contribution/type/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,140 @@
<!--#
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-input placeholder="请输入名称或编码查询" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch">
</el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="专题列表">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增专题
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<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 === 'createdAt'">
{{ $moment(row.createdAt).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'typeCode', label: '专题编号'},
{prop: 'typeName', label: '专题名称'},
{prop: 'createdAt', label: '创建时间'},
],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/contribution/type/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,35 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="专题编号">
{{ viewData.typeCode }}
</el-descriptions-item>
<el-descriptions-item label="专题名称">
{{ viewData.typeName }}
</el-descriptions-item>
<el-descriptions-item label="专题介绍" :span="2">
{{ viewData.contributionTypeIntroduce }}
</el-descriptions-item>
<el-descriptions-item label="封面图" :span="2">
<img :src="viewData.contributionTypeFiles"
style="height: 100px;width: auto" v-if="viewData.contributionTypeFiles">
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = clone(row)
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,124 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-dialog :visible.sync="addDialogVisible"
width="50%" title="心理咨询预约"
:close-on-click-modal="false"
append-to-body>
<div class="left-span-label">预约时间段</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="开始时间">
{{ formData.startTime }}
</el-descriptions-item>
<el-descriptions-item label="结束时间">
{{ formData.endTime }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">咨询师信息</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{ formData.doctorUserName }}
</el-descriptions-item>
<el-descriptions-item label="性别">
{{ formData.doctorSex }}
</el-descriptions-item>
<el-descriptions-item label="单位">
{{ formData.doctorUnitName }}
</el-descriptions-item>
<el-descriptions-item label="电话">
{{ formData.doctorMobile }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">预约人信息</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="姓名">
<el-input :value="$store.state.user.username" readonly></el-input>
</el-form-item>
<el-form-item label="工号">
<el-input :value="$store.state.user.loginname" readonly></el-input>
</el-form-item>
<el-form-item label="单位">
<el-input :value="$store.state.user.unit.name" readonly></el-input>
</el-form-item>
<el-form-item label="联系方式" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入联系方式"></el-input>
</el-form-item>
<el-form-item label="预约咨询方式" prop="askTypeValue">
<el-select
v-model="formData.askTypeValue"
filterable
style="width: 100%"
placeholder="请选择咨询方式">
<el-option v-for="item in askTypeOptions"
:key="item.code"
:label="item.name"
:value="item.code">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="预约备注" prop="remark">
<el-input type="textarea" :row="3" v-model="formData.remark"
placeholder="请输入预约备注事项"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('refresh'); addDialogVisible = false">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</span>
</el-dialog>
</div>
`,
dicts: ["LEGAL_ASK_TYPE"],
store,
data() {
return {
formData: {},
formRules: {
askTypeValue: [{required: true, message: '请选择咨询方式', trigger: ['change']}],
mobile: [{required: true, message: '请输入联系方式', trigger: ['change']}],
},
addDialogVisible: false,
askTypeOptions: [],
}
},
methods: {
onOpen(row) {
if(row.askType) {
row.askType = JSON.parse(row.askType)
this.askTypeOptions = this.dict.type.LEGAL_ASK_TYPE.filter(o => row.askType.includes(o.code))
}
this.formData = clone(row)
if(this.askTypeOptions.length > 0) {
this.$set(this.formData, 'askTypeValue', this.askTypeOptions[0].code)
}
this.$set(this.formData, 'mobile', this.$store.state.user.mobile)
this.addDialogVisible = true
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/legal/apply/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
this.addDialogVisible = false
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
created() {
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,213 @@
<!--#
layout("/layouts/platform.html"){
#-->
<link rel="stylesheet" href="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.css">
<script src="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.min.js"></script>
<style>
#calendar {
max-width: 1200px;
margin: 20px auto 0;
}
.fc-toolbar {
display: block !important;
visibility: unset !important;
}
.green {
color: #FFFFFF;
background-color: #369a5f;
border: 1px solid #257e4a;
}
.yellow {
color: #FFFFFF;
background-color: #f3b20f;
border: 1px solid #af7d00;
}
.red {
color: #FFFFFF;
background-color: #ea5454;
border: 1px solid #b11616;
}
.fc-time-grid-event.fc-short .fc-time:before {
content: none;
}
.fc-time-grid-event.fc-short .fc-time span {
display: block;
}
.fc-ltr .fc-time-grid .fc-event-container {
margin: 0;
}
.el-row--flex.is-justify-space-between {
justify-content: flex-start;
}
.fc-icon {
height: 1.5em;
line-height: 1.5em;
}
.fc-event .fc-content {
padding: 3px;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<div id="legal-calendar"></div>
</el-card>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</div>
<script>
<!--#include('basicForm.js'){}#-->
let calendar = null
const vue = new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
},
data() {
return {
calendarHeight: 0,
events: [],
}
},
methods: {
refresh() {
calendar.fullCalendar('unselect')
this.queryAppointmentInfo()
},
initCalendar() {
const that = this
const today = this.$moment().format('YYYY-MM-DD')
if (calendar) return
calendar = $('#legal-calendar').fullCalendar({
header: { //设置日历头部信息,false,则不显示头部信息。包括left,center,right左中右三个位置
left: 'prev, next, today', //上一个、下一个、今天
center: 'title', //标题
right: 'month,agendaWeek,agendaDay,listMonth' //月、周、日、日程列表
},
locale: 'zh-cn', //?没用?
timeFormat: 'HH:mm', //日程事件的时间格式
buttonText: { //各按钮的显示文本信息
today: '今天',
month: '月',
agendaWeek: '周',
agendaDay: '日',
listMonth: '日程',
},
slotMinTime: '11:00:00',
monthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], //月份全称
monthNamesShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], //月份简写
dayNames: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], //周全称
dayNamesShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], //周简写
noEventsMessage: "当月无数据", //listview视图下,无数据提示
allDayText: "全天", //自定义全天视图的名称
allDaySlot: false, //是否在周日历上方显示全天
allDayDefault: false, //是否为全天日程事件,显示这一天中所做的事情
slotDuration: "00:30:00", //一格时间槽代表多长时间,默认00:30:00(30分钟)
slotLabelFormat: "H(:mm)a", //日期视图左边那一列显示的每一格日期时间格式
slotLabelInterval: "00:30:00", //日期视图左边那一列多长间隔显示一条日期文字(默认跟着slotDuration走的,可自定义)
snapDuration: "00:30:00", //其实就是动态创建一个日程时,默认创建多长的时间块
firstDay: 1, //一周中显示的第一天是哪天,周日是0,周一是1,类推
hiddenDays: [], //隐藏一周中的某一天或某几天,数组形式,如隐藏周二和周五:[2,5],默认不隐藏,除非weekends设置为false。
weekends: true, //是否显示周六和周日,设为false则不显示周六和周日。默认值为true
weekMode: 'fixed', //月视图里显示周的模式,因每月周数不同月视图高度不定。fixed:固定显示6周高,日历高度保持不变liquid:不固定周数,高度随周数变化variable:不固定周数,但高度固定
weekNumbers: false, //是否在日历中显示周次(一年中的第几周),如果设置为true,则会在月视图的左侧、周视图和日视图的左上角显示周数。
weekNumberCalculation: 'iso', //周次的显示格式。
height: that.calendarHeight, //设置日历的高度,包括header日历头部,默认未设置,高度根据aspectRatio值自适应。
// contentHeight: 600, //设置日历主体内容的高度,不包括header部分,默认未设置,高度根据aspectRatio值自适应。
handleWindowResize: true, //是否随浏览器窗口大小变化而自动变化。
defaultView: 'agendaWeek', //初始化时默认视图,默认是月monthagendaWeek是周,agendaDay是当天
slotEventOverlap: false, //事件是否可以重叠覆盖
defaultDate: today, //默认显示那一天的日期视图getDates(true)2020-05-10
nowIndicator: false, //周/日视图中显示今天当前时间点(以红线标记),默认false不显示
eventLimit: 2, //数据条数太多时,限制显示条数(多余的以“+2more”格式显示),默认false不限制,支持输入数字设定固定的显示条数
eventLimitText: "更多", //当一块区域内容太多以"+2 more"格式显示时,这个more的名称自定义(应该与eventLimit: true一并用)
dayPopoverFormat: "YYYY年M月d日预约信息", //点开"+2 more"弹出的小窗口标题,与eventLimitClick可以结合用
render: (view) => { //method,绑定日历到id上。$('#id').fullCalendar('render');
},
viewRender: (view) => {
that.queryAppointmentInfo()
},
eventRender: (info) => {
},
//日历数据源
events: that.events,
//日程事件点击
eventClick: (event, jsEvent) => {
if (event.data.appointmentUser) return
if (new Date().getTime() > event.data.startTimeTs) return
this.$refs.basicFormRef.onOpen(clone(event.data))
},
selectable: false, //是否允许通过单击或拖动选择日历中的对象,包括天和时间
selectMirror: true, //镜像
lazyFetching: false, //是否启用懒加载技术--即只取当前条件下的视图数据,其它数据在切换时触发,默认true只取当前视图的,false是取全视图的
defaultTimedEventDuration: "00:30:00", //在Event Object中如果没有end参数时使用,如start=7:00pm,则该日程对象时间范围就是7:00~9:00
defaultAllDayEventDuration: {days: 1}, //默认1天是多长,(有的是采用工作时间模式,所以支持自定义)
});
},
//获取预约数据
async queryAppointmentInfo() {
if (!calendar) return
const view = calendar.fullCalendar('getView')
//这里取时间戳
const startTimeTs = view.start._i
const endTimeTs = view.end._i
const resp = await this.$axios.post('/platform/legal/appointmentSet/queryAppointmentInfo', {startTimeTs, endTimeTs})
let events = []
if (resp.code === 0) {
resp.data.forEach(v => {
let className = ''
let title = ''
if (new Date().getTime() > v.startTimeTs) {
className = 'gray'
title = '不可预约'
} else {
if (!v.appointmentUser) {
className = 'green'
title = '可预约'
} else if (v.appointmentUser === this.$store.state.user.id) {
className = 'blue'
title = '我已预约'
} else {
className = 'gray'
title = '不可预约'
}
}
events.push({
id: v.id,
title: title,
start: v.startTime,
end: v.endTime,
className: className,
data: v,
})
})
}
calendar.fullCalendar('removeEvents', () => true)
calendar.fullCalendar('addEventSource', events, true)
},
init() {
this.$nextTick(() => {
setTimeout(() => {
this.initCalendar()
this.queryAppointmentInfo()
}, 100)
})
},
},
mounted() {
this.calendarHeight = window.innerHeight - 160
},
async created() {
this.init()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,125 @@
const addForm = {
template: /*language=HTML*/ `
<div>
<el-dialog :visible.sync="addDialogVisible"
width="30%" title="新增预约时间段"
:close-on-click-modal="false"
append-to-body>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="80px" label-position="left">
<el-form-item label="开始时间" prop="startTime">
<el-date-picker
readonly
style="width: 100%"
v-model="formData.startTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
placeholder="请选择日期时间">
</el-date-picker>
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker
readonly
style="width: 100%"
v-model="formData.endTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
placeholder="请选择日期时间">
</el-date-picker>
</el-form-item>
<el-form-item label="咨询师" prop="doctorUser">
<el-select
v-model="formData.doctorUser"
filterable
remote
style="width: 100%"
reserve-keyword
placeholder="请输入关键词"
:remote-method="queryDoctorUser">
<el-option
v-for="item in doctorUserList"
:key="item.id"
:label="item.mobile ? item.doctorUserName + '' + item.mobile + '' : item.doctorUserName + '(暂无手机号)'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="咨询方式" prop="askType">
<el-select
v-model="formData.askType"
filterable multiple
style="width: 100%"
placeholder="请选择咨询方式">
<el-option v-for="item in dict.type.LEGAL_ASK_TYPE"
:key="item.code"
:label="item.label"
:value="item.code"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('refresh'); addDialogVisible = false">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</span>
</el-dialog>
</div>
`,
store,
dicts:["LEGAL_ASK_TYPE"],
data() {
return {
addDialogVisible: false,
formData: {},
formRules: {
startTime: [{required: true, message: '请选择开始时间', trigger: ['change', 'blur']}],
endTime: [{required: true, message: '请选择结束时间', trigger: ['change', 'blur']}],
doctorUser: [{required: true, message: '请选择咨询师', trigger: ['change', 'blur']}],
askType: [{type: 'array', required: true, message: '请选择咨询方式', trigger: 'change'}],
},
doctorUserList: [],
}
},
methods: {
onOpen(row) {
this.formData = row
this.addDialogVisible = true
},
async queryDoctorUser(keyWord) {
const resp = await this.$axios.post(loc() + '/queryDoctorUser', {
keyWord,
startTimeTs: this.formData.startTimeTs,
endTimeTs: this.formData.endTimeTs,
})
this.doctorUserList = resp.data
},
onSubmit() {
if (Date.parse(this.formData.startTime) < new Date().getTime()) {
this.$message.warning('预约时间不能小于当前时间,请重新设置')
this.$emit('refresh')
this.addDialogVisible = false
return
}
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
this.formData.askType = JSON.stringify(this.formData.askType)
const resp = await this.$axios.post("/platform/legal/appointmentSet/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
this.addDialogVisible = false
} else {
this.$message.warning(resp.msg)
}
}).catch(() => {})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,225 @@
<!--#
layout("/layouts/platform.html"){
#-->
<link rel="stylesheet" href="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.css">
<script src="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.min.js"></script>
<style>
#calendar {
max-width: 1200px;
margin: 20px auto 0;
}
.fc-toolbar {
display: block !important;
visibility: unset !important;
}
.green {
color: #FFFFFF;
background-color: #369a5f;
border: 1px solid #257e4a;
}
.yellow {
color: #FFFFFF;
background-color: #f3b20f;
border: 1px solid #af7d00;
}
.red {
color: #FFFFFF;
background-color: #ea5454;
border: 1px solid #b11616;
}
.fc-time-grid-event.fc-short .fc-time:before {
content: none;
}
.fc-time-grid-event.fc-short .fc-time span {
display: block;
}
.fc-ltr .fc-time-grid .fc-event-container {
margin: 0;
}
.el-row--flex.is-justify-space-between {
justify-content: flex-start;
}
.fc-icon {
height: 1.5em;
line-height: 1.5em;
}
.fc-event .fc-content {
padding: 3px;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<div id="legal-calendar"></div>
</el-card>
<add-form ref="addFormRef" @refresh="refresh"></add-form>
<info ref="infoRef" @refresh="refresh"></info>
</div>
<script>
<!--#include('addForm.js'){}#-->
<!--#include('info.js'){}#-->
let calendar = null
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"add-form": addForm,
"info": info,
},
data() {
return {
calendarHeight: 0,
events: [],
}
},
methods: {
refresh() {
calendar.fullCalendar('unselect')
this.queryAppointmentInfo()
},
initCalendar() {
const that = this
const today = this.$moment().format('YYYY-MM-DD')
if (calendar) return
calendar = $('#legal-calendar').fullCalendar({
header: { //设置日历头部信息,false,则不显示头部信息。包括left,center,right左中右三个位置
left: 'prev, next, today', //上一个、下一个、今天
center: 'title', //标题
right: 'month,agendaWeek,agendaDay,listMonth' //月、周、日、日程列表
},
locale: 'zh-cn', //?没用?
timeFormat: 'HH:mm', //日程事件的时间格式
buttonText: { //各按钮的显示文本信息
today: '今天',
month: '月',
agendaWeek: '周',
agendaDay: '日',
listMonth: '日程',
},
slotMinTime: '11:00:00',
monthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], //月份全称
monthNamesShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], //月份简写
dayNames: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], //周全称
dayNamesShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], //周简写
noEventsMessage: "当月无数据", //listview视图下,无数据提示
allDayText: "全天", //自定义全天视图的名称
allDaySlot: false, //是否在周日历上方显示全天
allDayDefault: false, //是否为全天日程事件,显示这一天中所做的事情
slotDuration: "00:30:00", //一格时间槽代表多长时间,默认00:30:00(30分钟)
slotLabelFormat: "H(:mm)a", //日期视图左边那一列显示的每一格日期时间格式
slotLabelInterval: "00:30:00", //日期视图左边那一列多长间隔显示一条日期文字(默认跟着slotDuration走的,可自定义)
snapDuration: "00:30:00", //其实就是动态创建一个日程时,默认创建多长的时间块
firstDay: 1, //一周中显示的第一天是哪天,周日是0,周一是1,类推
hiddenDays: [], //隐藏一周中的某一天或某几天,数组形式,如隐藏周二和周五:[2,5],默认不隐藏,除非weekends设置为false。
weekends: true, //是否显示周六和周日,设为false则不显示周六和周日。默认值为true
weekMode: 'fixed', //月视图里显示周的模式,因每月周数不同月视图高度不定。fixed:固定显示6周高,日历高度保持不变liquid:不固定周数,高度随周数变化variable:不固定周数,但高度固定
weekNumbers: false, //是否在日历中显示周次(一年中的第几周),如果设置为true,则会在月视图的左侧、周视图和日视图的左上角显示周数。
weekNumberCalculation: 'iso', //周次的显示格式。
height: that.calendarHeight, //设置日历的高度,包括header日历头部,默认未设置,高度根据aspectRatio值自适应。
// contentHeight: 600, //设置日历主体内容的高度,不包括header部分,默认未设置,高度根据aspectRatio值自适应。
handleWindowResize: true, //是否随浏览器窗口大小变化而自动变化。
defaultView: 'agendaWeek', //初始化时默认视图,默认是月monthagendaWeek是周,agendaDay是当天
slotEventOverlap: false, //事件是否可以重叠覆盖
defaultDate: today, //默认显示那一天的日期视图getDates(true)2020-05-10
nowIndicator: false, //周/日视图中显示今天当前时间点(以红线标记),默认false不显示
eventLimit: 2, //数据条数太多时,限制显示条数(多余的以“+2more”格式显示),默认false不限制,支持输入数字设定固定的显示条数
eventLimitText: "更多", //当一块区域内容太多以"+2 more"格式显示时,这个more的名称自定义(应该与eventLimit: true一并用)
dayPopoverFormat: "YYYY年M月d日预约信息", //点开"+2 more"弹出的小窗口标题,与eventLimitClick可以结合用
render: (view) => { //method,绑定日历到id上。$('#id').fullCalendar('render');
},
viewRender: (view) => {
that.queryAppointmentInfo()
},
eventRender: (info) => {
},
//日历数据源
events: that.events,
//日程事件点击
eventClick: (event, jsEvent) => {
this.$refs.infoRef.onOpen(clone(event.data))
},
selectable: true, //是否允许通过单击或拖动选择日历中的对象,包括天和时间
unselectAuto: false, //当点击页面日历以外的位置时,是否自动取消当前的选中状态。
selectHelper: true, //当点击或拖动选择时间时,是否预先画出“日程区块”的样式显示默认加载的提示信息,该属性只在周/天视图里可用
selectMirror: true, //镜像
selectOverlap: false, //是否允许选择被事件占用的时间段,默认true可占用时间段
select: (start, end, allDay) => { //点击空白区域/选择区域内容触发
if (calendar.fullCalendar('getView').name === 'month') {
return
}
const startTime = $.fullCalendar.formatDate(start, "YYYY-MM-DD HH:mm:ss")
const endTime = $.fullCalendar.formatDate(end, "YYYY-MM-DD HH:mm:ss")
if (new Date().getTime() > Date.parse(endTime)) {
that.$message.warning('该时段不可设置')
calendar.fullCalendar('unselect');
return
}
const row = {
startTime: startTime,
endTime: endTime,
doctorUser: '',
askType: [],
}
this.$refs.addFormRef.onOpen(row)
},
lazyFetching: false, //是否启用懒加载技术--即只取当前条件下的视图数据,其它数据在切换时触发,默认true只取当前视图的,false是取全视图的
defaultTimedEventDuration: "00:30:00", //在Event Object中如果没有end参数时使用,如start=7:00pm,则该日程对象时间范围就是7:00~9:00
defaultAllDayEventDuration: {days: 1}, //默认1天是多长,(有的是采用工作时间模式,所以支持自定义)
});
},
//获取预约数据
async queryAppointmentInfo() {
if (!calendar) return
const view = calendar.fullCalendar('getView')
//这里取时间戳
const startTimeTs = this.$moment(this.$moment(view.start._i).format('YYYY-MM-DD') + ' 00:00:00').unix()
const endTimeTs = view.end._i
const resp = await this.$axios.post(loc() + '/queryAppointmentInfo', {startTimeTs, endTimeTs})
let events = []
if (resp.code === 0) {
resp.data.forEach(v => {
let className = ''
if (!v.appointmentUser) {
className = ''
} else if (v.appointmentUser && !v.doctorUser) {
className = 'red'
} else if (v.appointmentUser && v.doctorUser) {
className = 'green'
}
events.push({
id: v.id,
title: v.doctorUserName,
start: v.startTime,
end: v.endTime,
className: className,
data: v
})
this.events = events
})
}
calendar.fullCalendar('removeEvents', () => true)
calendar.fullCalendar('addEventSource', events, true)
},
init() {
this.$nextTick(() => {
this.initCalendar()
this.queryAppointmentInfo()
})
},
},
mounted() {
this.calendarHeight = window.innerHeight - 160
},
async created() {
this.init()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,165 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-dialog :visible.sync="infoDialogVisible"
width="50%" title="预约信息"
:close-on-click-modal="false"
append-to-body>
<div class="left-span-label">预约时间段</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="开始时间">
{{ formData.startTime }}
</el-descriptions-item>
<el-descriptions-item label="结束时间">
{{ formData.endTime }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">预约人信息</div>
<el-descriptions v-if="formData.appointmentUser" :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{ formData.appointmentUserName }}
</el-descriptions-item>
<el-descriptions-item label="工号">
{{ formData.appointmentLoginName }}
</el-descriptions-item>
<el-descriptions-item label="单位">
{{ formData.appointmentUnitName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">
{{ formData.appointmentMobile }}
</el-descriptions-item>
<el-descriptions-item label="预约咨询方式" :span="2">
<dict-tag :options="dict.type.LEGAL_ASK_TYPE"
:value="formData.askTypeValue"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="预约人备注" :span="2">
{{ formData.remark }}
</el-descriptions-item>
</el-descriptions>
<el-empty v-else description="暂无人预约"></el-empty>
<div class="left-span-label">咨询师信息</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="80px" label-position="left">
<el-form-item label="咨询师" prop="doctorUser">
<el-select
v-model="formData.doctorUser"
filterable
remote
style="width: 100%"
reserve-keyword
placeholder="请输入关键词"
:remote-method="queryDoctorUser">
<el-option
v-for="item in doctorUserList"
:key="item.id"
:label="item.mobile ? item.doctorUserName + '' + item.mobile + '' : item.doctorUserName + '(暂无手机号)'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="咨询方式" prop="askType">
<el-select
v-model="formData.askType"
filterable multiple
style="width: 100%"
placeholder="请选择咨询方式">
<el-option v-for="item in dict.type.LEGAL_ASK_TYPE"
:key="item.code"
:label="item.label"
:value="item.code"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('refresh'); infoDialogVisible = false">取消</el-button>
<el-button @click="onDelete" type="danger">删除</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</span>
</el-dialog>
</div>
`,
dicts:["LEGAL_ASK_TYPE"],
data() {
return {
formData: {},
formRules: {
startTime: [{required: true, message: '请选择开始时间', trigger: ['change', 'blur']}],
endTime: [{required: true, message: '请选择结束时间', trigger: ['change', 'blur']}],
doctorUser: [{required: true, message: '请选择咨询师', trigger: ['change', 'blur']}],
askType: [{type: 'array', required: true, message: '请选择咨询方式', trigger: 'change'}],
},
infoDialogVisible: false,
doctorUserList: [],
}
},
methods: {
onOpen(row) {
if (row.doctorUser) {
this.doctorUserList = [{
id: row.doctorUser,
doctorUserName: row.doctorUserName,
mobile: row.doctorMobile,
}]
}
row.askType = row ? JSON.parse(row.askType) : []
this.formData = row
this.infoDialogVisible = true
},
onDelete() {
let msg = '您确定要删除吗?'
if (this.formData.appointmentUser) {
msg = "<span style='color: red'>该时间段已有预约人</span>,您确定要删除吗?"
}
this.$confirm(msg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
dangerouslyUseHTMLString: true,
type: 'warning'
}).then(async () => {
const resp = await this.$axios.post('/platform/legal/appointmentSet/onDelete', {id: this.formData.id})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
this.infoDialogVisible = false
}
}).catch(() => {})
},
onSubmit() {
let msg = ''
if (this.formData.appointmentUser) {
msg += "<span style='color: red'>该时间段已有预约人</span>"
}
msg += '这将清空预约人已选择的咨询方式,您确定要修改咨询方式吗?';
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
dangerouslyUseHTMLString: true,
type: "warning"
}).then(async () => {
this.formData.askType = JSON.stringify(this.formData.askType)
const resp = await this.$axios.post("/platform/legal/appointmentSet/onEdit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
this.infoDialogVisible = false
} else {
this.$message.warning(resp.msg)
}
}).catch(() => {})
}
})
},
async queryDoctorUser(keyWord) {
const resp = await this.$axios.post('/platform/legal/appointmentSet/queryDoctorUser', {
keyWord,
startTimeTs: this.formData.startTimeTs,
endTimeTs: this.formData.endTimeTs,
})
this.doctorUserList = resp.data
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,124 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="姓名" prop="userId">
<el-select
style="width: 100%"
v-model="formData.userId"
filterable
remote
reserve-keyword
placeholder="请输入关键词"
:remote-method="selectQueryUser"
@change="selectUserChange"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.userName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-select v-model="formData.sex" placeholder="请选择性别" style="width: 100%">
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
</el-form-item>
<el-form-item label="职称" prop="technicalTitle">
<el-input v-model="formData.technicalTitle" placeholder="请输入职称"></el-input>
</el-form-item>
<el-form-item label="单位" prop="unitName">
<el-input v-model="formData.unitName" placeholder="请输入单位"></el-input>
</el-form-item>
<el-form-item label="联系方式" prop="mobile">
<el-input v-model.trim="formData.mobile" placeholder="请输入联系方式"></el-input>
</el-form-item>
<el-form-item label="特长" prop="specialty">
<el-input type="textarea" :rows="3" v-model="formData.specialty" placeholder="请输入特长"></el-input>
</el-form-item>
<el-form-item label="简介" prop="introduce">
<el-input type="textarea" :rows="3" v-model="formData.introduce" placeholder="请输入简介"></el-input>
</el-form-item>
<el-form-item label="头像" prop="avatar">
<file-upload :value.sync="formData.avatar" accept=".jpg,.jpeg,.png"
:upload_number="1" upload_result_category="interval"
complete_result upload_mode="drag"></file-upload>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
store,
data() {
return {
formData: {},
formRules: {
userId: [{required: true, message: '请输入姓名', trigger: ['change', 'blur']}],
sex: [{required: true, message: '请选择性别', trigger: ['change', 'blur']}],
jobTitle: [{required: true, message: '请输入职称', trigger: ['change', 'blur']}],
specialty: [{required: true, message: '请输入特长', trigger: ['change', 'blur']}],
introduce: [{required: true, message: '请输入简介', trigger: ['change', 'blur']}],
avatar: [{required: true, message: '请上传头像', trigger: ['change', 'blur']}],
},
userOptions: [],
}
},
methods: {
selectQueryUser(keyword) {
this.$axios.post("/platform/legal/doctorManage/listUser", { keyword: keyword }).then((res) => {
if (res.code === 0) {
this.userOptions = res.data
}
})
},
selectUserChange(val) {
if (val) {
const user = this.userOptions.find(v => v.id === val)
this.$set(this.formData, 'sex', user.sex)
this.$set(this.formData, 'mobile', user.mobile)
this.$set(this.formData, 'unitName', user.unitName)
this.$set(this.formData, 'technicalTitle', user.technicalTitle)
}
},
onOpen(row) {
if(row && row.id) {
this.userOptions = [
{
id: row.userId,
userName: row.userName,
loginName: row.loginName
}
]
this.formData = clone(row)
}
},
onSubmit() {
this.$refs.formRef.validate(async (valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/legal/doctorManage/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,162 @@
<!--#
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-input placeholder="请输入姓名或工号查询" v-model="pageForm.searchKeyword" clearable @keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="咨询师列表">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增咨询师
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize" row-key="id">
<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 === 'avatar'">
<el-popover
placement="top-start"
width="100"
trigger="hover">
<el-image
:src="row.avatar"
fit="cover">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<el-image
slot="reference"
style="height: 30px;"
:src="row.avatar"
fit="cover">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
</el-popover>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'loginName', label: '工号'},
{prop: 'userName', label: '姓名'},
{prop: 'sex', label: '性别'},
{prop: 'unitName', label: '单位'},
{prop: 'jobTitle', label: '职称'},
{prop: 'mobile', label: '联系电话'},
{prop: 'avatar', label: '头像'}
],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/legal/doctorManage/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,47 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{viewData.userName}}
</el-descriptions-item>
<el-descriptions-item label="性别">
{{viewData.sex}}
</el-descriptions-item>
<el-descriptions-item label="职称">
{{viewData.technicalTitle}}
</el-descriptions-item>
<el-descriptions-item label="单位">
{{viewData.unitName}}
</el-descriptions-item>
<el-descriptions-item label="联系方式" :span="2">
{{viewData.mobile}}
</el-descriptions-item>
<el-descriptions-item label="特长" :span="2">
{{viewData.specialty}}
</el-descriptions-item>
<el-descriptions-item label="简介" :span="2">
{{viewData.introduce}}
</el-descriptions-item>
<el-descriptions-item label="头像" :span="2">
<img :src="viewData.avatar"
style="height: 100px;width: auto" v-if="viewData.avatar">
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = clone(row)
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,122 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</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">
<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 === 'appointmentTime'">
{{ row.startTime + ' 至 ' + row.endTime }}
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="$moment().unix() < $moment(row.startTime).unix()"
@click="onDelete(row)" size="mini" type="danger">取消</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'appointmentTime', label: '预约时间', width: '350'},
{prop: 'appointmentUserName', label: '姓名'},
{prop: 'appointmentLoginName', label: '工号'},
{prop: 'appointmentUnitName', label: '单位'},
{prop: 'doctorUserName', label: '心理咨询师'},
],
}
},
methods: {
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/legal/list/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,70 @@
const info = {
template: /*language=HTML*/ `
<div>
<div class="left-span-label">预约时间段</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="开始时间">
{{ viewData.startTime }}
</el-descriptions-item>
<el-descriptions-item label="结束时间">
{{ viewData.endTime }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">预约人信息</div>
<el-descriptions v-if="viewData.userId" :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{ viewData.appointmentUserName }}
</el-descriptions-item>
<el-descriptions-item label="工号">
{{ viewData.appointmentLoginName }}
</el-descriptions-item>
<el-descriptions-item label="单位">
{{ viewData.appointmentUnitName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">
{{ viewData.appointmentMobile }}
</el-descriptions-item>
<el-descriptions-item label="预约咨询方式" :span="2">
<dict-tag :options="dict.type.LEGAL_ASK_TYPE"
:value="viewData.askTypeValue"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="预约人备注" :span="2">
{{ viewData.remark }}
</el-descriptions-item>
</el-descriptions>
<el-empty v-else description="暂无人预约"></el-empty>
<div class="left-span-label">咨询师信息</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{ viewData.doctorUserName }}
</el-descriptions-item>
<el-descriptions-item label="工号">
{{ viewData.doctorUnitName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">
{{ viewData.doctorMobile }}
</el-descriptions-item>
<el-descriptions-item label="职称">
{{ viewData.doctorJobTitle }}
</el-descriptions-item>
<el-descriptions-item label="个人简介" :span="2">
{{ viewData.doctorIntroduce }}
</el-descriptions-item>
</el-descriptions>
</div>
`,
dicts:["LEGAL_ASK_TYPE"],
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = clone(row)
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,70 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="咨询人姓名">
<el-input :value="$store.state.user.username" readonly></el-input>
</el-form-item>
<el-form-item label="咨询人工号">
<el-input :value="$store.state.user.loginname" readonly></el-input>
</el-form-item>
<el-form-item label="咨询主题" prop="postTitle">
<el-input v-model="formData.postTitle" maxlength="20" placeholder="请简约填写咨询主题,不超过20个字"></el-input>
</el-form-item>
<el-form-item label="主要内容" prop="postContent">
<el-input type="textarea" rows="5" v-model="formData.postContent" maxlength="500"
placeholder="请输入内容"></el-input>
</el-form-item>
<el-form-item>
<div class="text-primary">
<i class="el-icon-warning"></i>
提示不会发布您的个人隐私信息您咨询的内容只有心理咨询师可查看并回复
</div>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
store,
data() {
return {
formData: {},
formRules: {
postTitle: [{required: true, message: '请输入咨询主题', trigger: ['change', 'blur']}],
postContent: [{required: true, message: '请输入咨询内容', trigger: ['change', 'blur']}],
},
}
},
methods: {
onOpen(row) {
if(row && row.id) {
this.formData = clone(row)
}
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/legal/onlinePost/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,160 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="是否回复:">
<el-select v-model="pageForm.isReply" style="width: 100%" @change="doSearch">
<el-option :value="null" label="全部"></el-option>
<el-option :value="true" label="已回复"></el-option>
<el-option :value="false" label="未回复"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="咨询记录">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
我要咨询
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize" row-key="id">
<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 === 'isReply'">
<el-tag type="success" v-if="row.isReply">已回复</el-tag>
<el-tag type="info" v-else>未回复</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button v-if="!row.isReply" @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'loginName', label: '工号'},
{prop: 'userName', label: '姓名'},
{prop: 'postTitle', label: '标题'},
{prop: 'postingTime', label: '咨询时间'},
{prop: 'isReply', label: '回复情况'}
],
pageForm: {
year: new Date().getFullYear() + '',
isReply: null,
},
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
const url = '/platform/legal/onlinePost/fetchOne'
this.$refs.infoRef.onOpen(row, url)
})
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/legal/onlinePost/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,73 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="咨询人">
{{ viewData.userName }}
</el-descriptions-item>
<el-descriptions-item label="咨询时间">
{{ viewData.postingTime }}
</el-descriptions-item>
<el-descriptions-item label="咨询主题" :span="2">
{{ viewData.postTitle }}
</el-descriptions-item>
<el-descriptions-item label="主要内容" :span="2">
{{ viewData.postContent }}
</el-descriptions-item>
<el-descriptions-item label="回复信息" :span="2">
<el-timeline v-if="viewData.replyList && viewData.replyList.length > 0">
<el-timeline-item
v-for="(item, index) in viewData.replyList"
:key="index"
size="large"
type="primary"
:timestamp="item.replyTime">
<div class="user-face">
<svg t="1639966214107" class="icon" viewBox="0 0 3208 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="6251" width="80" height="30">
<path d="M343.496334 367.185736m-225.049322 0a225.049322 225.049322 0 1 0 450.098644 0 225.049322 225.049322 0 1 0-450.098644 0Z"
fill="#FFFFFF" p-id="6252"></path>
<path d="M1879.043392 0H355.341035c-3.079622 0-20.846674 23.689402-23.689402 23.689402 14.687429 3.079622 23.689402-11.370913 33.638951 0C400.350899 58.512824 450.098644 99.49549 497.477449 94.757609h23.689402c37.903044 0 58.512824 5.685457 57.565248 41.693348a155.639373 155.639373 0 0 0 71.068207 118.447012 76.51677 76.51677 0 0 1 10.186443 6.869927 64.19828 64.19828 0 0 1 9.001973 93.573139 152.796645 152.796645 0 0 0-23.689403 134.318911 58.27593 58.27593 0 0 1 3.553411 12.555383A66.567221 66.567221 0 0 1 592.235058 578.495205a161.087936 161.087936 0 0 0-108.260569 87.650788 77.227452 77.227452 0 0 1-6.159244 12.555384c-14.924323 23.689402-19.42531 11.370913-47.378805 6.869926L426.409242 686.992667h9.001973l11.370913 23.689403h1432.261264C2071.164445 710.68207 2226.803818 562.149517 2226.803818 379.030437v-47.378804c0-183.11908-155.639373-331.651633-347.760426-331.651633z"
fill="#EDF5FE" p-id="6253"></path>
<path d="M688.650926 261.767896a74.147829 74.147829 0 0 0-9.949549-6.869927 156.586949 156.586949 0 0 1-67.514797-118.447012 65.619644 65.619644 0 0 0-63.961386-66.804114 61.355552 61.355552 0 0 0-13.266066 1.18447 154.218009 154.218009 0 0 1-126.975196-47.378805 65.145856 65.145856 0 0 0-36.718574-21.557356 21.320462 21.320462 0 0 0-12.318489 12.081595 324.544812 324.544812 0 0 0-58.039036 23.689403 334.020573 334.020573 0 0 1 58.27593-23.689403 21.79425 21.79425 0 0 1 12.555383-12.081595 64.19828 64.19828 0 0 0-54.722519 12.318489 78.88571 78.88571 0 0 0-10.423337 9.475761 154.691797 154.691797 0 0 1-126.975196 47.378805 65.619644 65.619644 0 0 0-76.51677 52.116685 61.355552 61.355552 0 0 0 0 13.266065 157.060737 157.060737 0 0 1-67.514797 118.447012 66.567221 66.567221 0 0 0-23.689402 90.967305 55.433201 55.433201 0 0 0 4.974775 9.475761 158.95589 158.95589 0 0 1 23.689402 134.555805 65.856538 65.856538 0 0 0 37.903044 85.281848 56.617672 56.617672 0 0 0 12.792277 3.553411 156.586949 156.586949 0 0 1 103.522688 87.650788 65.145856 65.145856 0 0 0 82.43912 40.982666 86.466318 86.466318 0 0 0 12.555383-5.92235 154.218009 154.218009 0 0 1 135.266488 0 66.567221 66.567221 0 0 0 22.268038 8.054397 64.672068 64.672068 0 0 0 66.330326-30.559329 59.934188 59.934188 0 0 0 5.685457-12.555384 156.586949 156.586949 0 0 1 103.522688-87.650788 66.330327 66.330327 0 0 0 54.248731-76.279876 58.27593 58.27593 0 0 0-3.55341-12.555383 158.482102 158.482102 0 0 1 23.689402-134.318911 66.330327 66.330327 0 0 0-7.580608-93.810033zM355.341035 564.281563v17.530158a129.107243 129.107243 0 0 0 99.258596 125.316938A129.107243 129.107243 0 0 1 355.341035 581.811721v-17.530158L194.016205 240.684328h81.017756L355.341035 416.933481V25.110766 416.933481l81.017756-176.486047h81.017756zM921.51775 298.249575a584.891343 584.891343 0 0 1-98.074125 96.415868l-20.60978-22.504932a501.978435 501.978435 0 0 0 94.757609-92.151776z m-86.703212-120.10527a415.275223 415.275223 0 0 1 71.068207 54.959414l-21.79425 21.320462a450.098644 450.098644 0 0 0-70.594419-55.433201z m295.643741 227.181369v154.691797h-29.848647v-20.846674h-218.890078v20.846674H852.818484v-154.691797z m-248.738725 104.944052h218.890078v-76.042981h-218.890078z m101.153748-275.507749a260.583426 260.583426 0 0 1-47.378804 62.303128l-19.188416-23.689402a225.996898 225.996898 0 0 0 60.171082-108.260569l30.559329 3.790305c-3.079622 11.607807-6.869927 23.689402-11.370913 36.718573H1160.780714v24.400085a351.55073 351.55073 0 0 1-41.930242 71.068207l-22.504932-18.003946a268.874716 268.874716 0 0 0 30.559329-47.378805h-68.462373c0 16.819476-2.36894 29.374859-3.553411 37.429256 18.003946 47.378805 61.118658 78.648816 129.581031 94.757609l-12.792277 29.137965c-65.619644-18.003946-108.023675-47.378805-127.448985-91.441093-20.372886 40.745772-62.540022 71.068207-126.264514 89.309047l-13.029171-27.716601c68.699267-18.003946 108.734357-48.800169 118.447011-92.151775a298.486469 298.486469 0 0 0 4.027199-38.85062zM1221.18869 299.197151h92.151775v189.515219c11.370913-9.949549 26.058343-23.689402 43.825394-41.693348l8.528185 32.454481A544.856253 544.856253 0 0 1 1286.334546 544.856253l-11.844701-27.242812a25.821449 25.821449 0 0 0 9.475761-18.951522v-170.089909h-62.776916z m51.169109-126.264514a502.926011 502.926011 0 0 1 71.068207 65.619644l-20.846674 21.320462a458.153041 458.153041 0 0 0-72.489571-66.093432z m170.089908 0a395.139231 395.139231 0 0 1-13.502959 42.640924h167.957863q0 231.445461-5.922351 288.53692a54.485625 54.485625 0 0 1-60.64487 53.301156l-40.508878-1.18447-7.343715-27.716601c23.689402 0 37.429256 1.658258 44.062289 1.658258 19.662204 0 31.033117-12.555383 34.586527-37.903044s4.500986-108.260569 5.448563-247.791148h-150.901493a310.33117 310.33117 0 0 1-56.617672 76.279875l-19.42531-23.689402a260.583426 260.583426 0 0 0 72.252677-129.581031z m-58.749717 121.526634h130.528607v195.200675h-130.528607z m29.848647 83.860484h71.068207v-58.749718h-71.068207z m71.068207 84.80806V402.71984h-71.068207v59.223505zM1741.881753 170.800591h29.848647v203.018178q-1.895152 126.975196-86.940107 185.961808l-23.689402-20.135992c52.827367-34.586527 79.359498-90.019729 80.307074-165.825816z m-75.095405 55.906989h29.848646V450.098644h-29.848646z m131.002394-40.508878H2037.2886v29.848647h-104.707158v52.353579h87.650788v208.940529c0 23.689402-10.660231 35.534103-32.217587 35.534103h-29.137965l-8.054397-29.848647 27.242813 1.658259c8.528185 0 12.792277-4.500986 12.792277-13.739854v-173.880213h-58.275929v260.583426h-30.085541v-260.583426h-58.27593v218.653184h-29.374859V268.400928h87.650789V216.047349h-104.707159z"
fill="#4492F4" p-id="6254"></path>
</svg>
<span>{{ item.userName }}</span>
</div>
<div>回复内容{{ item.replyContent }}</div>
</el-timeline-item>
</el-timeline>
<span v-else>暂无人回复</span>
</el-descriptions-item>
</el-descriptions>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row, url) {
this.$axios.post(url, { id: row.id })
.then((resp) => {
this.viewData = resp.data
})
},
},
style: /*language=CSS*/ `
.el-timeline-item {
padding-bottom: 20px;
}
.el-timeline-item__wrapper {
padding-left: 28px;
top: -3px;
}
.el-timeline-item__tail {
left: 4px;
}
.user-face{
display: flex;
}
`
}
@@ -0,0 +1,69 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<div class="left-span-label">基本情况</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="咨询人">
{{ viewData.posterUserName }}
</el-descriptions-item>
<el-descriptions-item label="咨询时间">
{{ viewData.postingTime }}
</el-descriptions-item>
<el-descriptions-item label="咨询主题" :span="2">
{{ viewData.postTitle }}
</el-descriptions-item>
<el-descriptions-item label="主要内容" :span="2">
{{ viewData.postContent }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">我来回复</div>
<el-form-item label="回复内容" prop="replyContent">
<el-input type="textarea" rows="3" v-model="formData.replyContent" placeholder="请输入回复内容"></el-input>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
store,
data() {
return {
formData: {},
formRules: {
replyContent: [{required: true, message: '请输入回复内容', trigger: ['change', 'blur']}],
},
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = clone({ ...row })
this.$set(this.formData, 'postId', row.id)
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/legal/onlineReply/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,132 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="是否回复:">
<el-select v-model="pageForm.isReply" style="width: 100%" @change="doSearch">
<el-option :value="null" label="全部"></el-option>
<el-option :value="true" label="已回复"></el-option>
<el-option :value="false" label="未回复"></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" row-key="id">
<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 === 'replyCount'">
<el-tag type="success" v-if="row.replyCount > 0">已回复</el-tag>
<el-tag type="info" v-else>未回复</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onReply(row)" size="mini" type="primary">回复</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('../onlinePost/info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'posterUserName', label: '姓名'},
{prop: 'postTitle', label: '标题'},
{prop: 'postingTime', label: '咨询时间'},
{prop: 'replyCount', label: '回复情况'}
],
pageForm: {
year: new Date().getFullYear() + '',
isReply: null,
},
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
const url = '/platform/legal/onlineReply/fetchOne'
this.$refs.infoRef.onOpen(row, url)
})
},
onReply(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,256 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.top-col {
background-color: white;
position: relative;
box-sizing: border-box;
padding: 20px;
width: calc((100% - (20px * 3)) / 4);
overflow: hidden;
color: #FFFFFF;
border-radius: 4px;
}
.top-col:hover {
transform: scale(1.01);
}
.top-col:not(:last-child), .center-col:not(:last-child) {
margin-right: 20px;
}
.col-title {
font-size: 14px;
margin-bottom: 10px;
color: #FFFFFF;
}
.top-col-member-number {
font-size: 30px;
color: #FFFFFF;
}
.top-col-chart {
height: 80px;
width: 100%;
position: relative;
}
.center-col {
background-color: white;
position: relative;
box-sizing: border-box;
padding: 20px;
}
.el-table__body-wrapper::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
.el-table__body-wrapper {
scrollbar-width: none; /* firefox */
-ms-overflow-style: none; /* IE 10+ */
overflow-x: hidden;
overflow-y: auto;
}
@media screen and (max-width: 500px) {
.num-card {
flex-direction: column;
}
.num-card .top-col {
width: 100%;
margin-bottom: 10px;
}
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<el-row type="flex" class="num-card">
<el-col :span="6" class="top-col" style="background: rgb(248, 108, 107)">
<div class="col-title">总开放场次</div>
<div class="top-col-member-number">
{{numAreaMap?.total || 0}}
<span style="font-size: 14px">&ensp;</span>
</div>
</el-col>
<el-col :span="6" class="top-col" style="background: rgb(133, 149, 244)">
<div class="col-title">预约成功场次</div>
<div class="top-col-member-number">
{{numAreaMap?.successNum || 0}}
<span style="font-size: 14px">&ensp;</span>
</div>
</el-col>
<el-col :span="6" class="top-col" style="background: rgb(254, 187, 80)">
<div @click="tableIndex = 1; tableChange()">
<div class="col-title">咨询师人数</div>
<div class="top-col-member-number">
{{numAreaMap?.doctorCount || 0}}
<span style="font-size: 14px">&ensp;</span>
</div>
</div>
</el-col>
<el-col :span="6" class="top-col" style="background: #26A65B">
<div @click="tableIndex = 2; tableChange()">
<div class="col-title">总计服务教师人数</div>
<div class="top-col-member-number">
{{numAreaMap?.serviceTeacherCount || 0}}
<span style="font-size: 14px">&ensp;</span>
</div>
</div>
</el-col>
</el-row>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool :label="tableLabel"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<el-table-column label="序号" type="index" 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-column v-if="tableIndex === 1" label="操作" width="100">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
</guava>
<el-dialog :visible.sync="infoDialogVisible"
width="60%" title="服务教师列表"
:close-on-click-modal="false"
append-to-body>
<el-table :data="infoTableData">
<el-table-column label="序号" type="index" 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 infoTableColumns"
>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="infoDialogVisible = false" type="primary">确定</el-button>
</span>
</el-dialog>
</div>
<script>
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
infoDialogVisible: false,
tableLabel: '按咨询师统计',
tableColumns: [],
infoTableColumns: [],
doctorTableColumns: [
{prop: 'doctorUserName', label: '咨询师'},
{prop: 'sex', label: '性别'},
{prop: 'jobTitle', label: '职称'},
{prop: 'serviceNum', label: '服务次数'},
],
teacherTableColumns: [
{prop: 'userName', label: '教师'},
{prop: 'unitName', label: '所属单位'},
{prop: 'unionName', label: '所属工会'},
{prop: 'startTime', label: '开始时间'},
{prop: 'endTime', label: '结束时间'},
{prop: 'doctorUserName', label: '咨询师'},
],
numAreaMap: {},
tableIndex: 1,
infoTableData: [],
}
},
methods: {
doSearch() {
this.queryCount()
this.tableChange()
},
onView(row) {
this.infoTableColumns = this.teacherTableColumns
this.$axios.post(loc() + "/pageData", {
year: this.pageForm.year,
tableIndex: 2,
doctorUser: row.userId
}).then((res) => {
if (res.code === 0) {
this.infoTableData = res.data
this.infoDialogVisible = true
}
})
},
tableChange() {
this.pageForm.tableIndex = this.tableIndex
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data
}
})
},
queryCount() {
this.$axios.post(loc() + "/queryCount", this.pageForm).then((res) => {
if (res.code === 0) {
this.numAreaMap = res.data
}
})
},
},
async created() {
this.tableColumns = this.doctorTableColumns
this.queryCount()
this.tableChange()
},
watch: {
tableIndex(val) {
this.tableColumns = val === 1 ? this.doctorTableColumns : this.teacherTableColumns
}
},
})
</script>
<!--#
}
#-->
@@ -0,0 +1,62 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item prop="title" label="标题">
<el-input type="text" v-model="formData.title" maxlength="50"
placeholder="请填写标题"></el-input>
</el-form-item>
<el-form-item prop="url" label="链接">
<el-input type="text" v-model="formData.url" maxlength="50"
placeholder="请填写链接"></el-input>
</el-form-item>
<el-form-item prop="bz" label="备注">
<el-input type="textarea" v-model="formData.bz"
placeholder="请填写备注"></el-input>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
data() {
return {
formData: {},
formRules: {
title: [{required: true, message: '必填', trigger: ['change', 'blur']}],
url: [{required: true, message: '必填', trigger: ['change', 'blur']}],
},
}
},
methods: {
onOpen(row) {
if (row && row.id) {
this.formData = clone(row)
}
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/legal/study/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,135 @@
<!--#
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-input placeholder="请输入标题或链接" v-model="pageForm.searchKeyword" clearable @keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="资料列表">
<el-button v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('SCHOOL_UNION_ADMIN')"
type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增资料
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize" row-key="id">
<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 === 'url'">
<el-link type="primary" @click="onView(row)">{{ row.url }}</el-link>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'createdAt'">
{{ $moment(row.createdAt).format('YYYY-MM-DD') }}
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
},
data() {
return {
tableColumns: [
{prop: 'title', label: '标题'},
{prop: 'url', label: '链接'},
{prop: 'username', label: '创建人'},
{prop: 'createdAt', label: '创建时间'},
],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
window.open(row.url)
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/legal/study/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,124 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-dialog :visible.sync="addDialogVisible"
width="50%" title="心理咨询预约"
:close-on-click-modal="false"
append-to-body>
<div class="left-span-label">预约时间段</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="开始时间">
{{ formData.startTime }}
</el-descriptions-item>
<el-descriptions-item label="结束时间">
{{ formData.endTime }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">咨询师信息</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{ formData.doctorUserName }}
</el-descriptions-item>
<el-descriptions-item label="性别">
{{ formData.doctorSex }}
</el-descriptions-item>
<el-descriptions-item label="单位">
{{ formData.doctorUnitName }}
</el-descriptions-item>
<el-descriptions-item label="电话">
{{ formData.doctorMobile }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">预约人信息</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="姓名">
<el-input :value="$store.state.user.username" readonly></el-input>
</el-form-item>
<el-form-item label="工号">
<el-input :value="$store.state.user.loginname" readonly></el-input>
</el-form-item>
<el-form-item label="单位">
<el-input :value="$store.state.user.unit.name" readonly></el-input>
</el-form-item>
<el-form-item label="联系方式" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入联系方式"></el-input>
</el-form-item>
<el-form-item label="预约咨询方式" prop="askTypeValue">
<el-select
v-model="formData.askTypeValue"
filterable
style="width: 100%"
placeholder="请选择咨询方式">
<el-option v-for="item in askTypeOptions"
:key="item.code"
:label="item.name"
:value="item.code">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="预约备注" prop="remark">
<el-input type="textarea" :row="3" v-model="formData.remark"
placeholder="请输入预约备注事项"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('refresh'); addDialogVisible = false">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</span>
</el-dialog>
</div>
`,
dicts: ["PSYCHOLOGY_ASK_TYPE"],
store,
data() {
return {
formData: {},
formRules: {
askTypeValue: [{required: true, message: '请选择咨询方式', trigger: ['change']}],
mobile: [{required: true, message: '请输入联系方式', trigger: ['change']}],
},
addDialogVisible: false,
askTypeOptions: [],
}
},
methods: {
onOpen(row) {
if(row.askType) {
row.askType = JSON.parse(row.askType)
this.askTypeOptions = this.dict.type.PSYCHOLOGY_ASK_TYPE.filter(o => row.askType.includes(o.code))
}
this.formData = clone(row)
if(this.askTypeOptions.length > 0) {
this.$set(this.formData, 'askTypeValue', this.askTypeOptions[0].code)
}
this.$set(this.formData, 'mobile', this.$store.state.user.mobile)
this.addDialogVisible = true
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/psychology/apply/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
this.addDialogVisible = false
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
created() {
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,213 @@
<!--#
layout("/layouts/platform.html"){
#-->
<link rel="stylesheet" href="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.css">
<script src="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.min.js"></script>
<style>
#calendar {
max-width: 1200px;
margin: 20px auto 0;
}
.fc-toolbar {
display: block !important;
visibility: unset !important;
}
.green {
color: #FFFFFF;
background-color: #369a5f;
border: 1px solid #257e4a;
}
.yellow {
color: #FFFFFF;
background-color: #f3b20f;
border: 1px solid #af7d00;
}
.red {
color: #FFFFFF;
background-color: #ea5454;
border: 1px solid #b11616;
}
.fc-time-grid-event.fc-short .fc-time:before {
content: none;
}
.fc-time-grid-event.fc-short .fc-time span {
display: block;
}
.fc-ltr .fc-time-grid .fc-event-container {
margin: 0;
}
.el-row--flex.is-justify-space-between {
justify-content: flex-start;
}
.fc-icon {
height: 1.5em;
line-height: 1.5em;
}
.fc-event .fc-content {
padding: 3px;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<div id="psychology-calendar"></div>
</el-card>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</div>
<script>
<!--#include('basicForm.js'){}#-->
let calendar = null
const vue = new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
},
data() {
return {
calendarHeight: 0,
events: [],
}
},
methods: {
refresh() {
calendar.fullCalendar('unselect')
this.queryAppointmentInfo()
},
initCalendar() {
const that = this
const today = this.$moment().format('YYYY-MM-DD')
if (calendar) return
calendar = $('#psychology-calendar').fullCalendar({
header: { //设置日历头部信息,false,则不显示头部信息。包括left,center,right左中右三个位置
left: 'prev, next, today', //上一个、下一个、今天
center: 'title', //标题
right: 'month,agendaWeek,agendaDay,listMonth' //月、周、日、日程列表
},
locale: 'zh-cn', //?没用?
timeFormat: 'HH:mm', //日程事件的时间格式
buttonText: { //各按钮的显示文本信息
today: '今天',
month: '月',
agendaWeek: '周',
agendaDay: '日',
listMonth: '日程',
},
slotMinTime: '11:00:00',
monthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], //月份全称
monthNamesShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], //月份简写
dayNames: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], //周全称
dayNamesShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], //周简写
noEventsMessage: "当月无数据", //listview视图下,无数据提示
allDayText: "全天", //自定义全天视图的名称
allDaySlot: false, //是否在周日历上方显示全天
allDayDefault: false, //是否为全天日程事件,显示这一天中所做的事情
slotDuration: "00:30:00", //一格时间槽代表多长时间,默认00:30:00(30分钟)
slotLabelFormat: "H(:mm)a", //日期视图左边那一列显示的每一格日期时间格式
slotLabelInterval: "00:30:00", //日期视图左边那一列多长间隔显示一条日期文字(默认跟着slotDuration走的,可自定义)
snapDuration: "00:30:00", //其实就是动态创建一个日程时,默认创建多长的时间块
firstDay: 1, //一周中显示的第一天是哪天,周日是0,周一是1,类推
hiddenDays: [], //隐藏一周中的某一天或某几天,数组形式,如隐藏周二和周五:[2,5],默认不隐藏,除非weekends设置为false。
weekends: true, //是否显示周六和周日,设为false则不显示周六和周日。默认值为true
weekMode: 'fixed', //月视图里显示周的模式,因每月周数不同月视图高度不定。fixed:固定显示6周高,日历高度保持不变liquid:不固定周数,高度随周数变化variable:不固定周数,但高度固定
weekNumbers: false, //是否在日历中显示周次(一年中的第几周),如果设置为true,则会在月视图的左侧、周视图和日视图的左上角显示周数。
weekNumberCalculation: 'iso', //周次的显示格式。
height: that.calendarHeight, //设置日历的高度,包括header日历头部,默认未设置,高度根据aspectRatio值自适应。
// contentHeight: 600, //设置日历主体内容的高度,不包括header部分,默认未设置,高度根据aspectRatio值自适应。
handleWindowResize: true, //是否随浏览器窗口大小变化而自动变化。
defaultView: 'agendaWeek', //初始化时默认视图,默认是月monthagendaWeek是周,agendaDay是当天
slotEventOverlap: false, //事件是否可以重叠覆盖
defaultDate: today, //默认显示那一天的日期视图getDates(true)2020-05-10
nowIndicator: false, //周/日视图中显示今天当前时间点(以红线标记),默认false不显示
eventLimit: 2, //数据条数太多时,限制显示条数(多余的以“+2more”格式显示),默认false不限制,支持输入数字设定固定的显示条数
eventLimitText: "更多", //当一块区域内容太多以"+2 more"格式显示时,这个more的名称自定义(应该与eventLimit: true一并用)
dayPopoverFormat: "YYYY年M月d日预约信息", //点开"+2 more"弹出的小窗口标题,与eventLimitClick可以结合用
render: (view) => { //method,绑定日历到id上。$('#id').fullCalendar('render');
},
viewRender: (view) => {
that.queryAppointmentInfo()
},
eventRender: (info) => {
},
//日历数据源
events: that.events,
//日程事件点击
eventClick: (event, jsEvent) => {
if (event.data.appointmentUser) return
if (new Date().getTime() > event.data.startTimeTs) return
this.$refs.basicFormRef.onOpen(clone(event.data))
},
selectable: false, //是否允许通过单击或拖动选择日历中的对象,包括天和时间
selectMirror: true, //镜像
lazyFetching: false, //是否启用懒加载技术--即只取当前条件下的视图数据,其它数据在切换时触发,默认true只取当前视图的,false是取全视图的
defaultTimedEventDuration: "00:30:00", //在Event Object中如果没有end参数时使用,如start=7:00pm,则该日程对象时间范围就是7:00~9:00
defaultAllDayEventDuration: {days: 1}, //默认1天是多长,(有的是采用工作时间模式,所以支持自定义)
});
},
//获取预约数据
async queryAppointmentInfo() {
if (!calendar) return
const view = calendar.fullCalendar('getView')
//这里取时间戳
const startTimeTs = view.start._i
const endTimeTs = view.end._i
const resp = await this.$axios.post('/platform/psychology/appointmentSet/queryAppointmentInfo', {startTimeTs, endTimeTs})
let events = []
if (resp.code === 0) {
resp.data.forEach(v => {
let className = ''
let title = ''
if (new Date().getTime() > v.startTimeTs) {
className = 'gray'
title = '不可预约'
} else {
if (!v.appointmentUser) {
className = 'green'
title = '可预约'
} else if (v.appointmentUser === this.$store.state.user.id) {
className = 'blue'
title = '我已预约'
} else {
className = 'gray'
title = '不可预约'
}
}
events.push({
id: v.id,
title: title,
start: v.startTime,
end: v.endTime,
className: className,
data: v,
})
})
}
calendar.fullCalendar('removeEvents', () => true)
calendar.fullCalendar('addEventSource', events, true)
},
init() {
this.$nextTick(() => {
setTimeout(() => {
this.initCalendar()
this.queryAppointmentInfo()
}, 100)
})
},
},
mounted() {
this.calendarHeight = window.innerHeight - 160
},
async created() {
this.init()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,125 @@
const addForm = {
template: /*language=HTML*/ `
<div>
<el-dialog :visible.sync="addDialogVisible"
width="30%" title="新增预约时间段"
:close-on-click-modal="false"
append-to-body>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="80px" label-position="left">
<el-form-item label="开始时间" prop="startTime">
<el-date-picker
readonly
style="width: 100%"
v-model="formData.startTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
placeholder="请选择日期时间">
</el-date-picker>
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker
readonly
style="width: 100%"
v-model="formData.endTime"
value-format="yyyy-MM-dd HH:mm:ss"
type="datetime"
placeholder="请选择日期时间">
</el-date-picker>
</el-form-item>
<el-form-item label="咨询师" prop="doctorUser">
<el-select
v-model="formData.doctorUser"
filterable
remote
style="width: 100%"
reserve-keyword
placeholder="请输入关键词"
:remote-method="queryDoctorUser">
<el-option
v-for="item in doctorUserList"
:key="item.id"
:label="item.mobile ? item.doctorUserName + '' + item.mobile + '' : item.doctorUserName + '(暂无手机号)'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="咨询方式" prop="askType">
<el-select
v-model="formData.askType"
filterable multiple
style="width: 100%"
placeholder="请选择咨询方式">
<el-option v-for="item in dict.type.PSYCHOLOGY_ASK_TYPE"
:key="item.code"
:label="item.label"
:value="item.code"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('refresh'); addDialogVisible = false">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</span>
</el-dialog>
</div>
`,
store,
dicts:["PSYCHOLOGY_ASK_TYPE"],
data() {
return {
addDialogVisible: false,
formData: {},
formRules: {
startTime: [{required: true, message: '请选择开始时间', trigger: ['change', 'blur']}],
endTime: [{required: true, message: '请选择结束时间', trigger: ['change', 'blur']}],
doctorUser: [{required: true, message: '请选择咨询师', trigger: ['change', 'blur']}],
askType: [{type: 'array', required: true, message: '请选择咨询方式', trigger: 'change'}],
},
doctorUserList: [],
}
},
methods: {
onOpen(row) {
this.formData = row
this.addDialogVisible = true
},
async queryDoctorUser(keyWord) {
const resp = await this.$axios.post(loc() + '/queryDoctorUser', {
keyWord,
startTimeTs: this.formData.startTimeTs,
endTimeTs: this.formData.endTimeTs,
})
this.doctorUserList = resp.data
},
onSubmit() {
if (Date.parse(this.formData.startTime) < new Date().getTime()) {
this.$message.warning('预约时间不能小于当前时间,请重新设置')
this.$emit('refresh')
this.addDialogVisible = false
return
}
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
this.formData.askType = JSON.stringify(this.formData.askType)
const resp = await this.$axios.post("/platform/psychology/appointmentSet/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
this.addDialogVisible = false
} else {
this.$message.warning(resp.msg)
}
}).catch(() => {})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,225 @@
<!--#
layout("/layouts/platform.html"){
#-->
<link rel="stylesheet" href="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.css">
<script src="${base!}/assets/platform/plugins/fullcalendar/fullcalendar.min.js"></script>
<style>
#calendar {
max-width: 1200px;
margin: 20px auto 0;
}
.fc-toolbar {
display: block !important;
visibility: unset !important;
}
.green {
color: #FFFFFF;
background-color: #369a5f;
border: 1px solid #257e4a;
}
.yellow {
color: #FFFFFF;
background-color: #f3b20f;
border: 1px solid #af7d00;
}
.red {
color: #FFFFFF;
background-color: #ea5454;
border: 1px solid #b11616;
}
.fc-time-grid-event.fc-short .fc-time:before {
content: none;
}
.fc-time-grid-event.fc-short .fc-time span {
display: block;
}
.fc-ltr .fc-time-grid .fc-event-container {
margin: 0;
}
.el-row--flex.is-justify-space-between {
justify-content: flex-start;
}
.fc-icon {
height: 1.5em;
line-height: 1.5em;
}
.fc-event .fc-content {
padding: 3px;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<div id="psychology-calendar"></div>
</el-card>
<add-form ref="addFormRef" @refresh="refresh"></add-form>
<info ref="infoRef" @refresh="refresh"></info>
</div>
<script>
<!--#include('addForm.js'){}#-->
<!--#include('info.js'){}#-->
let calendar = null
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"add-form": addForm,
"info": info,
},
data() {
return {
calendarHeight: 0,
events: [],
}
},
methods: {
refresh() {
calendar.fullCalendar('unselect')
this.queryAppointmentInfo()
},
initCalendar() {
const that = this
const today = this.$moment().format('YYYY-MM-DD')
if (calendar) return
calendar = $('#psychology-calendar').fullCalendar({
header: { //设置日历头部信息,false,则不显示头部信息。包括left,center,right左中右三个位置
left: 'prev, next, today', //上一个、下一个、今天
center: 'title', //标题
right: 'month,agendaWeek,agendaDay,listMonth' //月、周、日、日程列表
},
locale: 'zh-cn', //?没用?
timeFormat: 'HH:mm', //日程事件的时间格式
buttonText: { //各按钮的显示文本信息
today: '今天',
month: '月',
agendaWeek: '周',
agendaDay: '日',
listMonth: '日程',
},
slotMinTime: '11:00:00',
monthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], //月份全称
monthNamesShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"], //月份简写
dayNames: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], //周全称
dayNamesShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"], //周简写
noEventsMessage: "当月无数据", //listview视图下,无数据提示
allDayText: "全天", //自定义全天视图的名称
allDaySlot: false, //是否在周日历上方显示全天
allDayDefault: false, //是否为全天日程事件,显示这一天中所做的事情
slotDuration: "00:30:00", //一格时间槽代表多长时间,默认00:30:00(30分钟)
slotLabelFormat: "H(:mm)a", //日期视图左边那一列显示的每一格日期时间格式
slotLabelInterval: "00:30:00", //日期视图左边那一列多长间隔显示一条日期文字(默认跟着slotDuration走的,可自定义)
snapDuration: "00:30:00", //其实就是动态创建一个日程时,默认创建多长的时间块
firstDay: 1, //一周中显示的第一天是哪天,周日是0,周一是1,类推
hiddenDays: [], //隐藏一周中的某一天或某几天,数组形式,如隐藏周二和周五:[2,5],默认不隐藏,除非weekends设置为false。
weekends: true, //是否显示周六和周日,设为false则不显示周六和周日。默认值为true
weekMode: 'fixed', //月视图里显示周的模式,因每月周数不同月视图高度不定。fixed:固定显示6周高,日历高度保持不变liquid:不固定周数,高度随周数变化variable:不固定周数,但高度固定
weekNumbers: false, //是否在日历中显示周次(一年中的第几周),如果设置为true,则会在月视图的左侧、周视图和日视图的左上角显示周数。
weekNumberCalculation: 'iso', //周次的显示格式。
height: that.calendarHeight, //设置日历的高度,包括header日历头部,默认未设置,高度根据aspectRatio值自适应。
// contentHeight: 600, //设置日历主体内容的高度,不包括header部分,默认未设置,高度根据aspectRatio值自适应。
handleWindowResize: true, //是否随浏览器窗口大小变化而自动变化。
defaultView: 'agendaWeek', //初始化时默认视图,默认是月monthagendaWeek是周,agendaDay是当天
slotEventOverlap: false, //事件是否可以重叠覆盖
defaultDate: today, //默认显示那一天的日期视图getDates(true)2020-05-10
nowIndicator: false, //周/日视图中显示今天当前时间点(以红线标记),默认false不显示
eventLimit: 2, //数据条数太多时,限制显示条数(多余的以“+2more”格式显示),默认false不限制,支持输入数字设定固定的显示条数
eventLimitText: "更多", //当一块区域内容太多以"+2 more"格式显示时,这个more的名称自定义(应该与eventLimit: true一并用)
dayPopoverFormat: "YYYY年M月d日预约信息", //点开"+2 more"弹出的小窗口标题,与eventLimitClick可以结合用
render: (view) => { //method,绑定日历到id上。$('#id').fullCalendar('render');
},
viewRender: (view) => {
that.queryAppointmentInfo()
},
eventRender: (info) => {
},
//日历数据源
events: that.events,
//日程事件点击
eventClick: (event, jsEvent) => {
this.$refs.infoRef.onOpen(clone(event.data))
},
selectable: true, //是否允许通过单击或拖动选择日历中的对象,包括天和时间
unselectAuto: false, //当点击页面日历以外的位置时,是否自动取消当前的选中状态。
selectHelper: true, //当点击或拖动选择时间时,是否预先画出“日程区块”的样式显示默认加载的提示信息,该属性只在周/天视图里可用
selectMirror: true, //镜像
selectOverlap: false, //是否允许选择被事件占用的时间段,默认true可占用时间段
select: (start, end, allDay) => { //点击空白区域/选择区域内容触发
if (calendar.fullCalendar('getView').name === 'month') {
return
}
const startTime = $.fullCalendar.formatDate(start, "YYYY-MM-DD HH:mm:ss")
const endTime = $.fullCalendar.formatDate(end, "YYYY-MM-DD HH:mm:ss")
if (new Date().getTime() > Date.parse(endTime)) {
that.$message.warning('该时段不可设置')
calendar.fullCalendar('unselect');
return
}
const row = {
startTime: startTime,
endTime: endTime,
doctorUser: '',
askType: [],
}
this.$refs.addFormRef.onOpen(row)
},
lazyFetching: false, //是否启用懒加载技术--即只取当前条件下的视图数据,其它数据在切换时触发,默认true只取当前视图的,false是取全视图的
defaultTimedEventDuration: "00:30:00", //在Event Object中如果没有end参数时使用,如start=7:00pm,则该日程对象时间范围就是7:00~9:00
defaultAllDayEventDuration: {days: 1}, //默认1天是多长,(有的是采用工作时间模式,所以支持自定义)
});
},
//获取预约数据
async queryAppointmentInfo() {
if (!calendar) return
const view = calendar.fullCalendar('getView')
//这里取时间戳
const startTimeTs = this.$moment(this.$moment(view.start._i).format('YYYY-MM-DD') + ' 00:00:00').unix()
const endTimeTs = view.end._i
const resp = await this.$axios.post(loc() + '/queryAppointmentInfo', {startTimeTs, endTimeTs})
let events = []
if (resp.code === 0) {
resp.data.forEach(v => {
let className = ''
if (!v.appointmentUser) {
className = ''
} else if (v.appointmentUser && !v.doctorUser) {
className = 'red'
} else if (v.appointmentUser && v.doctorUser) {
className = 'green'
}
events.push({
id: v.id,
title: v.doctorUserName,
start: v.startTime,
end: v.endTime,
className: className,
data: v
})
this.events = events
})
}
calendar.fullCalendar('removeEvents', () => true)
calendar.fullCalendar('addEventSource', events, true)
},
init() {
this.$nextTick(() => {
this.initCalendar()
this.queryAppointmentInfo()
})
},
},
mounted() {
this.calendarHeight = window.innerHeight - 160
},
async created() {
this.init()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,165 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-dialog :visible.sync="infoDialogVisible"
width="50%" title="预约信息"
:close-on-click-modal="false"
append-to-body>
<div class="left-span-label">预约时间段</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="开始时间">
{{ formData.startTime }}
</el-descriptions-item>
<el-descriptions-item label="结束时间">
{{ formData.endTime }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">预约人信息</div>
<el-descriptions v-if="formData.appointmentUser" :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{ formData.appointmentUserName }}
</el-descriptions-item>
<el-descriptions-item label="工号">
{{ formData.appointmentLoginName }}
</el-descriptions-item>
<el-descriptions-item label="单位">
{{ formData.appointmentUnitName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">
{{ formData.appointmentMobile }}
</el-descriptions-item>
<el-descriptions-item label="预约咨询方式" :span="2">
<dict-tag :options="dict.type.PSYCHOLOGY_ASK_TYPE"
:value="formData.askTypeValue"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="预约人备注" :span="2">
{{ formData.remark }}
</el-descriptions-item>
</el-descriptions>
<el-empty v-else description="暂无人预约"></el-empty>
<div class="left-span-label">咨询师信息</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="80px" label-position="left">
<el-form-item label="咨询师" prop="doctorUser">
<el-select
v-model="formData.doctorUser"
filterable
remote
style="width: 100%"
reserve-keyword
placeholder="请输入关键词"
:remote-method="queryDoctorUser">
<el-option
v-for="item in doctorUserList"
:key="item.id"
:label="item.mobile ? item.doctorUserName + '' + item.mobile + '' : item.doctorUserName + '(暂无手机号)'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="咨询方式" prop="askType">
<el-select
v-model="formData.askType"
filterable multiple
style="width: 100%"
placeholder="请选择咨询方式">
<el-option v-for="item in dict.type.PSYCHOLOGY_ASK_TYPE"
:key="item.code"
:label="item.label"
:value="item.code"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="$emit('refresh'); infoDialogVisible = false">取消</el-button>
<el-button @click="onDelete" type="danger">删除</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</span>
</el-dialog>
</div>
`,
dicts:["PSYCHOLOGY_ASK_TYPE"],
data() {
return {
formData: {},
formRules: {
startTime: [{required: true, message: '请选择开始时间', trigger: ['change', 'blur']}],
endTime: [{required: true, message: '请选择结束时间', trigger: ['change', 'blur']}],
doctorUser: [{required: true, message: '请选择咨询师', trigger: ['change', 'blur']}],
askType: [{type: 'array', required: true, message: '请选择咨询方式', trigger: 'change'}],
},
infoDialogVisible: false,
doctorUserList: [],
}
},
methods: {
onOpen(row) {
if (row.doctorUser) {
this.doctorUserList = [{
id: row.doctorUser,
doctorUserName: row.doctorUserName,
mobile: row.doctorMobile,
}]
}
row.askType = row ? JSON.parse(row.askType) : []
this.formData = row
this.infoDialogVisible = true
},
onDelete() {
let msg = '您确定要删除吗?'
if (this.formData.appointmentUser) {
msg = "<span style='color: red'>该时间段已有预约人</span>,您确定要删除吗?"
}
this.$confirm(msg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
dangerouslyUseHTMLString: true,
type: 'warning'
}).then(async () => {
const resp = await this.$axios.post('/platform/psychology/appointmentSet/onDelete', {id: this.formData.id})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
this.infoDialogVisible = false
}
}).catch(() => {})
},
onSubmit() {
let msg = ''
if (this.formData.appointmentUser) {
msg += "<span style='color: red'>该时间段已有预约人</span>"
}
msg += '这将清空预约人已选择的咨询方式,您确定要修改咨询方式吗?';
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
dangerouslyUseHTMLString: true,
type: "warning"
}).then(async () => {
this.formData.askType = JSON.stringify(this.formData.askType)
const resp = await this.$axios.post("/platform/psychology/appointmentSet/onEdit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
this.infoDialogVisible = false
} else {
this.$message.warning(resp.msg)
}
}).catch(() => {})
}
})
},
async queryDoctorUser(keyWord) {
const resp = await this.$axios.post('/platform/psychology/appointmentSet/queryDoctorUser', {
keyWord,
startTimeTs: this.formData.startTimeTs,
endTimeTs: this.formData.endTimeTs,
})
this.doctorUserList = resp.data
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,124 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="姓名" prop="userId">
<el-select
style="width: 100%"
v-model="formData.userId"
filterable
remote
reserve-keyword
placeholder="请输入关键词"
:remote-method="selectQueryUser"
@change="selectUserChange"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.userName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-select v-model="formData.sex" placeholder="请选择性别" style="width: 100%">
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
</el-form-item>
<el-form-item label="职称" prop="technicalTitle">
<el-input v-model="formData.technicalTitle" placeholder="请输入职称"></el-input>
</el-form-item>
<el-form-item label="单位" prop="unitName">
<el-input v-model="formData.unitName" placeholder="请输入单位"></el-input>
</el-form-item>
<el-form-item label="联系方式" prop="mobile">
<el-input v-model.trim="formData.mobile" placeholder="请输入联系方式"></el-input>
</el-form-item>
<el-form-item label="特长" prop="specialty">
<el-input type="textarea" :rows="3" v-model="formData.specialty" placeholder="请输入特长"></el-input>
</el-form-item>
<el-form-item label="简介" prop="introduce">
<el-input type="textarea" :rows="3" v-model="formData.introduce" placeholder="请输入简介"></el-input>
</el-form-item>
<el-form-item label="头像" prop="avatar">
<file-upload :value.sync="formData.avatar" accept=".jpg,.jpeg,.png"
:upload_number="1" upload_result_category="interval"
complete_result upload_mode="drag"></file-upload>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
store,
data() {
return {
formData: {},
formRules: {
userId: [{required: true, message: '请输入姓名', trigger: ['change', 'blur']}],
sex: [{required: true, message: '请选择性别', trigger: ['change', 'blur']}],
jobTitle: [{required: true, message: '请输入职称', trigger: ['change', 'blur']}],
specialty: [{required: true, message: '请输入特长', trigger: ['change', 'blur']}],
introduce: [{required: true, message: '请输入简介', trigger: ['change', 'blur']}],
avatar: [{required: true, message: '请上传头像', trigger: ['change', 'blur']}],
},
userOptions: [],
}
},
methods: {
selectQueryUser(keyword) {
this.$axios.post("/platform/psychology/doctorManage/listUser", { keyword: keyword }).then((res) => {
if (res.code === 0) {
this.userOptions = res.data
}
})
},
selectUserChange(val) {
if (val) {
const user = this.userOptions.find(v => v.id === val)
this.$set(this.formData, 'sex', user.sex)
this.$set(this.formData, 'mobile', user.mobile)
this.$set(this.formData, 'unitName', user.unitName)
this.$set(this.formData, 'technicalTitle', user.technicalTitle)
}
},
onOpen(row) {
if(row && row.id) {
this.userOptions = [
{
id: row.userId,
userName: row.userName,
loginName: row.loginName
}
]
this.formData = clone(row)
}
},
onSubmit() {
this.$refs.formRef.validate(async (valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/psychology/doctorManage/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,162 @@
<!--#
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-input placeholder="请输入姓名或工号查询" v-model="pageForm.searchKeyword" clearable @keyup.enter.native="doSearch"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="咨询师列表">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增咨询师
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize" row-key="id">
<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 === 'avatar'">
<el-popover
placement="top-start"
width="100"
trigger="hover">
<el-image
:src="row.avatar"
fit="cover">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<el-image
slot="reference"
style="height: 30px;"
:src="row.avatar"
fit="cover">
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
</el-popover>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'loginName', label: '工号'},
{prop: 'userName', label: '姓名'},
{prop: 'sex', label: '性别'},
{prop: 'unitName', label: '单位'},
{prop: 'jobTitle', label: '职称'},
{prop: 'mobile', label: '联系电话'},
{prop: 'avatar', label: '头像'}
],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/psychology/doctorManage/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,47 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{viewData.userName}}
</el-descriptions-item>
<el-descriptions-item label="性别">
{{viewData.sex}}
</el-descriptions-item>
<el-descriptions-item label="职称">
{{viewData.technicalTitle}}
</el-descriptions-item>
<el-descriptions-item label="单位">
{{viewData.unitName}}
</el-descriptions-item>
<el-descriptions-item label="联系方式" :span="2">
{{viewData.mobile}}
</el-descriptions-item>
<el-descriptions-item label="特长" :span="2">
{{viewData.specialty}}
</el-descriptions-item>
<el-descriptions-item label="简介" :span="2">
{{viewData.introduce}}
</el-descriptions-item>
<el-descriptions-item label="头像" :span="2">
<img :src="viewData.avatar"
style="height: 100px;width: auto" v-if="viewData.avatar">
<span v-else>暂无</span>
</el-descriptions-item>
</el-descriptions>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = clone(row)
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,122 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</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">
<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 === 'appointmentTime'">
{{ row.startTime + ' 至 ' + row.endTime }}
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="$moment().unix() < $moment(row.startTime).unix()"
@click="onDelete(row)" size="mini" type="danger">取消</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'appointmentTime', label: '预约时间', width: '350'},
{prop: 'appointmentUserName', label: '姓名'},
{prop: 'appointmentLoginName', label: '工号'},
{prop: 'appointmentUnitName', label: '单位'},
{prop: 'doctorUserName', label: '心理咨询师'},
],
}
},
methods: {
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/psychology/list/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,70 @@
const info = {
template: /*language=HTML*/ `
<div>
<div class="left-span-label">预约时间段</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="开始时间">
{{ viewData.startTime }}
</el-descriptions-item>
<el-descriptions-item label="结束时间">
{{ viewData.endTime }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">预约人信息</div>
<el-descriptions v-if="viewData.userId" :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{ viewData.appointmentUserName }}
</el-descriptions-item>
<el-descriptions-item label="工号">
{{ viewData.appointmentLoginName }}
</el-descriptions-item>
<el-descriptions-item label="单位">
{{ viewData.appointmentUnitName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">
{{ viewData.appointmentMobile }}
</el-descriptions-item>
<el-descriptions-item label="预约咨询方式" :span="2">
<dict-tag :options="dict.type.PSYCHOLOGY_ASK_TYPE"
:value="viewData.askTypeValue"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="预约人备注" :span="2">
{{ viewData.remark }}
</el-descriptions-item>
</el-descriptions>
<el-empty v-else description="暂无人预约"></el-empty>
<div class="left-span-label">咨询师信息</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="姓名">
{{ viewData.doctorUserName }}
</el-descriptions-item>
<el-descriptions-item label="工号">
{{ viewData.doctorUnitName }}
</el-descriptions-item>
<el-descriptions-item label="联系方式">
{{ viewData.doctorMobile }}
</el-descriptions-item>
<el-descriptions-item label="职称">
{{ viewData.doctorJobTitle }}
</el-descriptions-item>
<el-descriptions-item label="个人简介" :span="2">
{{ viewData.doctorIntroduce }}
</el-descriptions-item>
</el-descriptions>
</div>
`,
dicts:["PSYCHOLOGY_ASK_TYPE"],
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = clone(row)
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,70 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="咨询人姓名">
<el-input :value="$store.state.user.username" readonly></el-input>
</el-form-item>
<el-form-item label="咨询人工号">
<el-input :value="$store.state.user.loginname" readonly></el-input>
</el-form-item>
<el-form-item label="咨询主题" prop="postTitle">
<el-input v-model="formData.postTitle" maxlength="20" placeholder="请简约填写咨询主题,不超过20个字"></el-input>
</el-form-item>
<el-form-item label="主要内容" prop="postContent">
<el-input type="textarea" rows="5" v-model="formData.postContent" maxlength="500"
placeholder="请输入内容"></el-input>
</el-form-item>
<el-form-item>
<div class="text-primary">
<i class="el-icon-warning"></i>
提示不会发布您的个人隐私信息您咨询的内容只有心理咨询师可查看并回复
</div>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
store,
data() {
return {
formData: {},
formRules: {
postTitle: [{required: true, message: '请输入咨询主题', trigger: ['change', 'blur']}],
postContent: [{required: true, message: '请输入咨询内容', trigger: ['change', 'blur']}],
},
}
},
methods: {
onOpen(row) {
if(row && row.id) {
this.formData = clone(row)
}
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/psychology/onlinePost/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,160 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="是否回复:">
<el-select v-model="pageForm.isReply" style="width: 100%" @change="doSearch">
<el-option :value="null" label="全部"></el-option>
<el-option :value="true" label="已回复"></el-option>
<el-option :value="false" label="未回复"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="咨询记录">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
我要咨询
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize" row-key="id">
<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 === 'isReply'">
<el-tag type="success" v-if="row.isReply">已回复</el-tag>
<el-tag type="info" v-else>未回复</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button v-if="!row.isReply" @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'loginName', label: '工号'},
{prop: 'userName', label: '姓名'},
{prop: 'postTitle', label: '标题'},
{prop: 'postingTime', label: '咨询时间'},
{prop: 'isReply', label: '回复情况'}
],
pageForm: {
year: new Date().getFullYear() + '',
isReply: null,
},
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
const url = '/platform/psychology/onlinePost/fetchOne'
this.$refs.infoRef.onOpen(row, url)
})
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/psychology/onlinePost/onDelete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,73 @@
const info = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="咨询人">
{{ viewData.userName }}
</el-descriptions-item>
<el-descriptions-item label="咨询时间">
{{ viewData.postingTime }}
</el-descriptions-item>
<el-descriptions-item label="咨询主题" :span="2">
{{ viewData.postTitle }}
</el-descriptions-item>
<el-descriptions-item label="主要内容" :span="2">
{{ viewData.postContent }}
</el-descriptions-item>
<el-descriptions-item label="回复信息" :span="2">
<el-timeline v-if="viewData.replyList && viewData.replyList.length > 0">
<el-timeline-item
v-for="(item, index) in viewData.replyList"
:key="index"
size="large"
type="primary"
:timestamp="item.replyTime">
<div class="user-face">
<svg t="1639966214107" class="icon" viewBox="0 0 3208 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg" p-id="6251" width="80" height="30">
<path d="M343.496334 367.185736m-225.049322 0a225.049322 225.049322 0 1 0 450.098644 0 225.049322 225.049322 0 1 0-450.098644 0Z"
fill="#FFFFFF" p-id="6252"></path>
<path d="M1879.043392 0H355.341035c-3.079622 0-20.846674 23.689402-23.689402 23.689402 14.687429 3.079622 23.689402-11.370913 33.638951 0C400.350899 58.512824 450.098644 99.49549 497.477449 94.757609h23.689402c37.903044 0 58.512824 5.685457 57.565248 41.693348a155.639373 155.639373 0 0 0 71.068207 118.447012 76.51677 76.51677 0 0 1 10.186443 6.869927 64.19828 64.19828 0 0 1 9.001973 93.573139 152.796645 152.796645 0 0 0-23.689403 134.318911 58.27593 58.27593 0 0 1 3.553411 12.555383A66.567221 66.567221 0 0 1 592.235058 578.495205a161.087936 161.087936 0 0 0-108.260569 87.650788 77.227452 77.227452 0 0 1-6.159244 12.555384c-14.924323 23.689402-19.42531 11.370913-47.378805 6.869926L426.409242 686.992667h9.001973l11.370913 23.689403h1432.261264C2071.164445 710.68207 2226.803818 562.149517 2226.803818 379.030437v-47.378804c0-183.11908-155.639373-331.651633-347.760426-331.651633z"
fill="#EDF5FE" p-id="6253"></path>
<path d="M688.650926 261.767896a74.147829 74.147829 0 0 0-9.949549-6.869927 156.586949 156.586949 0 0 1-67.514797-118.447012 65.619644 65.619644 0 0 0-63.961386-66.804114 61.355552 61.355552 0 0 0-13.266066 1.18447 154.218009 154.218009 0 0 1-126.975196-47.378805 65.145856 65.145856 0 0 0-36.718574-21.557356 21.320462 21.320462 0 0 0-12.318489 12.081595 324.544812 324.544812 0 0 0-58.039036 23.689403 334.020573 334.020573 0 0 1 58.27593-23.689403 21.79425 21.79425 0 0 1 12.555383-12.081595 64.19828 64.19828 0 0 0-54.722519 12.318489 78.88571 78.88571 0 0 0-10.423337 9.475761 154.691797 154.691797 0 0 1-126.975196 47.378805 65.619644 65.619644 0 0 0-76.51677 52.116685 61.355552 61.355552 0 0 0 0 13.266065 157.060737 157.060737 0 0 1-67.514797 118.447012 66.567221 66.567221 0 0 0-23.689402 90.967305 55.433201 55.433201 0 0 0 4.974775 9.475761 158.95589 158.95589 0 0 1 23.689402 134.555805 65.856538 65.856538 0 0 0 37.903044 85.281848 56.617672 56.617672 0 0 0 12.792277 3.553411 156.586949 156.586949 0 0 1 103.522688 87.650788 65.145856 65.145856 0 0 0 82.43912 40.982666 86.466318 86.466318 0 0 0 12.555383-5.92235 154.218009 154.218009 0 0 1 135.266488 0 66.567221 66.567221 0 0 0 22.268038 8.054397 64.672068 64.672068 0 0 0 66.330326-30.559329 59.934188 59.934188 0 0 0 5.685457-12.555384 156.586949 156.586949 0 0 1 103.522688-87.650788 66.330327 66.330327 0 0 0 54.248731-76.279876 58.27593 58.27593 0 0 0-3.55341-12.555383 158.482102 158.482102 0 0 1 23.689402-134.318911 66.330327 66.330327 0 0 0-7.580608-93.810033zM355.341035 564.281563v17.530158a129.107243 129.107243 0 0 0 99.258596 125.316938A129.107243 129.107243 0 0 1 355.341035 581.811721v-17.530158L194.016205 240.684328h81.017756L355.341035 416.933481V25.110766 416.933481l81.017756-176.486047h81.017756zM921.51775 298.249575a584.891343 584.891343 0 0 1-98.074125 96.415868l-20.60978-22.504932a501.978435 501.978435 0 0 0 94.757609-92.151776z m-86.703212-120.10527a415.275223 415.275223 0 0 1 71.068207 54.959414l-21.79425 21.320462a450.098644 450.098644 0 0 0-70.594419-55.433201z m295.643741 227.181369v154.691797h-29.848647v-20.846674h-218.890078v20.846674H852.818484v-154.691797z m-248.738725 104.944052h218.890078v-76.042981h-218.890078z m101.153748-275.507749a260.583426 260.583426 0 0 1-47.378804 62.303128l-19.188416-23.689402a225.996898 225.996898 0 0 0 60.171082-108.260569l30.559329 3.790305c-3.079622 11.607807-6.869927 23.689402-11.370913 36.718573H1160.780714v24.400085a351.55073 351.55073 0 0 1-41.930242 71.068207l-22.504932-18.003946a268.874716 268.874716 0 0 0 30.559329-47.378805h-68.462373c0 16.819476-2.36894 29.374859-3.553411 37.429256 18.003946 47.378805 61.118658 78.648816 129.581031 94.757609l-12.792277 29.137965c-65.619644-18.003946-108.023675-47.378805-127.448985-91.441093-20.372886 40.745772-62.540022 71.068207-126.264514 89.309047l-13.029171-27.716601c68.699267-18.003946 108.734357-48.800169 118.447011-92.151775a298.486469 298.486469 0 0 0 4.027199-38.85062zM1221.18869 299.197151h92.151775v189.515219c11.370913-9.949549 26.058343-23.689402 43.825394-41.693348l8.528185 32.454481A544.856253 544.856253 0 0 1 1286.334546 544.856253l-11.844701-27.242812a25.821449 25.821449 0 0 0 9.475761-18.951522v-170.089909h-62.776916z m51.169109-126.264514a502.926011 502.926011 0 0 1 71.068207 65.619644l-20.846674 21.320462a458.153041 458.153041 0 0 0-72.489571-66.093432z m170.089908 0a395.139231 395.139231 0 0 1-13.502959 42.640924h167.957863q0 231.445461-5.922351 288.53692a54.485625 54.485625 0 0 1-60.64487 53.301156l-40.508878-1.18447-7.343715-27.716601c23.689402 0 37.429256 1.658258 44.062289 1.658258 19.662204 0 31.033117-12.555383 34.586527-37.903044s4.500986-108.260569 5.448563-247.791148h-150.901493a310.33117 310.33117 0 0 1-56.617672 76.279875l-19.42531-23.689402a260.583426 260.583426 0 0 0 72.252677-129.581031z m-58.749717 121.526634h130.528607v195.200675h-130.528607z m29.848647 83.860484h71.068207v-58.749718h-71.068207z m71.068207 84.80806V402.71984h-71.068207v59.223505zM1741.881753 170.800591h29.848647v203.018178q-1.895152 126.975196-86.940107 185.961808l-23.689402-20.135992c52.827367-34.586527 79.359498-90.019729 80.307074-165.825816z m-75.095405 55.906989h29.848646V450.098644h-29.848646z m131.002394-40.508878H2037.2886v29.848647h-104.707158v52.353579h87.650788v208.940529c0 23.689402-10.660231 35.534103-32.217587 35.534103h-29.137965l-8.054397-29.848647 27.242813 1.658259c8.528185 0 12.792277-4.500986 12.792277-13.739854v-173.880213h-58.275929v260.583426h-30.085541v-260.583426h-58.27593v218.653184h-29.374859V268.400928h87.650789V216.047349h-104.707159z"
fill="#4492F4" p-id="6254"></path>
</svg>
<span>{{ item.userName }}</span>
</div>
<div>回复内容{{ item.replyContent }}</div>
</el-timeline-item>
</el-timeline>
<span v-else>暂无人回复</span>
</el-descriptions-item>
</el-descriptions>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row, url) {
this.$axios.post(url, { id: row.id })
.then((resp) => {
this.viewData = resp.data
})
},
},
style: /*language=CSS*/ `
.el-timeline-item {
padding-bottom: 20px;
}
.el-timeline-item__wrapper {
padding-left: 28px;
top: -3px;
}
.el-timeline-item__tail {
left: 4px;
}
.user-face{
display: flex;
}
`
}
@@ -0,0 +1,69 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<div class="left-span-label">基本情况</div>
<el-descriptions :column="2" border class="table_fixed">
<el-descriptions-item label="咨询人">
{{ viewData.posterUserName }}
</el-descriptions-item>
<el-descriptions-item label="咨询时间">
{{ viewData.postingTime }}
</el-descriptions-item>
<el-descriptions-item label="咨询主题" :span="2">
{{ viewData.postTitle }}
</el-descriptions-item>
<el-descriptions-item label="主要内容" :span="2">
{{ viewData.postContent }}
</el-descriptions-item>
</el-descriptions>
<div class="left-span-label">我来回复</div>
<el-form-item label="回复内容" prop="replyContent">
<el-input type="textarea" rows="3" v-model="formData.replyContent" placeholder="请输入回复内容"></el-input>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
store,
data() {
return {
formData: {},
formRules: {
replyContent: [{required: true, message: '请输入回复内容', trigger: ['change', 'blur']}],
},
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = clone({ ...row })
this.$set(this.formData, 'postId', row.id)
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/psychology/onlineReply/onSubmit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,132 @@
<!--#
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
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="是否回复:">
<el-select v-model="pageForm.isReply" style="width: 100%" @change="doSearch">
<el-option :value="null" label="全部"></el-option>
<el-option :value="true" label="已回复"></el-option>
<el-option :value="false" label="未回复"></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" row-key="id">
<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 === 'replyCount'">
<el-tag type="success" v-if="row.replyCount > 0">已回复</el-tag>
<el-tag type="info" v-else>未回复</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onReply(row)" size="mini" type="primary">回复</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
<!--#include('../onlinePost/info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": info,
},
data() {
return {
tableColumns: [
{prop: 'posterUserName', label: '姓名'},
{prop: 'postTitle', label: '标题'},
{prop: 'postingTime', label: '咨询时间'},
{prop: 'replyCount', label: '回复情况'}
],
pageForm: {
year: new Date().getFullYear() + '',
isReply: null,
},
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onView(row) {
this.$refs.guava.view(() => {
const url = '/platform/psychology/onlineReply/fetchOne'
this.$refs.infoRef.onOpen(row, url)
})
},
onReply(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
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.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,256 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.top-col {
background-color: white;
position: relative;
box-sizing: border-box;
padding: 20px;
width: calc((100% - (20px * 3)) / 4);
overflow: hidden;
color: #FFFFFF;
border-radius: 4px;
}
.top-col:hover {
transform: scale(1.01);
}
.top-col:not(:last-child), .center-col:not(:last-child) {
margin-right: 20px;
}
.col-title {
font-size: 14px;
margin-bottom: 10px;
color: #FFFFFF;
}
.top-col-member-number {
font-size: 30px;
color: #FFFFFF;
}
.top-col-chart {
height: 80px;
width: 100%;
position: relative;
}
.center-col {
background-color: white;
position: relative;
box-sizing: border-box;
padding: 20px;
}
.el-table__body-wrapper::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
.el-table__body-wrapper {
scrollbar-width: none; /* firefox */
-ms-overflow-style: none; /* IE 10+ */
overflow-x: hidden;
overflow-y: auto;
}
@media screen and (max-width: 500px) {
.num-card {
flex-direction: column;
}
.num-card .top-col {
width: 100%;
margin-bottom: 10px;
}
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
placeholder="请选择年度"
type="year"
@change="doSearch"
style="width: 100%"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<el-row type="flex" class="num-card">
<el-col :span="6" class="top-col" style="background: rgb(248, 108, 107)">
<div class="col-title">总开放场次</div>
<div class="top-col-member-number">
{{numAreaMap?.total || 0}}
<span style="font-size: 14px">&ensp;</span>
</div>
</el-col>
<el-col :span="6" class="top-col" style="background: rgb(133, 149, 244)">
<div class="col-title">预约成功场次</div>
<div class="top-col-member-number">
{{numAreaMap?.successNum || 0}}
<span style="font-size: 14px">&ensp;</span>
</div>
</el-col>
<el-col :span="6" class="top-col" style="background: rgb(254, 187, 80)">
<div @click="tableIndex = 1; tableChange()">
<div class="col-title">咨询师人数</div>
<div class="top-col-member-number">
{{numAreaMap?.doctorCount || 0}}
<span style="font-size: 14px">&ensp;</span>
</div>
</div>
</el-col>
<el-col :span="6" class="top-col" style="background: #26A65B">
<div @click="tableIndex = 2; tableChange()">
<div class="col-title">总计服务教师人数</div>
<div class="top-col-member-number">
{{numAreaMap?.serviceTeacherCount || 0}}
<span style="font-size: 14px">&ensp;</span>
</div>
</div>
</el-col>
</el-row>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool :label="tableLabel"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<el-table-column label="序号" type="index" 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-column v-if="tableIndex === 1" label="操作" width="100">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
</guava>
<el-dialog :visible.sync="infoDialogVisible"
width="60%" title="服务教师列表"
:close-on-click-modal="false"
append-to-body>
<el-table :data="infoTableData">
<el-table-column label="序号" type="index" 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 infoTableColumns"
>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="infoDialogVisible = false" type="primary">确定</el-button>
</span>
</el-dialog>
</div>
<script>
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
infoDialogVisible: false,
tableLabel: '按咨询师统计',
tableColumns: [],
infoTableColumns: [],
doctorTableColumns: [
{prop: 'doctorUserName', label: '咨询师'},
{prop: 'sex', label: '性别'},
{prop: 'jobTitle', label: '职称'},
{prop: 'serviceNum', label: '服务次数'},
],
teacherTableColumns: [
{prop: 'userName', label: '教师'},
{prop: 'unitName', label: '所属单位'},
{prop: 'unionName', label: '所属工会'},
{prop: 'startTime', label: '开始时间'},
{prop: 'endTime', label: '结束时间'},
{prop: 'doctorUserName', label: '咨询师'},
],
numAreaMap: {},
tableIndex: 1,
infoTableData: [],
}
},
methods: {
doSearch() {
this.queryCount()
this.tableChange()
},
onView(row) {
this.infoTableColumns = this.teacherTableColumns
this.$axios.post(loc() + "/pageData", {
year: this.pageForm.year,
tableIndex: 2,
doctorUser: row.userId
}).then((res) => {
if (res.code === 0) {
this.infoTableData = res.data
this.infoDialogVisible = true
}
})
},
tableChange() {
this.pageForm.tableIndex = this.tableIndex
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data
}
})
},
queryCount() {
this.$axios.post(loc() + "/queryCount", this.pageForm).then((res) => {
if (res.code === 0) {
this.numAreaMap = res.data
}
})
},
},
async created() {
this.tableColumns = this.doctorTableColumns
this.queryCount()
this.tableChange()
},
watch: {
tableIndex(val) {
this.tableColumns = val === 1 ? this.doctorTableColumns : this.teacherTableColumns
}
},
})
</script>
<!--#
}
#-->

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