Product.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. <?php
  2. /**
  3. * 产品管理控制器
  4. */
  5. namespace app\admin\controller\package;
  6. use app\common\controller\Backend;
  7. use ba\Filesystem;
  8. use think\facade\Db;
  9. class Product extends Backend
  10. {
  11. protected array $noNeedLogin = ['*'];
  12. /**
  13. * 产品列表
  14. * @return void
  15. */
  16. public function index():void
  17. {
  18. $where = [];
  19. // 产品名称搜索
  20. if (!empty($this->request->get('name'))) {
  21. $name = $this->request->get('name');
  22. $where[] = ['p.name', 'like', '%' . $name . '%'];
  23. }
  24. // 产品编码搜索
  25. if (!empty($this->request->get('code'))) {
  26. $code = $this->request->get('code');
  27. $where[] = ['p.code', 'like', '%' . $code . '%'];
  28. }
  29. // 产品类型筛选
  30. if (!empty($this->request->get('type'))) {
  31. $type = $this->request->get('type');
  32. $where['p.type'] = $type;
  33. }
  34. // 分类筛选
  35. if (!empty($this->request->get('category_id'))) {
  36. $categoryId = $this->request->get('category_id');
  37. $where['p.category_id'] = $categoryId;
  38. }
  39. // 库存状态筛选
  40. if (!empty($this->request->get('stock_status'))) {
  41. $stockStatus = $this->request->get('stock_status');
  42. $where['p.stock_status'] = $stockStatus;
  43. }
  44. // 产品状态筛选
  45. if (!empty($this->request->get('status'))) {
  46. $status = $this->request->get('status');
  47. $where['p.status'] = $status;
  48. }
  49. // 排序
  50. $order = [];
  51. if (!empty($this->request->get('order'))) {
  52. $order_a = $this->request->get('order');
  53. $order_a = explode(',', $order_a);
  54. $order[$order_a[0]] = $order_a[1];
  55. } else {
  56. $order['p.sort'] = 'asc';
  57. $order['p.id'] = 'desc';
  58. }
  59. // 分页
  60. $page = $this->request->param('page', 1);
  61. $limit = $this->request->param('limit', 20);
  62. // 查询数据
  63. $productList = Db::name('product')
  64. ->alias('p')
  65. ->leftJoin('package pk', 'p.package_id = pk.id')
  66. ->field('p.*, pk.name as package_name')
  67. ->where($where)
  68. ->order($order)
  69. ->paginate([
  70. 'list_rows' => $limit,
  71. 'page' => $page
  72. ]);
  73. // 转换图片字段
  74. $list = $productList->items();
  75. // foreach ($list as &$item) {
  76. // if (!empty($item['image'])) {
  77. // $item['image'] = json_decode($item['image'], true);
  78. // } else {
  79. // $item['image'] = [];
  80. // }
  81. //
  82. // if (!empty($item['key_attributes'])) {
  83. // $item['key_attributes'] = json_decode($item['key_attributes'], true);
  84. // } else {
  85. // $item['key_attributes'] = [];
  86. // }
  87. // }
  88. $this->success('查询成功', [
  89. 'list' => $list,
  90. 'total' => $productList->total()
  91. ]);
  92. }
  93. /**
  94. * 新增/编辑产品
  95. * @return void
  96. */
  97. public function edit():void
  98. {
  99. $id = $this->request->post('id');
  100. $name = $this->request->post('name');
  101. // $code = $this->request->post('code');
  102. $packageId = $this->request->post('package_id');
  103. $description = $this->request->post('description', '');
  104. $detail = $this->request->post('detail', '');
  105. $keyAttributes = $this->request->post('key_attributes', []);
  106. $image = $this->request->post('image');
  107. $stockStatus = $this->request->post('stock_status', 1);
  108. $status = $this->request->post('status', 1);
  109. $sort = $this->request->post('sort', 0);
  110. $type = $this->request->post('type', 0);
  111. $link = $this->request->post('link', 0);
  112. if (empty($name)) {
  113. $this->error(__('产品名称不能为空'));
  114. }
  115. if (empty($link)) {
  116. $this->error(__('产品链接不能为空'));
  117. }
  118. if (empty($packageId)) {
  119. $this->error(__('请选择套餐'));
  120. }
  121. // 验证套餐是否存在
  122. $packageInfo = Db::name('package')
  123. ->where('id', $packageId)
  124. ->find();
  125. if (!$packageInfo) {
  126. $this->error(__('选择的套餐不存在'));
  127. }
  128. // 处理图片和属性字段
  129. if (empty($image)) {
  130. $image = "";
  131. }
  132. if (!is_array($keyAttributes)) {
  133. $keyAttributes = [];
  134. }
  135. $data = [
  136. 'name' => $name,
  137. // 'code' => $code,
  138. 'package_id' => $packageId ?: null,
  139. 'description' => $description,
  140. 'detail' => $detail,
  141. 'key_attributes' => json_encode($keyAttributes, JSON_UNESCAPED_UNICODE),
  142. 'image' => $image,
  143. 'stock_status' => $stockStatus,
  144. 'status' => $status,
  145. 'sort' => $sort,
  146. 'type' => $type,
  147. 'link' =>$link,
  148. 'update_time' => date('Y-m-d H:i:s')
  149. ];
  150. try {
  151. if (!empty($id)) {
  152. // 编辑
  153. $productInfo = Db::name('product')
  154. ->where('id', $id)
  155. ->find();
  156. if (!$productInfo) {
  157. $this->error(__('产品不存在'));
  158. }
  159. $result = Db::name('product')
  160. ->where('id', $id)
  161. ->update($data);
  162. $message = '编辑成功';
  163. } else {
  164. // 新增
  165. $data['create_time'] = date('Y-m-d H:i:s');
  166. $result = Db::name('product')
  167. ->insert($data);
  168. $id = Db::name('product')->getLastInsID();
  169. $message = '新增成功';
  170. }
  171. } catch (\Exception $e) {
  172. $this->error('操作失败: ' . $e->getMessage());
  173. }
  174. if ($result) {
  175. $this->success($message, ['id' => $id]);
  176. } else {
  177. $this->error(__('操作失败'));
  178. }
  179. }
  180. /**
  181. * 删除产品
  182. * @return void
  183. */
  184. public function delete():void
  185. {
  186. $id = $this->request->post('id');
  187. if (empty($id)) {
  188. $this->error(__('参数错误'));
  189. }
  190. // 检查是否有订单关联
  191. $hasOrder = Db::name('order_item')
  192. ->where('product_id', $id)
  193. ->count();
  194. if ($hasOrder > 0) {
  195. $this->error(__('该产品已有订单记录,不能删除'));
  196. }
  197. try {
  198. $result = Db::name('product')
  199. ->where('id', $id)
  200. ->delete();
  201. } catch (\Exception $e) {
  202. $this->error('删除失败: ' . $e->getMessage());
  203. }
  204. if ($result) {
  205. $this->success('删除成功');
  206. } else {
  207. $this->error(__('删除失败'));
  208. }
  209. }
  210. /**
  211. * 产品详情
  212. * @return void
  213. */
  214. public function detail():void
  215. {
  216. $id = $this->request->get('id');
  217. if (empty($id)) {
  218. $this->error(__('参数错误'));
  219. }
  220. // 获取产品基础信息
  221. $productInfo = Db::name('product')
  222. ->alias('p')
  223. ->leftJoin('package pk', 'p.package_id = pk.id')
  224. ->where('p.id', $id)
  225. ->field('p.*, pk.name as package_name, pk.type as package_type')
  226. ->find();
  227. if (!$productInfo) {
  228. $this->error(__('产品不存在'));
  229. }
  230. // 获取所属套餐下的其他产品
  231. $samePackageProducts = Db::name('product')
  232. ->where('package_id', $productInfo['package_id'])
  233. ->where('id', '<>', $id)
  234. ->field('id, name, code')
  235. ->order('sort', 'asc')
  236. ->select()
  237. ->toArray();
  238. // 获取订单数量
  239. $orderCount = Db::name('order_item')
  240. ->where('product_id', $id)
  241. ->count();
  242. $result = [
  243. 'product_info' => $productInfo,
  244. 'same_package_products' => $samePackageProducts,
  245. 'order_count' => $orderCount
  246. ];
  247. $this->success('查询成功', $result);
  248. }
  249. /**
  250. * 批量更新产品状态
  251. * @return void
  252. */
  253. public function batchStatus():void
  254. {
  255. $ids = $this->request->post('ids');
  256. $status = $this->request->post('status');
  257. if (empty($ids) || empty($status)) {
  258. $this->error(__('参数错误'));
  259. }
  260. if (!is_array($ids)) {
  261. $ids = explode(',', $ids);
  262. }
  263. try {
  264. $result = Db::name('product')
  265. ->whereIn('id', $ids)
  266. ->update([
  267. 'status' => $status,
  268. 'update_time' => date('Y-m-d H:i:s')
  269. ]);
  270. } catch (\Exception $e) {
  271. $this->error('操作失败: ' . $e->getMessage());
  272. }
  273. if ($result) {
  274. $statusText = $status == 1 ? '上架' : '下架';
  275. $this->success("成功{$statusText}{$result}个产品");
  276. } else {
  277. $this->error(__('操作失败'));
  278. }
  279. }
  280. /**
  281. * 批量更新库存状态
  282. * @return void
  283. */
  284. public function batchStockStatus():void
  285. {
  286. $ids = $this->request->post('ids');
  287. $stockStatus = $this->request->post('stock_status');
  288. if (empty($ids) || empty($stockStatus)) {
  289. $this->error(__('参数错误'));
  290. }
  291. if (!is_array($ids)) {
  292. $ids = explode(',', $ids);
  293. }
  294. try {
  295. $result = Db::name('product')
  296. ->whereIn('id', $ids)
  297. ->update([
  298. 'stock_status' => $stockStatus,
  299. 'update_time' => date('Y-m-d H:i:s')
  300. ]);
  301. } catch (\Exception $e) {
  302. $this->error('操作失败: ' . $e->getMessage());
  303. }
  304. if ($result) {
  305. $statusText = [
  306. 1 => '充足',
  307. 2 => '缺货',
  308. 3 => '下架'
  309. ][$stockStatus] ?? '未知';
  310. $this->success("成功更新{$result}个产品的库存状态为{$statusText}");
  311. } else {
  312. $this->error(__('操作失败'));
  313. }
  314. }
  315. /**
  316. * 添加/编辑产品规格
  317. * @return void
  318. */
  319. public function editSpec():void
  320. {
  321. $id = $this->request->post('id');
  322. $productId = $this->request->post('product_id');
  323. $name = $this->request->post('name');
  324. $value = $this->request->post('value', []);
  325. $sort = $this->request->post('sort', 0);
  326. if (empty($productId) || empty($name)) {
  327. $this->error(__('参数不完整'));
  328. }
  329. // 检查产品是否存在
  330. $productInfo = Db::name('product')
  331. ->where('id', $productId)
  332. ->find();
  333. if (!$productInfo) {
  334. $this->error(__('产品不存在'));
  335. }
  336. // 处理规格值
  337. if (!is_array($value)) {
  338. $value = [];
  339. }
  340. $data = [
  341. 'product_id' => $productId,
  342. 'name' => $name,
  343. 'value' => json_encode($value, JSON_UNESCAPED_UNICODE),
  344. 'sort' => $sort
  345. ];
  346. try {
  347. if (!empty($id)) {
  348. // 编辑
  349. $result = Db::name('product_spec')
  350. ->where('id', $id)
  351. ->update($data);
  352. $message = '编辑成功';
  353. } else {
  354. // 新增
  355. $data['create_time'] = date('Y-m-d H:i:s');
  356. $result = Db::name('product_spec')
  357. ->insert($data);
  358. $id = Db::name('product_spec')->getLastInsID();
  359. $message = '新增成功';
  360. }
  361. } catch (\Exception $e) {
  362. $this->error('操作失败: ' . $e->getMessage());
  363. }
  364. if ($result) {
  365. $this->success($message, ['id' => $id]);
  366. } else {
  367. $this->error(__('操作失败'));
  368. }
  369. }
  370. /**
  371. * 删除产品规格
  372. * @return void
  373. */
  374. public function deleteSpec():void
  375. {
  376. $id = $this->request->post('id');
  377. if (empty($id)) {
  378. $this->error(__('参数错误'));
  379. }
  380. try {
  381. $result = Db::name('product_spec')
  382. ->where('id', $id)
  383. ->delete();
  384. } catch (\Exception $e) {
  385. $this->error('删除失败: ' . $e->getMessage());
  386. }
  387. if ($result) {
  388. $this->success('删除成功');
  389. } else {
  390. $this->error(__('删除失败'));
  391. }
  392. }
  393. /**
  394. * 获取产品规格列表
  395. * @return void
  396. */
  397. public function specList():void
  398. {
  399. $productId = $this->request->get('product_id');
  400. if (empty($productId)) {
  401. $this->error(__('参数错误'));
  402. }
  403. $specList = Db::name('product_spec')
  404. ->where('product_id', $productId)
  405. ->order('sort', 'asc')
  406. ->select()
  407. ->toArray();
  408. foreach ($specList as &$spec) {
  409. if (!empty($spec['value'])) {
  410. $spec['value'] = json_decode($spec['value'], true);
  411. } else {
  412. $spec['value'] = [];
  413. }
  414. }
  415. $this->success('查询成功', $specList);
  416. }
  417. /**
  418. * 获取产品状态选项
  419. * @return void
  420. */
  421. public function statusOptions():void
  422. {
  423. $options = [
  424. ['value' => 1, 'label' => '上架'],
  425. ['value' => 2, 'label' => '下架']
  426. ];
  427. $this->success('获取成功', $options);
  428. }
  429. /**
  430. * 获取库存状态选项
  431. * @return void
  432. */
  433. public function stockStatusOptions():void
  434. {
  435. $options = [
  436. ['value' => 1, 'label' => '充足'],
  437. ['value' => 2, 'label' => '缺货'],
  438. ['value' => 3, 'label' => '下架']
  439. ];
  440. $this->success('获取成功', $options);
  441. }
  442. /**
  443. * 导出产品列表
  444. * @return void
  445. */
  446. public function export():void
  447. {
  448. $where = [];
  449. // 根据筛选条件构建查询条件
  450. if (!empty($this->request->get('name'))) {
  451. $name = $this->request->get('name');
  452. $where[] = ['p.name', 'like', '%' . $name . '%'];
  453. }
  454. if (!empty($this->request->get('status'))) {
  455. $status = $this->request->get('status');
  456. $where['p.status'] = $status;
  457. }
  458. // 查询数据
  459. $productList = Db::name('product')
  460. ->alias('p')
  461. ->leftJoin('product_category pc', 'p.category_id = pc.id')
  462. ->field('p.id, p.name, p.code, pc.name as category_name,
  463. p.stock_status, p.status, p.sort, p.create_time')
  464. ->where($where)
  465. ->order('p.sort', 'asc')
  466. ->order('p.id', 'desc')
  467. ->select()
  468. ->toArray();
  469. // 状态映射
  470. $stockStatusMap = [1 => '充足', 2 => '缺货', 3 => '下架'];
  471. $statusMap = [1 => '上架', 2 => '下架'];
  472. foreach ($productList as &$item) {
  473. $item['stock_status'] = $stockStatusMap[$item['stock_status']] ?? '未知';
  474. $item['status'] = $statusMap[$item['status']] ?? '未知';
  475. }
  476. $this->success('查询成功', $productList);
  477. }
  478. }