GoodService.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. namespace app\common\service;
  3. use think\facade\Db;
  4. use app\common\model\Good;
  5. use think\facade\Validate;
  6. use app\common\model\Stock;
  7. use app\common\util\Result;
  8. use think\facade\Filesystem;
  9. use app\common\model\GoodClass;
  10. use app\common\service\Service;
  11. use app\common\util\WhereBuilder;
  12. use app\common\util\PhpSpreadsheetImport;
  13. use app\common\util\PhpSpreadsheetExportV2;
  14. class GoodService extends Service
  15. {
  16. /**
  17. * 分页查询商品列表
  18. *
  19. * @param array $params 参数数组
  20. * @return \think\Paginator 分页对象,包含商品列表
  21. */
  22. public function page($params = [])
  23. {
  24. // 自动处理参数
  25. $this->autoParams($params);
  26. // 获取关键字和商品分类ID
  27. $keyword = $this->pg('keyword');
  28. $valid = $this->pgd([], 'valid');
  29. $good_class_id = $this->pg('good_class_id');
  30. // 构建查询条件
  31. $where = WhereBuilder::builder()
  32. ->like('no|name|desc|unit|spec', $keyword)
  33. ->eq('good_class_id', $good_class_id)
  34. ->in('valid', $valid)
  35. ->build();
  36. // 执行分页查询
  37. $page = (new Good)
  38. ->where($where)
  39. ->paginate($this->tp6Page());
  40. // 关联加载商品分类信息
  41. $page->getCollection()->append(['goodClass']);
  42. // 返回分页对象
  43. return $page;
  44. }
  45. /**
  46. * 创建商品(事务处理)
  47. *
  48. * @param array $params 参数数组
  49. * @return Good 创建的商品对象
  50. */
  51. public function createTrans($params = [])
  52. {
  53. // 使用事务处理创建商品
  54. return Db::transaction(fn() => $this->create($params));
  55. }
  56. /**
  57. * 创建商品
  58. *
  59. * @param array $params 参数数组
  60. * @return Good 创建的商品对象
  61. * @throws \Exception 如果商品编号已存在,则抛出异常
  62. */
  63. public function create($params = [])
  64. {
  65. // 自动处理参数
  66. $params = $this->autoParams($params);
  67. // 获取商品编号
  68. $no = $this->pg('no');
  69. // 获取商品分类对象
  70. $goodClass = $this->one(GoodClass::class, 'good_class_id');
  71. // 根据编号查找商品
  72. $good = Good::getByNo($no);
  73. if ($good) {
  74. throw $this->exception("编号 $no 已存在");
  75. }
  76. // 创建商品
  77. return Good::create($params);
  78. }
  79. /**
  80. * 更新商品信息
  81. *
  82. * @param array $params 参数数组
  83. * @return array 更新成功的商品对象数组
  84. * @throws \Exception 如果未选中任何商品进行更新,则抛出异常
  85. */
  86. public function update($params = [])
  87. {
  88. // 自动处理参数
  89. $params = $this->autoParams($params);
  90. if (!$params) {
  91. throw $this->exception('未选中任何商品进行更新');
  92. }
  93. // 更新商品信息并返回更新成功的商品对象数组
  94. return (new Good)->allowField(['name', 'unit', 'img', 'valid', 'spec', 'good_class_id'])->saveAll($params);
  95. }
  96. /**
  97. * 删除商品
  98. *
  99. * @param array $params 参数数组
  100. * @return int 删除的商品数量
  101. * @throws \Exception 如果非强制删除商品时,存在库存未处理,则抛出异常
  102. */
  103. public function delete($params = [])
  104. {
  105. // 自动处理参数
  106. $this->autoParams($params);
  107. // 获取商品ID和是否强制删除标志
  108. $id = $this->req('id');
  109. $force = $this->pgd(false, 'force');
  110. if (is_int($id)) {
  111. $id = [$id];
  112. }
  113. // 非强制删除时,检查仓库库存
  114. if (!$force) {
  115. foreach ($id as $i) {
  116. $num = (new Stock)->where('good_id', '=', $i)->sum('num');
  117. if ($num > 0) {
  118. $good = (new Good)->find($id);
  119. throw $this->exception("商品{$good->name}仍有库存未处理,请使用调拨/出库清理库存", 1);
  120. }
  121. }
  122. }
  123. // 删除商品并返回删除的商品数量
  124. return Good::destroy($id);
  125. }
  126. /**
  127. * 导入商品数据
  128. *
  129. * @return \think\Response 导入结果的响应对象
  130. * @throws \think\Exception\ValidateException 如果上传文件格式或大小不符合要求,则抛出验证异常
  131. * @throws \think\Exception 如果上传图片失败,则抛出异常
  132. */
  133. public function import()
  134. {
  135. // 获取表单上传文件
  136. $files = request()->file();
  137. // 验证上传文件格式和大小
  138. $this->validate($files, Validate::rule(['file' => 'fileSize:20480000|fileExt:csv,xlsx']));
  139. $file = request()->file('file');
  140. try {
  141. $path = Filesystem::putFile('execl', $file);
  142. } catch (\Exception $e) {
  143. throw $this->warpException($e, '上传图片失败:\n');
  144. }
  145. // 读取导入的数据
  146. $data = PhpSpreadsheetImport::readData(runtime_path('../storage') . $path);
  147. static $MAP = [
  148. 'A' => 'no',
  149. 'B' => 'name',
  150. 'C' => 'desc',
  151. 'D' => 'unit',
  152. 'E' => 'img',
  153. 'F' => 'spec',
  154. 'G' => 'good_class_id'
  155. ];
  156. /**
  157. * @var GoodClassService $service
  158. */
  159. static $service;
  160. if (!$service) {
  161. $service = (new GoodClassService($this->app))->exceptionClass($this->exceptionClass);
  162. }
  163. $goods = [];
  164. // 处理导入的每一行数据
  165. foreach ($data as $row) {
  166. $good = [];
  167. foreach ($row as $key => $value) {
  168. $newKey = $MAP[$key];
  169. // 如果是分类字段,则替换为对应的ID,如果分类不存在则创建
  170. if ($newKey == 'good_class_id') {
  171. $class = (new GoodClass)->cache()->where('name', '=', $value)->find();
  172. if (!$class) {
  173. $class = $service->create(['name' => $value]);
  174. }
  175. $value = $class->id;
  176. }
  177. $good[$newKey] = $value;
  178. }
  179. $goods[] = $good;
  180. }
  181. // 批量保存商品数据
  182. $goods = (new Good)->saveAll($goods);
  183. return Result::rest(true, 0, "成功{$goods->count()}个");
  184. }
  185. /**
  186. * 导出商品数据
  187. *
  188. * @param array $params 导出参数
  189. * @return mixed 导出结果
  190. */
  191. public function export($params = [])
  192. {
  193. $this->autoParams($params);
  194. $keyword = $this->pg('name');
  195. $repo_id = $this->pg('repo_id');
  196. // 构建查询条件
  197. $where = WhereBuilder::builder()
  198. ->like('name', $keyword)
  199. ->in('repo_id', $repo_id)
  200. ->build();
  201. $header = [
  202. [
  203. 'id',
  204. '序号',
  205. '名称',
  206. '介绍',
  207. '单位',
  208. '图片地址',
  209. '创建时间',
  210. '更新时间',
  211. '删除时间',
  212. '状态',
  213. '规格',
  214. '类别id',
  215. '类别名称'
  216. ]
  217. ];
  218. // 查询商品数据,并关联查询商品类别信息
  219. $goods = (new Good)
  220. ->field('g.*, c.name as class_name')
  221. ->alias('g')
  222. ->join('good_class c', 'c.id = g.good_class_id', 'LEFT')
  223. ->where($where)
  224. ->select()
  225. ->map(fn(Good $good) => $good->getData())
  226. ->each(function (array $good) {
  227. // 格式化商品状态字段
  228. $good['valid'] = $good['valid'] ? '启用' : '禁用';
  229. return $good;
  230. });
  231. // 导出商品数据
  232. $res = PhpSpreadsheetExportV2::outputFile(
  233. $goods,
  234. $header,
  235. 'good' . date('Ymdis'),
  236. []
  237. );
  238. return $res;
  239. }
  240. }