|
|
@@ -0,0 +1,860 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace app\api\controller;
|
|
|
+
|
|
|
+use app\common\controller\Api;
|
|
|
+use think\Db;
|
|
|
+use think\Exception;
|
|
|
+use think\Log;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 设备生产信息统计
|
|
|
+ */
|
|
|
+class ProductionInformationStatistics extends Api
|
|
|
+{
|
|
|
+ protected $noNeedLogin = ['*'];
|
|
|
+ protected $noNeedRight = ['*'];
|
|
|
+
|
|
|
+ /** @var string 主表 */
|
|
|
+ protected $tableName = '设备_生产信息统计表';
|
|
|
+
|
|
|
+ /** @var string 日志表 */
|
|
|
+ protected $logTableName = '设备_生产信息统计操作日志';
|
|
|
+
|
|
|
+ /** @var array 固定班组 */
|
|
|
+ protected $defaultShifts = ['A班', 'B班'];
|
|
|
+
|
|
|
+ /** @var string 设备基本资料表 */
|
|
|
+ protected $equipmentTable = '设备_基本资料';
|
|
|
+
|
|
|
+ /** @var array 可编辑业务字段 */
|
|
|
+ protected $dataFields = [
|
|
|
+ 'sczl_jtbh',
|
|
|
+ 'sczl_bzdh',
|
|
|
+ 'sczl_rq',
|
|
|
+ 'theoretical_speed',
|
|
|
+ 'scheduled_production',
|
|
|
+ 'scheduled_maintenance',
|
|
|
+ 'scheduled_handover',
|
|
|
+ 'fault',
|
|
|
+ 'changeover',
|
|
|
+ 'proofing',
|
|
|
+ 'abnormal',
|
|
|
+ 'planned_output',
|
|
|
+ 'actual_output',
|
|
|
+ 'defective_product',
|
|
|
+ ];
|
|
|
+
|
|
|
+ /** @var array 字段中文名 */
|
|
|
+ protected $fieldLabels = [
|
|
|
+ 'sczl_jtbh' => '设备编号',
|
|
|
+ 'sczl_bzdh' => '班组代号',
|
|
|
+ 'sczl_rq' => '日期',
|
|
|
+ 'theoretical_speed' => '理论速度',
|
|
|
+ 'scheduled_production' => '计划生产时间',
|
|
|
+ 'scheduled_maintenance'=> '计划保养时间',
|
|
|
+ 'scheduled_handover' => '计划早会交接班时间',
|
|
|
+ 'fault' => '设备故障时间',
|
|
|
+ 'changeover' => '换型时间',
|
|
|
+ 'proofing' => '打样时间',
|
|
|
+ 'abnormal' => '异常时间',
|
|
|
+ 'planned_output' => '计划完成产量',
|
|
|
+ 'actual_output' => '实际产量',
|
|
|
+ 'defective_product' => '不良品数量',
|
|
|
+ ];
|
|
|
+
|
|
|
+ /** @var array 按月汇总时求和的字段 */
|
|
|
+ protected $sumFields = [
|
|
|
+ 'scheduled_production',
|
|
|
+ 'scheduled_maintenance',
|
|
|
+ 'scheduled_handover',
|
|
|
+ 'fault',
|
|
|
+ 'changeover',
|
|
|
+ 'proofing',
|
|
|
+ 'abnormal',
|
|
|
+ 'planned_output',
|
|
|
+ 'actual_output',
|
|
|
+ 'defective_product',
|
|
|
+ ];
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 1. 左侧菜单:年 -> 月 -> 日
|
|
|
+ * @ApiMethod (GET)
|
|
|
+ */
|
|
|
+ public function getMenu()
|
|
|
+ {
|
|
|
+ if (!$this->request->isGet()) {
|
|
|
+ $this->error('请求错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $dateList = Db::name($this->tableName)
|
|
|
+ ->where('sczl_rq', 'not null')
|
|
|
+ ->field("DISTINCT DATE_FORMAT(sczl_rq, '%Y-%m-%d') AS rq")
|
|
|
+ ->order('rq DESC')
|
|
|
+ ->select();
|
|
|
+
|
|
|
+ $tree = [];
|
|
|
+ foreach ($dateList as $item) {
|
|
|
+ $rq = $item['rq'];
|
|
|
+ if (empty($rq)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $year = date('Y', strtotime($rq));
|
|
|
+ $month = date('Y-m', strtotime($rq));
|
|
|
+
|
|
|
+ if (!isset($tree[$year])) {
|
|
|
+ $tree[$year] = [
|
|
|
+ 'year' => $year,
|
|
|
+ 'children' => [],
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ if (!isset($tree[$year]['children'][$month])) {
|
|
|
+ $tree[$year]['children'][$month] = [
|
|
|
+ 'month' => $month,
|
|
|
+ 'children' => [],
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ if (!in_array($rq, $tree[$year]['children'][$month]['children'], true)) {
|
|
|
+ $tree[$year]['children'][$month]['children'][] = $rq;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $result = array_values($tree);
|
|
|
+ foreach ($result as &$yearItem) {
|
|
|
+ $yearItem['children'] = array_values($yearItem['children']);
|
|
|
+ }
|
|
|
+ unset($yearItem);
|
|
|
+
|
|
|
+ $this->success('成功', $result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 2. 表格数据查询(联表设备基本资料)
|
|
|
+ * @ApiMethod (GET)
|
|
|
+ * @param string date 时间参数:Y-m-d 查日明细,Y-m 查月汇总
|
|
|
+ */
|
|
|
+ public function getList()
|
|
|
+ {
|
|
|
+ if (!$this->request->isGet()) {
|
|
|
+ $this->error('请求错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $time = trim((string)$this->request->param('date', ''));
|
|
|
+ if ($time === '') {
|
|
|
+ $this->error('请传入 date 参数,格式 Y-m-d 或 Y-m');
|
|
|
+ }
|
|
|
+
|
|
|
+ $query = $this->parseQueryTime($time);
|
|
|
+ if ($query['type'] === 'day') {
|
|
|
+ $list = $this->queryDailyList($query['start'], $query['end']);
|
|
|
+ } else {
|
|
|
+ $list = $this->queryMonthlyList($query['start'], $query['end'], $query['month']);
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->success('成功', $list);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析查询时间:Y-m-d 为日,Y-m 为月
|
|
|
+ */
|
|
|
+ protected function parseQueryTime($time)
|
|
|
+ {
|
|
|
+ if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $time)) {
|
|
|
+ $timestamp = strtotime($time);
|
|
|
+ if ($timestamp === false || date('Y-m-d', $timestamp) !== $time) {
|
|
|
+ $this->error('日期格式错误,请传 Y-m-d,如 2026-07-23');
|
|
|
+ }
|
|
|
+ return [
|
|
|
+ 'type' => 'day',
|
|
|
+ 'start' => date('Y-m-d 00:00:00', $timestamp),
|
|
|
+ 'end' => date('Y-m-d 23:59:59', $timestamp),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (preg_match('/^\d{4}-\d{2}$/', $time)) {
|
|
|
+ $timestamp = strtotime($time . '-01');
|
|
|
+ if ($timestamp === false || date('Y-m', $timestamp) !== $time) {
|
|
|
+ $this->error('月份格式错误,请传 Y-m,如 2026-07');
|
|
|
+ }
|
|
|
+ return [
|
|
|
+ 'type' => 'month',
|
|
|
+ 'month' => $time,
|
|
|
+ 'start' => date('Y-m-01 00:00:00', $timestamp),
|
|
|
+ 'end' => date('Y-m-t 23:59:59', $timestamp),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->error('时间格式错误,请传 Y-m-d(具体日期)或 Y-m(月份)');
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 3. 获取车间、机组、机台编号、机台名称、班组基础数据
|
|
|
+ * @ApiMethod (GET)
|
|
|
+ */
|
|
|
+ public function getBaseData()
|
|
|
+ {
|
|
|
+ if (!$this->request->isGet()) {
|
|
|
+ $this->error('请求错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $equipments = Db::name($this->equipmentTable)
|
|
|
+ ->where('设备编组', '<>', '')
|
|
|
+ ->where('sys_sbID', '<>', '')
|
|
|
+ ->where('使用部门', '<>', '研发中心')
|
|
|
+ ->field([
|
|
|
+ 'rtrim(使用部门) as 车间',
|
|
|
+ 'rtrim(设备编组) as 机组',
|
|
|
+ 'rtrim(设备编号) as 机台编号',
|
|
|
+ 'rtrim(设备名称) as 机台名称',
|
|
|
+ ])
|
|
|
+ ->order('设备编组,设备编号')
|
|
|
+ ->select();
|
|
|
+
|
|
|
+ if (empty($equipments)) {
|
|
|
+ $this->success('未获取到机台数据', []);
|
|
|
+ }
|
|
|
+
|
|
|
+ $list = [];
|
|
|
+ foreach ($equipments as $item) {
|
|
|
+ $code = $this->trimText($item['机台编号']);
|
|
|
+ $list[] = [
|
|
|
+ '车间' => $this->trimText($item['车间']),
|
|
|
+ '机组' => $this->trimText($item['机组']),
|
|
|
+ '机台编号' => $code,
|
|
|
+ '机台名称' => $this->trimText($item['机台名称']),
|
|
|
+ '设备编号' => $code,
|
|
|
+ '班组列表' => $this->defaultShifts,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->success('成功', $this->sortEquipmentList($list));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 4. 批量新增(每个机台每个班组一条)
|
|
|
+ * @ApiMethod (POST)
|
|
|
+ * @param array list 数据列表
|
|
|
+ * @param string sys_id 操作人
|
|
|
+ */
|
|
|
+ public function batchAdd()
|
|
|
+ {
|
|
|
+ if (!$this->request->isPost()) {
|
|
|
+ $this->error('请求错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $params = $this->request->post();
|
|
|
+ $list = isset($params['list']) ? $params['list'] : [];
|
|
|
+ $operator = isset($params['sys_id']) ? trim($params['sys_id']) : '';
|
|
|
+
|
|
|
+ if (empty($list) || !is_array($list)) {
|
|
|
+ $this->error('参数 list 不能为空');
|
|
|
+ }
|
|
|
+ if ($operator === '') {
|
|
|
+ $this->error('参数 sys_id 不能为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ $insertRows = [];
|
|
|
+ $logs = [];
|
|
|
+
|
|
|
+ Db::startTrans();
|
|
|
+ try {
|
|
|
+ foreach ($list as $index => $row) {
|
|
|
+ if (!is_array($row)) {
|
|
|
+ throw new Exception('第 ' . ($index + 1) . ' 条数据格式错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $data = $this->normalizeRow($row);
|
|
|
+ $this->validateRow($data, $index + 1);
|
|
|
+
|
|
|
+ $exists = Db::name($this->tableName)
|
|
|
+ ->where('sczl_jtbh', $data['sczl_jtbh'])
|
|
|
+ ->where('sczl_bzdh', $data['sczl_bzdh'])
|
|
|
+ ->where('sczl_rq', $data['sczl_rq'])
|
|
|
+ ->find();
|
|
|
+ if ($exists) {
|
|
|
+ throw new Exception(sprintf(
|
|
|
+ '第 %d 条记录已存在:设备[%s] 班组[%s] 日期[%s]',
|
|
|
+ $index + 1,
|
|
|
+ $data['sczl_jtbh'],
|
|
|
+ $data['sczl_bzdh'],
|
|
|
+ date('Y-m-d', strtotime($data['sczl_rq']))
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ $data['sys_id'] = $operator;
|
|
|
+ $data['sys_rq'] = $now;
|
|
|
+ $insertRows[] = $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($insertRows as $data) {
|
|
|
+ $recordId = Db::name($this->tableName)->insertGetId($data);
|
|
|
+ if (!$recordId) {
|
|
|
+ throw new Exception('新增失败');
|
|
|
+ }
|
|
|
+ $logs = array_merge($logs, $this->buildAddLogs($recordId, $data, $operator, $now));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($logs)) {
|
|
|
+ Db::name($this->logTableName)->insertAll($logs);
|
|
|
+ }
|
|
|
+
|
|
|
+ Db::commit();
|
|
|
+ $this->success('批量新增成功', ['count' => count($insertRows)]);
|
|
|
+ } catch (Exception $e) {
|
|
|
+ Db::rollback();
|
|
|
+ $this->error($e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 5. 批量修改
|
|
|
+ * @ApiMethod (POST)
|
|
|
+ * @param array list 含 id 的数据列表
|
|
|
+ * @param string sys_id 操作人
|
|
|
+ */
|
|
|
+ public function batchUpdate()
|
|
|
+ {
|
|
|
+ if (!$this->request->isPost()) {
|
|
|
+ $this->error('请求错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $params = $this->request->post();
|
|
|
+ $list = isset($params['list']) ? $params['list'] : [];
|
|
|
+ $operator = isset($params['sys_id']) ? trim($params['sys_id']) : '';
|
|
|
+
|
|
|
+ if (empty($list) || !is_array($list)) {
|
|
|
+ $this->error('参数 list 不能为空');
|
|
|
+ }
|
|
|
+ if ($operator === '') {
|
|
|
+ $this->error('参数 sys_id 不能为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ $logs = [];
|
|
|
+ $updateCount = 0;
|
|
|
+
|
|
|
+ Db::startTrans();
|
|
|
+ try {
|
|
|
+ foreach ($list as $index => $row) {
|
|
|
+ if (!is_array($row) || empty($row['id'])) {
|
|
|
+ throw new Exception('第 ' . ($index + 1) . ' 条数据缺少 id');
|
|
|
+ }
|
|
|
+
|
|
|
+ $id = (int)$row['id'];
|
|
|
+ $old = Db::name($this->tableName)->where('id', $id)->find();
|
|
|
+ if (empty($old)) {
|
|
|
+ throw new Exception('第 ' . ($index + 1) . ' 条记录不存在');
|
|
|
+ }
|
|
|
+
|
|
|
+ $data = $this->normalizeRow($row, false);
|
|
|
+ unset($data['id']);
|
|
|
+
|
|
|
+ if (array_key_exists('sczl_bzdh', $row)) {
|
|
|
+ if ($data['sczl_bzdh'] === '' || !in_array($data['sczl_bzdh'], $this->defaultShifts, true)) {
|
|
|
+ throw new Exception('第 ' . ($index + 1) . ' 条班组代号只能为 A班 或 B班');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $checkJtbh = isset($data['sczl_jtbh']) ? $data['sczl_jtbh'] : rtrim($old['sczl_jtbh']);
|
|
|
+ $checkBzdh = isset($data['sczl_bzdh']) ? $data['sczl_bzdh'] : rtrim($old['sczl_bzdh']);
|
|
|
+ $checkRq = isset($data['sczl_rq']) ? $data['sczl_rq'] : $old['sczl_rq'];
|
|
|
+
|
|
|
+ $duplicate = Db::name($this->tableName)
|
|
|
+ ->where('sczl_jtbh', $checkJtbh)
|
|
|
+ ->where('sczl_bzdh', $checkBzdh)
|
|
|
+ ->where('sczl_rq', $checkRq)
|
|
|
+ ->where('id', '<>', $id)
|
|
|
+ ->find();
|
|
|
+ if ($duplicate) {
|
|
|
+ throw new Exception(sprintf(
|
|
|
+ '第 %d 条修改后与已有记录冲突:设备[%s] 班组[%s] 日期[%s]',
|
|
|
+ $index + 1,
|
|
|
+ $checkJtbh,
|
|
|
+ $checkBzdh,
|
|
|
+ date('Y-m-d', strtotime($checkRq))
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ $data['mod_id'] = $operator;
|
|
|
+ $data['mod_rq'] = $now;
|
|
|
+
|
|
|
+ $changed = [];
|
|
|
+ foreach ($data as $field => $value) {
|
|
|
+ if (!array_key_exists($field, $old)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $oldValue = $old[$field];
|
|
|
+ if ((string)$oldValue !== (string)$value) {
|
|
|
+ $changed[$field] = $value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (empty($changed)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $result = Db::name($this->tableName)->where('id', $id)->update($changed + [
|
|
|
+ 'mod_id' => $operator,
|
|
|
+ 'mod_rq' => $now,
|
|
|
+ ]);
|
|
|
+ if ($result === false) {
|
|
|
+ throw new Exception('第 ' . ($index + 1) . ' 条修改失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ $logs = array_merge($logs, $this->buildUpdateLogs($id, $old, $changed, $operator, $now));
|
|
|
+ $updateCount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($logs)) {
|
|
|
+ Db::name($this->logTableName)->insertAll($logs);
|
|
|
+ }
|
|
|
+
|
|
|
+ Db::commit();
|
|
|
+ $this->success('批量修改成功', ['count' => $updateCount]);
|
|
|
+ } catch (Exception $e) {
|
|
|
+ Db::rollback();
|
|
|
+ $this->error($e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 6. 批量删除
|
|
|
+ * @ApiMethod (POST)
|
|
|
+ * @param string ids 逗号分隔 id
|
|
|
+ * @param string sys_id 操作人
|
|
|
+ */
|
|
|
+ public function batchDelete()
|
|
|
+ {
|
|
|
+ if (!$this->request->isPost()) {
|
|
|
+ $this->error('请求错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $params = $this->request->post();
|
|
|
+ $idsParam = isset($params['ids']) ? trim($params['ids']) : '';
|
|
|
+ $operator = isset($params['sys_id']) ? trim($params['sys_id']) : '';
|
|
|
+
|
|
|
+ if ($idsParam === '') {
|
|
|
+ $this->error('参数 ids 不能为空');
|
|
|
+ }
|
|
|
+ if ($operator === '') {
|
|
|
+ $this->error('参数 sys_id 不能为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ $ids = array_values(array_filter(array_map('intval', explode(',', $idsParam))));
|
|
|
+ if (empty($ids)) {
|
|
|
+ $this->error('ids 格式错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $records = Db::name($this->tableName)->where('id', 'in', $ids)->select();
|
|
|
+ if (count($records) !== count($ids)) {
|
|
|
+ $this->error('部分记录不存在,请刷新后重试');
|
|
|
+ }
|
|
|
+
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ $logs = [];
|
|
|
+
|
|
|
+ Db::startTrans();
|
|
|
+ try {
|
|
|
+ foreach ($records as $record) {
|
|
|
+ $logs = array_merge($logs, $this->buildDeleteLogs((int)$record['id'], $record, $operator, $now));
|
|
|
+ }
|
|
|
+
|
|
|
+ $deleteResult = Db::name($this->tableName)->where('id', 'in', $ids)->delete();
|
|
|
+ if ($deleteResult === false) {
|
|
|
+ throw new Exception('删除失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($logs)) {
|
|
|
+ Db::name($this->logTableName)->insertAll($logs);
|
|
|
+ }
|
|
|
+
|
|
|
+ Db::commit();
|
|
|
+ $this->success('批量删除成功', ['count' => $deleteResult]);
|
|
|
+ } catch (Exception $e) {
|
|
|
+ Db::rollback();
|
|
|
+ $this->error($e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按日查询明细
|
|
|
+ */
|
|
|
+ protected function queryDailyList($start, $end)
|
|
|
+ {
|
|
|
+ $list = Db::name($this->tableName)
|
|
|
+ ->alias('a')
|
|
|
+ ->join($this->equipmentTable . ' b', 'a.sczl_jtbh = b.设备编号', 'LEFT')
|
|
|
+ ->where('a.sczl_rq', '>=', $start)
|
|
|
+ ->where('a.sczl_rq', '<=', $end)
|
|
|
+ ->field($this->buildSelectFields(false))
|
|
|
+ ->select();
|
|
|
+
|
|
|
+ return $this->formatList($list);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按月汇总查询
|
|
|
+ */
|
|
|
+ protected function queryMonthlyList($start, $end, $month)
|
|
|
+ {
|
|
|
+ $sumExpr = [];
|
|
|
+ foreach ($this->sumFields as $field) {
|
|
|
+ $sumExpr[] = "SUM(a.{$field}) as {$field}";
|
|
|
+ }
|
|
|
+
|
|
|
+ $list = Db::name($this->tableName)
|
|
|
+ ->alias('a')
|
|
|
+ ->join($this->equipmentTable . ' b', 'a.sczl_jtbh = b.设备编号', 'LEFT')
|
|
|
+ ->where('a.sczl_rq', '>=', $start)
|
|
|
+ ->where('a.sczl_rq', '<=', $end)
|
|
|
+ ->field(array_merge([
|
|
|
+ 'MIN(a.id) as id',
|
|
|
+ 'a.sczl_jtbh',
|
|
|
+ 'a.sczl_bzdh',
|
|
|
+ 'MAX(a.theoretical_speed) as theoretical_speed',
|
|
|
+ 'rtrim(b.使用部门) as 车间',
|
|
|
+ 'rtrim(b.设备编组) as 机组',
|
|
|
+ 'rtrim(b.设备名称) as 机台名称',
|
|
|
+ ], $sumExpr))
|
|
|
+ ->group('a.sczl_jtbh,a.sczl_bzdh,b.使用部门,b.设备编组,b.设备名称')
|
|
|
+ ->select();
|
|
|
+
|
|
|
+ foreach ($list as &$row) {
|
|
|
+ $row['sczl_rq'] = $month . '-01 00:00:00';
|
|
|
+ $row['query_type'] = 'month';
|
|
|
+ $row['query_month'] = $month;
|
|
|
+ }
|
|
|
+ unset($row);
|
|
|
+
|
|
|
+ return $this->formatList($list);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询字段
|
|
|
+ */
|
|
|
+ protected function buildSelectFields($isMonth = false)
|
|
|
+ {
|
|
|
+ $fields = [
|
|
|
+ 'a.id',
|
|
|
+ 'a.sczl_jtbh',
|
|
|
+ 'a.sczl_bzdh',
|
|
|
+ 'a.sczl_rq',
|
|
|
+ 'a.theoretical_speed',
|
|
|
+ 'a.scheduled_production',
|
|
|
+ 'a.scheduled_maintenance',
|
|
|
+ 'a.scheduled_handover',
|
|
|
+ 'a.fault',
|
|
|
+ 'a.changeover',
|
|
|
+ 'a.proofing',
|
|
|
+ 'a.abnormal',
|
|
|
+ 'a.planned_output',
|
|
|
+ 'a.actual_output',
|
|
|
+ 'a.defective_product',
|
|
|
+ 'a.sys_id',
|
|
|
+ 'a.sys_rq',
|
|
|
+ 'a.mod_id',
|
|
|
+ 'a.mod_rq',
|
|
|
+ 'rtrim(b.使用部门) as 车间',
|
|
|
+ 'rtrim(b.设备编组) as 机组',
|
|
|
+ 'rtrim(b.设备名称) as 机台名称',
|
|
|
+ ];
|
|
|
+
|
|
|
+ return $fields;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 格式化返回列表
|
|
|
+ */
|
|
|
+ protected function formatList($list)
|
|
|
+ {
|
|
|
+ $result = [];
|
|
|
+ foreach ($list as $row) {
|
|
|
+ $result[] = [
|
|
|
+ 'id' => (int)$row['id'],
|
|
|
+ '车间' => isset($row['车间']) ? rtrim($row['车间']) : '',
|
|
|
+ '机组' => isset($row['机组']) ? rtrim($row['机组']) : '',
|
|
|
+ '机台编号' => rtrim($row['sczl_jtbh']),
|
|
|
+ '设备编号' => rtrim($row['sczl_jtbh']),
|
|
|
+ '机台名称' => isset($row['机台名称']) ? rtrim($row['机台名称']) : '',
|
|
|
+ '班组' => $this->normalizeShift($row['sczl_bzdh']),
|
|
|
+ 'sczl_jtbh' => rtrim($row['sczl_jtbh']),
|
|
|
+ 'sczl_bzdh' => $this->normalizeShift($row['sczl_bzdh']),
|
|
|
+ 'sczl_rq' => $row['sczl_rq'],
|
|
|
+ 'theoretical_speed' => $this->formatNumber($row['theoretical_speed']),
|
|
|
+ 'scheduled_production' => $this->formatNumber($row['scheduled_production']),
|
|
|
+ 'scheduled_maintenance'=> $this->formatNumber($row['scheduled_maintenance']),
|
|
|
+ 'scheduled_handover' => $this->formatNumber($row['scheduled_handover']),
|
|
|
+ 'fault' => $this->formatNumber($row['fault']),
|
|
|
+ 'changeover' => $this->formatNumber($row['changeover']),
|
|
|
+ 'proofing' => $this->formatNumber($row['proofing']),
|
|
|
+ 'abnormal' => $this->formatNumber($row['abnormal']),
|
|
|
+ 'planned_output' => $this->formatNumber($row['planned_output']),
|
|
|
+ 'actual_output' => $this->formatNumber($row['actual_output']),
|
|
|
+ 'defective_product' => $this->formatNumber($row['defective_product']),
|
|
|
+ 'sys_id' => isset($row['sys_id']) ? rtrim($row['sys_id']) : '',
|
|
|
+ 'sys_rq' => isset($row['sys_rq']) ? $row['sys_rq'] : '',
|
|
|
+ 'mod_id' => isset($row['mod_id']) ? rtrim($row['mod_id']) : '',
|
|
|
+ 'mod_rq' => isset($row['mod_rq']) ? $row['mod_rq'] : '',
|
|
|
+ 'query_type' => isset($row['query_type']) ? $row['query_type'] : 'day',
|
|
|
+ 'query_month' => isset($row['query_month']) ? $row['query_month'] : '',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return $this->sortEquipmentList($result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按设备编组、机台编号数字排序
|
|
|
+ */
|
|
|
+ protected function sortEquipmentList(array $list)
|
|
|
+ {
|
|
|
+ usort($list, function ($a, $b) {
|
|
|
+ return $this->compareEquipmentRow($a, $b);
|
|
|
+ });
|
|
|
+ return $list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设备行排序比较
|
|
|
+ */
|
|
|
+ protected function compareEquipmentRow($a, $b)
|
|
|
+ {
|
|
|
+ $groupA = $this->trimText(isset($a['机组']) ? $a['机组'] : '');
|
|
|
+ $groupB = $this->trimText(isset($b['机组']) ? $b['机组'] : '');
|
|
|
+
|
|
|
+ $groupOrderA = $this->extractGroupOrder($groupA);
|
|
|
+ $groupOrderB = $this->extractGroupOrder($groupB);
|
|
|
+ if ($groupOrderA !== $groupOrderB) {
|
|
|
+ return $groupOrderA <=> $groupOrderB;
|
|
|
+ }
|
|
|
+ if ($groupA !== $groupB) {
|
|
|
+ return strcmp($groupA, $groupB);
|
|
|
+ }
|
|
|
+
|
|
|
+ $codeA = $this->getMachineCodeFromRow($a);
|
|
|
+ $codeB = $this->getMachineCodeFromRow($b);
|
|
|
+ $numA = $this->extractMachineNumber($codeA);
|
|
|
+ $numB = $this->extractMachineNumber($codeB);
|
|
|
+ if ($numA !== $numB) {
|
|
|
+ return $numA <=> $numB;
|
|
|
+ }
|
|
|
+ if ($codeA !== $codeB) {
|
|
|
+ return strcmp($codeA, $codeB);
|
|
|
+ }
|
|
|
+
|
|
|
+ $shiftA = isset($a['班组']) ? $a['班组'] : (isset($a['sczl_bzdh']) ? $a['sczl_bzdh'] : '');
|
|
|
+ $shiftB = isset($b['班组']) ? $b['班组'] : (isset($b['sczl_bzdh']) ? $b['sczl_bzdh'] : '');
|
|
|
+ return strcmp($shiftA, $shiftB);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 提取设备编组前缀序号(如 03、卷凹机组 -> 3)
|
|
|
+ */
|
|
|
+ protected function extractGroupOrder($group)
|
|
|
+ {
|
|
|
+ $group = $this->trimText($group);
|
|
|
+ if (preg_match('/^(\d+)/', $group, $matches)) {
|
|
|
+ return (int)$matches[1];
|
|
|
+ }
|
|
|
+ return PHP_INT_MAX;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 提取机台编号中的数字(如 YWY01# -> 1)
|
|
|
+ */
|
|
|
+ protected function extractMachineNumber($code)
|
|
|
+ {
|
|
|
+ $code = $this->trimText($code);
|
|
|
+ if (preg_match('/(\d+)/', $code, $matches)) {
|
|
|
+ return (int)$matches[1];
|
|
|
+ }
|
|
|
+ return PHP_INT_MAX;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从返回行中获取机台编号
|
|
|
+ */
|
|
|
+ protected function getMachineCodeFromRow($row)
|
|
|
+ {
|
|
|
+ if (!empty($row['机台编号'])) {
|
|
|
+ return $this->trimText($row['机台编号']);
|
|
|
+ }
|
|
|
+ if (!empty($row['sczl_jtbh'])) {
|
|
|
+ return $this->trimText($row['sczl_jtbh']);
|
|
|
+ }
|
|
|
+ if (!empty($row['设备编号'])) {
|
|
|
+ return $this->trimText($row['设备编号']);
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 去除字符串首尾空白(含全角空格)
|
|
|
+ */
|
|
|
+ protected function trimText($value)
|
|
|
+ {
|
|
|
+ return preg_replace('/^[\s\x{3000}]+|[\s\x{3000}]+$/u', '', (string)$value);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 班组名称规范化:仅支持 A班、B班
|
|
|
+ */
|
|
|
+ protected function normalizeShift($shift)
|
|
|
+ {
|
|
|
+ $shift = $this->trimText($shift);
|
|
|
+ $shift = preg_replace('/\s+/u', '', $shift);
|
|
|
+ if ($shift === '') {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ if (preg_match('/^A(?:班)?$/iu', $shift)) {
|
|
|
+ return 'A班';
|
|
|
+ }
|
|
|
+ if (preg_match('/^B(?:班)?$/iu', $shift)) {
|
|
|
+ return 'B班';
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 标准化单行数据
|
|
|
+ */
|
|
|
+ protected function normalizeRow(array $row, $requireAll = true)
|
|
|
+ {
|
|
|
+ $data = [];
|
|
|
+ foreach ($this->dataFields as $field) {
|
|
|
+ if (!array_key_exists($field, $row)) {
|
|
|
+ if (!$requireAll) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $data[$field] = in_array($field, $this->sumFields, true) || $field === 'theoretical_speed' ? 0 : '';
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($field === 'sczl_rq') {
|
|
|
+ $data[$field] = date('Y-m-d 00:00:00', strtotime($row[$field]));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (in_array($field, ['sczl_jtbh', 'sczl_bzdh'], true)) {
|
|
|
+ $value = trim((string)$row[$field]);
|
|
|
+ $data[$field] = $field === 'sczl_bzdh' ? $this->normalizeShift($value) : $value;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($field === 'theoretical_speed') {
|
|
|
+ $data[$field] = (int)$row[$field];
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $data[$field] = $row[$field] === '' || $row[$field] === null ? 0 : $row[$field];
|
|
|
+ }
|
|
|
+
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验单行数据
|
|
|
+ */
|
|
|
+ protected function validateRow(array $data, $lineNo)
|
|
|
+ {
|
|
|
+ if ($data['sczl_jtbh'] === '') {
|
|
|
+ throw new Exception('第 ' . $lineNo . ' 条设备编号不能为空');
|
|
|
+ }
|
|
|
+ if ($data['sczl_bzdh'] === '') {
|
|
|
+ throw new Exception('第 ' . $lineNo . ' 条班组代号不能为空,且只能为 A班 或 B班');
|
|
|
+ }
|
|
|
+ if (!in_array($data['sczl_bzdh'], $this->defaultShifts, true)) {
|
|
|
+ throw new Exception('第 ' . $lineNo . ' 条班组代号只能为 A班 或 B班');
|
|
|
+ }
|
|
|
+ if (empty($data['sczl_rq'])) {
|
|
|
+ throw new Exception('第 ' . $lineNo . ' 条日期不能为空');
|
|
|
+ }
|
|
|
+
|
|
|
+ $equipment = Db::name($this->equipmentTable)
|
|
|
+ ->where('设备编号', $data['sczl_jtbh'])
|
|
|
+ ->find();
|
|
|
+ if (empty($equipment)) {
|
|
|
+ throw new Exception('第 ' . $lineNo . ' 条设备编号不存在:' . $data['sczl_jtbh']);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建新增日志
|
|
|
+ */
|
|
|
+ protected function buildAddLogs($recordId, array $data, $operator, $time)
|
|
|
+ {
|
|
|
+ $logs = [];
|
|
|
+ foreach ($this->dataFields as $field) {
|
|
|
+ if (!array_key_exists($field, $data)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $logs[] = [
|
|
|
+ 'record_id' => $recordId,
|
|
|
+ 'operation_type' => 'add',
|
|
|
+ 'field_name' => isset($this->fieldLabels[$field]) ? $this->fieldLabels[$field] : $field,
|
|
|
+ 'old_value' => null,
|
|
|
+ 'new_value' => (string)$data[$field],
|
|
|
+ 'operator_id' => $operator,
|
|
|
+ 'operation_time' => $time,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return $logs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建修改日志
|
|
|
+ */
|
|
|
+ protected function buildUpdateLogs($recordId, array $old, array $changed, $operator, $time)
|
|
|
+ {
|
|
|
+ $logs = [];
|
|
|
+ foreach ($changed as $field => $newValue) {
|
|
|
+ if ($field === 'mod_id' || $field === 'mod_rq') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $logs[] = [
|
|
|
+ 'record_id' => $recordId,
|
|
|
+ 'operation_type' => 'update',
|
|
|
+ 'field_name' => isset($this->fieldLabels[$field]) ? $this->fieldLabels[$field] : $field,
|
|
|
+ 'old_value' => isset($old[$field]) ? (string)$old[$field] : '',
|
|
|
+ 'new_value' => (string)$newValue,
|
|
|
+ 'operator_id' => $operator,
|
|
|
+ 'operation_time' => $time,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return $logs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建删除日志
|
|
|
+ */
|
|
|
+ protected function buildDeleteLogs($recordId, array $record, $operator, $time)
|
|
|
+ {
|
|
|
+ $logs = [];
|
|
|
+ foreach ($this->dataFields as $field) {
|
|
|
+ if (!array_key_exists($field, $record)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $logs[] = [
|
|
|
+ 'record_id' => $recordId,
|
|
|
+ 'operation_type' => 'delete',
|
|
|
+ 'field_name' => isset($this->fieldLabels[$field]) ? $this->fieldLabels[$field] : $field,
|
|
|
+ 'old_value' => (string)$record[$field],
|
|
|
+ 'new_value' => null,
|
|
|
+ 'operator_id' => $operator,
|
|
|
+ 'operation_time' => $time,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return $logs;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 数值格式化
|
|
|
+ */
|
|
|
+ protected function formatNumber($value)
|
|
|
+ {
|
|
|
+ if ($value === null || $value === '') {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return is_numeric($value) ? (float)$value : $value;
|
|
|
+ }
|
|
|
+}
|