|
|
@@ -9,6 +9,7 @@ use App\Model\Employee;
|
|
|
use App\Model\Fee;
|
|
|
use App\Model\Item;
|
|
|
use App\Model\ItemDetails;
|
|
|
+use App\Model\MonthlyPwOrder;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
use Maatwebsite\Excel\Facades\Excel;
|
|
|
@@ -22,6 +23,7 @@ class ImportService extends Service
|
|
|
'device', // 设备
|
|
|
'item', // 项目
|
|
|
'fee', // 费用
|
|
|
+ 'monthPwOrder', // 人员月度研发工时单
|
|
|
];
|
|
|
|
|
|
public function getTableTitleXls($data,$user){
|
|
|
@@ -30,6 +32,7 @@ class ImportService extends Service
|
|
|
|
|
|
//获取配置文件
|
|
|
$fuc = $data['type'];
|
|
|
+ if (! method_exists(self::class, $fuc)) return [false, "导入文件获取不存在,请联系开发"];
|
|
|
list($status,$return) = $this->$fuc($data,$user);
|
|
|
list($msg,$filename) = $return;
|
|
|
if(! $status) return [false, $msg];
|
|
|
@@ -85,6 +88,17 @@ class ImportService extends Service
|
|
|
return [true, [$config_array, $filename]];
|
|
|
}
|
|
|
|
|
|
+ private function monthPwOrder($data,$user){
|
|
|
+ $config = $this->getTableConfig($data['type']);
|
|
|
+ if(empty($config)) return [false, ['导入配置表头文件不存在','']];
|
|
|
+
|
|
|
+ $config_array = $config['array'] ?? [];
|
|
|
+ //生成下载文件
|
|
|
+ $filename = $config['name'] . "导入模板_" . time() . '.' . 'xlsx';
|
|
|
+
|
|
|
+ return [true, [$config_array, $filename]];
|
|
|
+ }
|
|
|
+
|
|
|
//导入入口
|
|
|
public function importAll($data,$user){
|
|
|
// //不超时
|
|
|
@@ -323,7 +337,7 @@ class ImportService extends Service
|
|
|
|
|
|
if (isset($detail_data_map[$key])) {
|
|
|
foreach ($detail_data_map[$key] as $d) {
|
|
|
- $all_detail_insert[] = array_merge($d, ['_code' => $main_tmp['code'], 'crt_time' => $time]);
|
|
|
+ $all_detail_insert[] = array_merge($d, ['_code' => $main_tmp['code'], 'crt_time' => $time, 'top_depart_id' => $main_tmp['top_depart_id']]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -731,6 +745,238 @@ class ImportService extends Service
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ // 人员月度工时单 ------------------------------
|
|
|
+ public function monthPwOrderImport($array, $user, $other_param)
|
|
|
+ {
|
|
|
+ $upload = $array[0];
|
|
|
+ list($status, $msg) = $this->compareTableAndReturn($upload, $other_param);
|
|
|
+ if (!$status) return [false, $msg];
|
|
|
+ $table_config = $msg;
|
|
|
+
|
|
|
+ unset($array[0]);
|
|
|
+ if (empty($array)) return [false, '导入数据不能为空'];
|
|
|
+
|
|
|
+ list($array, $error) = $this->checkCommon($array, $table_config);
|
|
|
+ if (!empty($error)) return [0, $error];
|
|
|
+
|
|
|
+ // 2. 详细校验 (这里会返回 update_map 和 dbEmps 映射)
|
|
|
+ list($error, $update_map, $dbEmps) = $this->monthPwOrderCheck($array, $user, $table_config);
|
|
|
+ if (!empty($error)) return [0, $error];
|
|
|
+
|
|
|
+ $keys = array_column($table_config, 'key');
|
|
|
+ $codeIdx = array_search('code', $keys);
|
|
|
+ $monthIdx = array_search('month', $keys);
|
|
|
+ $empIdx = array_search('employee_id', $keys);
|
|
|
+
|
|
|
+ // --- 步骤 1: 数据聚合分组 ---
|
|
|
+ // 将 Excel 数据按“单据”维度归类
|
|
|
+ $groups = [];
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
+ $cCode = trim($row[$codeIdx] ?? '');
|
|
|
+ $cMonthTs = $row[$monthIdx]; // 校验阶段已转为时间戳
|
|
|
+
|
|
|
+ // 聚合 Key:有编码用编码,没编码用月份标记
|
|
|
+ $aggKey = $cCode ?: "MONTH_" . $cMonthTs;
|
|
|
+
|
|
|
+ if (!isset($groups[$aggKey])) {
|
|
|
+ $groups[$aggKey] = [
|
|
|
+ 'main_id' => $update_map[$rowIndex] ?? 0, // 如果存在则是编辑
|
|
|
+ 'code' => $cCode,
|
|
|
+ 'month' => $cMonthTs,
|
|
|
+ 'details' => []
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 准备详情行数据
|
|
|
+ $detailTmp = [];
|
|
|
+ foreach ($table_config as $k => $conf) {
|
|
|
+ if (!$conf['is_main']) {
|
|
|
+ $fieldKey = $conf['key'];
|
|
|
+ $fieldVal = $row[$k];
|
|
|
+ // 如果是人员,转换为 ID
|
|
|
+ if ($fieldKey == 'employee_id') {
|
|
|
+ $fieldVal = $dbEmps[$fieldVal] ?? 0;
|
|
|
+ }
|
|
|
+ $detailTmp[$fieldKey] = $fieldVal;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $groups[$aggKey]['details'][] = $detailTmp;
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- 步骤 2: 开启事务写入 ---
|
|
|
+ DB::beginTransaction();
|
|
|
+ try {
|
|
|
+ $time = time();
|
|
|
+ foreach ($groups as $aggKey => $group) {
|
|
|
+ $mainId = $group['main_id'];
|
|
|
+
|
|
|
+ if ($mainId > 0) {
|
|
|
+ // 删除旧详情
|
|
|
+ DB::table('monthly_pw_order_details')->where('del_time',0)
|
|
|
+ ->where('main_id', $mainId)
|
|
|
+ ->update(['del_time' => $time]);
|
|
|
+ } else {
|
|
|
+ // B. 新增逻辑
|
|
|
+ $newCode = $this->generateBillNo([
|
|
|
+ 'top_depart_id' => $user['top_depart_id'],
|
|
|
+ 'type' => MonthlyPwOrder::Order_type,
|
|
|
+ 'period' => date("Ym", $group['month'])
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $mainId = DB::table('monthly_pw_order')->insertGetId([
|
|
|
+ 'code' => $newCode,
|
|
|
+ 'month' => $group['month'],
|
|
|
+ 'top_depart_id' => $user['top_depart_id'],
|
|
|
+ 'crt_id' => $user['id'],
|
|
|
+ 'crt_time' => $time,
|
|
|
+ 'upd_time' => $time,
|
|
|
+ 'del_time' => 0
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // C. 批量插入详情
|
|
|
+ $insertDetails = [];
|
|
|
+ foreach ($group['details'] as $detail) {
|
|
|
+ $detail['main_id'] = $mainId;
|
|
|
+ $detail['top_depart_id']= $user['top_depart_id'];
|
|
|
+ $detail['crt_time'] = $time;
|
|
|
+ $detail['del_time'] = 0;
|
|
|
+ $insertDetails[] = $detail;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($insertDetails)) {
|
|
|
+ DB::table('monthly_pw_order_details')->insert($insertDetails);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DB::commit();
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ DB::rollBack();
|
|
|
+ return [false, "失败:" . $e->getMessage() . " (行号:" . $e->getLine() . ")"];
|
|
|
+ }
|
|
|
+
|
|
|
+ return [true, ''];
|
|
|
+ }
|
|
|
+
|
|
|
+ private function monthPwOrderCheck(&$array, $user, $table_config)
|
|
|
+ {
|
|
|
+ $keys = array_column($table_config, 'key');
|
|
|
+ $codeIdx = array_search('code', $keys);
|
|
|
+ $monthIdx = array_search('month', $keys);
|
|
|
+ $empIdx = array_search('employee_id', $keys);
|
|
|
+ $startIdx = array_search('start_time', $keys);
|
|
|
+ $endIdx = array_search('end_time', $keys);
|
|
|
+
|
|
|
+ // 1. 预加载基础数据
|
|
|
+ $allEmpNumbers = array_filter(array_unique(array_column($array, $empIdx)));
|
|
|
+ $dbEmps = Employee::where('del_time', 0)
|
|
|
+ ->whereIn('number', $allEmpNumbers)
|
|
|
+ ->where('top_depart_id', $user['top_depart_id'])
|
|
|
+ ->pluck('id', 'number')->toArray();
|
|
|
+
|
|
|
+ $allCodes = array_filter(array_unique(array_column($array, $codeIdx)));
|
|
|
+ $dbOrders = DB::table('monthly_pw_order')
|
|
|
+ ->whereIn('code', $allCodes)
|
|
|
+ ->where('top_depart_id', $user['top_depart_id'])
|
|
|
+ ->get()->keyBy('code');
|
|
|
+
|
|
|
+ $existingMonths = DB::table('monthly_pw_order')
|
|
|
+ ->where('top_depart_id', $user['top_depart_id'])
|
|
|
+ ->pluck('month')
|
|
|
+ ->toArray();
|
|
|
+ $existingMonthsMap = array_fill_keys($existingMonths, true);
|
|
|
+
|
|
|
+ $excelAggregator = [];
|
|
|
+ $errors = [];
|
|
|
+ $update_map = [];
|
|
|
+
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
+ // 用户看到的行号(假设数据从第2行开始)
|
|
|
+ $displayLine = $rowIndex + 1;
|
|
|
+
|
|
|
+ $valCode = trim($row[$codeIdx] ?? '');
|
|
|
+ $valMonthRaw = trim($row[$monthIdx] ?? '');
|
|
|
+ $valEmp = trim($row[$empIdx] ?? '');
|
|
|
+ $valStartRaw = $row[$startIdx] ?? '';
|
|
|
+ $valEndRaw = $row[$endIdx] ?? '';
|
|
|
+
|
|
|
+ // --- A. 日期转换校验 ---
|
|
|
+ // 转换月份
|
|
|
+ list($mStatus, $valMonthTs) = $this->convertExcelCellToDate($valMonthRaw);
|
|
|
+ if (!$mStatus) {
|
|
|
+ $errors[] = "第{$displayLine}行:月份格式错误({$valMonthRaw})";
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 强制格式化为当月1号的时间戳,确保聚合逻辑一致
|
|
|
+ $valMonthTs = strtotime(date('Y-m-01', $valMonthTs));
|
|
|
+
|
|
|
+ // 转换开始日期
|
|
|
+ list($sStatus, $startTime) = $this->convertExcelCellToDate($valStartRaw);
|
|
|
+ if (!$sStatus) {
|
|
|
+ $errors[] = "第{$displayLine}行:开始日期格式错误";
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 转换结束日期
|
|
|
+ list($eStatus, $endTime) = $this->convertExcelCellToDate($valEndRaw);
|
|
|
+ if (!$eStatus) {
|
|
|
+ $errors[] = "第{$displayLine}行:结束日期格式错误";
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ $aggKey = $valCode ?: "NEW_ORDER_" . $valMonthTs;
|
|
|
+
|
|
|
+ // --- B. 校验单据与月份的一致性 ---
|
|
|
+ if ($valCode && isset($dbOrders[$valCode])) {
|
|
|
+ $dbOrder = $dbOrders[$valCode];
|
|
|
+ if ($dbOrder->month != $valMonthTs) {
|
|
|
+ $errors[] = "第{$displayLine}行:单据编码[{$valCode}]对应月份为[" . date('Y-m', $dbOrder->month) . "],与导入月份不符";
|
|
|
+ }
|
|
|
+ $update_map[$rowIndex] = $dbOrder->id;
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- C. 校验人员存在性与单据内唯一性 ---
|
|
|
+ if (!isset($dbEmps[$valEmp])) {
|
|
|
+ $errors[] = "第{$displayLine}行:人员工号[{$valEmp}]不存在";
|
|
|
+ } else {
|
|
|
+ if (isset($excelAggregator[$aggKey]['emps'][$valEmp])) {
|
|
|
+ $errors[] = "第{$displayLine}行:人员[{$valEmp}]在同一单据中重复";
|
|
|
+ }
|
|
|
+ $excelAggregator[$aggKey]['emps'][$valEmp] = true;
|
|
|
+
|
|
|
+ if (isset($excelAggregator[$aggKey]['month_ts']) && $excelAggregator[$aggKey]['month_ts'] !== $valMonthTs) {
|
|
|
+ $errors[] = "第{$displayLine}行:同组数据的月份不统一";
|
|
|
+ }
|
|
|
+ $excelAggregator[$aggKey]['month_ts'] = $valMonthTs;
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- D. 逻辑校验:日期范围 ---
|
|
|
+ if ($startTime > $endTime) {
|
|
|
+ $errors[] = "第{$displayLine}行:开始日期大于结束日期";
|
|
|
+ } else {
|
|
|
+ $monthEndTs = strtotime("+1 month", $valMonthTs) - 1;
|
|
|
+ if ($startTime < $valMonthTs || $endTime > $monthEndTs) {
|
|
|
+ $errors[] = "第{$displayLine}行:日期超出[ " . date('Y-m', $valMonthTs) . " ]范围";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- E. 月份唯一单据校验 (新增) ---
|
|
|
+ if (!$valCode) {
|
|
|
+ if (isset($existingMonthsMap[$valMonthTs])) {
|
|
|
+ $errors[] = "第{$displayLine}行:月份[ " . date('Y-m', $valMonthTs) . " ]已存在单据,请填编码编辑";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将转换后的时间戳写回原数组,方便后续写入数据库时直接使用
|
|
|
+ $array[$rowIndex][$monthIdx] = $valMonthTs;
|
|
|
+ $array[$rowIndex][$startIdx] = $startTime;
|
|
|
+ $array[$rowIndex][$endIdx] = $endTime;
|
|
|
+ }
|
|
|
+
|
|
|
+ $error_string = !empty($errors) ? implode('|', $errors) : "";
|
|
|
+ return [$error_string, $update_map, $dbEmps];
|
|
|
+ }
|
|
|
+
|
|
|
//公共校验 -----------------------------------------
|
|
|
private function checkCommon($array, $table_config) {
|
|
|
$error = [];
|