// +---------------------------------------------------------------------- namespace app\services\system\config; use app\dao\system\config\SystemConfigDao; use app\services\agent\AgentManageServices; use app\services\BaseServices; use crmeb\exceptions\AdminException; use crmeb\services\CacheService; use crmeb\services\FileService; use crmeb\services\FormBuilder; use think\facade\Log; /** * 系统配置 * Class SystemConfigServices * @package app\services\system\config * @method count(array $where = []) 获取指定条件下的count * @method save(array $data) 保存数据 * @method get(int $id, ?array $field = []) 获取一条数据 * @method update($id, array $data, ?string $key = null) 修改数据 * @method delete(int $id, ?string $key = null) 删除数据 * @method getUploadTypeList(string $configName) 获取上传配置中的上传类型 */ class SystemConfigServices extends BaseServices { /** * 系统配置数据访问层 * @var SystemConfigDao */ protected $dao; /** * form表单句柄 * @var FormBuilder */ protected $builder; /** * 表单数据切割符号 * @var string */ protected $cuttingStr = '=>'; /** * 表单提交url * @var string[] */ protected $postUrl = [ // 基础配置 'setting' => [ 'url' => '/setting/config/save_basics', 'auth' => [], ], // 服务配置 'serve' => [ 'url' => '/serve/sms_config/save_basics', 'auth' => ['short_letter_switch'], ], // 运费配置 'freight' => [ 'url' => '/freight/config/save_basics', 'auth' => ['express'], ], // 分销配置 'agent' => [ 'url' => '/agent/config/save_basics', 'auth' => ['fenxiao'], ], // 积分配置 'marketing' => [ 'url' => '/marketing/integral_config/save_basics', 'auth' => ['point'], ] ]; /** * 子集控制规则联动控制,新版单个配置可以配置联动,此配置为兼容旧版数据配置,不建议使用 * @var array[] */ protected $relatedRule = [ 'sign_status' => [ 'son_type' => [ 'sign_mode' => '', 'sign_remind' => [ 'son_type' => [ 'sign_remind_time' => '', 'sign_remind_type' => '', ], 'show_value' => 1 ], 'sign_give_point' => '', 'sign_give_exp' => '', ], 'show_value' => 1 ], 'brokerage_func_status' => [ 'son_type' => [ 'store_brokerage_statu' => [ 'son_type' => ['store_brokerage_price' => ''], 'show_value' => 3 ], 'brokerage_bindind' => '', 'store_brokerage_binding_status' => [ 'son_type' => ['store_brokerage_binding_time' => ''], 'show_value' => 2 ], 'spread_banner' => '', 'brokerage_level' => '', 'division_status' => '', 'agent_apply_open' => '', 'brokerage_window_switch' => '', ], 'show_value' => 1 ], 'brokerage_user_status' => [ 'son_type' => [ 'uni_brokerage_price' => '', 'day_brokerage_price_upper' => '', ], 'show_value' => 1 ], 'invoice_func_status' => [ 'son_type' => [ 'special_invoice_status' => '', ], 'show_value' => 1 ], 'member_func_status' => [ 'son_type' => [ 'order_give_exp' => '', 'invite_user_exp' => '' ], 'show_value' => 1 ], 'balance_func_status' => [ 'son_type' => [ 'recharge_attention' => '', 'recharge_switch' => '', 'store_user_min_recharge' => '', ], 'show_value' => 1 ], 'pay_wechat_type' => [ 'son_type' => [ 'pay_weixin_key' => '', ], 'show_value' => 0 ], 'pay_wechat_type@' => [ 'son_type' => [ 'pay_weixin_serial_no' => '', 'v3_transfer_scene_id' => '', 'pay_weixin_key_v3' => '', 'v3_pay_public_key' => '', 'v3_pay_public_pem' => '', ], 'show_value' => 1 ], 'image_watermark_status' => [ 'son_type' => [ 'watermark_type' => [ 'son_type' => [ 'watermark_image' => '', 'watermark_opacity' => '', 'watermark_rotate' => '', ], 'show_value' => 1 ], 'watermark_position' => '', 'watermark_x' => '', 'watermark_y' => '', 'watermark_type@' => [ 'son_type' => [ 'watermark_text' => '', 'watermark_text_size' => '', 'watermark_text_color' => '', 'watermark_text_angle' => '' ], 'show_value' => 2 ], ], 'show_value' => 1 ], 'customer_type' => [ 'son_type' => [ 'service_feedback' => '', ], 'show_value' => 0 ], 'customer_type#' => [ 'son_type' => [ 'customer_phone' => '', ], 'show_value' => 1 ], 'customer_type@' => [ 'son_type' => [ 'customer_url' => '', 'customer_corpId' => '', ], 'show_value' => 2 ], 'pay_new_weixin_open' => [ 'son_type' => [ 'pay_new_weixin_mchid' => '' ], 'show_value' => 1 ], 'mer_type' => [ 'son_type' => [ 'pay_sub_merchant_id' => '', 'sp_appid' => '' ], 'show_value' => 1 ], 'member_card_status' => [ 'son_type' => [ 'member_price_status' => '', ], 'show_value' => 1 ], ]; /** * SystemConfigServices constructor. * @param SystemConfigDao $dao * @param FormBuilder $builder */ public function __construct(SystemConfigDao $dao, FormBuilder $builder) { $this->dao = $dao; $this->builder = $builder; } /** * 获取单个系统配置 * @param string $configName * @param null $default * @return mixed|null * @throws \ReflectionException */ public function getConfigValue(string $configName, $default = null) { $value = $this->dao->getConfigValue($configName); return is_null($value) ? $default : json_decode($value, true); } /** * 获取全部配置 * @param array $configName * @return array * @throws \ReflectionException */ public function getConfigAll(array $configName = []) { return array_map(function ($item) { return json_decode($item, true); }, $this->dao->getConfigAll($configName)); } /** * 获取配置列表搜索并分页 * @param array $where * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function getConfigList(array $where) { [$page, $limit] = $this->getPageValue(); $list = $this->dao->getConfigList($where, $page, $limit); $count = $this->dao->count($where); $tidy_srr = []; $configTabList = app()->make(SystemConfigTabServices::class)->getColumn([], 'title', 'id'); foreach ($list as &$item) { $item['value'] = $item['value'] ? (json_decode($item['value'], true) ?: '') : ''; if ($item['type'] == 'radio' || $item['type'] == 'checkbox') { $item['value'] = $this->getRadioOrCheckboxValueInfo($item['menu_name'], $item['value']); } if ($item['type'] == 'upload' && !empty($item['value'])) { if ($item['upload_type'] == 1 || $item['upload_type'] == 3) { $item['value'] = [set_file_url($item['value'])]; } elseif ($item['upload_type'] == 2) { $tempValue = set_file_url($item['value']); $item['value'] = is_array($tempValue) ? $tempValue : []; } if (is_array($item['value']) && !empty($item['value'])) { foreach ($item['value'] as $key => $value) { $tidy_srr[$key]['filepath'] = $value; $tidy_srr[$key]['filename'] = basename($value); } $item['value'] = $tidy_srr; } else { $item['value'] = []; } } if ($item['level'] == 1) { $item['link_data'] = $this->getLinkData($item['link_id'], $item['link_value']); } $item['config_tab_name'] = $configTabList[$item['config_tab_id']] ?? ''; } return compact('count', 'list'); } /** * 配置列表页获取关联的值,展示:关联配置名称/关联值 * @param $id * @param $value * @return string * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException * @author wuhaotian * @email 442384644@qq.com * @date 2024/5/31 */ private function getLinkData($id, $value) { $info = $this->dao->get($id); if (!$info) return ''; $parameter = explode("\n", $info['parameter']); $result = []; foreach ($parameter as $item) { $parts = explode('=>', $item); $result[$parts[0]] = $parts[1]; } return $info['info'] . ':' . $result[$value].'(显示)'; } /** * 配置列表页获取单选按钮或者多选按钮的显示值 * @param $menu_name * @param $value * @return string * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ private function getRadioOrCheckboxValueInfo(string $menu_name, $value): string { $option = []; $config_one = $this->dao->getOne(['menu_name' => $menu_name]); if (!$config_one) { return ''; } $parameter = explode("\n", $config_one['parameter']); foreach ($parameter as $k => $v) { if (isset($v) && strlen($v) > 0) { $data = explode('=>', $v); $option[$data[0]] = $data[1]; } } $str = ''; if (is_array($value)) { foreach ($value as $v) { $str .= $option[$v] . ','; } } else { $str .= !empty($value) ? $option[$value] ?? '' : $option[0] ?? ''; } return $str; } /** * 根据配置tab id获取系统配置信息 * @param int $tabId * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function getReadList(int $tabId) { $info = $this->dao->getConfigTabAllList($tabId); foreach ($info as $k => $v) { if (!is_null(json_decode($v['value']))) $info[$k]['value'] = json_decode($v['value'], true); if ($v['type'] == 'upload' && !empty($v['value'])) { if ($v['upload_type'] == 1 || $v['upload_type'] == 3) $info[$k]['value'] = explode(',', $v['value']); } } return $info; } /** * 修改字段获取form表单 * @param int $id * @return array * @throws \FormBuilder\Exception\FormBuilderException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function editFieldForm(int $id) { $menu = $this->dao->get($id)->getData(); if (!$menu) { throw new AdminException('数据不存在'); } /** @var SystemConfigTabServices $service */ $service = app()->make(SystemConfigTabServices::class); $formbuider = []; $linkData = $this->linkData($menu['config_tab_id']); $formbuider[] = $this->builder->radio('level', '联动显示', $menu['level'])->options([['value' => 0, 'label' => '否'], ['value' => 1, 'label' => '是']])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => '否:默认正常展示此配置;是:此配置默认隐藏,当选中下方对应配置的值时,此配置才会显示'] ])->appendControl(1, [ $this->builder->cascader('link_data', '关联配置/值', [$menu['link_id'], $menu['link_value']])->options($linkData)->props(['props' => ['multiple' => false, 'checkStrictly' => false, 'emitPath' => true]])->style(['width' => '100%']), ])->requiredNum(); $formbuider[] = $this->builder->input('menu_name', '字段变量', $menu['menu_name'])->disabled(1); $formbuider[] = $this->builder->hidden('type', $menu['type']); [$configTabList, $data] = $service->getConfigTabListForm((int)($menu['config_tab_id'] ?? 0)); $formbuider[] = $this->builder->cascader('config_tab_id', '分类', $data)->options($configTabList)->filterable(true)->props(['props' => ['multiple' => false, 'checkStrictly' => true, 'emitPath' => true]])->style(['width' => '100%']); $formbuider[] = $this->builder->input('info', '配置名称', $menu['info'])->required('配置名称不能为空')->autofocus(1); $formbuider[] = $this->builder->input('desc', '配置简介', $menu['desc']); switch ($menu['type']) { case 'text': $menu['value'] = json_decode($menu['value'], true); $formbuider[] = $this->createTextInputTypeForm($menu, true); break; case 'textarea': $menu['value'] = json_decode($menu['value'], true); $formbuider[] = $this->builder->textarea('value', '默认值', $menu['value'])->rows(3); $formbuider[] = $this->builder->number('width', '文本框宽', (int)$menu['width'])->min(1)->max(24); $formbuider[] = $this->builder->number('high', '多行文本框高', (int)$menu['high'])->min(1); break; case 'radio': $formbuider = array_merge($formbuider, $this->createRadioForm($menu)); $formbuider[] = $this->builder->textarea('parameter', '配置参数', $menu['parameter'] ?? '')->rows(3)->placeholder("参数方式例如:\n1=>白色\n2=>红色\n3=>黑色"); break; case 'upload': $formbuider = array_merge($formbuider, $this->createUploadForm((int)$menu['upload_type'], $menu, true)); break; case 'checkbox': $menu['label'] = '默认值'; $formbuider = array_merge($formbuider, $this->createCheckboxForm($menu)); $formbuider[] = $this->builder->textarea('parameter', '配置参数', $menu['parameter'] ?? '')->rows(3)->placeholder("参数方式例如:\n1=>白色\n2=>红色\n3=>黑色"); break; case 'select': $formbuider = array_merge($formbuider, $this->createSelectForm($menu)); $formbuider[] = $this->builder->textarea('parameter', '配置参数', $menu['parameter'] ?? '')->rows(3)->placeholder("参数方式例如:\n1=>白色\n2=>红色\n3=>黑色"); break; case 'switch': $formbuider = array_merge($formbuider, $this->createSwitchForm($menu)); break; } // 是否必填(支持JSON格式) $requiredData = json_decode($menu['required'], true); if ($requiredData && isset($requiredData['required'])) { $menu['required'] = $requiredData['required'] ? 1 : 0; } else { $menu['required'] = $menu['required'] ? 1 : 0; } // 非switch类型,添加是否必填字段 if ($menu['type'] != 'switch') { $formbuider[] = $this->builder->radio('required', '是否必填', $menu['required'] ?? 0)->options([ ['value' => 0, 'label' => '否'], ['value' => 1, 'label' => '是'], ])->requiredNum(); } $formbuider[] = $this->builder->number('sort', '排序', (int)$menu['sort']); $formbuider[] = $this->builder->radio('status', '状态', $menu['status'] ?? 0)->options([ ['value' => 1, 'label' => '显示'], ['value' => 0, 'label' => '隐藏'], ])->requiredNum(); return create_form('编辑字段', $formbuider, $this->url('/setting/config/' . $id), 'PUT'); } /** * 创建和编辑文本类型的输入类型表单 * @param array $data 配置数据 * @param bool $isEdit 是否为编辑模式 * @return BaseForm|BaseForm[] */ private function createTextInputTypeForm(array $data, bool $isEdit = false) { // 拆分必填、格式规则和数字范围(支持JSON格式) $requiredRules = $data['required'] ?? ''; $requiredData = []; // 尝试解析JSON格式的验证规则 if ($requiredRules && $requiredData = json_decode($requiredRules, true)) { $data['required'] = isset($requiredData['required']) && $requiredData['required'] ? 'required:true' : ''; $data['regex'] = $requiredData['regex'] ?? ''; $data['min'] = $requiredData['min'] ?? ''; $data['max'] = $requiredData['max'] ?? ''; } else { // 兼容旧格式:逗号分隔的字符串格式 $data['required'] = strpos($requiredRules, 'required:true') !== false ? 'required:true' : ''; $data['regex'] = ''; $data['min'] = ''; $data['max'] = ''; // 提取 min 和 max if (preg_match('/\bmin:(-?\d+)/', $requiredRules, $minMatch)) { $data['min'] = (int)$minMatch[1]; } if (preg_match('/\bmax:(-?\d+)/', $requiredRules, $maxMatch)) { $data['max'] = (int)$maxMatch[1]; } // 提取正则表达式 if (preg_match('/regex:(\/.+\/[gimsuy]*)/', $requiredRules, $patternMatch)) { $data['regex'] = $patternMatch[1]; } } // 创建输入类型选择器 $inputTypeSelect = $this->builder->select('input_type', '类型', $data['input_type'] ?? 'input')->setOptions([ ['value' => 'input', 'label' => '文本框'], ['value' => 'number', 'label' => '数字'], ['value' => 'dateTime', 'label' => '日期时间'], ['value' => 'date', 'label' => '日期'], ['value' => 'time', 'label' => '时间'], ['value' => 'color', 'label' => '颜色'] ])->required(); // 正则表达式(输入框) $regexField = $this->builder->input('regex', '表单验证', $data['regex'] ?? '') ->placeholder('输入正则表达式,如:/^\d+$/') ->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => '邮箱:/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
手机号:/^1[3-9]\d{9}$/
URL:/^https?:\/\/.+/i
电话:/^1[3-9]\d{9}$|^0\d{2,3}-\d{7,8}$|^400-\d{3}-\d{3}$/
长度:/^.{6,20}$/'] ]); // 宽度字段 $col = isset($data['width']) && $data['width'] != 0 && $data['width'] >= 4 && $data['width'] <= 24 ? (int)$data['width'] : 13; $widthField = $this->builder->number('width', '表单框宽', $col)->min(4)->max(24); // 不同类型的默认值 $inputValue = $data['input_type'] == 'input' ? ($data['value'] ?? '') : ''; $inputValueField = $this->builder->input('value', '默认值', $inputValue); $numberValue = $data['input_type'] == 'number' ? ($data['value'] ?? '0') : ''; $numberValueField = $this->builder->input('value', '默认值', $numberValue); $dateTimeValue = $data['input_type'] == 'dateTime' ? ($data['value'] ?? date('Y-m-d H:i:s')) : ''; $dateTimeValueField = $this->builder->dateTime('value', '默认值', $dateTimeValue); $dateValue = $data['input_type'] == 'date' ? ($data['value'] ?? date('Y-m-d')) : ''; $dateValueField = $this->builder->date('value', '默认值', $dateValue); $timeValue = $data['input_type'] == 'time' ? ($data['value'] ?? date('H:i:s')) : ''; $timeValueField = $this->builder->time('value', '默认值', $timeValue); $colorValue = $data['input_type'] == 'color' ? ($data['value'] ?? '#000000') : '#000000'; $colorValueField = $this->builder->color('value', '默认值', $colorValue); // 数字类型的最小值和最大值 $numberMinField = $this->builder->input('min', '最小值', $data['min'] ?? '')->type('number'); $numberMaxField = $this->builder->input('max', '最大值', $data['max'] ?? '')->type('number'); // 根据类型联动显示不同的控件 $inputTypeSelect->appendControl('input', [$regexField, $inputValueField, $widthField]); $inputTypeSelect->appendControl('number', [$numberMinField, $numberMaxField, $numberValueField, $widthField]); $inputTypeSelect->appendControl('dateTime', [$dateTimeValueField]); $inputTypeSelect->appendControl('date', [$dateValueField]); $inputTypeSelect->appendControl('time', [$timeValueField]); $inputTypeSelect->appendControl('color', [$colorValueField]); return $inputTypeSelect; } /** * 创建单行表单 * @param string $type * @param array $data * @return array */ public function createTextForm(string $type, array $data) { $formbuider = []; $inputRule = ''; switch ($type) { case 'number': // 解析验证规则(支持 JSON 格式) $requiredRules = $data['required'] ?? ''; $requiredData = json_decode($requiredRules, true); if ($requiredData) { // JSON 格式 $data['min'] = $requiredData['min'] ?? null; $data['max'] = $requiredData['max'] ?? null; } else { // 兼容旧格式:提取 min 和 max $data['min'] = null; $data['max'] = null; if (preg_match('/\bmin:(-?\d+)/', $requiredRules, $minMatch)) { $data['min'] = (int)$minMatch[1]; } if (preg_match('/\bmax:(-?\d+)/', $requiredRules, $maxMatch)) { $data['max'] = (int)$maxMatch[1]; } } $data['value'] = isset($data['value']) ? json_decode($data['value'], true) : 0; // 最小值和最大值提示(有值才显示) $minMaxTip = ''; if (isset($data['min']) && $data['min'] !== null) { $minMaxTip = '
最小值:' . $data['min']; } if (isset($data['max']) && $data['max'] !== null) { $minMaxTip .= ($minMaxTip ? ',' : '
') . '最大值:' . $data['max']; } // 宽度字段 $col = isset($data['width']) && $data['width'] != 0 && $data['width'] >= 4 && $data['width'] <= 24 ? (int)$data['width'] : 13; $inputRule = $this->builder->number($data['menu_name'], $data['info'], (float)$data['value'])->controls(false)->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc'] . $minMaxTip] ])->col($col); break; case 'dateTime': $inputRule = $this->builder->dateTime($data['menu_name'], $data['info'], $data['value'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ]); break; case 'date': $data['value'] = json_decode($data['value'], true) ?: ''; $inputRule = $this->builder->date($data['menu_name'], $data['info'], $data['value'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ]); break; case 'time': $data['value'] = json_decode($data['value'], true) ?: ''; $inputRule = $this->builder->time($data['menu_name'], $data['info'], $data['value'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ]); break; case 'color': $data['value'] = isset($data['value']) ? json_decode($data['value'], true) : ''; $inputRule = $this->builder->color($data['menu_name'], $data['info'], $data['value'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ]); break; default: $data['value'] = isset($data['value']) ? json_decode($data['value'], true) : ''; // 如果配置项是api或routine_api,需要添加site_url,并且是只读的 if ($data['menu_name'] == 'api' || $data['menu_name'] == 'routine_api') { $inputRule = $this->builder->input($data['menu_name'], $data['info'], strpos($data['value'], 'http') === false ? sys_config('site_url') . $data['value'] : $data['value'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ])->col($data['width'] ?? 13)->readonly(true); } else { // 宽宽度设置 $col = isset($data['width']) && $data['width'] != 0 && $data['width'] >= 4 && $data['width'] <= 24 ? (int)$data['width'] : 13; $inputRule = $this->builder->input($data['menu_name'], $data['info'], $data['value'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ])->col($col)->placeholder('请输入'.$data['info']); } break; } // 是否必填项 $this->isRequired($data['required']) && $inputRule = $inputRule->required($data['info'].'不能为空'); $formbuider[] = $inputRule; return $formbuider; } /** * 创建多行文本框 * @param array $data * @return mixed */ private function createTextareaForm(array $data) { $formbuider = []; $textareaRule = ''; $data['value'] = json_decode($data['value'], true) ?: ''; if ($data['menu_name'] == 'param_filter_data') $data['value'] = base64_decode($data['value']); // 宽度设置 $col = isset($data['width']) && $data['width'] < 24 && $data['width'] > 4 ? $data['width'] : 13; $textareaRule = $this->builder->textarea($data['menu_name'], $data['info'], $data['value'])->placeholder($data['desc'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ])->rows($data['high'] ?? 6)->col($col); // 是否必填项 $this->isRequired($data['required']) && $textareaRule = $textareaRule->required($data['info'].'不能为空')->placeholder($data['desc']); $formbuider[] = $textareaRule; return $formbuider; } /** * 创建单选表单 * @param array $data * @param array $control * @param array $control_two * @return array */ private function createRadioForm(array $data, $control = [], $control_two = [], $control_three = []) { $formbuider = []; $value = json_decode($data['value'], true); $data['value'] = $this->normalizeOptionValue(($value === null || $value === '' || $value === false) ? '0' : $value); $parameter = explode("\n", $data['parameter']); $options = []; if ($parameter) { foreach ($parameter as $v) { if (strstr($v, $this->cuttingStr) !== false) { $pdata = explode($this->cuttingStr, $v, 2); $options[] = ['label' => trim($pdata[1]), 'value' => $this->normalizeOptionValue($pdata[0])]; } } $formbuider[] = $radio = $this->builder->radio($data['menu_name'], $data['info'], $data['value'])->options($options)->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ])->appendValidate([ 'required' => true, 'message' => $data['info'] . '必选项', 'trigger' => 'change', ])->col(13); if ($control) { $radio->appendControl($data['show_value'] ?? 1, is_array($control) ? $control : [$control]); } if ($control_two && isset($data['show_value2'])) { $radio->appendControl($data['show_value2'] ?? 2, is_array($control_two) ? $control_two : [$control_two]); } if ($control_three && isset($data['show_value3'])) { $radio->appendControl($data['show_value3'] ?? 3, is_array($control_three) ? $control_three : [$control_three]); } return $formbuider; } } /** * 创建上传组件表单 * @param int $type * @param array $data * @param bool $showTypeSelect 是否显示上传类型选择器 * @return array */ private function createUploadForm(int $type, array $data, bool $showTypeSelect = false) { $formbuider = []; // 单图控件 if($type == 1){ $singleDataValue = json_decode($data['value'], true) ?: ''; if ($singleDataValue != '') $singleDataValue = set_file_url($singleDataValue); } else{ $singleDataValue = ''; } $singleImageField = $this->builder->frameImage($data['menu_name'], $data['info'], $this->url(config('app.admin_prefix', 'admin') . '/widget.images/index', ['fodder' => $data['menu_name']], true), $singleDataValue) ->icon('el-icon-picture-outline')->width('950px')->height('560px')->Props(['footer' => false, 'modalTitle' => '预览'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc'] ?? ''] ])->col(13); // 多图控件 if($type == 2){ $multiDataValue = json_decode($data['value'], true) ?: []; if (!empty($multiDataValue)) { $multiDataValue = set_file_url($multiDataValue); } } else{ $multiDataValue = []; } $multiImageField = $this->builder->frameImages($data['menu_name'], $data['info'], $this->url(config('app.admin_prefix', 'admin') . '/widget.images/index', ['fodder' => $data['menu_name'], 'type' => 'many', 'maxLength' => 5], true), $multiDataValue) ->maxLength(5)->icon('el-icon-picture-outline')->width('950px')->height('560px')->Props(['footer' => false, 'modalTitle' => '预览']) ->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc'] ?? ''] ])->col(13); // 文件控件 if($type == 3){ $fileDataValue = json_decode($data['value'], true) ?: ''; if ($fileDataValue != '') $fileDataValue = set_file_url($fileDataValue); } else{ $fileDataValue = ''; } $fileField = $this->builder->uploadFile($data['menu_name'], $data['info'], $this->url('/adminapi/file/upload/1', ['type' => 1], false, true), $fileDataValue) ->name('file')->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc'] ?? ''] ])->col(13)->data(['menu_name' => $data['menu_name']])->headers([ 'Authori-zation' => app()->request->header('Authori-zation'), ]); // 如果需要显示类型选择器(编辑模式) if ($showTypeSelect) { // 创建上传类型的radio选择器 $uploadTypeSelect = $this->builder->radio('upload_type', '上传类型', $type)->options($this->uploadType()); // 联动:切换类型时显示对应的上传控件 $uploadTypeSelect->appendControl(1, [$singleImageField]); $uploadTypeSelect->appendControl(2, [$multiImageField]); $uploadTypeSelect->appendControl(3, [$fileField]); $uploadRule = $uploadTypeSelect; } else { // 新建模式:根据类型只显示对应的上传控件 switch ($type) { case 1: // 是否必填项 $this->isRequired($data['required']) && $singleImageField = $singleImageField->appendValidate((new \FormBuilder\UI\Elm\Validate(\FormBuilder\UI\Elm\Validate::TYPE_STRING))->required()->message($data['info'].'请选择图片')); $uploadRule = $singleImageField; break; case 2: // 是否必填项 $this->isRequired($data['required']) && $multiImageField = $multiImageField->appendValidate((new \FormBuilder\UI\Elm\Validate(\FormBuilder\UI\Elm\Validate::TYPE_ARRAY))->required()->message($data['info'].'请选择图片')); $uploadRule = $multiImageField; break; case 3: // 是否必填项 $this->isRequired($data['required']) && $fileField = $fileField->appendValidate((new \FormBuilder\UI\Elm\Validate(\FormBuilder\UI\Elm\Validate::TYPE_STRING))->required()->message($data['info'].'请选择文件')); $uploadRule = $fileField; break; } } $formbuider[] = $uploadRule; return $formbuider; } /** * 创建单选框 * @param array $data * @return array * @throws \FormBuilder\Exception\FormBuilderException */ private function createCheckboxForm(array $data) { $formbuider = []; $checkboxRule = null; $data['value'] = json_decode($data['value'], true) ?: []; $parameter = explode("\n", $data['parameter']); $options = []; if ($parameter) { foreach ($parameter as $v) { if (strstr($v, $this->cuttingStr) !== false) { $pdata = explode($this->cuttingStr, $v); $options[] = ['label' => $pdata[1], 'value' => $pdata[0]]; } } $checkboxRule = $this->builder->checkbox($data['menu_name'], $data['info'], $data['value'])->options($options)->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ])->col(13); } // 是否必填项 $isRequired = $this->isRequired($data['required']); if ($isRequired) { $checkboxRule = $checkboxRule->required($data['info'].'至少选择一个'); } $formbuider[] = $checkboxRule; return $formbuider; } /** * 创建选择框表单 * @param array $data * @return array * @throws \FormBuilder\Exception\FormBuilderException */ private function createSelectForm(array $data) { $formbuider = []; $selectRule = null; $data['value'] = json_decode($data['value'], true) ?: []; $parameter = explode("\n", $data['parameter']); $options = []; if ($parameter) { foreach ($parameter as $v) { if (strstr($v, $this->cuttingStr) !== false) { $pdata = explode($this->cuttingStr, $v); $options[] = ['label' => $pdata[1], 'value' => $pdata[0]]; } } $selectRule = $this->builder->select($data['menu_name'], $data['info'], $data['value'])->options($options)->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ])->col(13); } // 是否必填项 $this->isRequired($data['required']) && $selectRule = $selectRule->required($data['info'].'请选择'); $formbuider[] = $selectRule; return $formbuider; } /** * 开关选择 * @param $data * @return array * @author: 吴汐 * @email: 442384644@qq.com * @date: 2023/9/6 */ private function createSwitchForm($data) { $formbuider = []; $switchRule = null; $data['value'] = json_decode($data['value'], true) ?: ''; $switchRule = $this->builder->switches($data['menu_name'], $data['info'], $data['value'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ])->required($data['info'].'必选项')->col(13); $formbuider[] = $switchRule; return $formbuider; } /** * 创建颜色选择器 * @param array $data * @return mixed */ private function createColorForm(array $data) { $data['value'] = json_decode($data['value'], true) ?: ''; $formbuider[] = $this->builder->color($data['menu_name'], $data['info'], $data['value'])->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => $data['desc']] ])->col(13); return $formbuider; } /** * 统一配置项选项值类型:普通数字保持数字,字符串编码保持字符串。 * * @param mixed $value * @return int|string */ private function normalizeOptionValue($value) { if (is_int($value)) { return $value; } if (is_string($value)) { $value = trim($value); if (preg_match('/^-?(0|[1-9]\d*)$/', $value)) { return (int)$value; } } return $value; } /** * 上传类型 * @return array */ private function uploadType(): array { return [ ['value' => 1, 'label' => '单图'] , ['value' => 2, 'label' => '多图'] , ['value' => 3, 'label' => '文件'] ]; } /** * 根据验证规则判断是否必填项 * @param string $required * @return bool */ private function isRequired(string $required) { // 支持 JSON 格式 $requiredData = json_decode($required, true); if ($requiredData) { return isset($requiredData['required']) && $requiredData['required'] ? true : false; } // 兼容旧格式:逗号分隔 return strpos($required, 'required:true') !== false; } /** * 获取系统配置表单 * @param $data * @param bool $control * @param array $controle_two * @return array * @throws \FormBuilder\Exception\FormBuilderException */ public function formTypeShine($data, $control = false, $controle_two = [], $controle_three = []) { switch ($data['type']) { case 'text'://文本框 return $this->createTextForm($data['input_type'], $data); case 'radio'://单选框 return $this->createRadioForm($data, $control, $controle_two, $controle_three); case 'textarea'://多行文本框 return $this->createTextareaForm($data); case 'upload'://文件上传 return $this->createUploadForm((int)$data['upload_type'], $data,false); case 'checkbox'://多选框 return $this->createCheckboxForm($data); case 'select'://多选框 return $this->createSelectForm($data); // case 'color': // return $this->createColorForm($data); case 'switch'://开关 return $this->createSwitchForm($data); } } /** * 根据系统多个配置自动生成form表单页面 * @param array $list * @return array * @throws \FormBuilder\Exception\FormBuilderException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ private function createForm(array $list) { if (!$list) return []; $list = array_combine(array_column($list, 'menu_name'), $list); $formbuider = []; $sonConfig = $this->getSonConfig(); $sonConfig = array_merge($sonConfig, $this->dao->getColumn(['level' => 1], 'menu_name')); foreach ($list as $key => $data) { if (in_array($key, $sonConfig)) { continue; } switch ($data['type']) { case 'text'://文本框 $formbuider = array_merge($formbuider, $this->createTextForm($data['input_type'], $data)); break; case 'radio'://单选框 $relateRule = $this->relatedRule; $builder = []; if (!isset($relateRule[$key])) { $relateRule = []; $sonData = $this->dao->getColumn(['level' => 1, 'link_id' => $data['id']], 'menu_name,link_value'); $sonValue = []; foreach ($sonData as $sv) { $sonValue[$sv['link_value']][] = $sv['menu_name']; } $i = 0; foreach ($sonValue as $pk => $pv) { $label = $data['menu_name']; if ($i == 1) $label = $data['menu_name'] . '@'; if ($i == 2) $label = $data['menu_name'] . '#'; $relateRule[$label]['show_value'] = $this->normalizeOptionValue($pk); foreach ($pv as $pvv) { $relateRule[$label]['son_type'][$pvv] = ''; } $i++; } } else { $sonData = $this->dao->getColumn(['level' => 1, 'link_id' => $data['id']], 'menu_name,link_value'); if ($sonData) { $sonValue = []; foreach ($sonData as $sv) { $sonValue[$sv['link_value']][] = $sv['menu_name']; } $i = 0; foreach ($sonValue as $pk => $pv) { $label = $data['menu_name']; if ($i == 1) $label = $data['menu_name'] . '@'; if ($i == 2) $label = $data['menu_name'] . '#'; if (!isset($relateRule[$label])) { $relateRule[$label]['show_value'] = $this->normalizeOptionValue($pk); } foreach ($pv as $pvv) { $relateRule[$label]['son_type'][$pvv] = ''; } $i++; } } } if (isset($relateRule[$key])) { $role = $relateRule[$key]; $data['show_value'] = $role['show_value']; foreach ($role['son_type'] as $sk => $sv) { if (isset($list[$sk])) { $son_data = $list[$sk]; $son_data['show_value'] = $role['show_value']; $son_build = []; if (isset($sv['son_type'])) { foreach ($sv['son_type'] as $ssk => $ssv) { $son_data['show_value'] = $sv['show_value']; $son_build[] = $this->formTypeShine($list[$ssk])[0]; unset($list[$ssk]); } } $son_build_two = []; if (isset($role['son_type'][$sk . '@'])) { $son_type_two = $role['son_type'][$sk . '@']; $son_data['show_value2'] = $son_type_two['show_value']; if (isset($son_type_two['son_type'])) { foreach ($son_type_two['son_type'] as $ssk => $ssv) { if (isset($list[$ssk]['menu_name']) && $list[$ssk]['menu_name'] == 'watermark_text_color') $list[$ssk]['type'] = 'color'; $son_build_two[] = $this->formTypeShine($list[$ssk])[0]; unset($list[$ssk]); } } } $son_build_three = []; if (isset($role['son_type'][$sk . '#'])) { $son_type_three = $role['son_type'][$sk . '#']; $son_data['show_value3'] = $son_type_three['show_value']; if (isset($son_type_three['son_type'])) { foreach ($son_type_three['son_type'] as $ssk => $ssv) { if (isset($list[$ssk]['menu_name']) && $list[$ssk]['menu_name'] == 'watermark_text_color') $list[$ssk]['type'] = 'color'; $son_build_three[] = $this->formTypeShine($list[$ssk])[0]; unset($list[$ssk]); } } } $builder[] = $this->formTypeShine($son_data, $son_build, $son_build_two, $son_build_three)[0]; unset($list[$sk]); } } $data['show_value'] = $role['show_value']; } $builder_two = []; if (isset($relateRule[$key . '@'])) { $role = $relateRule[$key . '@']; $data['show_value2'] = $role['show_value']; foreach ($role['son_type'] as $sk => $sv) { $son_data = $list[$sk]; $son_data['show_value'] = $role['show_value']; $builder_two[] = $this->formTypeShine($son_data)[0]; } } $builder_three = []; if (isset($relateRule[$key . '#'])) { $role = $relateRule[$key . '#']; $data['show_value3'] = $role['show_value']; foreach ($role['son_type'] as $sk => $sv) { $son_data = $list[$sk]; $son_data['show_value'] = $role['show_value']; $builder_three[] = $this->formTypeShine($son_data)[0]; } } $formbuider = array_merge($formbuider, $this->createRadioForm($data, $builder, $builder_two, $builder_three)); break; case 'textarea'://多行文本框 $formbuider = array_merge($formbuider, $this->createTextareaForm($data)); break; case 'upload'://文件上传 $formbuider = array_merge($formbuider, $this->createUploadForm((int)$data['upload_type'], $data,false)); break; case 'checkbox'://多选框 $formbuider = array_merge($formbuider, $this->createCheckboxForm($data)); break; case 'select'://多选框 $formbuider = array_merge($formbuider, $this->createSelectForm($data)); break; case 'switch'://开关 $formbuider = array_merge($formbuider, $this->createSwitchForm($data)); break; } } return $formbuider; } /** * 根据关联规则获取获取所有子配置 * @return array|int[]|string[] * @author 吴汐 * @email 442384644@qq.com * @date 2023/04/12 */ public function getSonConfig() { $sonConfig = []; $rolateRule = $this->relatedRule; if ($rolateRule) { foreach ($rolateRule as $key => $value) { $sonConfig = array_merge($sonConfig, array_keys($value['son_type'])); foreach ($value['son_type'] as $k => $v) { if (isset($v['son_type'])) { $sonConfig = array_merge($sonConfig, array_keys($v['son_type'])); } } } } return $sonConfig; } /**无组件绑定规则 * @param array $list * @return array|bool * @throws \FormBuilder\Exception\FormBuilderException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function createNoCrontrolForm(array $list) { if (!$list) return false; $formbuider = []; foreach ($list as $key => $data) { switch ($data['type']) { case 'text'://文本框 $formbuider = array_merge($formbuider, $this->createTextForm($data['input_type'], $data)); break; case 'radio'://单选框 $formbuider = array_merge($formbuider, $this->createRadioForm($data)); break; case 'textarea'://多行文本框 $formbuider = array_merge($formbuider, $this->createTextareaForm($data)); break; case 'upload'://文件上传 $formbuider = array_merge($formbuider, $this->createUploadForm((int)$data['upload_type'], $data, true)); break; case 'checkbox'://多选框 $formbuider = array_merge($formbuider, $this->createCheckboxForm($data)); break; case 'select'://多选框 $formbuider = array_merge($formbuider, $this->createSelectForm($data)); break; case 'switch'://开关 $formbuider = array_merge($formbuider, $this->createSwitchForm($data)); break; } } return $formbuider; } /** * 有组件绑定规则 * @param array $list * @param array $relatedRule * @return array|bool * @throws \FormBuilder\Exception\FormBuilderException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function createBindCrontrolForm(array $list, array $relatedRule) { if (!$list || !$relatedRule) return false; $formbuider = []; $new_data = array(); foreach ($list as $dk => $dv) { $new_data[$dv['menu_name']] = $dv; } foreach ($relatedRule as $rk => $rv) { if (isset($rv['son_type'])) { $data = $new_data[$rk]; switch ($data['type']) { case 'text'://文本框 $formbuider = array_merge($formbuider, $this->createTextForm($data['input_type'], $data)); break; case 'radio'://单选框 $son_builder = array(); foreach ($rv['son_type'] as $sk => $sv) { if (isset($sv['son_type'])) { foreach ($sv['son_type'] as $ssk => $ssv) { $son_data = $new_data[$sk]; $son_data['show_value'] = $sv['show_value']; $son_builder[] = $this->formTypeShine($son_data, $this->formTypeShine($new_data[$ssk])[0])[0]; } } else { $son_data = $new_data[$sk]; $son_data['show_value'] = $rv['show_value']; $son_builder[] = $this->formTypeShine($son_data)[0]; } } $formbuider = array_merge($formbuider, $this->createRadioForm($data, $son_builder)); break; case 'textarea'://多行文本框 $formbuider = array_merge($formbuider, $this->createTextareaForm($data)); break; case 'upload'://文件上传 $formbuider = array_merge($formbuider, $this->createUploadForm((int)$data['upload_type'], $data, false)); break; case 'checkbox'://多选框 $formbuider = array_merge($formbuider, $this->createCheckboxForm($data)); break; case 'select'://多选框 $formbuider = array_merge($formbuider, $this->createSelectForm($data)); break; case 'switch'://开关 $formbuider = array_merge($formbuider, $this->createSwitchForm($data)); break; } } } return $formbuider; } /** * 根据tabid获取系统配置form表单创建 * @param $url * @param int $tabId * @return array * @throws \FormBuilder\Exception\FormBuilderException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function getConfigForm($url, int $tabId) { /** @var SystemConfigTabServices $service */ $service = app()->make(SystemConfigTabServices::class); $title = $service->value(['id' => $tabId], 'title'); $list = $this->dao->getConfigTabAllList($tabId); $formbuider = $this->createForm($list); $name = 'setting'; if ($url) { $name = explode('/', $url)[2] ?? $name; } $postUrl = $this->postUrl[$name]['url'] ?? '/setting/config/save_basics'; return create_form($title, $formbuider, $this->url($postUrl), 'POST'); } /** * 新增路由增加设置项验证 * @param $url * @param $post * @return bool */ public function checkParam($url, $post) { $name = ''; if ($url) { $name = explode('/', $url)[2] ?? $name; } $auth = $this->postUrl[$name]['auth'] ?? false; if ($auth === false) { throw new AdminException('请求不被允许'); } if ($auth) { /** @var SystemConfigTabServices $systemConfigTabServices */ $systemConfigTabServices = app()->make(SystemConfigTabServices::class); foreach ($post as $key => $value) { $tab_ids = $systemConfigTabServices->getColumn([['eng_title', 'IN', $auth]], 'id'); if (!$tab_ids || !in_array($key, $this->dao->getColumn([['config_tab_id', 'IN', $tab_ids]], 'menu_name'))) { throw new AdminException('设置类目不被允许'); } } } return true; } /** * 添加配置字段 * @param int $type * @param int $tab_id * @retuarr@throws \FormBuilder\Exception\FormBuilderException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function addFieldForm(int $type, int $tab_id): array { /** @var SystemConfigTabServices $service */ $service = app()->make(SystemConfigTabServices::class); $formbuider = []; $form_type = ''; $info_type = []; $parameter = []; switch ($type) { case 0://文本框 $form_type = 'text'; $parameter[] = $this->createTextInputTypeForm(['input_type' => 'input']); break; case 1://多行文本框 $form_type = 'textarea'; $parameter[] = $this->builder->textarea('value', '默认值'); $parameter[] = $this->builder->number('width', '文本框宽', 100); $parameter[] = $this->builder->number('high', '多行文本框高', 5); break; case 2://单选框 $form_type = 'radio'; $parameter[] = $this->builder->textarea('parameter', '配置参数', "1=>男\n2=>女\n3=>保密")->rows(3)->placeholder("参数方式例如:\n1=>男\n2=>女\n3=>保密")->required('配置参数不能为空')->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => '参数说明:=>前面是参数值,后面是参数名称,每行一个参数,=>分割符不能换,例如:
1=>男
2=>女
3=>保密'] ]); $parameter[] = $this->builder->input('value', '默认值'); break; case 3://文件上传 $form_type = 'upload'; $parameter = array_merge($parameter, $this->createUploadForm(1, ['menu_name' => 'value', 'info' => '默认值', 'value' => ''], true)); break; case 4://多选框 $form_type = 'checkbox'; $parameter[] = $this->builder->textarea('parameter', '配置参数', "1=>白色\n2=>红色\n3=>黑色")->rows(3)->placeholder("参数方式例如:\n1=>白色\n2=>红色\n3=>黑色")->required('配置参数不能为空')->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => '参数说明:=>前面是参数值,后面是参数名称,每行一个参数,=>分割符不能换,例如:
1=>白色
2=>红色
3=>黑色'] ]); break; case 5://下拉框 $form_type = 'select'; $parameter[] = $this->builder->textarea('parameter', '配置参数', "1=>分类一\n2=>分类二\n3=>分类三")->rows(3)->placeholder("参数方式例如:\n1=>分类一\n2=>分类二\n3=>分类三")->required('配置参数不能为空')->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => '参数说明:=>前面是参数值,后面是参数名称,每行一个参数,=>分割符不能换,例如:
1=>分类一
2=>分类二
3=>分类三'] ]); break; case 6://开关 $form_type = 'switch'; $parameter[] = $this->builder->switches('value', '默认'); break; } if ($form_type) { $formbuider[] = $this->builder->hidden('type', $form_type); [$configTabList, $data] = $service->getConfigTabListForm((int)($tab_id ?? 0)); $linkData = $this->linkData($tab_id); $formbuider[] = $this->builder->radio('level', '联动显示', 0)->options([['value' => 0, 'label' => '否'], ['value' => 1, 'label' => '是']])->requiredNum()->appendRule('suffix', [ 'type' => 'div', 'class' => 'tips-info', 'domProps' => ['innerHTML' => '否:默认正常展示此配置;是:此配置默认隐藏,当选中下方对应配置的值时,此配置才会显示'] ])->appendControl(1, [ $this->builder->cascader('link_data', '关联配置/值')->options($linkData)->props(['props' => ['multiple' => false, 'checkStrictly' => false, 'emitPath' => true]])->style(['width' => '100%']), ]); $formbuider[] = $this->builder->cascader('config_tab_id', '分类', $data)->options($configTabList)->filterable(true)->props(['props' => ['multiple' => false, 'checkStrictly' => true, 'emitPath' => false]])->style(['width' => '100%']); if ($info_type) { $formbuider[] = $info_type; } $formbuider[] = $this->builder->input('info', '配置名称')->required('配置名称不能为空')->autofocus(1); $formbuider[] = $this->builder->input('menu_name', '字段变量')->required('字段变量不能为空')->placeholder('例如:site_url'); $formbuider[] = $this->builder->input('desc', '配置简介'); $formbuider = array_merge($formbuider, $parameter); // 是否必填 if ($form_type != 'switch') { $formbuider[] = $this->builder->radio('required', '是否必填', 0)->options([ ['value' => 0, 'label' => '否'], ['value' => 1, 'label' => '是'], ])->requiredNum(); } $formbuider[] = $this->builder->number('sort', '排序', 0); $formbuider[] = $this->builder->radio('status', '状态', 1)->options([['value' => 1, 'label' => '显示'], ['value' => 0, 'label' => '隐藏']])->requiredNum(); } return create_form('添加字段', $formbuider, $this->url('/setting/config'), 'POST'); } /** * 联动选择关联配置/值 * 根据指定的标签ID,链接数据并以特定格式返回。 * @param $tab_id * @return array * @author wuhaotian * @email 442384644@qq.com * @date 2024/5/30 */ public function linkData($tab_id) { $linkData = $this->selectList(['config_tab_id' => $tab_id, 'type' => 'radio', 'level' => 0], 'info as label,id as value,parameter,sort', 0, 0, 'sort DESC')->toArray(); foreach ($linkData as &$item) { $parameter = []; $parameter = explode("\n", $item['parameter']); foreach ($parameter as $pv) { $pvArr = explode('=>', $pv, 2); if (count($pvArr) < 2) { continue; } $item['children'][] = [ 'label' => trim($pvArr[1]), 'value' => $this->normalizeOptionValue($pvArr[0]) ]; } } return $linkData; } /** * radio 和 checkbox规则的判断 * @param $data * @return bool */ public function valiDateRadioAndCheckbox($data) { $option = []; $option_new = []; $data['parameter'] = str_replace("\r\n", "\n", $data['parameter']);//防止不兼容 $parameter = explode("\n", $data['parameter']); if (count($parameter) < 2) { throw new AdminException('请输入正确格式的配置参数'); } foreach ($parameter as $k => $v) { if (isset($v) && !empty($v)) { $option[$k] = explode('=>', $v); } } if (count($option) < 2) { throw new AdminException('请输入正确格式的配置参数'); } $bool = 1; foreach ($option as $k => $v) { $option_new[$k] = $option[$k][0]; foreach ($v as $kk => $vv) { $vv_num = strlen($vv); if (!$vv_num) { $bool = 0; } } } if (!$bool) { throw new AdminException('请输入正确格式的配置参数'); } $num1 = count($option_new);//提取该数组的数目 $arr2 = array_unique($option_new);//合并相同的元素 $num2 = count($arr2);//提取合并后数组个数 if ($num1 > $num2) { throw new AdminException('请输入正确格式的配置参数'); } return true; } /** * 验证参数 * @param $data * @return bool */ public function valiDateValue($data) { // 检查数据和验证规则是否存在 if (!$data || !isset($data['required']) || !$data['required']) { return true; } $name = $data['info'] ?? ''; $value = $data['value'] ?? ''; // 支持JSON格式的验证规则 $requiredData = json_decode($data['required'], true); if ($requiredData) { // JSON格式 if (isset($requiredData['required']) && $requiredData['required']) { if ($value === '' || $value === null) { throw new AdminException($name . '不能为空'); } } if (isset($requiredData['regex']) && $requiredData['regex']) { if ($value && !preg_match($requiredData['regex'], $value)) { throw new AdminException($name . '请输入正确的格式'); } } if (isset($requiredData['min']) && $value !== '' && $value !== null) { if ((float)$value < $requiredData['min']) { throw new AdminException($name . '不能小于' . $requiredData['min']); } } if (isset($requiredData['max']) && $value !== '' && $value !== null) { if ((float)$value > $requiredData['max']) { throw new AdminException($name . '不能大于' . $requiredData['max']); } } } else { // 兼容旧格式:逗号分隔的字符串 $valids = explode(',', $data['required']); foreach ($valids as $valid) { $valid = explode(':', $valid); if (isset($valid[0]) && isset($valid[1])) { $k = strtolower(trim($valid[0])); $v = strtolower(trim($valid[1])); if ($v != 'true') { continue; } switch ($k) { case 'required': if ($value === '' || $value === null) { throw new AdminException($name . '不能为空'); } break; case 'regex': if ($value && !preg_match($data['regex'], $value)) { throw new AdminException($name . '请输入正确的格式'); } break; } } } } return true; } /** * 保存平台电子面单打印信息 * @param array $data * @return bool */ public function saveExpressInfo(array $data) { if (!is_array($data) || !$data) return false; // config_export_id 快递公司id // config_export_temp_id 快递公司模板id // config_export_com 快递公司编码 // config_export_to_name 发货人姓名 // config_export_to_tel 发货人电话 // config_export_to_address 发货人详细地址 // config_export_siid 电子面单打印机编号 foreach ($data as $key => $value) { $this->dao->update(['menu_name' => 'config_export_' . $key], ['value' => json_encode($value)]); } CacheService::clear(); return true; } /** * 获取分享海报 兼容方法 */ public function getSpreadBanner() { //配置 $banner = sys_config('spread_banner', []); if (!$banner) { //组合数据 $banner = sys_data('routine_spread_banner'); if ($banner) { $banner = array_column($banner, 'pic'); $this->dao->update(['menu_name' => 'spread_banner'], ['value' => json_encode($banner)]); CacheService::clear(); } } return $banner; } /** * 保存wss配置 * @param int $wssOpen * @param string $wssLocalpk * @param string $wssLocalCert */ public function saveSslFilePath(int $wssOpen, string $wssLocalpk, string $wssLocalCert) { $wssFile = root_path() . '.wss'; $content = <<make(SystemConfigTabServices::class); //上传配置->基础配置 $tab_id = $systemConfigTabServices->getColumn(['eng_title' => 'base_config'], 'id'); if ($tab_id) { $all = $this->dao->getColumn(['config_tab_id' => $tab_id], 'value', 'menu_name'); if (array_intersect(array_keys($all), array_keys($post))) { foreach ($post as $key => $item) { //配置更改删除原来生成的缩略图 if (isset($all[$key]) && $item != json_decode($all[$key], true)) { try { FileService::delDir(public_path('uploads/thumb_water')); break; } catch (\Throwable $e) { } } } } } return true; } /** * 变更分销绑定关系模式 * @param array $post * @return bool */ public function checkBrokerageBinding(array $post) { try { $config_data = $post['store_brokerage_binding_status']; $config_one = $this->dao->getOne(['menu_name' => 'store_brokerage_binding_status']); $config_old = json_decode($config_one['value'], true); if ($config_old != 2 && $config_data == 2) { //自动解绑上级绑定 /** @var AgentManageServices $agentManage */ $agentManage = app()->make(AgentManageServices::class); $agentManage->resetSpreadTime(); } } catch (\Throwable $e) { Log::error('变更分销绑定模式重置绑定时间失败,失败原因:' . $e->getMessage()); return false; } return true; } /** 停用 * 根据系统配置分类自动生成form表单页面 * @param int $tabId * @param array $formData * @param array $relatedRule * @return array|bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function createConfigForm(int $tabId, array $relatedRule) { $list = $this->dao->getConfigTabAllList($tabId); if (!$relatedRule) { $formbuider = $this->createNoCrontrolForm($list); } else { $formbuider = $this->createBindCrontrolForm($list, $relatedRule); } return $formbuider; } /** 停用 * 绑定表单数据 * @param $data * @param $relatedRule * @return array */ private function bindBuilderData($data, $relatedRule) { if (!$data) return false; $p_list = array(); foreach ($relatedRule as $rk => $rv) { $p_list[$rk] = $data[$rk]; if (isset($rv['son_type']) && is_array($rv['son_type'])) { foreach ($rv['son_type'] as $sk => $sv) { if (is_array($sv) && isset($sv['son_type'])) { foreach ($sv['son_type'] as $ssk => $ssv) { $tmp = $data[$sk]; $tmp['console'] = $data[$ssk]; $p_list[$rk]['console'][] = $tmp; } } else { $p_list[$rk]['console'][] = $data[$sk]; } } } } return array_values($p_list); } }