feat(hrm/meal&employee): 新增员工吃辣偏好字段与就餐统计矩阵
1. 在员工入职/信息页面新增是否吃辣单选表单字段 2. 重构就餐统计模块,替换原有简单统计为吃辣/不吃辣 × 堂食/打包 × 有效/无效的三维交叉统计矩阵 3. 新增员工吃辣偏好映射接口,自动获取员工饮食偏好进行分类统计
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div style="display: flex; align-items: center; margin-bottom: 12px;">
|
<div style="display: flex; align-items: center; margin-bottom: 0px;">
|
||||||
<el-select v-model="selectedValue" placeholder="请选择合同" style="width: 100%">
|
<el-select v-model="selectedValue" placeholder="请选择合同" style="width: 100%" clearable>
|
||||||
<el-option v-for="item in contractList" :key="item.orderId" :value="item.orderId"
|
<el-option v-for="item in contractList" :key="item.orderId" :value="item.orderId"
|
||||||
:label="item.contractCode" />
|
:label="item.contractCode" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|||||||
@@ -158,11 +158,11 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-dialog title="完成退火" :visible.sync="completeOpen" width="720px" append-to-body>
|
<el-dialog title="完成退火" :visible.sync="completeOpen" width="800px" append-to-body>
|
||||||
<div class="complete-tip">请为每条钢卷分配逻辑库区去向和关联合同,未分配将无法完成。</div>
|
<div class="complete-tip">请为每条钢卷分配逻辑库区去向和关联合同,未分配将无法完成。</div>
|
||||||
<el-table :data="completeCoils" v-loading="completeLoading" height="360px">
|
<el-table :data="completeCoils" v-loading="completeLoading" height="360px">
|
||||||
<el-table-column label="入场钢卷号" prop="enterCoilNo" align="center" />
|
<el-table-column label="入场钢卷号" prop="enterCoilNo" align="center" />
|
||||||
<el-table-column label="钢卷去向" align="center" width="240">
|
<el-table-column label="钢卷去向" align="center" width="270">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-select v-model="scope.row.warehouseId" @change="handlePLanCoilChange(scope.row)">
|
<el-select v-model="scope.row.warehouseId" @change="handlePLanCoilChange(scope.row)">
|
||||||
<el-option v-for="item in warehouseList" :key="item.warehouseId" :label="item.warehouseName"
|
<el-option v-for="item in warehouseList" :key="item.warehouseId" :label="item.warehouseName"
|
||||||
@@ -170,9 +170,11 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="关联合同" align="center" width="240">
|
<el-table-column label="关联合同" align="center" width="270">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<ContractSelect v-model="scope.row.contractId" placeholder="请选择合同" />
|
<div style="width: 100%; display: flex; align-items: center;">
|
||||||
|
<ContractSelect v-model="scope.row.contractId" placeholder="请选择合同" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
@@ -160,6 +160,14 @@
|
|||||||
<el-input v-model="form.phone" placeholder="请输入联系电话" />
|
<el-input v-model="form.phone" placeholder="请输入联系电话" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="是否吃辣" prop="isSpicyEater">
|
||||||
|
<el-radio-group v-model="form.isSpicyEater" size="small">
|
||||||
|
<el-radio :label="1">是</el-radio>
|
||||||
|
<el-radio :label="0">否</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="家庭住址" prop="homeAddress">
|
<el-form-item label="家庭住址" prop="homeAddress">
|
||||||
<el-input v-model="form.homeAddress" placeholder="请输入家庭住址" />
|
<el-input v-model="form.homeAddress" placeholder="请输入家庭住址" />
|
||||||
@@ -404,6 +412,7 @@ export default {
|
|||||||
homeAddress: undefined,
|
homeAddress: undefined,
|
||||||
phone: undefined,
|
phone: undefined,
|
||||||
entryTime: undefined,
|
entryTime: undefined,
|
||||||
|
isSpicyEater: undefined,
|
||||||
emergencyContact: undefined,
|
emergencyContact: undefined,
|
||||||
relationship: undefined,
|
relationship: undefined,
|
||||||
emergencyContactPhone: undefined,
|
emergencyContactPhone: undefined,
|
||||||
|
|||||||
@@ -216,6 +216,14 @@
|
|||||||
<el-input v-model="form.phone" placeholder="请输入联系电话" />
|
<el-input v-model="form.phone" placeholder="请输入联系电话" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="是否吃辣" prop="isSpicyEater">
|
||||||
|
<el-radio-group v-model="form.isSpicyEater" size="small">
|
||||||
|
<el-radio :label="1">是</el-radio>
|
||||||
|
<el-radio :label="0">否</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="家庭住址" prop="homeAddress">
|
<el-form-item label="家庭住址" prop="homeAddress">
|
||||||
<el-input v-model="form.homeAddress" placeholder="请输入家庭住址" />
|
<el-input v-model="form.homeAddress" placeholder="请输入家庭住址" />
|
||||||
@@ -432,6 +440,7 @@ export default {
|
|||||||
homeAddress: undefined,
|
homeAddress: undefined,
|
||||||
phone: undefined,
|
phone: undefined,
|
||||||
entryTime: undefined,
|
entryTime: undefined,
|
||||||
|
isSpicyEater: undefined,
|
||||||
emergencyContact: undefined,
|
emergencyContact: undefined,
|
||||||
relationship: undefined,
|
relationship: undefined,
|
||||||
emergencyContactPhone: undefined,
|
emergencyContactPhone: undefined,
|
||||||
|
|||||||
@@ -65,18 +65,44 @@
|
|||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 修改:统计组件扩展为6列,展示有效/无效的6项统计 -->
|
<!-- 三维交叉统计矩阵表 -->
|
||||||
<el-descriptions size="small" border class="mb8" :column="3">
|
<div class="stats-matrix mb8">
|
||||||
<el-descriptions-item label="堂食人数">{{ validDineIn + invalidDineIn }}</el-descriptions-item>
|
<table class="matrix-table">
|
||||||
<el-descriptions-item label="打包人数">{{ validTakeout + invalidTakeout }}</el-descriptions-item>
|
<thead>
|
||||||
<el-descriptions-item label="总人数">{{ validTotal + invalidTotal }}</el-descriptions-item>
|
<tr>
|
||||||
<el-descriptions-item label="有效堂食人数">{{ validDineIn }}</el-descriptions-item>
|
<th rowspan="2" class="label-col"></th>
|
||||||
<el-descriptions-item label="有效打包人数">{{ validTakeout }}</el-descriptions-item>
|
<th colspan="3" class="group-header group-valid">有效</th>
|
||||||
<el-descriptions-item label="有效总人数">{{ validTotal }}</el-descriptions-item>
|
<th colspan="3" class="group-header group-invalid">无效</th>
|
||||||
<el-descriptions-item label="无效堂食人数">{{ invalidDineIn }}</el-descriptions-item>
|
<th colspan="3" class="group-header group-all">合计</th>
|
||||||
<el-descriptions-item label="无效打包人数">{{ invalidTakeout }}</el-descriptions-item>
|
</tr>
|
||||||
<el-descriptions-item label="无效总人数">{{ invalidTotal }}</el-descriptions-item>
|
<tr>
|
||||||
</el-descriptions>
|
<th>堂食</th><th>打包</th><th>小计</th>
|
||||||
|
<th>堂食</th><th>打包</th><th>小计</th>
|
||||||
|
<th>堂食</th><th>打包</th><th>小计</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="label-col">吃辣</td>
|
||||||
|
<td>{{ matrix.spicy.validDine }}</td><td>{{ matrix.spicy.validTake }}</td><td class="subtotal">{{ matrix.spicy.validTotal }}</td>
|
||||||
|
<td>{{ matrix.spicy.invalidDine }}</td><td>{{ matrix.spicy.invalidTake }}</td><td class="subtotal">{{ matrix.spicy.invalidTotal }}</td>
|
||||||
|
<td>{{ matrix.spicy.dine }}</td><td>{{ matrix.spicy.take }}</td><td class="subtotal">{{ matrix.spicy.total }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label-col">不吃辣</td>
|
||||||
|
<td>{{ matrix.nonSpicy.validDine }}</td><td>{{ matrix.nonSpicy.validTake }}</td><td class="subtotal">{{ matrix.nonSpicy.validTotal }}</td>
|
||||||
|
<td>{{ matrix.nonSpicy.invalidDine }}</td><td>{{ matrix.nonSpicy.invalidTake }}</td><td class="subtotal">{{ matrix.nonSpicy.invalidTotal }}</td>
|
||||||
|
<td>{{ matrix.nonSpicy.dine }}</td><td>{{ matrix.nonSpicy.take }}</td><td class="subtotal">{{ matrix.nonSpicy.total }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="total-row">
|
||||||
|
<td class="label-col">合计</td>
|
||||||
|
<td>{{ matrix.all.validDine }}</td><td>{{ matrix.all.validTake }}</td><td class="subtotal">{{ matrix.all.validTotal }}</td>
|
||||||
|
<td>{{ matrix.all.invalidDine }}</td><td>{{ matrix.all.invalidTake }}</td><td class="subtotal">{{ matrix.all.invalidTotal }}</td>
|
||||||
|
<td>{{ matrix.all.dine }}</td><td>{{ matrix.all.take }}</td><td class="subtotal">{{ matrix.all.total }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 修改:添加行样式判断,为无效报餐行加背景色 -->
|
<!-- 修改:添加行样式判断,为无效报餐行加背景色 -->
|
||||||
<el-table
|
<el-table
|
||||||
@@ -196,6 +222,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listMealReport, getMealReport, delMealReport, addMealReport, updateMealReport } from "@/api/wms/mealReport";
|
import { listMealReport, getMealReport, delMealReport, addMealReport, updateMealReport } from "@/api/wms/mealReport";
|
||||||
|
import { listEmployeeInfo } from "@/api/wms/employeeInfo";
|
||||||
import DictSelect from "@/components/DictSelect";
|
import DictSelect from "@/components/DictSelect";
|
||||||
import EmployeeSelector from "@/components/EmployeeSelector";
|
import EmployeeSelector from "@/components/EmployeeSelector";
|
||||||
import { listDept } from "@/api/wms/dept"
|
import { listDept } from "@/api/wms/dept"
|
||||||
@@ -254,13 +281,13 @@ export default {
|
|||||||
updateTime: undefined,
|
updateTime: undefined,
|
||||||
remark: undefined
|
remark: undefined
|
||||||
},
|
},
|
||||||
// 替换原有统计变量,新增6个有效/无效统计项
|
// 三维交叉统计矩阵
|
||||||
validDineIn: 0, // 有效堂食人数
|
matrix: {
|
||||||
validTakeout: 0, // 有效打包人数
|
spicy: { validDine: 0, validTake: 0, validTotal: 0, invalidDine: 0, invalidTake: 0, invalidTotal: 0, dine: 0, take: 0, total: 0 },
|
||||||
validTotal: 0, // 有效总人数
|
nonSpicy: { validDine: 0, validTake: 0, validTotal: 0, invalidDine: 0, invalidTake: 0, invalidTotal: 0, dine: 0, take: 0, total: 0 },
|
||||||
invalidDineIn: 0, // 无效堂食人数
|
all: { validDine: 0, validTake: 0, validTotal: 0, invalidDine: 0, invalidTake: 0, invalidTotal: 0, dine: 0, take: 0, total: 0 }
|
||||||
invalidTakeout: 0, // 无效打包人数
|
},
|
||||||
invalidTotal: 0, // 无效总人数
|
employeeSpicyMap: {},
|
||||||
// 表单校验规则
|
// 表单校验规则
|
||||||
rules: {
|
rules: {
|
||||||
reportDate: [{ required: true, message: '用餐日期不能为空', trigger: 'change' }],
|
reportDate: [{ required: true, message: '用餐日期不能为空', trigger: 'change' }],
|
||||||
@@ -278,6 +305,7 @@ export default {
|
|||||||
this.getList();
|
this.getList();
|
||||||
this.getDeptList();
|
this.getDeptList();
|
||||||
this.getDeadlineConfig();
|
this.getDeadlineConfig();
|
||||||
|
this.buildEmployeeMap();
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'form.dineInPeople': {
|
'form.dineInPeople': {
|
||||||
@@ -324,37 +352,78 @@ export default {
|
|||||||
this.form.takeoutPeople = val?.length || 0;
|
this.form.takeoutPeople = val?.length || 0;
|
||||||
this.calcTotalPeople();
|
this.calcTotalPeople();
|
||||||
},
|
},
|
||||||
/** 核心修改:区分有效/无效统计 */
|
/** 构建员工吃辣偏好映射(name -> isSpicyEater) */
|
||||||
|
buildEmployeeMap() {
|
||||||
|
listEmployeeInfo({ pageNum: 1, pageSize: 9999 }).then(response => {
|
||||||
|
const map = {};
|
||||||
|
(response.rows || []).forEach(emp => {
|
||||||
|
if (emp.name && emp.isLeave !== 1 && emp.isSpicyEater !== undefined && emp.isSpicyEater !== null) {
|
||||||
|
map[emp.name] = emp.isSpicyEater == 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.employeeSpicyMap = map;
|
||||||
|
this.calcTableSum();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 根据人员名单统计不吃辣人数 */
|
||||||
|
countNonSpicy(nameList) {
|
||||||
|
if (!nameList) return 0;
|
||||||
|
const names = nameList.split(',').map(n => n.trim()).filter(n => n);
|
||||||
|
let count = 0;
|
||||||
|
const counted = {};
|
||||||
|
names.forEach(name => {
|
||||||
|
if (!counted[name] && this.employeeSpicyMap[name] === 0) {
|
||||||
|
count++;
|
||||||
|
counted[name] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
/** 三维交叉统计:吃辣/不吃辣 × 堂食/打包 × 有效/无效 */
|
||||||
calcTableSum(){
|
calcTableSum(){
|
||||||
// 初始化统计变量
|
const m = {
|
||||||
let validDine = 0, validTake = 0, validAll = 0;
|
spicy: { validDine: 0, validTake: 0, validTotal: 0, invalidDine: 0, invalidTake: 0, invalidTotal: 0, dine: 0, take: 0, total: 0 },
|
||||||
let invalidDine = 0, invalidTake = 0, invalidAll = 0;
|
nonSpicy: { validDine: 0, validTake: 0, validTotal: 0, invalidDine: 0, invalidTake: 0, invalidTotal: 0, dine: 0, take: 0, total: 0 },
|
||||||
|
all: { validDine: 0, validTake: 0, validTotal: 0, invalidDine: 0, invalidTake: 0, invalidTotal: 0, dine: 0, take: 0, total: 0 }
|
||||||
|
};
|
||||||
|
|
||||||
this.mealReportList.forEach(item => {
|
this.mealReportList.forEach(item => {
|
||||||
// 处理空值,转为数字
|
|
||||||
const dine = item.dineInPeople ? Number(item.dineInPeople) : 0;
|
const dine = item.dineInPeople ? Number(item.dineInPeople) : 0;
|
||||||
const take = item.takeoutPeople ? Number(item.takeoutPeople) : 0;
|
const take = item.takeoutPeople ? Number(item.takeoutPeople) : 0;
|
||||||
const total = item.totalPeople ? Number(item.totalPeople) : 0;
|
const total = item.totalPeople ? Number(item.totalPeople) : 0;
|
||||||
|
|
||||||
// 判断当前报餐是否有效
|
const nonSpicyDine = this.countNonSpicy(item.dineInPeopleList);
|
||||||
if (this.isValidMealReport(item.createTime)) {
|
const nonSpicyTake = this.countNonSpicy(item.takeoutPeopleList);
|
||||||
validDine += dine;
|
const spicyDine = dine - nonSpicyDine;
|
||||||
validTake += take;
|
const spicyTake = take - nonSpicyTake;
|
||||||
validAll += total;
|
const nonSpicyTotal = nonSpicyDine + nonSpicyTake;
|
||||||
} else {
|
const spicyTotal = spicyDine + spicyTake;
|
||||||
invalidDine += dine;
|
|
||||||
invalidTake += take;
|
const v = this.isValidMealReport(item.createTime) ? 'valid' : 'invalid';
|
||||||
invalidAll += total;
|
|
||||||
}
|
m.spicy[v + 'Dine'] += spicyDine;
|
||||||
|
m.spicy[v + 'Take'] += spicyTake;
|
||||||
|
m.spicy[v + 'Total'] += spicyTotal;
|
||||||
|
m.spicy.dine += spicyDine;
|
||||||
|
m.spicy.take += spicyTake;
|
||||||
|
m.spicy.total += spicyTotal;
|
||||||
|
|
||||||
|
m.nonSpicy[v + 'Dine'] += nonSpicyDine;
|
||||||
|
m.nonSpicy[v + 'Take'] += nonSpicyTake;
|
||||||
|
m.nonSpicy[v + 'Total'] += nonSpicyTotal;
|
||||||
|
m.nonSpicy.dine += nonSpicyDine;
|
||||||
|
m.nonSpicy.take += nonSpicyTake;
|
||||||
|
m.nonSpicy.total += nonSpicyTotal;
|
||||||
|
|
||||||
|
m.all[v + 'Dine'] += dine;
|
||||||
|
m.all[v + 'Take'] += take;
|
||||||
|
m.all[v + 'Total'] += total;
|
||||||
|
m.all.dine += dine;
|
||||||
|
m.all.take += take;
|
||||||
|
m.all.total += total;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 赋值到统计变量
|
this.matrix = m;
|
||||||
this.validDineIn = validDine;
|
|
||||||
this.validTakeout = validTake;
|
|
||||||
this.validTotal = validAll;
|
|
||||||
this.invalidDineIn = invalidDine;
|
|
||||||
this.invalidTakeout = invalidTake;
|
|
||||||
this.invalidTotal = invalidAll;
|
|
||||||
},
|
},
|
||||||
/** 新增:判断报餐是否有效(仅比较时分秒) */
|
/** 新增:判断报餐是否有效(仅比较时分秒) */
|
||||||
isValidMealReport(createTime) {
|
isValidMealReport(createTime) {
|
||||||
@@ -504,12 +573,69 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 新增:无效报餐行样式 */
|
/* 无效报餐行样式 */
|
||||||
.invalid-meal-row {
|
.invalid-meal-row {
|
||||||
background-color: #fff0f0 !important; /* 浅红色背景,可根据需求调整 */
|
background-color: #fff0f0 !important;
|
||||||
}
|
}
|
||||||
/* 优化表格行hover样式 */
|
|
||||||
::v-deep .el-table .invalid-meal-row:hover>td {
|
::v-deep .el-table .invalid-meal-row:hover>td {
|
||||||
background-color: #ffe0e0 !important;
|
background-color: #ffe0e0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 三维交叉统计矩阵表 */
|
||||||
|
.matrix-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 13px;
|
||||||
|
border: 1px solid #EBEEF5;
|
||||||
|
}
|
||||||
|
.matrix-table th,
|
||||||
|
.matrix-table td {
|
||||||
|
padding: 8px 6px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #EBEEF5;
|
||||||
|
min-width: 52px;
|
||||||
|
}
|
||||||
|
.matrix-table th {
|
||||||
|
background-color: #F5F7FA;
|
||||||
|
color: #909399;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.matrix-table .label-col {
|
||||||
|
background-color: #F5F7FA;
|
||||||
|
color: #909399;
|
||||||
|
font-weight: 500;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 60px;
|
||||||
|
}
|
||||||
|
.matrix-table .group-header {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
.matrix-table .group-valid {
|
||||||
|
background-color: #F0F9EB;
|
||||||
|
color: #67C23A;
|
||||||
|
}
|
||||||
|
.matrix-table .group-invalid {
|
||||||
|
background-color: #FEF0F0;
|
||||||
|
color: #F56C6C;
|
||||||
|
}
|
||||||
|
.matrix-table .group-all {
|
||||||
|
background-color: #ECF5FF;
|
||||||
|
color: #409EFF;
|
||||||
|
}
|
||||||
|
.matrix-table .subtotal {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
background-color: #FAFAFA;
|
||||||
|
}
|
||||||
|
.matrix-table .total-row td {
|
||||||
|
font-weight: 700;
|
||||||
|
border-top: 2px solid #DCDFE6;
|
||||||
|
}
|
||||||
|
.matrix-table .total-row .label-col {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.matrix-table .total-row .subtotal {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user