Common.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\constant\CommonConstant;
  4. use app\common\constant\MaintainConstant;
  5. use app\common\model\Goods;
  6. use app\common\service\ApproveInfoService;
  7. use app\common\service\CommonService;
  8. use app\common\service\GoodsCategoryService;
  9. use app\common\service\UserService;
  10. use hg\apidoc\annotation as Apidoc;
  11. use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
  12. use PhpOffice\PhpSpreadsheet\Reader\Csv;
  13. use PhpOffice\PhpSpreadsheet\Reader\Xls;
  14. use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
  15. use think\db\exception\BindParamException;
  16. use think\Exception;
  17. use think\exception\PDOException;
  18. use think\Db;
  19. /**
  20. * @Apidoc\Title("公用")
  21. * @Apidoc\Group("api")
  22. * @Apidoc\Sort("4")
  23. */
  24. class Common extends Base
  25. {
  26. // 需要登录
  27. protected $need_login = ['get_user_list'];
  28. public function initialize()
  29. {
  30. parent::initialize();
  31. }
  32. /**
  33. * 类型数据
  34. *
  35. * @Apidoc\Method("POST")
  36. * @Apidoc\Returned("module_list", type="array", desc="模块列表")
  37. * @Apidoc\Returned("degree_list", type="array", desc="缓急程度列表")
  38. * @Apidoc\Returned("pay_type_list", type="array", desc="采购支付方式列表")
  39. * @Apidoc\Returned("time_list", type="array", desc="请假周期列表")
  40. * @Apidoc\Returned("data1", type="array", desc="采购类型列表")
  41. * @Apidoc\Returned("data2", type="array", desc="呈批类型列表")
  42. * @Apidoc\Returned("data5", type="array", desc="出差类型列表")
  43. * @Apidoc\Returned("data6", type="array", desc="请假类型列表")
  44. * @Apidoc\Returned("data8", type="array", desc="维修类型列表")
  45. * @Apidoc\Returned("data9", type="array", desc="合同类型列表")
  46. */
  47. public function get_type_list()
  48. {
  49. $data = CommonService::get_data();
  50. $this->success('类型数据', $data);
  51. }
  52. /**
  53. * 发起人列表
  54. *
  55. * @Apidoc\Desc("入库模块")
  56. * @Apidoc\Method("POST")
  57. * @Apidoc\Param("page", type="integer",require=true, desc="页数")
  58. * @Apidoc\Param("page_num", type="integer", require=true, desc="每页数量")
  59. * @Apidoc\Returned("userid", type="string", desc="userid")
  60. * @Apidoc\Returned("name", type="string", desc="姓名")
  61. **/
  62. public function get_user_list()
  63. {
  64. $offset = $this->off_set;
  65. $length = $this->page_num;
  66. $user = $this->user;
  67. $list = UserService::get_list(0,$offset, $length);
  68. $this->success('发起人列表', $list);
  69. }
  70. /**
  71. * 维修人员列表
  72. *
  73. * @Apidoc\Desc("维修模块")
  74. * @Apidoc\Method("POST")
  75. * @Apidoc\Param("type", type="integer", require=true, desc="类型:1=物业主管,2=信息负责人")
  76. **/
  77. public function get_maintain_user(){
  78. $type = $this->request->post('type');
  79. if (!array_key_exists($type, MaintainConstant::get_type_list())) {
  80. $this->success('维修人员列表.');
  81. }
  82. $list = UserService::get_maintain_user($type);
  83. $this->success('维修人员列表',$list);
  84. }
  85. /**
  86. * 获取导入模板
  87. *
  88. * @Apidoc\Desc("申购模块,入库模块,领用模块")
  89. * @Apidoc\Method("POST")
  90. * @Apidoc\Param("module", type="integer", require=true, desc="模块类型:1=申购申请,3=入库申请,4=领用申请")
  91. * @Apidoc\Returned("url", type="string", desc="导入模板路径")
  92. **/
  93. public function get_import_template(){
  94. $module = $this->request->post('module');
  95. if (!in_array($module, [CommonConstant::MODULE_1, CommonConstant::MODULE_3, CommonConstant::MODULE_4])) {
  96. $this->error('请选择正确的模块类型');
  97. }
  98. switch ($module){
  99. case CommonConstant::MODULE_1:
  100. $url = $this->request->domain().'/导入模板-采购物品.xlsx';
  101. break;
  102. case CommonConstant::MODULE_3:
  103. $url = $this->request->domain().'/导入模板-入库物品.xlsx';
  104. break;
  105. case CommonConstant::MODULE_4:
  106. $url = $this->request->domain().'/导入模板-领用物品.xlsx';
  107. break;
  108. }
  109. $data = compact("url");
  110. $this->success('导入模板',$data);
  111. }
  112. /**
  113. * 导入
  114. *
  115. * @Apidoc\Desc("申购模块,入库模块,领用模块")
  116. * @Apidoc\Method("POST")
  117. * @Apidoc\Param("module", type="integer", require=true, desc="模块类型:1=申购申请,3=入库申请,4=领用申请")
  118. * @Apidoc\Param("file", type="string", require=true, desc="上传后的文件路径")
  119. * @return void
  120. * @throws PDOException
  121. * @throws BindParamException
  122. */
  123. public function import()
  124. {
  125. $module = $this->request->post('module');
  126. $file = $this->request->post('file');
  127. if (!in_array($module, [CommonConstant::MODULE_1, CommonConstant::MODULE_3, CommonConstant::MODULE_4])) {
  128. $this->error('请选择正确的模块类型');
  129. }
  130. if (!$file) {
  131. $this->error('请选择文件');
  132. }
  133. $filePath = $_SERVER['DOCUMENT_ROOT'] . '/' . $file;
  134. if (!is_file($filePath)) {
  135. $this->error('文件未找到');
  136. }
  137. //实例化reader
  138. $ext = pathinfo($filePath, PATHINFO_EXTENSION);
  139. if (!in_array($ext, ['csv', 'xls', 'xlsx'])) {
  140. $this->error('未知的数据格式');
  141. }
  142. if ($ext === 'csv') {
  143. $file = fopen($filePath, 'r');
  144. $filePath = tempnam(sys_get_temp_dir(), 'import_csv');
  145. $fp = fopen($filePath, 'w');
  146. $n = 0;
  147. while ($line = fgets($file)) {
  148. $line = rtrim($line, "\n\r\0");
  149. $encoding = mb_detect_encoding($line, ['utf-8', 'gbk', 'latin1', 'big5']);
  150. if ($encoding !== 'utf-8') {
  151. $line = mb_convert_encoding($line, 'utf-8', $encoding);
  152. }
  153. if ($n == 0 || preg_match('/^".*"$/', $line)) {
  154. fwrite($fp, $line . "\n");
  155. } else {
  156. fwrite($fp, '"' . str_replace(['"', ','], ['""', '","'], $line) . "\"\n");
  157. }
  158. $n++;
  159. }
  160. fclose($file) || fclose($fp);
  161. $reader = new Csv();
  162. } elseif ($ext === 'xls') {
  163. $reader = new Xls();
  164. } else {
  165. $reader = new Xlsx();
  166. }
  167. //加载文件
  168. $insert = [];
  169. $data = []; // 导入的同一一级分类和二级分类和商品名称的数组
  170. $category_first_data = []; // 导入的分类数组
  171. $use_data = []; // 筛选后的领用数组
  172. $apply_goods_data = []; // 返回的数组
  173. $error_data = []; // 错误提示数组
  174. $flag = 2; // 默认批量导入
  175. try {
  176. if (!$PHPExcel = $reader->load($filePath)) {
  177. $this->error('未知的数据格式!');
  178. }
  179. $currentSheet = $PHPExcel->getSheet(0); //读取文件中的第一个工作表
  180. $allColumn = $currentSheet->getHighestDataColumn(); //取得最大的列号
  181. $allRow = $currentSheet->getHighestRow(); //取得一共有多少行
  182. $maxColumnNumber = Coordinate::columnIndexFromString($allColumn);
  183. if ($module == CommonConstant::MODULE_4) {
  184. $fields = ['goods_no', 'goods_category_first', 'goods_category_id', 'goods_name', 'goods_sku_value', 'stock'];
  185. } else {
  186. $fields = ['goods_no', 'goods_category_first', 'goods_category_id', 'goods_brand', 'goods_name', 'goods_sku_value', 'stock', 'price', 'total_price'];
  187. }
  188. for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) {
  189. $values = [];
  190. for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
  191. $val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
  192. $values[] = is_null($val) ? '' : trim($val); // 消除空格
  193. }
  194. $values = array_filter($values); // 过滤空值
  195. $temp = array_combine($fields, $values); // 合并两个数组来创建一个新数组,其中的一个数组元素为键名,另一个数组元素为键值
  196. if ($temp) {
  197. $insert[] = $temp;
  198. if ($module == CommonConstant::MODULE_4) {
  199. $data[$values[1] . ',' . $values[2] . ',' . $values[3]][] = $temp;
  200. $category_first_data[$values[1]][$values[2]] = $values[2];
  201. } else {
  202. $data[$values[1] . ',' . $values[2] . ',' . $values[4]][] = $temp;
  203. }
  204. }
  205. }
  206. } catch (Exception $exception) {
  207. $this->error('出现错误:' . $exception->getMessage());
  208. }
  209. if (!$insert) {
  210. $this->error('记录未找到');
  211. }
  212. if ($module == CommonConstant::MODULE_4) {
  213. $category_first_list = GoodsCategoryService::get_list([['name', 'in', array_keys($category_first_data)]],1);
  214. $category_first_object = $category_first_list ? array_column($category_first_list->toArray(), null, 'name') : [];
  215. $msg = '导入的物品:';
  216. foreach ($data as $key => $value) {
  217. $arr = explode(',', $key);
  218. $goods_name = $arr[2];
  219. if(array_key_exists($arr[0],$category_first_object)){
  220. // 一级里有该商品分类
  221. $category_first_info = $category_first_object[$arr[0]];
  222. $goods_category_first_id = $category_first_info['id'];
  223. $category_second_object = $category_first_info['childlist'] ? array_column($category_first_info['childlist'], null, 'name') : [];
  224. if(array_key_exists($arr[1],$category_second_object)){
  225. // 二级里有该商品分类
  226. $category_second_info = $category_second_object[$arr[1]];
  227. $goods_category_id = $category_second_info['id'];
  228. $goods_info = Goods::field('status,is_deleted,create_at', true)
  229. ->where('goods_category_first', $goods_category_first_id)
  230. ->where('goods_category_id', $goods_category_id)
  231. ->where('goods_name', $goods_name)
  232. ->where('is_deleted', CommonConstant::IS_DELETED_0)
  233. ->with([
  234. 'goodsStock',
  235. ])
  236. ->find();
  237. if ($goods_info) {
  238. // 商品库里有该商品
  239. $goods_info = $goods_info->toArray();
  240. $goods_stock_object = array_column($goods_info['goods_stock'], null, 'name');
  241. foreach ($value as $kk=>$val) {
  242. if (array_key_exists($val['goods_sku_value'], $goods_stock_object)) {
  243. // 商品库里有该商品规格
  244. $goods_stock_info = $goods_stock_object[$val['goods_sku_value']];
  245. $total_stock = $goods_stock_info['stock']; // 商品库的库存
  246. $stock = isset($val['stock']) && $val['stock'] > 0 ? $val['stock'] : 0; // 要领用的数量
  247. $lack_stock = $stock - $total_stock;
  248. if($total_stock > 0){
  249. // 商品规格有库存
  250. $use_data[$key][] = $val;
  251. $use_data[$key][$kk]['goods_id'] = $goods_info['id'];
  252. $use_data[$key][$kk]['goods_category_first'] = $goods_category_first_id;
  253. $use_data[$key][$kk]['goods_category_id'] = $goods_category_id;
  254. $use_data[$key][$kk]['id'] = $goods_stock_info['id'];
  255. if($lack_stock > 0){
  256. // 商品规格库存不足
  257. $use_data[$key][$kk]['stock'] = $total_stock; // 替换库存
  258. $error_data[] = [
  259. 'msg' => $msg . $goods_name . '-' . $val['goods_sku_value'] . '库存不足,缺少' . $lack_stock . '件',
  260. ];
  261. }
  262. } else{
  263. $error_data[] = [
  264. 'msg' => $msg . $goods_name . '-' . $val['goods_sku_value'] . '库存不足,缺少' . $lack_stock . '件',
  265. ];
  266. }
  267. } else {
  268. // 商品库里没有该商品规格
  269. $error_data[] = [
  270. 'msg' => $msg . $goods_name . '-' . $val['goods_sku_value'] . '商品库不存在',
  271. ];
  272. }
  273. }
  274. } else {
  275. // 商品库里没有该商品
  276. $error_data[] = [
  277. 'msg' => $msg . $goods_name . '商品库不存在',
  278. ];
  279. }
  280. } else{
  281. // 二级里没有该商品分类
  282. $error_data[] = [
  283. 'msg' => $msg . $goods_name . '商品库不存在',
  284. ];
  285. }
  286. } else{
  287. // 一级里没有该商品分类
  288. $error_data[] = [
  289. 'msg' => $msg . $goods_name . '商品库不存在',
  290. ];
  291. }
  292. }
  293. $data = $use_data;
  294. $flag = 3; // 商品库选择
  295. }
  296. foreach ($data as $key => $value) {
  297. // 商品
  298. $goods_data = [];
  299. $goods_stock_data = [];
  300. $total_price = 0;
  301. foreach ($value as $kk => $val) {
  302. // 规格值
  303. $stock = isset($val['stock']) && $val['stock'] > 0 ? $val['stock'] : 0;
  304. $price = isset($val['price']) && $val['price'] > 0 ? $val['price'] : 0;
  305. $total_price = bcadd($total_price, $stock * $price, 2);
  306. $goods_stock_data[] = [
  307. 'id' => isset($val['id']) ? $val['id'] : 0,
  308. 'name' => $val['goods_sku_value'],
  309. 'stock' => $stock,
  310. 'price' => $price,
  311. ];
  312. $goods_data = [
  313. 'goods_id' => isset($val['goods_id']) ? $val['goods_id'] : 0,
  314. 'goods_category_first' => $val['goods_category_first'],
  315. 'goods_category_id' => $val['goods_category_id'],
  316. 'goods_no' => $val['goods_no'],
  317. 'goods_name' => $val['goods_name'],
  318. 'goods_brand' => isset($val['goods_brand']) ? $val['goods_brand'] : '',
  319. ];
  320. }
  321. $goods_data['flag'] = $flag;
  322. $goods_data['total_price'] = $total_price;
  323. $goods_data['goods_stock'] = $goods_stock_data;
  324. $apply_goods_data[] = $goods_data;
  325. }
  326. $data = compact("apply_goods_data", "error_data");
  327. $error_data ? $this->success('领用物品提示', $data) : $this->success('导入成功', $data);
  328. }
  329. /**
  330. * 导入1
  331. */
  332. public function import1()
  333. {
  334. $file = $this->request->post('file');
  335. if (!$file) {
  336. $this->error('请选择文件');
  337. }
  338. $filePath = $_SERVER['DOCUMENT_ROOT'] . '/' . $file;
  339. if (!is_file($filePath)) {
  340. $this->error('文件未找到');
  341. }
  342. //实例化reader
  343. $ext = pathinfo($filePath, PATHINFO_EXTENSION);
  344. if (!in_array($ext, ['csv', 'xls', 'xlsx'])) {
  345. $this->error('未知的数据格式');
  346. }
  347. if ($ext === 'csv') {
  348. $file = fopen($filePath, 'r');
  349. $filePath = tempnam(sys_get_temp_dir(), 'import_csv');
  350. $fp = fopen($filePath, 'w');
  351. $n = 0;
  352. while ($line = fgets($file)) {
  353. $line = rtrim($line, "\n\r\0");
  354. $encoding = mb_detect_encoding($line, ['utf-8', 'gbk', 'latin1', 'big5']);
  355. if ($encoding !== 'utf-8') {
  356. $line = mb_convert_encoding($line, 'utf-8', $encoding);
  357. }
  358. if ($n == 0 || preg_match('/^".*"$/', $line)) {
  359. fwrite($fp, $line . "\n");
  360. } else {
  361. fwrite($fp, '"' . str_replace(['"', ','], ['""', '","'], $line) . "\"\n");
  362. }
  363. $n++;
  364. }
  365. fclose($file) || fclose($fp);
  366. $reader = new Csv();
  367. } elseif ($ext === 'xls') {
  368. $reader = new Xls();
  369. } else {
  370. $reader = new Xlsx();
  371. }
  372. //加载文件
  373. $insert = [];
  374. try {
  375. if (!$PHPExcel = $reader->load($filePath)) {
  376. $this->error('未知的数据格式!');
  377. }
  378. $currentSheet = $PHPExcel->getSheet(0); //读取文件中的第一个工作表
  379. $allColumn = $currentSheet->getHighestDataColumn(); //取得最大的列号
  380. $allRow = $currentSheet->getHighestRow(); //取得一共有多少行
  381. $maxColumnNumber = Coordinate::columnIndexFromString($allColumn);
  382. for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) {
  383. $values = [];
  384. for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
  385. $val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
  386. $values[] = is_null($val) ? '' : trim($val); // 消除空格
  387. }
  388. $values = array_filter($values); // 过滤空值
  389. $first[$values[0]] = $values[0];
  390. $second[$values[0]][$values[1]] = $values[1];
  391. $third[$values[1]][$values[2]] = $values[2];
  392. }
  393. } catch (Exception $exception) {
  394. $this->error('出现错误:' . $exception->getMessage());
  395. }
  396. // p($first);
  397. // p($second);
  398. // p($third);
  399. // exit;
  400. foreach ($first as $key=>$val){
  401. if(array_key_exists($val,$second)){
  402. $first1 = Db::table('dd_category_job')->insertGetId(['name'=>$val]);
  403. $second_list = $second[$val];
  404. foreach ($second_list as $v){
  405. if(array_key_exists($v,$third)){
  406. $second1 = Db::table('dd_category_job')->insertGetId(['pid'=>$first1,'name'=>$v]);
  407. $third_list = $third[$v];
  408. foreach ($third_list as $vv){
  409. Db::table('dd_category_job')->insertGetId(['pid'=>$second1,'name'=>$vv]);
  410. }
  411. }
  412. }
  413. }
  414. }
  415. $this->success('导入成功');
  416. }
  417. /**
  418. * 重置合同编号(定时任务 每年1月1日0点1分执行)
  419. *
  420. * @Apidoc\Method("POST")
  421. **/
  422. public function change_contract_no(){
  423. $data = date('md') == '0101' ? CommonService::change_contract_no() : [];
  424. $this->success('重置合同编号成功',$data);
  425. }
  426. /**
  427. * 测试
  428. *
  429. * @Apidoc\Method("POST")
  430. * @Apidoc\Param("id", type="integer",require=true, desc="ID")
  431. */
  432. public function test()
  433. {
  434. $id = input('id') ?: 0;
  435. $data = '';
  436. $name = '';
  437. $html = ApproveInfoService::get_html($data);
  438. $realpath = ApproveInfoService::getPath($name);
  439. $pdf = new \TCPDF();
  440. $pdf = ApproveInfoService::setPdfAttr($pdf);
  441. ApproveInfoService::exportPdf($pdf, $html, $realpath);
  442. $this->success('success',['url' => $realpath, 'fullurl' => 'https://' . $_SERVER['HTTP_HOST'] . $realpath]);
  443. }
  444. }