密文列 */ private const SECRET_FIELDS = ['app_secret', 'mch_key', 'mch_private_key']; public function __construct() { parent::__construct(); $this->model = WxAppModel::class; $this->selectField = [ 'id', 'code', 'name', 'app_id', 'mch_id', 'mch_serial_no', 'notify_url', 'template_code', 'status', 'remark', 'created_at', 'updated_at', ]; $this->queryField = ['code' => '=', 'name' => 'like', 'status' => '=']; $this->orderBy = ['name' => 'id', 'sort' => 'asc']; } public function list(): array { $result = $this->getPageList(); foreach ($result['items'] as &$item) { $item = $this->withSecretFlags($item); } unset($item); return $result; } public function option(): mixed { $this->optionField = ['id', 'name', 'code']; return $this->getOption(); } public function detail($id): mixed { $info = $this->getDetail($id); return $this->withSecretFlags(is_array($info) ? $info : $info->toArray()); } public function create($params): mixed { return $this->insert($this->encryptSecrets($params)); } public function update($id, $params): mixed { return $this->save($id, $this->encryptSecrets($params)); } public function delete($ids): mixed { return $this->del($ids); } public function status($id, $status): mixed { return $this->save($id, ['status' => (int) $status]); } /** * 按 .env 的 WX_DEFAULT_APP_CODE / WX_APP_ID 引导落库一条空密钥记录 * 方便首次部署:先建壳子,再进后台填 AppSecret(密钥仍不进 .env) */ public function initFromEnv(): array { $code = trim((string) config('nl.wx.default_app_code', '')); $appId = trim((string) config('nl.wx.env_app_id', '')); $name = trim((string) config('nl.wx.env_app_name', '')); if ($code === '' || $appId === '') { $this->utils->errorThrow('请先在 .env 配置 WX_DEFAULT_APP_CODE 与 WX_APP_ID,再点初始化'); } $row = WxAppModel::where('code', $code)->where('deleted_at', 0)->first(); if (!empty($row)) { $row->update([ 'app_id' => $appId, 'name' => $name !== '' ? $name : $row->name, 'updated_at' => time(), ]); return [ 'created' => false, 'id' => (int) $row->id, 'code' => $code, 'app_id' => $appId, 'app_secret_set' => trim((string) ($row->app_secret ?? '')) !== '', 'message' => '已更新 AppID/名称,请编辑该行填写 AppSecret', ]; } $id = WxAppModel::insertGetId([ 'code' => $code, 'name' => $name !== '' ? $name : $code, 'app_id' => $appId, 'status' => 0, 'created_at' => time(), 'updated_at' => time(), ]); return [ 'created' => true, 'id' => (int) $id, 'code' => $code, 'app_id' => $appId, 'app_secret_set' => false, 'message' => '已创建应用记录,请编辑填写 AppSecret', ]; } /** * 加密要落库的密钥;留空表示不改动 */ private function encryptSecrets(array $params): array { $encrypt = FieldEncryptService::getInstance(); foreach (self::SECRET_FIELDS as $field) { if (!array_key_exists($field, $params)) { continue; } $value = trim((string) $params[$field]); if ($value === '') { unset($params[$field]); continue; } if ($encrypt->isEncrypted($value)) { continue; } $params[$field] = $encrypt->encryptForStorage($value); } return $params; } /** * 只告诉前端「配没配」,不回显密文也不回显明文 */ private function withSecretFlags(array $row): array { $raw = WxAppModel::where('id', $row['id'] ?? 0)->first(self::SECRET_FIELDS); foreach (self::SECRET_FIELDS as $field) { $row[$field . '_set'] = !empty($raw[$field] ?? ''); unset($row[$field]); } return $row; } }