diff --git a/app/common/model/InquiryChannel.php b/app/common/model/InquiryChannel.php new file mode 100644 index 0000000..fb387ba --- /dev/null +++ b/app/common/model/InquiryChannel.php @@ -0,0 +1,49 @@ +hasOne(User::class, 'id', 'recipient'); } - // public function enter() - // { - // return $this->belongsTo(User::class, 'enter_user_id'); - // } - - // public function recipient() - // { - // return $this->belongsTo(User::class, 'recipient'); - // } + public function channel() + { + return $this->hasOne(InquiryChannel::class, 'id', 'channel'); + } public function country() { diff --git a/app/common/traits/crud/CrudLogicTrait.php b/app/common/traits/crud/CrudLogicTrait.php index 4e2b794..e648f2f 100644 --- a/app/common/traits/crud/CrudLogicTrait.php +++ b/app/common/traits/crud/CrudLogicTrait.php @@ -38,14 +38,6 @@ trait CrudLogicTrait return CrudUtil::findOneBy(CrudUtil::buildQuery($config)); } - /** - * 任意条件查询单条(可带 dataLimit) - */ - // public function logicShowBy(array $where, array $with = [], array $dataLimit = []) - // { - // return CrudUtil::findOneBy($this->modelClass, $where, $with, $dataLimit); - // } - /** * 创建(可带 dataLimit) */ @@ -54,14 +46,6 @@ trait CrudLogicTrait return CrudUtil::create($this->modelClass, $data, $dataLimit); } - /** - * 主键更新(可带 dataLimit) - */ - // public function logicUpdateByPk($id, array $data, array $dataLimit = []) - // { - // return CrudUtil::updateByPk($this->modelClass, $id, $data, $dataLimit); - // } - /** * 任意条件更新(可带 dataLimit) */ @@ -70,14 +54,6 @@ trait CrudLogicTrait return CrudUtil::updateBy(CrudUtil::buildQuery($config), $data); } - /** - * 主键删除(批量) - */ - // public function logicDeleteByPk(array $ids) - // { - // return CrudUtil::deleteByPk($this->modelClass, $ids); - // } - /** * 任意条件删除(可带 dataLimit) */ diff --git a/app/common/traits/crud/CrudServiceTrait.php b/app/common/traits/crud/CrudServiceTrait.php index c042b5f..bf17abc 100644 --- a/app/common/traits/crud/CrudServiceTrait.php +++ b/app/common/traits/crud/CrudServiceTrait.php @@ -32,8 +32,8 @@ trait CrudServiceTrait $result = $this->complexQuery($request->get()); } else { $config = $this->buildQueryConfig($request, 'index'); - $limit = (int)$request->get('limit', 15); - $page = (int)$request->get('page', 1); + $limit = (int)$request->get('size', 15); + $page = (int)$request->get('current', 1); $result = $this->logicList($config, $limit, $page); } return $this->postProcess('List', $result); @@ -62,7 +62,7 @@ trait CrudServiceTrait /** 创建 */ public function serviceStore(Request $request, array $data = []) { - // $data = $request->post(); + $data = $this->preProcess('Store', $data, $request); $dl = $this->getDataLimitFromRequest($request); $created = $this->logicCreate($data, $dl); return $this->postProcess('Store', $created); @@ -71,7 +71,7 @@ trait CrudServiceTrait /** 更新 */ public function serviceUpdate(Request $request, array $data = []) { - // $data= $request->post(); + $data = $this->preProcess('Update', $data, $request); $config = $this->buildQueryConfig($request, 'update'); $updated = $this->logicUpdateBy($config, $data); return $this->postProcess('Update', $updated); @@ -88,16 +88,7 @@ trait CrudServiceTrait /** ----------------- 公共辅助方法 ----------------- */ /** - * 构造 CrudUtil 的查询配置1 - * - * 前端可以通过以下参数控制: - * - filter_= → where - * - sort_by=&order= - * - fields=id,name,email → select - * - with=roles,posts → 关联 - * - withFields=roles:id,name;... → 关联字段 - * - dataLimitType=personal|auth - * - dataLimitField=admin_id + * 构造 CrudUtil 查询配置 */ protected function buildQueryConfig(Request $request, string $scene = 'default'): array { @@ -126,42 +117,11 @@ trait CrudServiceTrait $config['where']['id'] = $p['id']; break; case 'destroy': - $config['where']['id'] = $p['id']; + // $config['where']['id'] = $p['id']; break; } return $config; - - // // 1. where 从 filter_ 前缀自动映射 - // $where = []; - // foreach ($p as $key => $val) { - // if (strpos($key, 'filter_') === 0 && $val !== '') { - // $col = substr($key, 7); - // // 支持 %like% 查询 - // $where[$col] = strpos($val, '%') !== false - // ? ['like', $val] - // : $val; - // } - // } - - // // 2. 其余配置 - // return [ - // 'model' => $this->modelClass, - // 'where' => $where, - // 'order' => [ - // $p['sort_by'] ?? 'id' => $p['order'] ?? 'desc' - // ], - // 'fields' => !empty($p['fields']) - // ? explode(',', $p['fields']) - // : [], - // 'with' => !empty($p['with']) - // ? explode(',', $p['with']) - // : [], - // 'withFields' => $this->parseWithFields( - // $p['withFields'] ?? '' - // ), - // 'dataLimit' => $this->getDataLimitFromRequest($request), - // ]; } /** 解析 withFields 字符串 "rel:field,field;..." */ @@ -191,14 +151,20 @@ trait CrudServiceTrait ]; } - /** - * 处理复杂查询 - * 覆盖此方法,实现复杂查询逻辑 + /** + * $data 前置处理 + * + * @param array $data + * @param Request $request + * @return array */ - // protected function complexQuery(array $params): array - // { - // throw new \LogicException('请在子类实现 complexQuery'); - // } + protected function preProcess(string $op, mixed $data, Request $request): mixed + { + $hook = "beforeService{$op}"; + return method_exists($this, $hook) + ? $this->{$hook}($data, $request) + : $data; + } /** * 根据操作类型,调用对应的后置钩子 @@ -214,4 +180,14 @@ trait CrudServiceTrait ? $this->{$hook}($data) : $data; } + + + /** + * 处理复杂查询 + * 覆盖此方法,实现复杂查询逻辑 + */ + // protected function complexQuery(array $params): array + // { + // throw new \LogicException('请在子类实现 complexQuery'); + // } } \ No newline at end of file diff --git a/app/common/utils/CrudUtil.php b/app/common/utils/CrudUtil.php index 979181f..dec779b 100644 --- a/app/common/utils/CrudUtil.php +++ b/app/common/utils/CrudUtil.php @@ -326,7 +326,7 @@ class CrudUtil } /** - * 真正执行一个条件的 where + * 执行条件 where */ protected static function applySingleWhere(Builder $q, string $col, string $op, $v): void { diff --git a/app/common/utils/scaffold/Generate.php b/app/common/utils/scaffold/Generate.php index 6735997..753a9cf 100644 --- a/app/common/utils/scaffold/Generate.php +++ b/app/common/utils/scaffold/Generate.php @@ -24,44 +24,51 @@ class Generate { $fs = new Filesystem(); - // 模板路径 $templateDir = __DIR__ . '/templates/'; - $controllerPath = __DIR__ . "/../../../{$this->options['controller']['module']}/controller/".$this->rName($this->options['controller']['name'])."Controller.php"; - $servicePath = __DIR__ . "/../../../{$this->options['service']['module']}/service/".$this->rName($this->options['service']['name'])."Service.php"; - $logicPath = __DIR__ . "/../../../{$this->options['logic']['module']}/logic/".$this->rName($this->options['logic']['name'])."Logic.php"; - $modelPath = __DIR__ . "/../../../{$this->options['model']['module']}/model/".$this->rName($this->options['model']['name']).".php"; - $validatePath = __DIR__ . "/../../../{$this->options['validate']['module']}/validate/".$this->rName($this->options['validate']['name'])."Validate.php"; - // 创建目录(如果不存在) - $fs->mkdir(__DIR__ . "/../../../{$this->options['controller']['module']}/controller"); - $fs->mkdir(__DIR__ . "/../../../{$this->options['service']['module']}/service"); - $fs->mkdir(__DIR__ . "/../../../{$this->options['logic']['module']}/logic"); - $fs->mkdir(__DIR__ . "/../../../{$this->options['model']['module']}/model"); - $fs->mkdir(__DIR__ . "/../../../{$this->options['validate']['module']}/validate"); + $resultStr = ''; - // // 删除已存在的文件并重新生成 - $this->deleteFileIfExists($controllerPath); - $this->deleteFileIfExists($servicePath); - $this->deleteFileIfExists($logicPath); - $this->deleteFileIfExists($modelPath); - $this->deleteFileIfExists($validatePath); + if (!empty($this->options['controller'])) { + $controllerPath = __DIR__ . "/../../../{$this->options['controller']['module']}/controller/".$this->rName($this->options['controller']['name'])."Controller.php"; + $fs->mkdir(__DIR__ . "/../../../{$this->options['controller']['module']}/controller"); + $this->deleteFileIfExists($controllerPath); + $ControllerStub = $this->generateFile($templateDir, 'ControllerStub.stub', $controllerPath, 'controller'); + $resultStr .= $ControllerStub; + } - // 生成控制器文件 - $ControllerStub = $this->generateFile($templateDir, 'ControllerStub.stub', $controllerPath, 'controller'); - - // 生成服务类文件 - $ServiceStub = $this->generateFile($templateDir, 'ServiceStub.stub', $servicePath, 'service'); - - // 生成逻辑类文件 - $LogicStub = $this->generateFile($templateDir, 'LogicStub.stub', $logicPath, 'logic'); - - // 生成模型类文件 - $ModelStub = $this->generateFile($templateDir, 'ModelStub.stub', $modelPath, 'model'); - - // 生成验证器类文件 - $ValidatorStub = $this->generateFile($templateDir, 'ValidateStub.stub', $validatePath, 'validate'); - - return $ControllerStub . $ServiceStub . $LogicStub . $ModelStub . $ValidatorStub . "文件生成成功!
"; + if (!empty($this->options['service'])) { + $servicePath = __DIR__ . "/../../../{$this->options['service']['module']}/service/".$this->rName($this->options['service']['name'])."Service.php"; + $fs->mkdir(__DIR__ . "/../../../{$this->options['service']['module']}/service"); + $this->deleteFileIfExists($servicePath); + $ServiceStub = $this->generateFile($templateDir, 'ServiceStub.stub', $servicePath, 'service'); + $resultStr .= $ServiceStub; + } + + if (!empty($this->options['logic'])) { + $logicPath = __DIR__ . "/../../../{$this->options['logic']['module']}/logic/".$this->rName($this->options['logic']['name'])."Logic.php"; + $fs->mkdir(__DIR__ . "/../../../{$this->options['logic']['module']}/logic"); + $this->deleteFileIfExists($logicPath); + $LogicStub = $this->generateFile($templateDir, 'LogicStub.stub', $logicPath, 'logic'); + $resultStr .= $LogicStub; + } + + if (!empty($this->options['model'])) { + $modelPath = __DIR__ . "/../../../{$this->options['model']['module']}/model/".$this->rName($this->options['model']['name']).".php"; + $fs->mkdir(__DIR__ . "/../../../{$this->options['model']['module']}/model"); + $this->deleteFileIfExists($modelPath); + $ModelStub = $this->generateFile($templateDir, 'ModelStub.stub', $modelPath, 'model'); + $resultStr .= $ModelStub; + } + + if (!empty($this->options['validate'])) { + $validatePath = __DIR__ . "/../../../{$this->options['validate']['module']}/validate/".$this->rName($this->options['validate']['name'])."Validate.php"; + $fs->mkdir(__DIR__ . "/../../../{$this->options['validate']['module']}/validate"); + $this->deleteFileIfExists($validatePath); + $ValidatorStub = $this->generateFile($templateDir, 'ValidateStub.stub', $validatePath, 'validate'); + $resultStr .= $ValidatorStub; + } + + return $resultStr ? $resultStr . "文件生成成功!
" : '未生成任何文件'; } /** diff --git a/app/common/validate/InquiryLogValidate.php b/app/common/validate/InquiryLogValidate.php index ca266b1..58058cb 100644 --- a/app/common/validate/InquiryLogValidate.php +++ b/app/common/validate/InquiryLogValidate.php @@ -3,27 +3,118 @@ namespace app\common\validate; use think\Validate; +use app\common\model\InquiryLog; class InquiryLogValidate extends Validate { // 规则 protected $rule = [ - + 'id' => 'require|integer|gt:0', + 'order_no' => 'require|alphaDash|length:36', + 'enter_user_id'=> 'integer|egt:0', + 'recipient' => 'integer|egt:0', + 'quality' => 'require|in:1,2,3', + 'channel' => 'integer|between:0,99', + 'email' => 'email|max:255|checkEmailContactUnique', + 'tel' => 'max:255|checkTelContactUnique', + 'whatsapp' => 'max:255|checkWhatsappContactUnique', + 'country' => 'integer|egt:0|requireWith:contacts', + 'contacts' => 'require|max:255|requireWithout:email,tel,whatsapp|checkContactUnique', + 'content' => 'string', + 'status' => 'in:0,1,2', + 'r_time' => 'integer|egt:0', + 't_time' => 'integer|egt:0' ]; // 提示 protected $message = [ - + 'id.require' => 'ID不能为空', + 'id.integer' => 'ID必须是整数', + 'id.gt' => 'ID必须大于0', + 'order_no.require' => '订单号不能为空', + 'order_no.alphaDash'=> '订单号只能包含字母、数字和下划线', + 'order_no.length' => '订单号长度必须为36位', + 'enter_user_id.integer' => '录入人ID必须是整数', + 'enter_user_id.egt' => '录入人ID不能为负数', + 'recipient.integer' => '接单人ID必须是整数', + 'recipient.egt' => '接单人ID不能为负数', + 'quality.require' => '询单等级不能为空', + 'quality.in' => '询单等级只能是1、2或3', + 'channel.integer' => '渠道编号必须是整数', + 'channel.between' => '渠道编号范围0-99', + 'email.email' => '邮箱格式不正确', + 'email.max' => '邮箱长度不能超过255个字符', + 'tel.max' => '电话长度不能超过255个字符', + 'whatsapp.max' => 'WhatsApp长度不能超过255个字符', + 'country.integer' => '国家代码必须是整数', + 'country.egt' => '国家代码不能为负数', + 'contacts.require' => '联系人不能为空', + 'contacts.max' => '联系人长度不能超过255个字符', + 'content.string' => '询单内容必须是字符串', + 'status.in' => '状态值只能是0、1或2', + 'r_time.integer' => '发布时间必须是整数', + 'r_time.egt' => '发布时间不能为负数', + 't_time.integer' => '跟踪时间必须是整数', + 't_time.egt' => '跟踪时间不能为负数', + 'email.checkEmailContactUnique' => '邮箱联系方式已存在', + 'tel.checkTelContactUnique' => '电话联系方式已存在', + 'whatsapp.checkWhatsappContactUnique' => 'WhatsApp联系方式已存在', + 'contacts.requireWithout' => '至少需要提供一种联系方式', + 'contacts.checkContactUnique' => '联系人已存在', + 'country.requireWith' => '国家必须与联系人一起提供' ]; // 场景 protected $scene = [ 'store' => [ - + 'enter_user_id', 'quality', 'channel', 'email', 'tel', 'whatsapp', 'country', 'contacts', 'content' ], 'update' => [ - + 'quality', 'channel', 'email', 'tel', 'whatsapp', 'country', 'contacts', 'content' ] ]; + + /** + * 验证联系方式唯一性 + */ + protected function checkContactUnique($value, $rule, $data) + { + // 至少需要提供一种联系方式 + if (empty($data['email']) && empty($data['tel']) && empty($data['whatsapp'])) { + $exists = InquiryLog::where('contacts', trim($data['contacts'])) + ->where('country', $data['country']) + ->exists(); + return !$exists; + } + + return true; + } + + /** + * 验证邮箱联系方式唯一性 + */ + protected function checkEmailContactUnique($value) + { + if (empty($value)) return true; + return !InquiryLog::where('email', trim($value))->exists(); + } + + /** + * 验证电话联系方式唯一性 + */ + protected function checkTelContactUnique($value) + { + if (empty($value)) return true; + return !InquiryLog::where('tel', trim($value))->exists(); + } + + /** + * 验证WhatsApp联系方式唯一性 + */ + protected function checkWhatsappContactUnique($value) + { + if (empty($value)) return true; + return !InquiryLog::where('whatsapp', trim($value))->exists(); + } } \ No newline at end of file diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php index 50a3280..48977c2 100644 --- a/app/controller/IndexController.php +++ b/app/controller/IndexController.php @@ -70,27 +70,27 @@ class IndexController public function createResource() { $options = [ - 'controller' => [ - 'module' => 'inquiry', - 'name' => 'country' - ], + // 'controller' => [ + // 'module' => 'inquiry', + // 'name' => 'country' + // ], 'model' => [ - 'module' => 'inquiry', - 'name' => 'country' + 'module' => 'common', + 'name' => 'inquiry_channel' ], - 'service' => [ - 'module' => 'inquiry', - 'name' => 'country' - ], - 'logic' => [ - 'module' => 'inquiry', - 'name' => 'country' - ], - 'validate' => [ - 'module' => 'inquiry', - 'name' => 'country' - ], - 'table' => 'country' + // 'service' => [ + // 'module' => 'inquiry', + // 'name' => 'country' + // ], + // 'logic' => [ + // 'module' => 'inquiry', + // 'name' => 'country' + // ], + // 'validate' => [ + // 'module' => 'inquiry', + // 'name' => 'country' + // ], + 'table' => 'inquiry_channel' ]; $result = (new Generate($options))->doGenerate(); diff --git a/app/functions.php b/app/functions.php index 2a05e3f..3fed6a2 100644 --- a/app/functions.php +++ b/app/functions.php @@ -66,6 +66,15 @@ if (!function_exists('getConfig')) { } } +/* + * 询单号生成 + */ +if (!function_exists('orderNum')) { + function orderNum() { + return "SN".date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT); + } +} + /* * 调试用 */ diff --git a/app/inquiry/controller/InquiryLogController.php b/app/inquiry/controller/InquiryLogController.php index 9b48395..8fbd985 100644 --- a/app/inquiry/controller/InquiryLogController.php +++ b/app/inquiry/controller/InquiryLogController.php @@ -22,14 +22,18 @@ class InquiryLogController extends BaseController * @param array $data * @return array */ - // protected function indexFormat($data) - // { - // if (isset($data['created_at'])) - // $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); - // if (isset($data['updated_at'])) - // $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); - // return $data; - // } + protected function indexFormat($data) + { + if (isset($data['created_at'])) + $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); + if (isset($data['updated_at'])) + $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); + if (isset($data['r_time'])) + $data['r_time'] = $data['r_time'] > 0 ? date('Y-m-d H:i:s', $data['r_time']) : 0; + if (isset($data['t_time'])) + $data['t_time'] = $data['t_time'] > 0 ? date('Y-m-d H:i:s', $data['t_time']) : 0; + return $data; + } // 列表 diff --git a/app/inquiry/service/InquiryLogService.php b/app/inquiry/service/InquiryLogService.php index bc966f4..754280d 100644 --- a/app/inquiry/service/InquiryLogService.php +++ b/app/inquiry/service/InquiryLogService.php @@ -54,14 +54,9 @@ class InquiryLogService // 时间 if (isset($p['time']) && $p['time']) { - // $time = explode(' - ', $p['time']); - // $config['where']['created_at'] = [ - // ['>=', strtotime($time[0])], - // ['<=', strtotime($time[1])], - // ]; + $time = explode(' - ', $p['time']); $config['where']['created_at'] = [ - strtotime(explode(' - ', $p['time'])[0]), - strtotime(explode(' - ', $p['time'])[1]), + 'between', [strtotime($time[0]), strtotime($time[1])] ]; } @@ -79,15 +74,13 @@ class InquiryLogService } // 关联 - $config['with'][] = 'country'; - $config['with']['enter'][] = 'id'; + $config['with']['country'][] = 'cn_addr'; $config['with']['enter'][] = 'name'; - $config['with']['recipient'][] = 'id'; $config['with']['recipient'][] = 'name'; + $config['with']['channel'][] = 'name'; break; case 'show': $config['where']['id'] = $p['id']; - $config['where']['status'] = 1; break; case 'store': break; @@ -101,4 +94,22 @@ class InquiryLogService return $config; } + + public function beforeServiceStore($data, Request $request) + { + $data['order_no'] = orderNum(); + $data['enter_user_id'] = $request->user->uid; + $data['recipient'] = 0; + $data['email'] = trim($data["email"]); + $data['tel'] = trim($data['tel']); + $data['whatsapp'] = trim($data['whatsapp']); + return $data; + } + + // public function afterServiceList($data) + // { + // var_dump($data); + + // return $data; + // } } \ No newline at end of file diff --git a/config/route.php b/config/route.php index 01953d0..6238ffd 100644 --- a/config/route.php +++ b/config/route.php @@ -77,10 +77,10 @@ Route::group('/admin', function () { // 询单 Route::group('/inquiry', function () { Route::any('/list', [app\inquiry\controller\InquiryLogController::class, 'index']); - // Route::any('/show', [app\admin\controller\CorpController::class, 'show']); - // Route::any('/store', [app\admin\controller\CorpController::class, 'store']); - // Route::any('/update', [app\admin\controller\CorpController::class, 'update']); - // Route::any('/destroy', [app\admin\controller\CorpController::class, 'destroy']); + Route::any('/show', [app\inquiry\controller\InquiryLogController::class, 'show']); + Route::any('/store', [app\inquiry\controller\InquiryLogController::class, 'store']); + Route::any('/update', [app\inquiry\controller\InquiryLogController::class, 'update']); + Route::any('/destroy', [app\inquiry\controller\InquiryLogController::class, 'destroy']); }); });