首页/ phph5/ 甜趣蛋糕 · 烘焙蛋糕店 PHP+H5 商城 + 商家后台/ 代码预览

💻 代码预览 · 甜趣蛋糕 · 烘焙蛋糕店 PHP+H5 商城 + 商家后台

ph_mall · 上传者 驰旭教育
← 返回详情
r117/app/controllers/AdminController.php · 约 13305 字符
1<?php2/**3 * 后台管理 API(商户端)4 * 写操作统一经 guardWrite() 拦截:ADMIN_READ_ONLY=true 时拒绝写入(后台只读)。5 */6class AdminController extends Controller {7    private function imgStr($arr) { return is_array($arr) ? implode('|', $arr) : (string)$arr; }89    public function login() {10        $user = trim((string)$this->input('user', ''));11        $pass = trim((string)$this->input('pass', ''));12        if ($user === ADMIN_USER && $pass === ADMIN_PASS) {13            $this->json(['ok' => 1, 'token' => 'demo-token', 'msg' => '登录成功']);14        }15        $this->json(['ok' => 0, 'msg' => '账号或密码错误'], 401);16    }1718    // 后台全局配置(含只读开关状态)19    public function config() {20        $this->json([21            'ok' => 1,22            'read_only' => defined('ADMIN_READ_ONLY') ? ADMIN_READ_ONLY : false,23            'admin_user' => ADMIN_USER,24            'site_name' => SITE_NAME25        ]);26    }2728    // 数据看板29    public function dashboard() {30        $d = [];31        $d['sales_today'] = (float)$this->db->query("SELECT COALESCE(SUM(pay_amount),0) FROM orders WHERE status<>'canceled' AND DATE(created_at)=DATE('now','localtime')")->fetchColumn();32        $d['orders_today'] = (int)$this->db->query("SELECT COUNT(*) FROM orders WHERE DATE(created_at)=DATE('now','localtime')")->fetchColumn();33        $d['order_total'] = (int)$this->db->query("SELECT COUNT(*) FROM orders")->fetchColumn();34        $d['member_total'] = (int)$this->db->query("SELECT COUNT(*) FROM members")->fetchColumn();35        $d['product_total'] = (int)$this->db->query("SELECT COUNT(*) FROM products")->fetchColumn();36        $d['review_total'] = (int)$this->db->query("SELECT COUNT(*) FROM reviews")->fetchColumn();37        $d['pending_orders'] = (int)$this->db->query("SELECT COUNT(*) FROM orders WHERE status IN ('paid','making')")->fetchColumn();38        // 近 7 日销售额39        $trend = $this->db->query("SELECT DATE(created_at) AS d, COALESCE(SUM(pay_amount),0) AS s FROM orders WHERE created_at >= datetime('now','-6 days','localtime') AND status<>'canceled' GROUP BY DATE(created_at) ORDER BY d")->fetchAll();40        $d['trend'] = $trend;41        // 热销 TOP542        $top = $this->db->query("SELECT p.name, SUM(oi.qty) AS qty FROM order_items oi JOIN products p ON p.id=oi.product_id GROUP BY oi.product_id ORDER BY qty DESC LIMIT 5")->fetchAll();43        $d['top_products'] = $top;44        // 会员等级分布45        $lv = $this->db->query("SELECT level, COUNT(*) AS c FROM members GROUP BY level")->fetchAll();46        $d['level_dist'] = $lv;47        $this->json(['ok' => 1, 'data' => $d]);48    }4950    // ---- 商品 ----51    public function products_list() {52        $rows = $this->db->query("SELECT p.*, c.name AS kind_name FROM products p LEFT JOIN categories c ON c.id=p.kind_id ORDER BY p.id DESC")->fetchAll();53        $data = array_map(function ($p) {54            return [55                'id' => $p['id'], 'name' => $p['name'], 'kind_name' => $p['kind_name'],56                'price' => (float)$p['price'], 'original_price' => (float)$p['original_price'],57                'sales' => (int)$p['sales'], 'stock' => (int)$p['stock'], 'status' => (int)$p['status'],58                'is_new' => (int)$p['is_new'], 'is_hot' => (int)$p['is_hot'], 'is_recommend' => (int)$p['is_recommend'],59                'scenes' => $p['scenes']60            ];61        }, $rows);62        $this->json(['ok' => 1, 'data' => $data]);63    }6465    public function product_save() {66        $this->guardWrite();67        $id = (int)$this->input('id', 0);68        $data = [69            'name' => trim((string)$this->input('name', '未命名蛋糕')),70            'kind_id' => (int)$this->input('kind_id', 0),71            'scenes' => trim((string)$this->input('scenes', '')),72            'price' => (float)$this->input('price', 0),73            'original_price' => (float)$this->input('original_price', 0),74            'stock' => (int)$this->input('stock', 99),75            'is_new' => (int)$this->input('is_new', 0),76            'is_hot' => (int)$this->input('is_hot', 0),77            'is_recommend' => (int)$this->input('is_recommend', 0),78            'description' => trim((string)$this->input('description', '')),79            'ingredients' => trim((string)$this->input('ingredients', '')),80            'allergen' => trim((string)$this->input('allergen', '')),81            'shelf_life' => trim((string)$this->input('shelf_life', '')),82            'advice' => trim((string)$this->input('advice', '')),83            'images' => $this->imgStr($this->input('images', '🎂')),84            'tags' => trim((string)$this->input('tags', '')),85        ];86        if ($id) {87            (new ProductModel())->update($id, $data);88            $this->json(['ok' => 1, 'id' => $id, 'msg' => '已更新']);89        } else {90            $newId = (new ProductModel())->create($data);91            // 新商品默认生成 4 尺寸 × 原味 SKU92            $ins = $this->db->prepare("INSERT INTO skus (product_id,size,flavor,price,stock) VALUES (?,?,?,?,?)");93            $base = $data['price'] ?: 168;94            foreach (['6寸' => 0.7, '8寸' => 1.0, '10寸' => 1.35, '12寸' => 1.7] as $sz => $mul) {95                $ins->execute([$newId, $sz, '原味', round($base * $mul), 99]);96            }97            $this->json(['ok' => 1, 'id' => $newId, 'msg' => '已新增']);98        }99    }100101    public function product_delete() {102        $this->guardWrite();103        $id = (int)$this->input('id', 0);104        (new ProductModel())->delete($id);105        $this->db->prepare("DELETE FROM skus WHERE product_id=?")->execute([$id]);106        $this->json(['ok' => 1]);107    }108109    public function product_toggle() {110        $this->guardWrite();111        $id = (int)$this->input('id', 0);112        $st = $this->db->prepare("UPDATE products SET status = 1 - status WHERE id=?");113        $st->execute([$id]);114        $this->json(['ok' => 1]);115    }116117    // ---- 订单 ----118    public function orders_list() {119        $status = trim((string)$this->input('status', ''));120        $sql = "SELECT * FROM orders";121        $params = [];122        if ($status) { $sql .= " WHERE status=?"; $params[] = $status; }123        $sql .= " ORDER BY id DESC LIMIT 200";124        $st = $this->db->prepare($sql);125        $st->execute($params);126        $this->json(['ok' => 1, 'data' => $st->fetchAll()]);127    }128129    public function order_detail() {130        $id = (int)$this->input('id', 0);131        $o = (new OrderModel())->find($id);132        if (!$o) $this->json(['ok' => 0, 'msg' => '订单不存在'], 404);133        $it = $this->db->prepare("SELECT * FROM order_items WHERE order_id=?");134        $it->execute([$id]);135        $this->json(['ok' => 1, 'order' => array_merge($o, ['items' => $it->fetchAll()])]);136    }137138    public function order_update_status() {139        $this->guardWrite();140        $id = (int)$this->input('id', 0);141        $status = trim((string)$this->input('status', ''));142        (new OrderModel())->update($id, ['status' => $status]);143        $this->json(['ok' => 1, 'msg' => '状态已更新']);144    }145146    // ---- 会员 ----147    public function members_list() {148        $rows = (new MemberModel())->all();149        $data = array_map(fn($m) => [150            'id' => $m['id'], 'username' => $m['username'], 'phone' => $m['phone'],151            'level' => $m['level'], 'points' => (int)$m['points'], 'balance' => (float)$m['balance'],152            'growth' => (int)$m['growth'], 'birthday' => $m['birthday'], 'status' => (int)$m['status']153        ], $rows);154        $this->json(['ok' => 1, 'data' => $data]);155    }156157    public function member_save() {158        $this->guardWrite();159        $id = (int)$this->input('id', 0);160        $data = [161            'username' => trim((string)$this->input('username', '')),162            'phone' => trim((string)$this->input('phone', '')),163            'level' => trim((string)$this->input('level', 'normal')),164            'points' => (int)$this->input('points', 0),165            'balance' => (float)$this->input('balance', 0),166            'growth' => (int)$this->input('growth', 0),167            'birthday' => trim((string)$this->input('birthday', '')),168        ];169        if ($id) { (new MemberModel())->update($id, $data); }170        else { $id = (new MemberModel())->create($data); }171        $this->json(['ok' => 1, 'id' => $id]);172    }173174    public function member_delete() {175        $this->guardWrite();176        (new MemberModel())->delete((int)$this->input('id', 0));177        $this->json(['ok' => 1]);178    }179180    // ---- 优惠券 ----181    public function coupons_list() {182        $rows = (new CouponModel())->all();183        $data = array_map(fn($c) => [184            'id' => $c['id'], 'name' => $c['name'], 'type' => $c['type'],185            'threshold' => (float)$c['threshold'], 'value' => (float)$c['value'],186            'discount' => (float)$c['discount'], 'valid_days' => (int)$c['valid_days'],187            'total' => (int)$c['total'], 'received' => (int)$c['received'], 'used' => (int)$c['used'],188            'status' => (int)$c['status']189        ], $rows);190        $this->json(['ok' => 1, 'data' => $data]);191    }192193    public function coupon_save() {194        $this->guardWrite();195        $id = (int)$this->input('id', 0);196        $data = [197            'name' => trim((string)$this->input('name', '新券')),198            'type' => trim((string)$this->input('type', 'full_reduce')),199            'threshold' => (float)$this->input('threshold', 0),200            'value' => (float)$this->input('value', 0),201            'discount' => (float)$this->input('discount', 1),202            'valid_days' => (int)$this->input('valid_days', 30),203            'total' => (int)$this->input('total', 999),204            'status' => (int)$this->input('status', 1),205        ];206        if ($id) { (new CouponModel())->update($id, $data); }207        else { $id = (new CouponModel())->create($data); }208        $this->json(['ok' => 1, 'id' => $id]);209    }210211    public function coupon_delete() {212        $this->guardWrite();213        (new CouponModel())->delete((int)$this->input('id', 0));214        $this->json(['ok' => 1]);215    }216217    // ---- 评价 ----218    public function reviews_list() {219        $st = $this->db->query("SELECT r.*, p.name AS pname, m.username FROM reviews r LEFT JOIN products p ON p.id=r.product_id LEFT JOIN members m ON m.id=r.member_id ORDER BY r.id DESC");220        $this->json(['ok' => 1, 'data' => $st->fetchAll()]);221    }222223    public function review_reply() {224        $this->guardWrite();225        $id = (int)$this->input('id', 0);226        (new ReviewModel())->update($id, ['reply' => trim((string)$this->input('reply', ''))]);227        $this->json(['ok' => 1]);228    }229230    public function review_delete() {231        $this->guardWrite();232        (new ReviewModel())->delete((int)$this->input('id', 0));233        $this->json(['ok' => 1]);234    }235236    // ---- 轮播 ----237    public function banners_list() {238        $this->json(['ok' => 1, 'data' => (new BannerModel())->all()]);239    }240241    public function banner_save() {242        $this->guardWrite();243        $id = (int)$this->input('id', 0);244        $data = [245            'title' => trim((string)$this->input('title', '')),246            'image' => trim((string)$this->input('image', '🎂')),247            'link' => trim((string)$this->input('link', '#home')),248            'sort' => (int)$this->input('sort', 0),249            'status' => (int)$this->input('status', 1),250        ];251        if ($id) { (new BannerModel())->update($id, $data); }252        else { $id = (new BannerModel())->create($data); }253        $this->json(['ok' => 1, 'id' => $id]);254    }255256    public function banner_delete() {257        $this->guardWrite();258        (new BannerModel())->delete((int)$this->input('id', 0));259        $this->json(['ok' => 1]);260    }261262    // ---- 定制需求 ----263    public function custom_list() {264        $st = $this->db->query("SELECT c.*, m.username FROM custom_cakes c LEFT JOIN members m ON m.id=c.member_id ORDER BY c.id DESC");265        $this->json(['ok' => 1, 'data' => $st->fetchAll()]);266    }267268    public function custom_update() {269        $this->guardWrite();270        $id = (int)$this->input('id', 0);271        (new CustomCakeModel())->update($id, ['status' => trim((string)$this->input('status', 'approved'))]);272        $this->json(['ok' => 1]);273    }274275    // ---- 设置 ----276    public function settings_get() {277        $rs = $this->db->query("SELECT k,v FROM settings");278        $data = [];279        foreach ($rs as $row) $data[$row['k']] = $row['v'];280        $data['read_only'] = defined('ADMIN_READ_ONLY') ? ADMIN_READ_ONLY : false;281        $this->json(['ok' => 1, 'data' => $data]);282    }283284    public function settings_save() {285        $this->guardWrite();286        $keys = ['shop_name','phone','address','delivery_fee','free_delivery_amount','delivery_range_km','delivery_advance_hours','open_time','notice'];287        foreach ($keys as $k) {288            $v = $this->input($k, null);289            if ($v !== null) {290                $this->db->prepare("INSERT INTO settings (k,v) VALUES (?,?) ON CONFLICT(k) DO UPDATE SET v=excluded.v")291                    ->execute([$k, trim((string)$v)]);292            }293        }294        $this->json(['ok' => 1, 'msg' => '设置已保存']);295    }296}297