158 lines
4.8 KiB
PHP
158 lines
4.8 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
namespace App\Service;
|
|||
|
|
|
|||
|
|
use App\BaseApp\BaseService;
|
|||
|
|
use App\Models\WxAppModel;
|
|||
|
|
use App\Service\common\FieldEncryptService;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 小程序应用配置管理(后台)
|
|||
|
|
*
|
|||
|
|
* 密钥列只写不读:列表与详情一律返回掩码,前端留空表示不修改。
|
|||
|
|
* 这么做的原因是老项目把 AppSecret 明文放源码里、还进了 git 历史。
|
|||
|
|
*/
|
|||
|
|
class WxAppConfigService extends BaseService
|
|||
|
|
{
|
|||
|
|
/**
|
|||
|
|
* @var array<int, string> 密文列
|
|||
|
|
*/
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|