diff --git a/apps/hand-factory/api/wms/employeeInfo.js b/apps/hand-factory/api/wms/employeeInfo.js new file mode 100644 index 0000000..ba694c6 --- /dev/null +++ b/apps/hand-factory/api/wms/employeeInfo.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询员工信息列表 +export function listEmployeeInfo(query) { + return request({ + url: '/wms/employeeInfo/list', + method: 'get', + params: query + }) +} + +// 查询员工信息详细 +export function getEmployeeInfo(infoId) { + return request({ + url: '/wms/employeeInfo/' + infoId, + method: 'get' + }) +} + +// 新增员工信息 +export function addEmployeeInfo(data) { + return request({ + url: '/wms/employeeInfo', + method: 'post', + data: data + }) +} + +// 修改员工信息 +export function updateEmployeeInfo(data) { + return request({ + url: '/wms/employeeInfo', + method: 'put', + data: data + }) +} + +// 删除员工信息 +export function delEmployeeInfo(infoId) { + return request({ + url: '/wms/employeeInfo/' + infoId, + method: 'delete' + }) +} diff --git a/apps/hand-factory/config.js b/apps/hand-factory/config.js index 90812a9..b198d01 100644 --- a/apps/hand-factory/config.js +++ b/apps/hand-factory/config.js @@ -9,7 +9,7 @@ module.exports = { // 应用名称 name: "ruoyi-app", // 应用版本 - version: "1.3.34", + version: "1.3.37", // 应用logo logo: "/static/logo.jpg", // 官方网站 diff --git a/apps/hand-factory/manifest.json b/apps/hand-factory/manifest.json index 8327ca4..4584875 100644 --- a/apps/hand-factory/manifest.json +++ b/apps/hand-factory/manifest.json @@ -15,7 +15,18 @@ "delay" : 0 }, "modules" : { - "Barcode" : {} + "Barcode" : {}, + "Contacts" : {}, + "Bluetooth" : {}, + "FaceID" : {}, + "Fingerprint" : {}, + "Geolocation" : {}, + "Record" : {}, + "Camera" : {}, + "iBeacon" : {}, + "LivePusher" : {}, + "Messaging" : {}, + "VideoPlayer" : {} }, "distribute" : { "android" : { @@ -41,7 +52,13 @@ "ios" : { "dSYMs" : false }, - "sdkConfigs" : {}, + "sdkConfigs" : { + "geolocation" : { + "system" : { + "__platform__" : [ "android" ] + } + } + }, "icons" : { "android" : { "hdpi" : "unpackage/res/icons/72x72.png", diff --git a/apps/hand-factory/pages/meal/meal.vue b/apps/hand-factory/pages/meal/meal.vue index 415e558..5d68947 100644 --- a/apps/hand-factory/pages/meal/meal.vue +++ b/apps/hand-factory/pages/meal/meal.vue @@ -23,51 +23,93 @@ - + + + ✅ 有效报餐 + + + + 堂食 + 打包 + 小计 + + + 🌶 吃辣 + {{ ms.validDine }} + {{ ms.validTake }} + {{ ms.validTotal }} + + + 🌿 不吃辣 + {{ mn.validDine }} + {{ mn.validTake }} + {{ mn.validTotal }} + + + 小计 + {{ ma.validDine }} + {{ ma.validTake }} + {{ ma.validTotal }} + + + + + + ❌ 无效报餐 + + + + 堂食 + 打包 + 小计 + + + 🌶 吃辣 + {{ ms.invalidDine }} + {{ ms.invalidTake }} + {{ ms.invalidTotal }} + + + 🌿 不吃辣 + {{ mn.invalidDine }} + {{ mn.invalidTake }} + {{ mn.invalidTotal }} + + + 小计 + {{ ma.invalidDine }} + {{ ma.invalidTake }} + {{ ma.invalidTotal }} + + + + - 报餐人数统计 - - - - 堂食人数 - {{ validDineIn + invalidDineIn }} - - - 打包人数 - {{ validTakeout + invalidTakeout }} - - - 总人数 - {{ validTotal + invalidTotal }} - + 📊 总计 + + + + 堂食 + 打包 + 小计 - - - 有效堂食人数 - {{ validDineIn }} - - - 有效打包人数 - {{ validTakeout }} - - - 有效总人数 - {{ validTotal }} - + + 🌶 吃辣 + {{ ms.dine }} + {{ ms.take }} + {{ ms.total }} - - - 无效堂食人数 - {{ invalidDineIn }} - - - 无效打包人数 - {{ invalidTakeout }} - - - 无效总人数 - {{ invalidTotal }} - + + 🌿 不吃辣 + {{ mn.dine }} + {{ mn.take }} + {{ mn.total }} + + + 小计 + {{ ma.dine }} + {{ ma.take }} + {{ ma.total }} @@ -115,6 +157,9 @@ import { listMealReport } from "@/api/wms/mealReport"; + import { + listEmployeeInfo + } from "@/api/wms/employeeInfo"; import { getDicts } from '@/api/system/dict/data.js' @@ -127,13 +172,17 @@ data() { return { queryParams: { - mealType: '', + mealType: undefined, reportDate: '', + deptName: undefined, + reportUserName: undefined, + status: undefined, + deadlineTime: '16:00:00', pageSize: 9999, pageNum: 1 }, - deadlineDate: '', // 截止日期 - deadlineTime: '12:00:00', // 截止时间(原始值) + deadlineDate: '', + deadlineTime: '16:00:00', // 截止时间(原始值) // 时分秒选择器临时变量 timeSelect: { hour: 12, @@ -141,14 +190,14 @@ second: 0 }, list: [], + employeeSpicyMap: {}, // name -> isSpicyEater (1吃辣/0不吃辣) loading: false, - // 统计数据 - validDineIn: 0, - validTakeout: 0, - validTotal: 0, - invalidDineIn: 0, - invalidTakeout: 0, - invalidTotal: 0, + // 三维交叉统计矩阵(吃辣×打包×有效) + matrix: { + spicy: { validDine: 0, validTake: 0, validTotal: 0, invalidDine: 0, invalidTake: 0, invalidTotal: 0, dine: 0, take: 0, total: 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 } + }, range: [] } }, @@ -157,7 +206,11 @@ formattedDeadlineTime() { const [hour, minute, second] = this.deadlineTime.split(':'); return `${hour.padStart(2, '0')}:${minute.padStart(2, '0')}:${second.padStart(2, '0')}`; - } + }, + // 从 matrix 对象中提取快捷访问属性(保持模板简洁) + ms() { return this.matrix.spicy; }, + mn() { return this.matrix.nonSpicy; }, + ma() { return this.matrix.all; } }, onLoad() { // 初始化今日日期 @@ -166,6 +219,8 @@ this.deadlineDate = this.queryParams.reportDate; // 获取餐别字典数据 this.getRangeData(); + // 加载员工信息(含吃辣偏好) + this.getEmployeeList(); // 加载报餐数据 this.getList(); this.getDeadlineConfig(); @@ -182,7 +237,9 @@ getDeadlineConfig() { getConfigKey('hrm.meal.deadline').then(response => { - this.queryParams.deadlineTime = response.msg || '16:00:00' + const time = response.msg || '16:00:00'; + this.queryParams.deadlineTime = time; + this.deadlineTime = time; }) }, @@ -196,6 +253,94 @@ }); }, + /** 构建员工吃辣偏好映射(name -> isSpicyEater) */ + getEmployeeList() { + listEmployeeInfo({ pageSize: 9999, pageNum: 1 }).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; + if (this.list.length > 0) { + this.calcTableSum(); + } + }).catch(err => { + console.error('获取员工信息失败:', err); + }); + }, + + /** 从逗号分隔的姓名列表中统计不吃辣人数 */ + 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() { + const m = { + spicy: { validDine: 0, validTake: 0, validTotal: 0, invalidDine: 0, invalidTake: 0, invalidTotal: 0, dine: 0, take: 0, total: 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.list.forEach(item => { + const dine = item.dineInPeople ? Number(item.dineInPeople) : 0; + const take = item.takeoutPeople ? Number(item.takeoutPeople) : 0; + const total = item.totalPeople ? Number(item.totalPeople) : 0; + + // 从姓名列表统计不吃辣人数 + const nonSpicyDine = this.countNonSpicy(item.dineInPeopleList); + const nonSpicyTake = this.countNonSpicy(item.takeoutPeopleList); + const spicyDine = dine - nonSpicyDine; + const spicyTake = take - nonSpicyTake; + const nonSpicyTotal = nonSpicyDine + nonSpicyTake; + const spicyTotal = spicyDine + spicyTake; + + // 有效/无效 + const v = this.isValidMealReport(item.createTime) ? 'valid' : 'invalid'; + + // 吃辣 + 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; + console.log('【移动端矩阵结果】吃辣总计:', m.spicy.total, '不吃辣总计:', m.nonSpicy.total, '合计:', m.all.total); + console.log('【移动端矩阵明细】吃辣:', JSON.stringify(m.spicy), '不吃辣:', JSON.stringify(m.nonSpicy)); + }, + /** 查询部门报餐列表 */ getList() { this.loading = true; @@ -209,53 +354,23 @@ }); }, - /** 核心逻辑:区分有效/无效报餐统计 */ - calcTableSum() { - let validDine = 0, - validTake = 0, - validAll = 0; - let invalidDine = 0, - invalidTake = 0, - invalidAll = 0; - - this.list.forEach(item => { - // 处理空值,转为数字 - const dine = item.dineInPeople ? Number(item.dineInPeople) : 0; - const take = item.takeoutPeople ? Number(item.takeoutPeople) : 0; - const total = item.totalPeople ? Number(item.totalPeople) : 0; - - // 判断当前报餐是否有效 - if (this.isValidMealReport(item.createTime)) { - validDine += dine; - validTake += take; - validAll += total; - } else { - invalidDine += dine; - invalidTake += take; - invalidAll += total; - } - }); - - // 赋值到统计变量 - this.validDineIn = validDine; - this.validTakeout = validTake; - this.validTotal = validAll; - this.invalidDineIn = invalidDine; - this.invalidTakeout = invalidTake; - this.invalidTotal = invalidAll; + /** 判断报餐是否有效:仅比较时分秒(参考PC端逻辑) */ + isValidMealReport(createTime) { + if (!createTime || !this.queryParams.deadlineTime) return true; // 无时间默认有效 + + // 提取报餐时间的时分秒 + const reportTime = new Date(createTime); + const reportHms = this.addZero(reportTime.getHours()) + ':' + + this.addZero(reportTime.getMinutes()) + ':' + + this.addZero(reportTime.getSeconds()); + + // 比较时分秒字符串(格式HH:mm:ss,可直接字符串比较) + return reportHms <= this.queryParams.deadlineTime; }, - /** 判断报餐是否有效:创建时间在截止时间之前则有效 */ - isValidMealReport(createTime) { - if (!createTime) return false; - - // 拼接完整的截止时间字符串 - const deadlineDateTime = `${this.deadlineDate || this.queryParams.reportDate} ${this.deadlineTime}`; - // 比较时间 - const createTimeObj = new Date(createTime); - const deadlineTimeObj = new Date(deadlineDateTime); - - return createTimeObj <= deadlineTimeObj; + /** 数字补零 */ + addZero(num) { + return num < 10 ? '0' + num : num; }, /** 报餐日期选择确认 */ @@ -307,8 +422,9 @@ const hour = String(this.timeSelect.hour).padStart(2, '0'); const minute = String(this.timeSelect.minute).padStart(2, '0'); const second = String(this.timeSelect.second).padStart(2, '0'); - // 更新截止时间 + // 更新截止时间(同步到 queryParams 供有效性判断使用) this.deadlineTime = `${hour}:${minute}:${second}`; + this.queryParams.deadlineTime = `${hour}:${minute}:${second}`; // 重新计算统计数据 this.calcTableSum(); // 关闭弹窗 @@ -394,6 +510,14 @@ border-top: none; } + /* 交叉表网格:4列(标签 + 堂食 + 打包 + 小计) */ + .cross-grid { + display: grid; + grid-template-columns: 70px repeat(3, 1fr); + border: 1px solid #eee; + border-top: none; + } + /* 统计项样式 */ .stats-item { padding: 12px 8px; @@ -404,18 +528,54 @@ font-size: 14px; } - /* 去掉最后一列右边框 */ + /* 3列网格:去掉最后一列右边框 */ .stats-grid .stats-item:nth-child(3n) { border-right: none; } - /* 去掉最后一行下边框 */ + /* 3列网格:去掉最后一行下边框 */ .stats-grid .stats-item:last-child, .stats-grid .stats-item:nth-last-child(2), .stats-grid .stats-item:nth-last-child(3) { border-bottom: none; } + /* 4列交叉网格:去掉最后一列右边框 */ + .cross-grid .stats-item:nth-child(4n) { + border-right: none; + } + + /* 4列交叉网格:去掉最后一行下边框(每行4个,最后4个) */ + .cross-grid .stats-item:nth-last-child(-n+4) { + border-bottom: none; + } + + /* 交叉表行标签(吃辣/不吃辣/小计) */ + .cross-label { + display: flex; + align-items: center; + justify-content: center; + gap: 3px; + font-weight: 500; + color: #333; + font-size: 13px; + background-color: #fafafa; + } + + /* 交叉表头(堂食/打包/小计) */ + .cross-header { + font-weight: 600; + color: #555; + font-size: 12px; + background-color: #f5f7fa; + } + + /* 交叉表汇总行背景 */ + .cross-total { + background-color: #f9f9f9; + font-weight: 600; + } + /* 标签和值样式 */ .item-label { display: block; @@ -496,12 +656,6 @@ color: #999; } - .colon { - font-size: 20px; - color: #333; - margin: 0 5px; - } - /* 适配小屏手机 */ @media (max-width: 375px) { .stats-item { diff --git a/apps/hand-factory/utils/update.js b/apps/hand-factory/utils/update.js index eb9e0aa..d60f080 100644 --- a/apps/hand-factory/utils/update.js +++ b/apps/hand-factory/utils/update.js @@ -73,7 +73,7 @@ function checkStorageSpace() { function checkUpdate(forceCheck = false) { // 1. 准备本地版本信息 const localVersion = plus.runtime.version; // 基座版本 - const staticVersion = '1.3.34'; // 静态默认版本 + const staticVersion = '1.3.37'; // 静态默认版本 // const localWgtVersion = staticVersion; const localWgtVersion = uni.getStorageSync('wgtVersion') || staticVersion; // 本地wgt版本(从存储获取或用默认) const currentVersion = compareVersion(localWgtVersion, localVersion) > 0 diff --git a/apps/hand-factory/version.json b/apps/hand-factory/version.json index 5a14ab8..d5e2c86 100644 --- a/apps/hand-factory/version.json +++ b/apps/hand-factory/version.json @@ -1,5 +1,5 @@ { - "version": "klp 1.3.34", + "version": "klp 1.3.37", "wgtUrl": "http://49.232.154.205:10900/fadapp-update/klp/klp.wgt", "apkUrl": "http://49.232.154.205:10900/fadapp-update/klp/klp.apk" } \ No newline at end of file