|
|
@@ -16,6 +16,7 @@ use App\Model\ItemDetails;
|
|
|
use App\Model\MonthlyDdOrder;
|
|
|
use App\Model\MonthlyPsOrder;
|
|
|
use App\Model\MonthlyPwOrder;
|
|
|
+use App\Model\PLeaveOverOrder;
|
|
|
use App\Model\RuleSet;
|
|
|
use App\Model\RuleSetDetails;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
@@ -39,6 +40,8 @@ class ImportService extends Service
|
|
|
'ruleSet', // 规则配置单
|
|
|
'dailyPwOrder', // 人员日工时单
|
|
|
'dailyDwOrder', // 设备日工时单
|
|
|
+ 'leaveOrder', // 请假单
|
|
|
+ 'overtimeOrder', // 加班单
|
|
|
];
|
|
|
|
|
|
public function getTableTitleXls($data,$user){
|
|
|
@@ -380,77 +383,6 @@ class ImportService extends Service
|
|
|
return [$error_str, $update_mapping, $detail_storage];
|
|
|
}
|
|
|
|
|
|
- private function employeeCheck111(&$array, $user, $table_config)
|
|
|
- {
|
|
|
- $keys = array_column($table_config, 'key');
|
|
|
- $codeIdx = array_search('number', $keys);
|
|
|
- $sexIdx = array_search('sex', $keys);
|
|
|
- $eductionIdx = array_search('education', $keys);
|
|
|
- $stateIdx = array_search('state', $keys);
|
|
|
- $depIdx = array_search('depart_code', $keys);
|
|
|
-
|
|
|
- $code_map = $this->getEmployeeList($array, $user, $codeIdx);
|
|
|
- $dep_map = $this->getEDataList($array, $user, $depIdx);
|
|
|
-
|
|
|
- $errors = [];
|
|
|
- $update_mapping = [];
|
|
|
- $detail_storage = [];
|
|
|
- $sex_map = array_flip(Employee::SEX_TYPE);
|
|
|
- $e_map = array_flip(Employee::Education);
|
|
|
- $state_map = array_flip(Employee::State_Type);
|
|
|
-
|
|
|
- foreach ($array as $rowIndex => $rowValue) {
|
|
|
- $displayLine = $rowIndex + 1;
|
|
|
-
|
|
|
- $valCode = $rowValue[$codeIdx] ?? '';
|
|
|
-
|
|
|
- // 1. 判定更新还是新增
|
|
|
- if (isset($code_map[$valCode])) {
|
|
|
- $update_mapping[$rowIndex] = $code_map[$valCode];
|
|
|
- }
|
|
|
-
|
|
|
- // 2. 校验
|
|
|
- $sex_text = $rowValue[$sexIdx] ?? '';
|
|
|
- if(! empty($sex_text)){
|
|
|
- if (!isset($sex_map[$sex_text])) {
|
|
|
- $errors[] = "第{$displayLine}行:性别[{$sex_text}]无效";
|
|
|
- } else {
|
|
|
- $array[$rowIndex][$sexIdx] = $sex_map[$sex_text];
|
|
|
- }
|
|
|
- }
|
|
|
- $e_text = $rowValue[$eductionIdx] ?? '';
|
|
|
- if(! empty($e_text)){
|
|
|
- if (!isset($e_map[$e_text])) {
|
|
|
- $errors[] = "第{$displayLine}行:性别[{$e_text}]无效";
|
|
|
- } else {
|
|
|
- $array[$rowIndex][$eductionIdx] = $e_map[$e_text];
|
|
|
- }
|
|
|
- }
|
|
|
- $state_text = $rowValue[$stateIdx] ?? '';
|
|
|
- if (!isset($state_map[$state_text])) {
|
|
|
- $errors[] = "第{$displayLine}行:状态[{$state_text}]无效";
|
|
|
- } else {
|
|
|
- $array[$rowIndex][$stateIdx] = $state_map[$state_text];
|
|
|
- }
|
|
|
-
|
|
|
- // 4. 解析部门 (分行模式:一行一个部门)
|
|
|
- if ($depIdx !== false && !empty($rowValue[$depIdx])) {
|
|
|
- $mNum = trim($rowValue[$depIdx]);
|
|
|
- if (!isset($dep_map[$mNum])) {
|
|
|
- $errors[] = "第{$displayLine}行:部门编码[{$mNum}]不存在";
|
|
|
- } else {
|
|
|
- // 依然按行索引存,方便 Import 方法对应
|
|
|
- $detail_storage[$rowIndex][] = [
|
|
|
- 'depart_id' => $dep_map[$mNum],
|
|
|
- ];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- $error_str = !empty($errors) ? implode('|', $errors) : "";
|
|
|
- return [$error_str, $update_mapping, $detail_storage];
|
|
|
- }
|
|
|
-
|
|
|
private function getEDataList($array, $user, $index1)
|
|
|
{
|
|
|
$depNums = [];
|
|
|
@@ -840,234 +772,6 @@ class ImportService extends Service
|
|
|
}
|
|
|
|
|
|
// 项目 -----------------------------------
|
|
|
- public function itemImport1($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, '导入数据不能为空'];
|
|
|
-
|
|
|
- // 1. 公共校验 (必填、唯一性等)
|
|
|
- list($array, $error) = $this->checkCommon($array, $table_config);
|
|
|
- if (!empty($error)) return [0, $error];
|
|
|
-
|
|
|
- // 2. 业务详细校验 (获取更新映射及明细数据)
|
|
|
- list($error, $update_map, $detail_data_map) = $this->itemCheck($array, $user, $table_config);
|
|
|
- if (!empty($error)) return [0, $error];
|
|
|
-
|
|
|
- $time = time();
|
|
|
- $insert_data = [];
|
|
|
- $update_data = [];
|
|
|
- $all_detail_insert = [];
|
|
|
- $update_main_ids = [];
|
|
|
-
|
|
|
- // 3. 数据分拣
|
|
|
- foreach ($array as $key => $value) {
|
|
|
- $main_tmp = [];
|
|
|
- foreach ($value as $k => $val) {
|
|
|
- if (!empty($table_config[$k]['is_main'])) {
|
|
|
- $main_tmp[$table_config[$k]['key']] = $val;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (isset($update_map[$key])) {
|
|
|
- // 更新逻辑
|
|
|
- $itemId = $update_map[$key];
|
|
|
- $update_data[] = array_merge($main_tmp, ['id' => $itemId]);
|
|
|
- $update_main_ids[] = $itemId;
|
|
|
-
|
|
|
- // 收集明细 (后续统一插入)
|
|
|
- if (isset($detail_data_map[$key])) {
|
|
|
- foreach ($detail_data_map[$key] as $d) {
|
|
|
- $all_detail_insert[] = array_merge($d, ['item_id' => $itemId, 'crt_time' => $time, 'top_depart_id' => $user['top_depart_id']]);
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 新增逻辑
|
|
|
- $main_tmp['top_depart_id'] = $user['top_depart_id'];
|
|
|
- $main_tmp['crt_id'] = $user['id'];
|
|
|
- $main_tmp['crt_time'] = $time;
|
|
|
- // 以 code 为键,方便后续回填 ID
|
|
|
- $insert_data[$main_tmp['code']] = $main_tmp;
|
|
|
-
|
|
|
- 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, 'top_depart_id' => $main_tmp['top_depart_id']]);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- DB::beginTransaction();
|
|
|
- try {
|
|
|
- // 4. 执行新增主表
|
|
|
- if (!empty($insert_data)) {
|
|
|
- foreach (array_chunk($insert_data, 500) as $chunk) {
|
|
|
- Item::insert($chunk);
|
|
|
- }
|
|
|
- // 获取新插入数据的 ID 映射
|
|
|
- $new_item_maps = Item::whereIn('code', array_keys($insert_data))
|
|
|
- ->where('del_time', 0)
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
- ->pluck('id', 'code')->toArray();
|
|
|
- }
|
|
|
-
|
|
|
- // 5. 执行更新主表 (分批更新)
|
|
|
- if (!empty($update_data)) {
|
|
|
- foreach (array_chunk($update_data, 100) as $chunk) {
|
|
|
- foreach ($chunk as $uItem) {
|
|
|
- $id = $uItem['id'];
|
|
|
- unset($uItem['id']);
|
|
|
- Item::where('id', $id)->update($uItem);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 6. 处理明细表 (先删后插策略)
|
|
|
- // 删除旧明细 (逻辑删除)
|
|
|
- if (!empty($update_main_ids)) {
|
|
|
- ItemDetails::whereIn('item_id', $update_main_ids)
|
|
|
- ->where('del_time', 0)
|
|
|
- ->update(['del_time' => $time]);
|
|
|
- }
|
|
|
-
|
|
|
- // 回填新增主表的 ID 到明细数组
|
|
|
- foreach ($all_detail_insert as &$di) {
|
|
|
- if (isset($di['_code'])) {
|
|
|
- $di['item_id'] = $new_item_maps[$di['_code']] ?? 0;
|
|
|
- unset($di['_code']);
|
|
|
- }
|
|
|
- }
|
|
|
- unset($di);
|
|
|
-
|
|
|
- // 批量插入所有明细
|
|
|
- if (!empty($all_detail_insert)) {
|
|
|
- foreach (array_chunk($all_detail_insert, 500) as $chunk) {
|
|
|
- ItemDetails::insert($chunk);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- DB::commit();
|
|
|
- } catch (\Exception $e) {
|
|
|
- DB::rollBack();
|
|
|
- return [false, "失败:" . $e->getMessage() . " (行号:" . $e->getLine() . ")"];
|
|
|
- }
|
|
|
-
|
|
|
- return [true, ''];
|
|
|
- }
|
|
|
-
|
|
|
- private function itemCheck1(&$array, $user, $table_config)
|
|
|
- {
|
|
|
- $keys = array_column($table_config, 'key');
|
|
|
- $codeIdx = array_search('code', $keys);
|
|
|
- $stateIdx = array_search('state', $keys);
|
|
|
- $manIdx = array_search('man_list', $keys);
|
|
|
- $deviceIdx = array_search('device_list', $keys);
|
|
|
- // 日期索引
|
|
|
- $dateIdx = array_search('start_time', $keys);
|
|
|
- $date2Idx = array_search('end_time', $keys);
|
|
|
-
|
|
|
- $code_map = $this->getItemList($array, $user, $codeIdx);
|
|
|
- list($man_map, $device_map) = $this->getDataList($array, $user, $manIdx, $deviceIdx);
|
|
|
-
|
|
|
- $errors = [];
|
|
|
- $update_mapping = [];
|
|
|
- $detail_storage = [];
|
|
|
- $state_type_map = array_flip(Item::State_Type);
|
|
|
-
|
|
|
- foreach ($array as $rowIndex => $rowValue) {
|
|
|
- $displayLine = $rowIndex + 1;
|
|
|
-
|
|
|
- $valCode = $rowValue[$codeIdx] ?? '';
|
|
|
-
|
|
|
- // 1. 判定更新还是新增
|
|
|
- if (isset($code_map[$valCode])) {
|
|
|
- $update_mapping[$rowIndex] = $code_map[$valCode];
|
|
|
- }
|
|
|
-
|
|
|
- // 2. 状态校验
|
|
|
- $state_text = $rowValue[$stateIdx] ?? '';
|
|
|
- if (!isset($state_type_map[$state_text])) {
|
|
|
- $errors[] = "第{$displayLine}行:状态[{$state_text}]无效";
|
|
|
- } else {
|
|
|
- $array[$rowIndex][$stateIdx] = $state_type_map[$state_text];
|
|
|
- }
|
|
|
-
|
|
|
- // 3. 日期转换
|
|
|
- foreach ([$dateIdx, $date2Idx] as $dIdx) {
|
|
|
- if ($dIdx !== false && !empty($rowValue[$dIdx])) {
|
|
|
- list($s, $m) = $this->convertExcelCellToDate($rowValue[$dIdx]);
|
|
|
- if (!$s) $errors[] = "第{$displayLine}行:日期格式非法";
|
|
|
- else $array[$rowIndex][$dIdx] = $m;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 4. 解析人员 (明细类型1)
|
|
|
- if ($manIdx !== false && !empty($rowValue[$manIdx])) {
|
|
|
- foreach (explode(',', $rowValue[$manIdx]) as $mNum) {
|
|
|
- $mNum = trim($mNum);
|
|
|
- if (!isset($man_map[$mNum])) {
|
|
|
- $errors[] = "第{$displayLine}行:人员工号[{$mNum}]不存在";
|
|
|
- } else {
|
|
|
- $detail_storage[$rowIndex][] = [
|
|
|
- 'type' => ItemDetails::type_one,
|
|
|
- 'data_id' => $man_map[$mNum],
|
|
|
- ];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 5. 解析设备 (明细类型2)
|
|
|
- if ($deviceIdx !== false && !empty($rowValue[$deviceIdx])) {
|
|
|
- foreach (explode(',', $rowValue[$deviceIdx]) as $dCode) {
|
|
|
- $dCode = trim($dCode);
|
|
|
- if (!isset($device_map[$dCode])) {
|
|
|
- $errors[] = "第{$displayLine}行:设备的资产编码[{$dCode}]不存在";
|
|
|
- } else {
|
|
|
- $detail_storage[$rowIndex][] = [
|
|
|
- 'type' => ItemDetails::type_two,
|
|
|
- 'data_id' => $device_map[$dCode],
|
|
|
- ];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- $error_str = !empty($errors) ? implode('|', $errors) : "";
|
|
|
- return [$error_str, $update_mapping, $detail_storage];
|
|
|
- }
|
|
|
-
|
|
|
- private function getDataList($array, $user, $index1, $index2)
|
|
|
- {
|
|
|
- $manNums = [];
|
|
|
- $devCodes = [];
|
|
|
-
|
|
|
- // 去重收集
|
|
|
- foreach ($array as $row) {
|
|
|
- if (!empty($row[$index1])) {
|
|
|
- foreach (explode(',', $row[$index1]) as $v) $manNums[trim($v)] = true;
|
|
|
- }
|
|
|
- if (!empty($row[$index2])) {
|
|
|
- foreach (explode(',', $row[$index2]) as $v) $devCodes[trim($v)] = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- $manMap = Employee::where('del_time', 0)
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
- ->whereIn('number', array_keys($manNums))
|
|
|
- ->pluck('id', 'number')->toArray();
|
|
|
-
|
|
|
- $devMap = Device::where('del_time', 0)
|
|
|
- ->where('top_depart_id', $user['top_depart_id'])
|
|
|
- ->whereIn('code', array_keys($devCodes))
|
|
|
- ->pluck('id', 'code')->toArray();
|
|
|
-
|
|
|
- return [$manMap, $devMap];
|
|
|
- }
|
|
|
-
|
|
|
private function getItemList($array, $user, $index){
|
|
|
//查找设备
|
|
|
$codes = array_unique(array_filter(array_column($array,$index)));
|
|
|
@@ -1686,8 +1390,6 @@ class ImportService extends Service
|
|
|
$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);
|
|
|
|
|
|
$numIdx = array_search('total_days', $keys);
|
|
|
$num2Idx = array_search('rd_total_days', $keys);
|
|
|
@@ -1794,24 +1496,6 @@ class ImportService extends Service
|
|
|
$excelAggregator[$aggKey]['emps'][$valEmp] = true;
|
|
|
}
|
|
|
|
|
|
- // F. 日期逻辑检查
|
|
|
- list($sStatus, $startTime) = $this->convertExcelCellToDate($row[$startIdx] ?? '');
|
|
|
- list($eStatus, $endTime) = $this->convertExcelCellToDate($row[$endIdx] ?? '');
|
|
|
- if (!$sStatus || !$eStatus) {
|
|
|
- $errors[] = "第{$displayLine}行:日期格式无效";
|
|
|
- } else {
|
|
|
- if ($startTime > $endTime) {
|
|
|
- $errors[] = "第{$displayLine}行:开始日期大于结束日期";
|
|
|
- } else {
|
|
|
- $monthEndTs = strtotime("+1 month", $valMonthTs) - 1;
|
|
|
- if ($startTime < $valMonthTs || $endTime > $monthEndTs) {
|
|
|
- $errors[] = "第{$displayLine}行:日期超出月度范围";
|
|
|
- }
|
|
|
- }
|
|
|
- $array[$rowIndex][$startIdx] = $startTime;
|
|
|
- $array[$rowIndex][$endIdx] = $endTime;
|
|
|
- }
|
|
|
-
|
|
|
// G. 数字有效性校验
|
|
|
$numFields = [
|
|
|
$numIdx => '出勤天数', $num2Idx => '研发天数',
|
|
|
@@ -3329,6 +3013,515 @@ class ImportService extends Service
|
|
|
return [$error_string, $update_map, $dbDevices, $dbItems];
|
|
|
}
|
|
|
|
|
|
+ // 人员请假单 --------------------------------
|
|
|
+ public function leaveOrderImport($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, '导入数据不能为空'];
|
|
|
+
|
|
|
+ // 1. 基础格式检查
|
|
|
+ list($array, $error) = $this->checkCommon($array, $table_config);
|
|
|
+ if (!empty($error)) return [0, $error];
|
|
|
+
|
|
|
+ // 2. 详细业务校验 (固定为请假单校验)
|
|
|
+ list($error, $update_map, $dbEmps) = $this->leaveOrderCheck($array, $user, $table_config);
|
|
|
+ if (!empty($error)) return [0, $error];
|
|
|
+
|
|
|
+ $keys = array_column($table_config, 'key');
|
|
|
+ $codeIdx = array_search('code', $keys);
|
|
|
+ $timeIdx = array_search('order_time', $keys);
|
|
|
+ $empIdx = array_search('employee_id', $keys);
|
|
|
+ $startIdx = array_search('start_time', $keys);
|
|
|
+ $endIdx = array_search('end_time', $keys);
|
|
|
+
|
|
|
+ // 3. 数据聚合分组 (按日期聚合)
|
|
|
+ $groups = [];
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
+ $cTimeTs = $row[$timeIdx];
|
|
|
+ $mainId = $update_map[$rowIndex] ?? 0;
|
|
|
+
|
|
|
+ // 聚合Key:如果是更新则按主表ID;如果是新增则按日期
|
|
|
+ $aggKey = $mainId > 0 ? "ID_" . $mainId : "DATE_" . $cTimeTs;
|
|
|
+
|
|
|
+ if (!isset($groups[$aggKey])) {
|
|
|
+ $groups[$aggKey] = [
|
|
|
+ 'main_id' => $mainId,
|
|
|
+ 'order_time' => $cTimeTs,
|
|
|
+ 'details' => []
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ list($sH, $sM) = $this->parseTimeHourMin($row[$startIdx]);
|
|
|
+ list($eH, $eM) = $this->parseTimeHourMin($row[$endIdx]);
|
|
|
+
|
|
|
+ $groups[$aggKey]['details'][] = [
|
|
|
+ 'employee_id' => $dbEmps[trim($row[$empIdx])] ?? 0,
|
|
|
+ 'start_time_hour' => $sH,
|
|
|
+ 'start_time_min' => $sM,
|
|
|
+ 'end_time_hour' => $eH,
|
|
|
+ 'end_time_min' => $eM,
|
|
|
+ 'total_min' => ($eH * 60 + $eM) - ($sH * 60 + $sM),
|
|
|
+ 'type' => PLeaveOverOrder::TYPE_ONE, // 固定请假类型
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 执行写入
|
|
|
+ DB::beginTransaction();
|
|
|
+ try {
|
|
|
+ $time = time();
|
|
|
+ foreach ($groups as $group) {
|
|
|
+ if ($group['main_id'] > 0) {
|
|
|
+ $mainId = $group['main_id'];
|
|
|
+ // 删除旧明细准备覆盖
|
|
|
+ DB::table('p_leave_over_order_details')->where('main_id', $mainId)->update(['del_time' => $time]);
|
|
|
+ } else {
|
|
|
+ // 生成请假单号
|
|
|
+ $newCode = $this->generateBillNo([
|
|
|
+ 'top_depart_id' => $user['top_depart_id'],
|
|
|
+ 'type' => PLeaveOverOrder::Order_type,
|
|
|
+ 'period' => date("Ym", $group['order_time'])
|
|
|
+ ]);
|
|
|
+ $mainId = DB::table('p_leave_over_order')->insertGetId([
|
|
|
+ 'code' => $newCode,
|
|
|
+ 'order_time' => $group['order_time'],
|
|
|
+ 'type' => PLeaveOverOrder::TYPE_ONE,
|
|
|
+ 'top_depart_id' => $user['top_depart_id'],
|
|
|
+ 'crt_id' => $user['id'],
|
|
|
+ 'crt_time' => $time,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($group['details'] as &$d) {
|
|
|
+ $d['main_id'] = $mainId;
|
|
|
+ $d['top_depart_id'] = $user['top_depart_id'];
|
|
|
+ $d['crt_time'] = $time;
|
|
|
+ }
|
|
|
+ DB::table('p_leave_over_order_details')->insert($group['details']);
|
|
|
+ }
|
|
|
+ DB::commit();
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ DB::rollBack();
|
|
|
+ return [false, "失败:" . $e->getMessage()];
|
|
|
+ }
|
|
|
+ return [true, ''];
|
|
|
+ }
|
|
|
+
|
|
|
+ private function leaveOrderCheck(&$array, $user, $table_config)
|
|
|
+ {
|
|
|
+ $keys = array_column($table_config, 'key');
|
|
|
+ $codeIdx = array_search('code', $keys);
|
|
|
+ $timeIdx = array_search('order_time', $keys);
|
|
|
+ $empIdx = array_search('employee_id', $keys);
|
|
|
+ $startIdx = array_search('start_time', $keys);
|
|
|
+ $endIdx = array_search('end_time', $keys);
|
|
|
+
|
|
|
+ $topDepartId = $user['top_depart_id'];
|
|
|
+ $errors = [];
|
|
|
+ $update_map = [];
|
|
|
+
|
|
|
+ // --- 1. 基础档案预加载 (代码省略,保持原样) ---
|
|
|
+ $empCodes = array_filter(array_unique(array_column($array, $empIdx)));
|
|
|
+ $empModels = Employee::where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('number', $empCodes)->get(['id', 'number', 'title']);
|
|
|
+ $dbEmps = $empModels->pluck('id', 'number')->toArray();
|
|
|
+ $empDisplayMap = $empModels->mapWithKeys(fn($item) => [$item->id => "[{$item->number}]{$item->title}"])->toArray();
|
|
|
+
|
|
|
+ // --- 2. 日历 & 主表预查 (代码省略,保持原样) ---
|
|
|
+ $allDateTs = [];
|
|
|
+ foreach ($array as $row) {
|
|
|
+ list($status, $ts) = $this->convertExcelCellToDate($row[$timeIdx] ?? '');
|
|
|
+ if ($status) $allDateTs[] = strtotime(date('Y-m-d', $ts));
|
|
|
+ }
|
|
|
+ $allDateTs = array_unique($allDateTs);
|
|
|
+ $calendarMap = DB::table('calendar_details')->where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('time', $allDateTs)->pluck('is_work', 'time')->toArray();
|
|
|
+
|
|
|
+ $existMainOrders = DB::table('p_leave_over_order')
|
|
|
+ ->where('top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('order_time', $allDateTs)
|
|
|
+ ->where('type', PLeaveOverOrder::TYPE_ONE)
|
|
|
+ ->where('del_time', 0)->get()->keyBy('order_time');
|
|
|
+
|
|
|
+ // --- 3. 工时设置 (代码省略,保持原样) ---
|
|
|
+ $specialWorkMap = DB::table('employee_work_range')->whereIn('employee_id', array_values($dbEmps))
|
|
|
+ ->where('top_depart_id', $topDepartId)->get()->groupBy('employee_id');
|
|
|
+ $commonWorkRanges = DB::table('work_range_details')->where('del_time', 0)->where('top_depart_id', $topDepartId)->get();
|
|
|
+ $commonPeriods = [];
|
|
|
+ foreach ($commonWorkRanges as $wr) {
|
|
|
+ $commonPeriods[] = ['s' => $wr->start_time_hour * 60 + $wr->start_time_min, 'e' => $wr->end_time_hour * 60 + $wr->end_time_min];
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- 4. 库内明细校验数据 (代码省略,保持原样) ---
|
|
|
+ $allCodes = array_filter(array_unique(array_column($array, $codeIdx)));
|
|
|
+ $dbExistingWork = DB::table('p_leave_over_order_details as d')
|
|
|
+ ->join('p_leave_over_order as m', 'd.main_id', '=', 'm.id')
|
|
|
+ ->where('m.top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('m.order_time', $allDateTs)
|
|
|
+ ->where('m.type', PLeaveOverOrder::TYPE_ONE)
|
|
|
+ ->where('m.del_time', 0)->where('d.del_time', 0)
|
|
|
+ ->whereNotIn('m.code', $allCodes)
|
|
|
+ ->select('m.order_time', 'd.employee_id', 'd.start_time_hour', 'd.start_time_min', 'd.end_time_hour', 'd.end_time_min')
|
|
|
+ ->get()->groupBy(fn($item) => $item->order_time . '_' . $item->employee_id);
|
|
|
+
|
|
|
+ $dbOrders = DB::table('p_leave_over_order')->where('top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('code', $allCodes)->where('del_time', 0)->get()->keyBy('code');
|
|
|
+
|
|
|
+ $internalOverlapMap = [];
|
|
|
+
|
|
|
+ // --- 5. 循环校验 (全量提示版) ---
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
+ $line = $rowIndex + 1;
|
|
|
+ $rowErrors = []; // 临时收集本行的所有错误
|
|
|
+
|
|
|
+ list($status, $ts) = $this->convertExcelCellToDate($row[$timeIdx] ?? '');
|
|
|
+ $ts = $status ? strtotime(date('Y-m-d', $ts)) : 0;
|
|
|
+ $array[$rowIndex][$timeIdx] = $ts;
|
|
|
+
|
|
|
+ if (!$ts) {
|
|
|
+ $errors[] = "第{$line}行:日期格式错误";
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 单据与编辑逻辑检查
|
|
|
+ $valCode = trim($row[$codeIdx] ?? '');
|
|
|
+ if ($valCode === '') {
|
|
|
+ if (isset($existMainOrders[$ts])) {
|
|
|
+ $rowErrors[] = date('Y-m-d', $ts) . "已存在请假单[{$existMainOrders[$ts]->code}],请填写单号进行编辑";
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (isset($dbOrders[$valCode])) {
|
|
|
+ if ($dbOrders[$valCode]->order_time != $ts) {
|
|
|
+ $rowErrors[] = "单据[{$valCode}]原日期不符,不允许跨日期编辑";
|
|
|
+ }
|
|
|
+ $update_map[$rowIndex] = $dbOrders[$valCode]->id;
|
|
|
+ } else {
|
|
|
+ $rowErrors[] = "单据号[{$valCode}]不存在";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 日历检查
|
|
|
+ if (!isset($calendarMap[$ts]) || (int)$calendarMap[$ts] !== 1) {
|
|
|
+ $rowErrors[] = "该日期非工作日,无需请假";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 人员检查
|
|
|
+ $empId = $dbEmps[trim($row[$empIdx])] ?? 0;
|
|
|
+ $empName = $empDisplayMap[$empId] ?? "工号:".$row[$empIdx];
|
|
|
+ if (!$empId) {
|
|
|
+ $rowErrors[] = "人员不存在";
|
|
|
+ // 如果人都不存在,后面的时间校验没意义,报错合并
|
|
|
+ $errors[] = "第{$line}行:" . implode(';', $rowErrors);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 时间段合法性检查
|
|
|
+ list($sH, $sM) = $this->parseTimeHourMin($row[$startIdx] ?? '');
|
|
|
+ list($eH, $eM) = $this->parseTimeHourMin($row[$endIdx] ?? '');
|
|
|
+ $curS = $sH * 60 + $sM; $curE = $eH * 60 + $eM;
|
|
|
+
|
|
|
+ if ($curS >= $curE) {
|
|
|
+ $rowErrors[] = "结束时间需晚于开始时间";
|
|
|
+ } else {
|
|
|
+ // 只有在时间段本身合法的情况下,才检查范围和重叠
|
|
|
+
|
|
|
+ // A. 工作范围检查
|
|
|
+ $empPeriods = isset($specialWorkMap[$empId]) ? [] : $commonPeriods;
|
|
|
+ if (isset($specialWorkMap[$empId])) {
|
|
|
+ foreach ($specialWorkMap[$empId] as $sw) {
|
|
|
+ $empPeriods[] = ['s' => $sw->start_time_hour * 60 + $sw->start_time_min, 'e' => $sw->end_time_hour * 60 + $sw->end_time_min];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $inRange = false;
|
|
|
+ foreach ($empPeriods as $p) { if ($curS >= $p['s'] && $curE <= $p['e']) { $inRange = true; break; } }
|
|
|
+ if (!$inRange) {
|
|
|
+ $rowErrors[] = "请假需在规定的工作时间内";
|
|
|
+ }
|
|
|
+
|
|
|
+ // B. 重叠检查 (不再 continue,两个都查)
|
|
|
+ $checkKey = $ts . "_" . $empId;
|
|
|
+ // 表内
|
|
|
+ if (isset($internalOverlapMap[$checkKey])) {
|
|
|
+ foreach ($internalOverlapMap[$checkKey] as $p) {
|
|
|
+ if ($curS < $p['e'] && $p['s'] < $curE) {
|
|
|
+ $rowErrors[] = "在表内存在时间重叠";
|
|
|
+ break; // 同一行的“表内重叠”只提示一次
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 库内
|
|
|
+ if (isset($dbExistingWork[$checkKey])) {
|
|
|
+ foreach ($dbExistingWork[$checkKey] as $p) {
|
|
|
+ $exS = $p->start_time_hour * 60 + $p->start_time_min;
|
|
|
+ $exE = $p->end_time_hour * 60 + $p->end_time_min;
|
|
|
+ if ($curS < $exE && $exS < $curE) {
|
|
|
+ $rowErrors[] = "与已有的请假单时间重叠";
|
|
|
+ break; // 同一行的“库内重叠”只提示一次
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 收集汇总错误
|
|
|
+ if (!empty($rowErrors)) {
|
|
|
+ $errors[] = "第{$line}行:{$empName}" . implode(',', $rowErrors);
|
|
|
+ } else {
|
|
|
+ // 只有完全没错误的数据,才放入 internalOverlapMap 供后续行比对
|
|
|
+ // 这样可以防止第2行报错了,第3行又提示跟第2行重叠,造成提示混乱
|
|
|
+ $checkKey = $ts . "_" . $empId;
|
|
|
+ $internalOverlapMap[$checkKey][] = ['s' => $curS, 'e' => $curE];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [!empty($errors) ? implode('|', $errors) : "", $update_map, $dbEmps];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 人员加班单
|
|
|
+ public function overtimeOrderImport($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, '导入数据不能为空'];
|
|
|
+
|
|
|
+ // 1. 基础格式检查
|
|
|
+ list($array, $error) = $this->checkCommon($array, $table_config);
|
|
|
+ if (!empty($error)) return [0, $error];
|
|
|
+
|
|
|
+ // 2. 业务逻辑校验 (专用于加班)
|
|
|
+ list($error, $update_map, $dbEmps) = $this->overtimeOrderCheck($array, $user, $table_config);
|
|
|
+ if (!empty($error)) return [0, $error];
|
|
|
+
|
|
|
+ $keys = array_column($table_config, 'key');
|
|
|
+ $codeIdx = array_search('code', $keys);
|
|
|
+ $timeIdx = array_search('order_time', $keys);
|
|
|
+ $empIdx = array_search('employee_id', $keys);
|
|
|
+ $startIdx = array_search('start_time', $keys);
|
|
|
+ $endIdx = array_search('end_time', $keys);
|
|
|
+
|
|
|
+ // 3. 数据聚合分组 (按日期聚合)
|
|
|
+ $groups = [];
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
+ $cTimeTs = $row[$timeIdx];
|
|
|
+ $mainId = $update_map[$rowIndex] ?? 0;
|
|
|
+ $aggKey = $mainId > 0 ? "ID_" . $mainId : "DATE_" . $cTimeTs;
|
|
|
+
|
|
|
+ if (!isset($groups[$aggKey])) {
|
|
|
+ $groups[$aggKey] = [
|
|
|
+ 'main_id' => $mainId,
|
|
|
+ 'order_time' => $cTimeTs,
|
|
|
+ 'details' => []
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ list($sH, $sM) = $this->parseTimeHourMin($row[$startIdx]);
|
|
|
+ list($eH, $eM) = $this->parseTimeHourMin($row[$endIdx]);
|
|
|
+
|
|
|
+ $groups[$aggKey]['details'][] = [
|
|
|
+ 'employee_id' => $dbEmps[trim($row[$empIdx])] ?? 0,
|
|
|
+ 'start_time_hour' => $sH,
|
|
|
+ 'start_time_min' => $sM,
|
|
|
+ 'end_time_hour' => $eH,
|
|
|
+ 'end_time_min' => $eM,
|
|
|
+ 'total_min' => ($eH * 60 + $eM) - ($sH * 60 + $sM),
|
|
|
+ 'type' => PLeaveOverOrder::TYPE_TWO, // 加班类型
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 执行写入
|
|
|
+ DB::beginTransaction();
|
|
|
+ try {
|
|
|
+ $time = time();
|
|
|
+ foreach ($groups as $group) {
|
|
|
+ if ($group['main_id'] > 0) {
|
|
|
+ $mainId = $group['main_id'];
|
|
|
+ DB::table('p_leave_over_order_details')->where('main_id', $mainId)->update(['del_time' => $time]);
|
|
|
+ } else {
|
|
|
+ $newCode = $this->generateBillNo([
|
|
|
+ 'top_depart_id' => $user['top_depart_id'],
|
|
|
+ 'type' => PLeaveOverOrder::Order_type,
|
|
|
+ 'period' => date("Ym", $group['order_time'])
|
|
|
+ ]);
|
|
|
+ $mainId = DB::table('p_leave_over_order')->insertGetId([
|
|
|
+ 'code' => $newCode,
|
|
|
+ 'order_time' => $group['order_time'],
|
|
|
+ 'type' => PLeaveOverOrder::TYPE_TWO,
|
|
|
+ 'top_depart_id' => $user['top_depart_id'],
|
|
|
+ 'crt_id' => $user['id'],
|
|
|
+ 'crt_time' => $time,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($group['details'] as &$d) {
|
|
|
+ $d['main_id'] = $mainId;
|
|
|
+ $d['top_depart_id'] = $user['top_depart_id'];
|
|
|
+ $d['crt_time'] = $time;
|
|
|
+ }
|
|
|
+ DB::table('p_leave_over_order_details')->insert($group['details']);
|
|
|
+ }
|
|
|
+ DB::commit();
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ DB::rollBack();
|
|
|
+ return [false, "失败:" . $e->getMessage()];
|
|
|
+ }
|
|
|
+
|
|
|
+ return [true, ''];
|
|
|
+ }
|
|
|
+
|
|
|
+ private function overtimeOrderCheck(&$array, $user, $table_config)
|
|
|
+ {
|
|
|
+ $keys = array_column($table_config, 'key');
|
|
|
+ $codeIdx = array_search('code', $keys);
|
|
|
+ $timeIdx = array_search('order_time', $keys);
|
|
|
+ $empIdx = array_search('employee_id', $keys);
|
|
|
+ $startIdx = array_search('start_time', $keys);
|
|
|
+ $endIdx = array_search('end_time', $keys);
|
|
|
+
|
|
|
+ $topDepartId = $user['top_depart_id'];
|
|
|
+ $errors = [];
|
|
|
+ $update_map = [];
|
|
|
+
|
|
|
+ // 1. 档案预加载
|
|
|
+ $empCodes = array_filter(array_unique(array_column($array, $empIdx)));
|
|
|
+ $empModels = Employee::where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('number', $empCodes)->get(['id', 'number', 'title']);
|
|
|
+ $dbEmps = $empModels->pluck('id', 'number')->toArray();
|
|
|
+ $empDisplayMap = $empModels->mapWithKeys(fn($item) => [$item->id => "[{$item->number}]{$item->title}"])->toArray();
|
|
|
+
|
|
|
+ // 2. 日期、日历、主表预查
|
|
|
+ $allDateTs = [];
|
|
|
+ foreach ($array as $row) {
|
|
|
+ list($status, $ts) = $this->convertExcelCellToDate($row[$timeIdx] ?? '');
|
|
|
+ if ($status) $allDateTs[] = strtotime(date('Y-m-d', $ts));
|
|
|
+ }
|
|
|
+ $allDateTs = array_unique($allDateTs);
|
|
|
+ $calendarMap = DB::table('calendar_details')->where('del_time', 0)->where('top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('time', $allDateTs)->pluck('is_work', 'time')->toArray();
|
|
|
+
|
|
|
+ $existMainOrders = DB::table('p_leave_over_order')
|
|
|
+ ->where('top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('order_time', $allDateTs)
|
|
|
+ ->where('type', PLeaveOverOrder::TYPE_TWO)
|
|
|
+ ->where('del_time', 0)->get()->keyBy('order_time');
|
|
|
+
|
|
|
+ // 3. 工时设置预加载
|
|
|
+ $specialWorkMap = DB::table('employee_work_range')->whereIn('employee_id', array_values($dbEmps))
|
|
|
+ ->where('top_depart_id', $topDepartId)->get()->groupBy('employee_id');
|
|
|
+ $commonWorkRanges = DB::table('work_range_details')->where('del_time', 0)->where('top_depart_id', $topDepartId)->get();
|
|
|
+ $commonPeriods = [];
|
|
|
+ foreach ($commonWorkRanges as $wr) {
|
|
|
+ $commonPeriods[] = ['s' => $wr->start_time_hour * 60 + $wr->start_time_min, 'e' => $wr->end_time_hour * 60 + $wr->end_time_min];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 库内明细预查 (跨单重叠校验)
|
|
|
+ $allCodes = array_filter(array_unique(array_column($array, $codeIdx)));
|
|
|
+ $dbExistingWork = DB::table('p_leave_over_order_details as d')
|
|
|
+ ->join('p_leave_over_order as m', 'd.main_id', '=', 'm.id')
|
|
|
+ ->where('m.top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('m.order_time', $allDateTs)
|
|
|
+ ->where('m.type', PLeaveOverOrder::TYPE_TWO)
|
|
|
+ ->where('m.del_time', 0)->where('d.del_time', 0)
|
|
|
+ ->whereNotIn('m.code', $allCodes)
|
|
|
+ ->select('m.order_time', 'd.employee_id', 'd.start_time_hour', 'd.start_time_min', 'd.end_time_hour', 'd.end_time_min')
|
|
|
+ ->get()->groupBy(fn($item) => $item->order_time . '_' . $item->employee_id);
|
|
|
+
|
|
|
+ $dbOrders = DB::table('p_leave_over_order')->where('top_depart_id', $topDepartId)
|
|
|
+ ->whereIn('code', $allCodes)->where('del_time', 0)->get()->keyBy('code');
|
|
|
+
|
|
|
+ $internalOverlapMap = [];
|
|
|
+
|
|
|
+ // 5. 全量循环检查
|
|
|
+ foreach ($array as $rowIndex => $row) {
|
|
|
+ $line = $rowIndex + 1;
|
|
|
+ $rowErrors = [];
|
|
|
+
|
|
|
+ list($status, $ts) = $this->convertExcelCellToDate($row[$timeIdx] ?? '');
|
|
|
+ $ts = $status ? strtotime(date('Y-m-d', $ts)) : 0;
|
|
|
+ $array[$rowIndex][$timeIdx] = $ts;
|
|
|
+
|
|
|
+ if (!$ts) { $errors[] = "第{$line}行:日期格式错误"; continue; }
|
|
|
+
|
|
|
+ // A. 单据存在性逻辑
|
|
|
+ $valCode = trim($row[$codeIdx] ?? '');
|
|
|
+ if ($valCode === '') {
|
|
|
+ if (isset($existMainOrders[$ts])) {
|
|
|
+ $rowErrors[] = date('Y-m-d', $ts) . "已存在加班单[{$existMainOrders[$ts]->code}],请填写单号进行编辑";
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (isset($dbOrders[$valCode])) {
|
|
|
+ if ($dbOrders[$valCode]->order_time != $ts) $rowErrors[] = "单据[{$valCode}]原日期不符";
|
|
|
+ $update_map[$rowIndex] = $dbOrders[$valCode]->id;
|
|
|
+ } else { $rowErrors[] = "单据号[{$valCode}]不存在"; }
|
|
|
+ }
|
|
|
+
|
|
|
+ // B. 人员校验
|
|
|
+ $empId = $dbEmps[trim($row[$empIdx])] ?? 0;
|
|
|
+ $empName = $empDisplayMap[$empId] ?? "工号:".$row[$empIdx];
|
|
|
+ if (!$empId) {
|
|
|
+ $errors[] = "第{$line}行:人员不存在"; continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // C. 时间格式校验
|
|
|
+ list($sH, $sM) = $this->parseTimeHourMin($row[$startIdx] ?? '');
|
|
|
+ list($eH, $eM) = $this->parseTimeHourMin($row[$endIdx] ?? '');
|
|
|
+ $curS = $sH * 60 + $sM; $curE = $eH * 60 + $eM;
|
|
|
+
|
|
|
+ if ($curS >= $curE) {
|
|
|
+ $rowErrors[] = "结束时间需晚于开始时间";
|
|
|
+ } else {
|
|
|
+ // D. 加班规则校验 (核心逻辑)
|
|
|
+ $isWorkDay = (int)($calendarMap[$ts] ?? 0) === 1;
|
|
|
+
|
|
|
+ if ($isWorkDay) {
|
|
|
+ // 如果是工作日,加班不能在工作时间内
|
|
|
+ $empPeriods = isset($specialWorkMap[$empId]) ? [] : $commonPeriods;
|
|
|
+ if (isset($specialWorkMap[$empId])) {
|
|
|
+ foreach ($specialWorkMap[$empId] as $sw) {
|
|
|
+ $empPeriods[] = ['s' => $sw->start_time_hour * 60 + $sw->start_time_min, 'e' => $sw->end_time_hour * 60 + $sw->end_time_min];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ foreach ($empPeriods as $p) {
|
|
|
+ if ($curS < $p['e'] && $p['s'] < $curE) {
|
|
|
+ $rowErrors[] = "加班时间不能与正常工作时间重叠";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // E. 重叠校验
|
|
|
+ $checkKey = $ts . "_" . $empId;
|
|
|
+ // 表内重叠
|
|
|
+ if (isset($internalOverlapMap[$checkKey])) {
|
|
|
+ foreach ($internalOverlapMap[$checkKey] as $p) {
|
|
|
+ if ($curS < $p['e'] && $p['s'] < $curE) { $rowErrors[] = "在表内存在时间重叠"; break; }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 库内重叠
|
|
|
+ if (isset($dbExistingWork[$checkKey])) {
|
|
|
+ foreach ($dbExistingWork[$checkKey] as $p) {
|
|
|
+ $exS = $p->start_time_hour * 60 + $p->start_time_min; $exE = $p->end_time_hour * 60 + $p->end_time_min;
|
|
|
+ if ($curS < $exE && $exS < $curE) { $rowErrors[] = "与已有的加班单时间重叠"; break; }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($rowErrors)) {
|
|
|
+ $errors[] = "第{$line}行:{$empName} " . implode(',', $rowErrors);
|
|
|
+ } else {
|
|
|
+ $internalOverlapMap[$ts . "_" . $empId][] = ['s' => $curS, 'e' => $curE];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [!empty($errors) ? implode('|', $errors) : "", $update_map, $dbEmps];
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 解析并校验时间
|
|
|
*/
|