兵马未动 粮草先行
This commit is contained in:
154
src/views/stuwork/psychologicalcounselingduty/form.vue
Normal file
154
src/views/stuwork/psychologicalcounselingduty/form.vue
Normal file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="新增排班"
|
||||
v-model="visible"
|
||||
:width="500"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="form"
|
||||
:rules="dataRules"
|
||||
label-width="100px"
|
||||
v-loading="loading">
|
||||
<el-form-item label="值班日期" prop="date">
|
||||
<el-date-picker
|
||||
v-model="form.date"
|
||||
type="date"
|
||||
placeholder="选择值班日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
:disabled-date="disabledDate"
|
||||
style="width: 100%" />
|
||||
</el-form-item>
|
||||
<el-form-item label="预约师" prop="teacherUserName">
|
||||
<el-select
|
||||
v-model="form.teacherUserName"
|
||||
placeholder="请选择预约师"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in teacherList"
|
||||
:key="item.userName"
|
||||
:label="(item.realName || '') + (item.userName ? ` (${item.userName})` : '')"
|
||||
:value="item.userName" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="周类型" prop="weekType">
|
||||
<el-select
|
||||
v-model="form.weekType"
|
||||
placeholder="请选择"
|
||||
clearable
|
||||
style="width: 100%">
|
||||
<el-option label="单周" value="single" />
|
||||
<el-option label="双周" value="double" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确 认</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PsychologicalCounselingDutyFormDialog">
|
||||
import { ref, reactive, nextTick, watch } from 'vue'
|
||||
import { useMessage } from '/@/hooks/message'
|
||||
import { saveDuty } from '/@/api/stuwork/psychologicalcounselingduty'
|
||||
import { getList } from '/@/api/stuwork/psychologicalcounselingteacher'
|
||||
|
||||
const props = defineProps<{
|
||||
year?: number
|
||||
month?: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const dataFormRef = ref()
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
const teacherList = ref<any[]>([])
|
||||
|
||||
const form = reactive({
|
||||
date: '',
|
||||
teacherUserName: '',
|
||||
weekType: 'single'
|
||||
})
|
||||
|
||||
const dataRules = {
|
||||
date: [{ required: true, message: '请选择值班日期', trigger: 'change' }],
|
||||
teacherUserName: [{ required: true, message: '请选择预约师', trigger: 'change' }]
|
||||
}
|
||||
|
||||
// 限制只能选当前年月的日期
|
||||
const disabledDate = (time: Date) => {
|
||||
if (!props.year || !props.month) return false
|
||||
const y = time.getFullYear()
|
||||
const m = time.getMonth() + 1
|
||||
if (y !== props.year) return true
|
||||
if (m !== props.month) return true
|
||||
return false
|
||||
}
|
||||
|
||||
const loadTeacherList = async () => {
|
||||
try {
|
||||
const res = await getList()
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
teacherList.value = res.data
|
||||
} else {
|
||||
teacherList.value = []
|
||||
}
|
||||
} catch (err) {
|
||||
teacherList.value = []
|
||||
}
|
||||
}
|
||||
|
||||
const openDialog = () => {
|
||||
visible.value = true
|
||||
nextTick(() => {
|
||||
dataFormRef.value?.resetFields()
|
||||
form.date = ''
|
||||
form.teacherUserName = ''
|
||||
form.weekType = 'single'
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (!dataFormRef.value) return
|
||||
await dataFormRef.value.validate(async (valid: boolean) => {
|
||||
if (!valid) return
|
||||
loading.value = true
|
||||
try {
|
||||
await saveDuty([
|
||||
{
|
||||
date: form.date,
|
||||
teacherUserName: form.teacherUserName,
|
||||
weekType: form.weekType || 'single'
|
||||
}
|
||||
])
|
||||
useMessage().success('排班成功')
|
||||
visible.value = false
|
||||
emit('refresh')
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '排班失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
watch(visible, (v) => {
|
||||
if (v) loadTeacherList()
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
openDialog
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
310
src/views/stuwork/psychologicalcounselingduty/index.vue
Normal file
310
src/views/stuwork/psychologicalcounselingduty/index.vue
Normal file
@@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<div class="modern-page-container">
|
||||
<div class="page-wrapper">
|
||||
<!-- 筛选条件 -->
|
||||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Search /></el-icon>
|
||||
筛选条件
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form
|
||||
:model="searchForm"
|
||||
ref="searchFormRef"
|
||||
:inline="true"
|
||||
@keyup.enter="getDataList"
|
||||
class="search-form">
|
||||
<el-form-item label="年份" prop="year">
|
||||
<el-select
|
||||
v-model="searchForm.year"
|
||||
placeholder="请选择年份"
|
||||
clearable
|
||||
style="width: 120px">
|
||||
<el-option
|
||||
v-for="y in yearOptions"
|
||||
:key="y"
|
||||
:label="y + '年'"
|
||||
:value="y" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="月份" prop="month">
|
||||
<el-select
|
||||
v-model="searchForm.month"
|
||||
placeholder="请选择月份"
|
||||
clearable
|
||||
style="width: 120px">
|
||||
<el-option
|
||||
v-for="m in 12"
|
||||
:key="m"
|
||||
:label="m + '月'"
|
||||
:value="m" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 内容卡片 -->
|
||||
<el-card class="content-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">
|
||||
<el-icon class="title-icon"><Calendar /></el-icon>
|
||||
值班管理列表
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="FolderAdd"
|
||||
type="primary"
|
||||
@click="formDialogRef?.openDialog()">
|
||||
新增排班
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Delete"
|
||||
type="danger"
|
||||
plain
|
||||
:disabled="!dataList.length"
|
||||
@click="handleClearMonth">
|
||||
一键清空本月
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
class="ml10"
|
||||
@queryTable="getDataList">
|
||||
<TableColumnControl
|
||||
ref="columnControlRef"
|
||||
:columns="tableColumns"
|
||||
v-model="visibleColumns"
|
||||
trigger-type="default"
|
||||
trigger-circle
|
||||
@change="handleColumnChange"
|
||||
@order-change="handleColumnOrderChange">
|
||||
<template #trigger>
|
||||
<el-tooltip class="item" effect="dark" content="列设置" placement="top">
|
||||
<el-button circle style="margin-left: 0;">
|
||||
<el-icon><Menu /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</TableColumnControl>
|
||||
</right-toolbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 表格 -->
|
||||
<el-table
|
||||
:data="dataList"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle"
|
||||
class="modern-table">
|
||||
<el-table-column type="index" label="序号" width="70" align="center">
|
||||
<template #header>
|
||||
<el-icon><List /></el-icon>
|
||||
</template>
|
||||
<template #default="{ $index }">
|
||||
{{ $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template v-for="col in visibleColumnsSorted" :key="col.prop || col.label">
|
||||
<el-table-column
|
||||
v-if="checkColumnVisible(col.prop || '') && col.prop !== '操作'"
|
||||
:prop="col.prop"
|
||||
:label="col.label"
|
||||
:min-width="col.minWidth"
|
||||
:width="col.width"
|
||||
show-overflow-tooltip
|
||||
align="center">
|
||||
<template #header>
|
||||
<el-icon v-if="col.icon"><component :is="col.icon" /></el-icon>
|
||||
<span :style="{ marginLeft: col.icon ? '4px' : '0' }">{{ col.label }}</span>
|
||||
</template>
|
||||
<template v-if="col.prop === 'reservation'" #default="scope">
|
||||
<el-tag :type="scope.row.reservation === '1' ? 'success' : 'info'" size="small">
|
||||
{{ scope.row.reservation === '1' ? '是' : '否' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
||||
<template #header>
|
||||
<el-icon><Setting /></el-icon>
|
||||
<span style="margin-left: 4px">操作</span>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
icon="Delete"
|
||||
link
|
||||
type="danger"
|
||||
@click="handleClearOne(scope.row)">
|
||||
清除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="暂无值班数据,请选择年月查询或新增排班" :image-size="120">
|
||||
<el-button type="primary" icon="FolderAdd" @click="formDialogRef?.openDialog()">新增排班</el-button>
|
||||
</el-empty>
|
||||
</template>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 新增排班弹窗 -->
|
||||
<FormDialog
|
||||
ref="formDialogRef"
|
||||
:year="searchForm.year"
|
||||
:month="searchForm.month"
|
||||
@refresh="getDataList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="PsychologicalCounselingDuty">
|
||||
import { reactive, ref, computed, onMounted, defineAsyncComponent } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useMessage, useMessageBox } from '/@/hooks/message'
|
||||
import { getDutyByMonth, clearDuty, clearOneDuty } from '/@/api/stuwork/psychologicalcounselingduty'
|
||||
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
|
||||
import { List, Calendar, UserFilled, Phone, Document, Setting, Menu, Search } from '@element-plus/icons-vue'
|
||||
import { useTableColumnControl } from '/@/hooks/tableColumn'
|
||||
|
||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'))
|
||||
|
||||
const route = useRoute()
|
||||
const formDialogRef = ref()
|
||||
const searchFormRef = ref()
|
||||
const columnControlRef = ref<any>()
|
||||
const showSearch = ref(true)
|
||||
const loading = ref(false)
|
||||
const dataList = ref<any[]>([])
|
||||
|
||||
// 年份选项:当前年前后各 5 年
|
||||
const yearOptions = computed(() => {
|
||||
const y = new Date().getFullYear()
|
||||
return Array.from({ length: 11 }, (_, i) => y - 5 + i)
|
||||
})
|
||||
|
||||
// 表格列配置(与其它页面一致,icon 写在列上)
|
||||
const tableColumns = [
|
||||
{ prop: 'date', label: '值班日期', icon: Calendar },
|
||||
{ prop: 'dutyTime', label: '值班时间', icon: Calendar },
|
||||
{ prop: 'realName', label: '教师姓名', icon: UserFilled },
|
||||
{ prop: 'userName', label: '用户名', icon: UserFilled },
|
||||
{ prop: 'phone', label: '联系方式', icon: Phone, minWidth: 120 },
|
||||
{ prop: 'reservation', label: '是否预约', icon: Document }
|
||||
]
|
||||
|
||||
const {
|
||||
visibleColumns,
|
||||
visibleColumnsSorted,
|
||||
checkColumnVisible,
|
||||
handleColumnChange,
|
||||
handleColumnOrderChange
|
||||
} = useTableColumnControl(tableColumns, route.path)
|
||||
|
||||
// 表格样式(与 useTable 一致)
|
||||
const tableStyle = {
|
||||
cellStyle: {},
|
||||
headerCellStyle: {}
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
year: new Date().getFullYear(),
|
||||
month: new Date().getMonth() + 1
|
||||
})
|
||||
|
||||
const getDataList = async () => {
|
||||
if (!searchForm.year || !searchForm.month) {
|
||||
useMessage().warning('请选择年份和月份')
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getDutyByMonth({
|
||||
year: searchForm.year,
|
||||
month: searchForm.month
|
||||
})
|
||||
dataList.value = Array.isArray(res.data) ? res.data : []
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取值班表失败')
|
||||
dataList.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
const now = new Date()
|
||||
searchForm.year = now.getFullYear()
|
||||
searchForm.month = now.getMonth() + 1
|
||||
getDataList()
|
||||
}
|
||||
|
||||
const handleClearMonth = async () => {
|
||||
if (!searchForm.year || !searchForm.month) {
|
||||
useMessage().warning('请先选择年份和月份')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm(
|
||||
`确定要清空 ${searchForm.year}年${searchForm.month}月 的全部值班吗?`,
|
||||
'提示',
|
||||
{ confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await clearDuty({
|
||||
year: Number(searchForm.year),
|
||||
month: Number(searchForm.month)
|
||||
})
|
||||
useMessage().success('清空成功')
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '清空失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleClearOne = async (row: any) => {
|
||||
const dateStr = row.date || row.dutyTime || ''
|
||||
if (!dateStr) {
|
||||
useMessage().warning('无法获取日期')
|
||||
return
|
||||
}
|
||||
const day = dateStr.split(' ')[0] || dateStr
|
||||
try {
|
||||
await useMessageBox().confirm(`确定要清除 ${day} 的值班吗?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await clearOneDuty({ days: day })
|
||||
useMessage().success('清除成功')
|
||||
getDataList()
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '清除失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDataList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user