Merge remote-tracking branch 'origin/0.8.X' into 0.8.X

This commit is contained in:
2026-06-06 17:11:09 +08:00
11 changed files with 969 additions and 58 deletions

View File

@@ -0,0 +1,44 @@
import request from '@/utils/request'
// 查询排班模板列表
export function listAttendanceTemplate(query) {
return request({
url: '/wms/attendanceTemplate/list',
method: 'get',
params: query
})
}
// 查询排班模板详细
export function getAttendanceTemplate(templateId) {
return request({
url: '/wms/attendanceTemplate/' + templateId,
method: 'get'
})
}
// 新增排班模板
export function addAttendanceTemplate(data) {
return request({
url: '/wms/attendanceTemplate',
method: 'post',
data: data
})
}
// 修改排班模板
export function updateAttendanceTemplate(data) {
return request({
url: '/wms/attendanceTemplate',
method: 'put',
data: data
})
}
// 删除排班模板
export function delAttendanceTemplate(templateId) {
return request({
url: '/wms/attendanceTemplate/' + templateId,
method: 'delete'
})
}

View File

@@ -1,11 +1,28 @@
<template>
<div class="template-manager">
<div class="left-panel">
<div class="custom-tabs">
<div
:class="['custom-tab', { active: activeTab === 'shared' }]"
@click="switchTab('shared')"
>共享模板</div>
<div
:class="['custom-tab', { active: activeTab === 'personal' }]"
@click="switchTab('personal')"
>自用模板</div>
</div>
<div class="panel-header">
<span class="panel-title">模板列表</span>
<el-button icon="el-icon-plus" size="mini" type="primary" @click="addTemplate">新增</el-button>
<div class="panel-header-actions">
<el-button icon="el-icon-plus" size="mini" type="primary" @click="addTemplate">新增</el-button>
<el-button icon="el-icon-download" size="mini" type="success" @click="exportCsv" :disabled="!currentTemplate.id">导出</el-button>
<el-button icon="el-icon-upload2" size="mini" type="info" @click="importCsv">导入</el-button>
</div>
</div>
<div class="template-list">
<div class="shared-toolbar" v-show="activeTab === 'shared'">
<el-input v-model="sharedQueryParams.templateName" placeholder="搜索模板名称" size="small" clearable prefix-icon="el-icon-search" @input="handleSearchTemplate" style="width: 200px;" />
</div>
<div class="template-list" v-loading="templateLoading">
<div
v-for="template in templateList"
:key="template.id"
@@ -25,7 +42,18 @@
<el-empty description="暂无模板" />
</div>
</div>
<div class="shared-pagination" v-show="activeTab === 'shared'">
<el-pagination
background
layout="prev, pager, next"
:current-page="sharedQueryParams.pageNum"
:page-size="sharedQueryParams.pageSize"
:total="sharedTotal"
@current-change="handleSharedPageChange"
/>
</div>
</div>
<input type="file" ref="csvInput" accept=".csv" style="display:none" @change="handleCsvImport" />
<div class="right-panel">
<div class="panel-header">
<span class="panel-title">员工配置</span>
@@ -62,6 +90,8 @@
</template>
<script>
import { listAttendanceTemplate, addAttendanceTemplate, updateAttendanceTemplate, delAttendanceTemplate } from '@/api/wms/attendanceTemplate'
export default {
name: 'AttendanceTemplateManager',
props: {
@@ -72,7 +102,16 @@ export default {
},
data() {
return {
templateList: [],
activeTab: 'shared',
sharedTemplateList: [],
sharedTemplateLoading: false,
sharedQueryParams: {
pageNum: 1,
pageSize: 20,
templateName: ''
},
sharedTotal: 0,
personalTemplateList: [],
currentTemplate: {
id: '',
name: '',
@@ -83,22 +122,202 @@ export default {
selectedEmployeeIds: [],
}
},
computed: {
templateList() {
return this.activeTab === 'shared' ? this.sharedTemplateList : this.personalTemplateList
},
templateLoading() {
return this.activeTab === 'shared' ? this.sharedTemplateLoading : false
}
},
mounted() {
this.loadTemplates()
},
methods: {
loadTemplates() {
try {
const templates = localStorage.getItem('attendanceTemplates')
this.templateList = templates ? JSON.parse(templates) : []
} catch (e) {
this.templateList = []
if (this.activeTab === 'shared') {
this.sharedTemplateLoading = true
const query = {
pageNum: this.sharedQueryParams.pageNum,
pageSize: this.sharedQueryParams.pageSize
}
if (this.sharedQueryParams.templateName) {
query.templateName = this.sharedQueryParams.templateName
}
listAttendanceTemplate(query).then(res => {
this.sharedTemplateList = (res.rows || []).map(row => ({
id: row.templateId,
name: row.templateName,
employeeIds: this.parseTemplateContent(row.templateContent),
employeeCount: this.parseTemplateContent(row.templateContent).length,
createTime: row.createTime
}))
this.sharedTotal = res.total || 0
}).finally(() => {
this.sharedTemplateLoading = false
})
} else {
try {
const templates = localStorage.getItem('attendanceTemplates')
this.personalTemplateList = templates ? JSON.parse(templates) : []
} catch (e) {
this.personalTemplateList = []
}
}
},
saveTemplates() {
localStorage.setItem('attendanceTemplates', JSON.stringify(this.templateList))
this.$emit('update')
parseTemplateContent(content) {
if (!content) return []
try {
const parsed = JSON.parse(content)
return Array.isArray(parsed) ? parsed : []
} catch (e) {
return content.split(',').filter(Boolean)
}
},
buildTemplateContent(employeeIds) {
return JSON.stringify(employeeIds)
},
handleSearchTemplate() {
this.sharedQueryParams.pageNum = 1
this.loadTemplates()
},
handleSharedPageChange(pageNum) {
this.sharedQueryParams.pageNum = pageNum
this.loadTemplates()
},
switchTab(tab) {
if (this.activeTab === tab) return
this.activeTab = tab
this.loadTemplates()
this.resetForm()
},
savePersonalTemplates() {
localStorage.setItem('attendanceTemplates', JSON.stringify(this.personalTemplateList))
},
exportCsv() {
if (!this.currentTemplate.id || !this.currentTemplate.employeeIds.length) {
this.$message.warning('当前模板没有员工可导出')
return
}
const empMap = {}
this.employeeList.forEach(emp => {
empMap[emp.key] = emp.label
})
let csvContent = '\uFEFF员工ID,员工姓名\n'
this.currentTemplate.employeeIds.forEach(id => {
const name = empMap[id] || id
csvContent += `${id},${name}\n`
})
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
const link = document.createElement('a')
const url = URL.createObjectURL(blob)
link.setAttribute('href', url)
link.setAttribute('download', `${this.currentTemplate.name}.csv`)
link.style.visibility = 'hidden'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
},
importCsv() {
this.$refs.csvInput.click()
},
handleCsvImport(event) {
const file = event.target.files[0]
if (!file) return
const reader = new FileReader()
reader.onload = async (e) => {
const content = e.target.result
const lines = content.split('\n').filter(line => line.trim())
if (lines.length === 0) {
this.$message.warning('CSV文件内容为空')
event.target.value = ''
return
}
const header = lines[0].trim()
if (header !== '员工ID,员工姓名' && header !== '员工ID\t员工姓名') {
this.$message.warning('CSV文件格式不正确表头应为"员工ID,员工姓名"')
event.target.value = ''
return
}
const empKeySet = new Set()
const empLabelMap = {}
this.employeeList.forEach(emp => {
empKeySet.add(String(emp.key))
empLabelMap[emp.label] = emp.key
})
const matchedIds = []
const notFoundNames = []
const lines_data = lines.slice(1)
for (const line of lines_data) {
const trimmed = line.trim()
if (!trimmed) continue
const parts = trimmed.includes('\t') ? trimmed.split('\t') : trimmed.split(',')
const key = parts[0] ? parts[0].trim() : ''
const label = parts.length > 1 ? parts.slice(1).join(',').trim() : key
if (key && empKeySet.has(String(key))) {
matchedIds.push(key)
} else if (label && empLabelMap[label] !== undefined) {
matchedIds.push(empLabelMap[label])
} else {
notFoundNames.push(label || key)
}
}
if (matchedIds.length === 0) {
this.$message.warning('CSV文件中没有匹配到任何员工')
event.target.value = ''
return
}
const templateName = file.name.replace(/\.csv$/i, '')
if (this.activeTab === 'shared') {
await addAttendanceTemplate({
templateName: templateName,
templateContent: this.buildTemplateContent(matchedIds)
})
this.loadTemplates()
const newTemplate = this.sharedTemplateList.find(t => t.name === templateName)
if (newTemplate) {
this.currentTemplate = JSON.parse(JSON.stringify(newTemplate))
this.selectedEmployeeIds = [...newTemplate.employeeIds]
}
} else {
const templateData = {
id: Date.now().toString(),
name: templateName,
employeeIds: matchedIds,
employeeCount: matchedIds.length,
createTime: new Date().toLocaleString('zh-CN')
}
this.personalTemplateList.push(templateData)
this.savePersonalTemplates()
this.currentTemplate = JSON.parse(JSON.stringify(templateData))
this.selectedEmployeeIds = [...matchedIds]
}
this.$emit('update')
if (notFoundNames.length > 0) {
this.$message.warning(`成功导入${matchedIds.length}名员工,${notFoundNames.length}名未匹配:${notFoundNames.join('、')}`)
} else {
this.$message.success(`成功导入${matchedIds.length}名员工`)
}
}
reader.readAsText(file, 'UTF-8')
event.target.value = ''
},
addTemplate() {
@@ -118,20 +337,29 @@ export default {
},
deleteTemplate(template) {
this.$confirm('确定删除?', '提示', {
const confirmMsg = this.activeTab === 'shared'
? '删除后该模板所有人都无法使用,确定删除?'
: '确定删除?'
this.$confirm(confirmMsg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const index = this.templateList.findIndex(t => t.id === template.id)
if (index > -1) {
this.templateList.splice(index, 1)
this.saveTemplates()
this.$message.success('删除成功')
if (this.currentTemplate.id === template.id) {
this.resetForm()
}).then(async () => {
if (this.activeTab === 'shared') {
await delAttendanceTemplate(template.id)
} else {
const index = this.personalTemplateList.findIndex(t => t.id === template.id)
if (index > -1) {
this.personalTemplateList.splice(index, 1)
this.savePersonalTemplates()
}
}
this.$message.success('删除成功')
if (this.currentTemplate.id === template.id) {
this.resetForm()
}
this.loadTemplates()
this.$emit('update')
}).catch(() => {
this.$message.info('已取消')
})
@@ -142,32 +370,52 @@ export default {
this.selectedEmployeeIds = [...template.employeeIds]
},
saveTemplate() {
async saveTemplate() {
if (!this.currentTemplate.name.trim()) {
this.$message.warning('请输入模板名称')
return
}
const templateData = {
id: this.currentTemplate.id || Date.now().toString(),
name: this.currentTemplate.name.trim(),
employeeIds: [...this.selectedEmployeeIds],
employeeCount: this.selectedEmployeeIds.length,
createTime: this.currentTemplate.id ? this.currentTemplate.createTime : new Date().toLocaleString('zh-CN')
}
if (this.currentTemplate.id) {
const index = this.templateList.findIndex(t => t.id === this.currentTemplate.id)
if (index > -1) {
this.templateList[index] = templateData
if (this.activeTab === 'shared') {
const apiData = {
templateName: this.currentTemplate.name.trim(),
templateContent: this.buildTemplateContent(this.selectedEmployeeIds)
}
this.$message.success('修改成功')
} else {
this.templateList.push(templateData)
this.$message.success('新增成功')
}
this.saveTemplates()
if (this.currentTemplate.id) {
apiData.templateId = this.currentTemplate.id
await updateAttendanceTemplate(apiData)
this.$message.success('修改成功')
} else {
await addAttendanceTemplate(apiData)
this.$message.success('新增成功')
}
this.loadTemplates()
this.$emit('update')
} else {
const templateData = {
id: this.currentTemplate.id || Date.now().toString(),
name: this.currentTemplate.name.trim(),
employeeIds: [...this.selectedEmployeeIds],
employeeCount: this.selectedEmployeeIds.length,
createTime: this.currentTemplate.id ? this.currentTemplate.createTime : new Date().toLocaleString('zh-CN')
}
if (this.currentTemplate.id) {
const index = this.personalTemplateList.findIndex(t => t.id === this.currentTemplate.id)
if (index > -1) {
this.personalTemplateList[index] = templateData
}
this.$message.success('修改成功')
} else {
this.personalTemplateList.push(templateData)
this.$message.success('新增成功')
}
this.savePersonalTemplates()
this.$emit('update')
}
},
resetForm() {
@@ -220,6 +468,21 @@ export default {
color: #303133;
}
.panel-header-actions {
display: flex;
gap: 6px;
}
.shared-toolbar {
margin-bottom: 10px;
}
.shared-pagination {
display: flex;
justify-content: center;
padding: 10px 0 4px;
}
.template-list {
flex: 1;
overflow-y: auto;
@@ -315,4 +578,31 @@ export default {
padding-top: 10px;
border-top: 1px solid #e4e7ed;
}
.custom-tabs {
display: flex;
border-bottom: 1px solid #e4e7ed;
margin-bottom: 12px;
}
.custom-tab {
padding: 6px 14px;
font-size: 13px;
color: #909399;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: color 0.2s, border-color 0.2s;
user-select: none;
}
.custom-tab:hover {
color: #606266;
}
.custom-tab.active {
color: #1890ff;
border-bottom-color: #1890ff;
font-weight: 500;
}
</style>

View File

@@ -226,8 +226,15 @@
</el-dialog>
<!-- 班次模板选择弹窗 -->
<el-dialog title="选择人员模板" :visible.sync="showTemplateDialog" width="500px">
<el-table :data="templateList" border style="width: 100%;">
<el-dialog title="选择人员模板" :visible.sync="showTemplateDialog" width="540px">
<div class="template-dialog-tabs">
<div :class="['template-dialog-tab', { active: templateDialogTab === 'personal' }]" @click="switchTemplateDialogTab('personal')">自用模板</div>
<div :class="['template-dialog-tab', { active: templateDialogTab === 'shared' }]" @click="switchTemplateDialogTab('shared')">共享模板</div>
</div>
<div class="template-dialog-toolbar" v-show="templateDialogTab === 'shared'">
<el-input v-model="sharedDialogSearch" placeholder="搜索模板名称" size="small" clearable prefix-icon="el-icon-search" @input="handleDialogSearch" style="width: 200px;" />
</div>
<el-table :data="filteredTemplateList" border style="width: 100%;" v-loading="sharedDialogLoading">
<el-table-column prop="name" label="模板名称" />
<el-table-column prop="employeeCount" label="员工数量" align="center" />
<el-table-column prop="createTime" label="创建时间" />
@@ -238,6 +245,16 @@
</template>
</el-table-column>
</el-table>
<div class="template-dialog-pagination" v-show="templateDialogTab === 'shared' && sharedDialogTotal > sharedDialogPageSize">
<el-pagination
background
layout="prev, pager, next"
:current-page="sharedDialogPageNum"
:page-size="sharedDialogPageSize"
:total="sharedDialogTotal"
@current-change="handleDialogPageChange"
/>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="showTemplateDialog = false">关闭</el-button>
</div>
@@ -358,6 +375,7 @@ import { listAttendanceSchedule, generateenerateSchedule, updateAttendanceSchedu
import { listShift } from '@/api/wms/attendanceShift'
import { listAttendanceShiftRule } from '@/api/wms/attendanceShiftRule'
import { listEmployeeInfo } from '@/api/wms/employeeInfo'
import { listAttendanceTemplate, delAttendanceTemplate } from '@/api/wms/attendanceTemplate'
export default {
name: 'AttendanceSchedule',
@@ -387,6 +405,15 @@ export default {
editDialogVisible: false,
showTemplateDialog: false,
showTemplateManager: false,
templateDialogTab: 'personal',
sharedDialogList: [],
sharedDialogLoading: false,
sharedDialogPageNum: 1,
sharedDialogPageSize: 20,
sharedDialogTotal: 0,
sharedDialogSearch: '',
sharedTemplateList: [],
personalTemplateList: [],
templateList: [],
currentShiftIndex: -1,
employeeList: [],
@@ -543,6 +570,12 @@ export default {
if (!this.batchCellEditShiftId) return ''
const shift = this.shiftList.find(s => s.shiftId === this.batchCellEditShiftId)
return shift ? shift.shiftType : ''
},
filteredTemplateList() {
if (this.templateDialogTab === 'shared') {
return this.sharedDialogList
}
return this.personalTemplateList
}
},
created() {
@@ -1323,22 +1356,51 @@ export default {
this.getScheduleList()
},
// 加载模板列表
// 加载模板列表(共享 + 自用)
loadTemplates() {
try {
const templates = localStorage.getItem('attendanceTemplates')
this.templateList = templates ? JSON.parse(templates) : []
this.personalTemplateList = (templates ? JSON.parse(templates) : []).map(t => ({ ...t, source: 'personal' }))
} catch (e) {
this.templateList = []
this.personalTemplateList = []
}
listAttendanceTemplate().then(res => {
this.sharedTemplateList = (res.rows || []).map(row => ({
id: row.templateId,
name: row.templateName,
employeeIds: this.parseTemplateContent(row.templateContent),
employeeCount: this.parseTemplateContent(row.templateContent).length,
createTime: row.createTime,
source: 'shared'
}))
this.templateList = [...this.sharedTemplateList, ...this.personalTemplateList]
}).catch(() => {
this.templateList = [...this.personalTemplateList]
})
},
parseTemplateContent(content) {
if (!content) return []
try {
const parsed = JSON.parse(content)
return Array.isArray(parsed) ? parsed : []
} catch (e) {
return content.split(',').filter(Boolean)
}
},
// 保存模板到localStorage
saveTemplates() {
localStorage.setItem('attendanceTemplates', JSON.stringify(this.templateList))
// 保存自用模板到localStorage
savePersonalTemplates() {
const plainList = this.personalTemplateList.map(t => {
const { source, ...rest } = t
return rest
})
localStorage.setItem('attendanceTemplates', JSON.stringify(plainList))
this.templateList = [...this.sharedTemplateList, ...this.personalTemplateList]
},
// 保存单个班次为模板
// 保存单个班次为模板(保存到自用模板)
saveSingleTemplate(index) {
const shiftItem = this.form.shiftList[index]
if (!shiftItem.employeeIds || !shiftItem.employeeIds.trim()) {
@@ -1357,17 +1419,18 @@ export default {
}
const employeeIds = shiftItem.employeeIds.split(',').filter(id => id.trim())
const template = {
id: Date.now().toString(),
name: value.trim(),
employeeIds: employeeIds,
employeeCount: employeeIds.length,
createTime: new Date().toLocaleString('zh-CN')
createTime: new Date().toLocaleString('zh-CN'),
source: 'personal'
}
this.templateList.push(template)
this.saveTemplates()
this.personalTemplateList.push(template)
this.savePersonalTemplates()
this.$message.success('模板保存成功')
}).catch(() => {
this.$message.info('已取消保存')
@@ -1378,6 +1441,57 @@ export default {
openTemplateDialog(index) {
this.currentShiftIndex = index
this.showTemplateDialog = true
if (this.templateDialogTab === 'shared') {
this.sharedDialogPageNum = 1
this.sharedDialogSearch = ''
this.loadSharedDialogTemplates()
}
},
// 切换模板弹窗的 tab
switchTemplateDialogTab(tab) {
if (this.templateDialogTab === tab) return
this.templateDialogTab = tab
if (tab === 'shared') {
this.sharedDialogPageNum = 1
this.sharedDialogSearch = ''
this.loadSharedDialogTemplates()
}
},
// 加载共享模板弹窗列表(带分页)
loadSharedDialogTemplates() {
this.sharedDialogLoading = true
const query = {
pageNum: this.sharedDialogPageNum,
pageSize: this.sharedDialogPageSize
}
if (this.sharedDialogSearch) {
query.templateName = this.sharedDialogSearch
}
listAttendanceTemplate(query).then(res => {
this.sharedDialogList = (res.rows || []).map(row => ({
id: row.templateId,
name: row.templateName,
employeeIds: this.parseTemplateContent(row.templateContent),
employeeCount: this.parseTemplateContent(row.templateContent).length,
createTime: row.createTime,
source: 'shared'
}))
this.sharedDialogTotal = res.total || 0
}).finally(() => {
this.sharedDialogLoading = false
})
},
handleDialogSearch() {
this.sharedDialogPageNum = 1
this.loadSharedDialogTemplates()
},
handleDialogPageChange(pageNum) {
this.sharedDialogPageNum = pageNum
this.loadSharedDialogTemplates()
},
// 应用单个模板到当前班次
@@ -1392,16 +1506,26 @@ export default {
// 删除单个模板
deleteSingleTemplate(template) {
this.$confirm('确定要删除这个模板吗?', '提示', {
const confirmMsg = template.source === 'shared'
? '删除后该模板所有人都无法使用,确定删除?'
: '确定要删除这个模板吗?'
this.$confirm(confirmMsg, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const index = this.templateList.findIndex(t => t.id === template.id)
if (index > -1) {
this.templateList.splice(index, 1)
this.saveTemplates()
}).then(async () => {
if (template.source === 'shared') {
await delAttendanceTemplate(template.id)
this.$message.success('删除成功')
this.loadTemplates()
this.loadSharedDialogTemplates()
} else {
const index = this.personalTemplateList.findIndex(t => t.id === template.id)
if (index > -1) {
this.personalTemplateList.splice(index, 1)
this.savePersonalTemplates()
this.$message.success('删除成功')
}
}
}).catch(() => {
this.$message.info('已取消删除')
@@ -1782,4 +1906,41 @@ export default {
justify-content: flex-end;
gap: 12px;
}
.template-dialog-tabs {
display: flex;
border-bottom: 1px solid #e4e7ed;
margin-bottom: 12px;
}
.template-dialog-tab {
padding: 6px 14px;
font-size: 13px;
color: #909399;
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: color 0.2s, border-color 0.2s;
user-select: none;
}
.template-dialog-tab:hover {
color: #606266;
}
.template-dialog-tab.active {
color: #1890ff;
border-bottom-color: #1890ff;
font-weight: 500;
}
.template-dialog-toolbar {
margin-bottom: 10px;
}
.template-dialog-pagination {
display: flex;
justify-content: center;
padding-top: 10px;
}
</style>

View File

@@ -0,0 +1,99 @@
package com.klp.controller;
import java.util.List;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.klp.common.annotation.RepeatSubmit;
import com.klp.common.annotation.Log;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.domain.R;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.domain.vo.WmsAttendanceTemplateVo;
import com.klp.domain.bo.WmsAttendanceTemplateBo;
import com.klp.service.IWmsAttendanceTemplateService;
import com.klp.common.core.page.TableDataInfo;
/**
* 排班模板
*
* @author klp
* @date 2026-06-06
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/wms/attendanceTemplate")
public class WmsAttendanceTemplateController extends BaseController {
private final IWmsAttendanceTemplateService iWmsAttendanceTemplateService;
/**
* 查询排班模板列表
*/
@GetMapping("/list")
public TableDataInfo<WmsAttendanceTemplateVo> list(WmsAttendanceTemplateBo bo, PageQuery pageQuery) {
return iWmsAttendanceTemplateService.queryPageList(bo, pageQuery);
}
/**
* 导出排班模板列表
*/
@Log(title = "排班模板", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(WmsAttendanceTemplateBo bo, HttpServletResponse response) {
List<WmsAttendanceTemplateVo> list = iWmsAttendanceTemplateService.queryList(bo);
ExcelUtil.exportExcel(list, "排班模板", WmsAttendanceTemplateVo.class, response);
}
/**
* 获取排班模板详细信息
*
* @param templateId 主键
*/
@GetMapping("/{templateId}")
public R<WmsAttendanceTemplateVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long templateId) {
return R.ok(iWmsAttendanceTemplateService.queryById(templateId));
}
/**
* 新增排班模板
*/
@Log(title = "排班模板", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody WmsAttendanceTemplateBo bo) {
return toAjax(iWmsAttendanceTemplateService.insertByBo(bo));
}
/**
* 修改排班模板
*/
@Log(title = "排班模板", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody WmsAttendanceTemplateBo bo) {
return toAjax(iWmsAttendanceTemplateService.updateByBo(bo));
}
/**
* 删除排班模板
*
* @param templateIds 主键串
*/
@Log(title = "排班模板", businessType = BusinessType.DELETE)
@DeleteMapping("/{templateIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] templateIds) {
return toAjax(iWmsAttendanceTemplateService.deleteWithValidByIds(Arrays.asList(templateIds), true));
}
}

View File

@@ -0,0 +1,45 @@
package com.klp.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 排班模板对象 wms_attendance_template
*
* @author klp
* @date 2026-06-06
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("wms_attendance_template")
public class WmsAttendanceTemplate extends BaseEntity {
private static final long serialVersionUID=1L;
/**
* 主键ID
*/
@TableId(value = "template_id")
private Long templateId;
/**
* 模板名称
*/
private String templateName;
/**
* 模板内容
*/
private String templateContent;
/**
* 删除标志0=存在 2=删除)
*/
@TableLogic
private String delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,33 @@
package com.klp.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
/**
* 排班模板业务对象 wms_attendance_template
*
* @author klp
* @date 2026-06-06
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class WmsAttendanceTemplateBo extends BaseEntity {
/**
* 主键ID
*/
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
private Long templateId;
private String templateName;
private String templateContent;
private String remark;
}

View File

@@ -0,0 +1,45 @@
package com.klp.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 排班模板视图对象 wms_attendance_template
*
* @author klp
* @date 2026-06-06
*/
@Data
@ExcelIgnoreUnannotated
public class WmsAttendanceTemplateVo {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@ExcelProperty(value = "主键ID")
private Long templateId;
/**
* 模板名称
*/
@ExcelProperty(value = "模板名称")
private String templateName;
/**
* 模板内容
*/
@ExcelProperty(value = "模板内容")
private String templateContent;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,15 @@
package com.klp.mapper;
import com.klp.domain.WmsAttendanceTemplate;
import com.klp.domain.vo.WmsAttendanceTemplateVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 排班模板Mapper接口
*
* @author klp
* @date 2026-06-06
*/
public interface WmsAttendanceTemplateMapper extends BaseMapperPlus<WmsAttendanceTemplateMapper, WmsAttendanceTemplate, WmsAttendanceTemplateVo> {
}

View File

@@ -0,0 +1,49 @@
package com.klp.service;
import com.klp.domain.WmsAttendanceTemplate;
import com.klp.domain.vo.WmsAttendanceTemplateVo;
import com.klp.domain.bo.WmsAttendanceTemplateBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 排班模板Service接口
*
* @author klp
* @date 2026-06-06
*/
public interface IWmsAttendanceTemplateService {
/**
* 查询排班模板
*/
WmsAttendanceTemplateVo queryById(Long templateId);
/**
* 查询排班模板列表
*/
TableDataInfo<WmsAttendanceTemplateVo> queryPageList(WmsAttendanceTemplateBo bo, PageQuery pageQuery);
/**
* 查询排班模板列表
*/
List<WmsAttendanceTemplateVo> queryList(WmsAttendanceTemplateBo bo);
/**
* 新增排班模板
*/
Boolean insertByBo(WmsAttendanceTemplateBo bo);
/**
* 修改排班模板
*/
Boolean updateByBo(WmsAttendanceTemplateBo bo);
/**
* 校验并批量删除排班模板信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,110 @@
package com.klp.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.common.utils.StringUtils;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.domain.bo.WmsAttendanceTemplateBo;
import com.klp.domain.vo.WmsAttendanceTemplateVo;
import com.klp.domain.WmsAttendanceTemplate;
import com.klp.mapper.WmsAttendanceTemplateMapper;
import com.klp.service.IWmsAttendanceTemplateService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 排班模板Service业务层处理
*
* @author klp
* @date 2026-06-06
*/
@RequiredArgsConstructor
@Service
public class WmsAttendanceTemplateServiceImpl implements IWmsAttendanceTemplateService {
private final WmsAttendanceTemplateMapper baseMapper;
/**
* 查询排班模板
*/
@Override
public WmsAttendanceTemplateVo queryById(Long templateId){
return baseMapper.selectVoById(templateId);
}
/**
* 查询排班模板列表
*/
@Override
public TableDataInfo<WmsAttendanceTemplateVo> queryPageList(WmsAttendanceTemplateBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<WmsAttendanceTemplate> lqw = buildQueryWrapper(bo);
Page<WmsAttendanceTemplateVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询排班模板列表
*/
@Override
public List<WmsAttendanceTemplateVo> queryList(WmsAttendanceTemplateBo bo) {
LambdaQueryWrapper<WmsAttendanceTemplate> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<WmsAttendanceTemplate> buildQueryWrapper(WmsAttendanceTemplateBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<WmsAttendanceTemplate> lqw = Wrappers.lambdaQuery();
lqw.like(StringUtils.isNotBlank(bo.getTemplateName()), WmsAttendanceTemplate::getTemplateName, bo.getTemplateName());
lqw.eq(StringUtils.isNotBlank(bo.getTemplateContent()), WmsAttendanceTemplate::getTemplateContent, bo.getTemplateContent());
return lqw;
}
/**
* 新增排班模板
*/
@Override
public Boolean insertByBo(WmsAttendanceTemplateBo bo) {
WmsAttendanceTemplate add = BeanUtil.toBean(bo, WmsAttendanceTemplate.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setTemplateId(add.getTemplateId());
}
return flag;
}
/**
* 修改排班模板
*/
@Override
public Boolean updateByBo(WmsAttendanceTemplateBo bo) {
WmsAttendanceTemplate update = BeanUtil.toBean(bo, WmsAttendanceTemplate.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(WmsAttendanceTemplate entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除排班模板
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.klp.mapper.WmsAttendanceTemplateMapper">
<resultMap type="com.klp.domain.WmsAttendanceTemplate" id="WmsAttendanceTemplateResult">
<result property="templateId" column="template_id"/>
<result property="templateName" column="template_name"/>
<result property="templateContent" column="template_content"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
</mapper>