diff --git a/app/Enums/BaseType.php b/app/Enums/BaseType.php new file mode 100644 index 0000000..1d17ebe --- /dev/null +++ b/app/Enums/BaseType.php @@ -0,0 +1,9 @@ +input('crops_ids', []); + + // $type = $request->input('type'); + // //已添加区域无法变更类型 + // if($type == BaseType::Town->value) { + // return $this->error('无法添加城镇'); + // } try { DB::beginTransaction(); //添加基地信息 @@ -53,6 +60,11 @@ class AgriculturalBaseController extends Controller public function update(AgriculturalBase $agriculturalBasic, AgriculturalBaseRequest $request) { $cropsIds = $request->input('crops_ids', []); + $type = $request->input('type'); + //已添加区域无法变更类型 + if($type !== $agriculturalBasic->type->value) { + return $this->error('无法变更类型'); + } try { DB::beginTransaction(); //添加基地信息 diff --git a/app/Http/Controllers/CropController.php b/app/Http/Controllers/CropController.php new file mode 100644 index 0000000..c1c0c52 --- /dev/null +++ b/app/Http/Controllers/CropController.php @@ -0,0 +1,70 @@ +input()); + $list = $query->sort()->get(); + + return $this->json(CropResource::collection($list)); + } + + public function store(CropRequest $request) + { + $input = $request->input(); + //如果有上级,录入path + if($input['parent_id'] ?? 0){ + $parent = Crop::findOrFail($input['parent_id']); + $input['path'] = ($parent?->path ?? '').$parent?->id.'-'; + } + Crop::create($input); + + return $this->success('添加成功'); + } + + public function show(Crop $crop) + { + return $this->json(CropResource::make($crop)); + } + + public function update(Crop $crop, CropRequest $request) + { + //如果原本是结点,不允许修改为非节点 + //如果原本非结点,且有子节点,同样无法修改; + $input = $request->input(); + if($input['is_end'] != $crop->is_end){ + if($crop->is_end || Crop::where(['parent_id', $crop->id])->exists()){ + return $this->error('无法修改结点状态'); + } + } + + $crop->update(array_merge($request->input())); + + return $this->success('修改成功'); + } + + public function destroy(Crop $crop) + { + //如果有关联数据,无法删除 + if(CropYield::where('crop_id', $crop->id)->exists()){ + return $this->error('该结点有关联产量数据, 无法删除'); + } + //如果有子节点,无法删除 + if(Crop::where(['parent_id', $crop->id])->exists()){ + return $this->error('该结点有关联产量数据, 无法删除'); + } + + $crop->delete(); + + return $this->success('删除成功'); + } +} diff --git a/app/Http/Controllers/CropYieldController.php b/app/Http/Controllers/CropYieldController.php index d3d082f..bdbdb69 100644 --- a/app/Http/Controllers/CropYieldController.php +++ b/app/Http/Controllers/CropYieldController.php @@ -26,18 +26,7 @@ class CropYieldController extends Controller public function store(CropYieldRequest $request) { - $yields = $request->input('yields'); - CropYield::insert(array_map(function ($item) use ($request) { - return array_merge($item, [ - 'time_year' => $request->input('time_year'), - 'crop_id' => $request->input('crop_id'), - 'created_by' => auth('api')->user()?->id ?? 0, - 'updated_by' => auth('api')->user()?->id ?? 0, - 'created_at' => now(), - 'updated_at' => now(), - ]); - }, $yields)); - + //-todo return $this->success('添加成功'); } @@ -50,10 +39,7 @@ class CropYieldController extends Controller public function update(CropYield $cropYield, CropYieldUpdateRequest $request) { - $cropYield->update(array_merge($request->input(), - ['updated_by' => auth('api')->user()?->id ?? 0] - )); - + //-todo return $this->success('修改成功'); } diff --git a/app/Http/Controllers/KeywordController.php b/app/Http/Controllers/KeywordController.php index b0f68fd..e65ba1c 100644 --- a/app/Http/Controllers/KeywordController.php +++ b/app/Http/Controllers/KeywordController.php @@ -8,17 +8,17 @@ use Peidikeji\Keywords\Models\Keywords; class KeywordController extends Controller { - /** - * 农作物 - * - * @return void - */ - public function crops(Request $request) - { - $list = Keywords::filter($request->all())->where('type_key', 'like', 'crops-cate-%')->get(); + // /** + // * 农作物 + // * + // * @return void + // */ + // public function crops(Request $request) + // { + // $list = Keywords::filter($request->all())->where('type_key', 'like', 'crops-cate-%')->get(); - return $this->json(KeywordResource::collection($list)); - } + // return $this->json(KeywordResource::collection($list)); + // } /** * 农作物产业分类 @@ -27,18 +27,8 @@ class KeywordController extends Controller */ public function cropsCate(Request $request) { - $cropsId = $request->input('crops_id', 0); - $crops = null; - if ($cropsId) { - $crops = Keywords::find($cropsId); - } - $query = Keywords::filter($request->all())->where('type_key', 'crops-category'); - if ($crops) { - $query->where('id', $crops->parent_id); - } - $list = $query->get(); return $this->json(KeywordResource::collection($list)); diff --git a/app/Http/Requestes/AgriculturalBaseRequest.php b/app/Http/Requestes/AgriculturalBaseRequest.php index 7e2923c..8d68c66 100644 --- a/app/Http/Requestes/AgriculturalBaseRequest.php +++ b/app/Http/Requestes/AgriculturalBaseRequest.php @@ -2,8 +2,10 @@ namespace App\Http\Requestes; -use Illuminate\Contracts\Validation\Validator; +use App\Enums\BaseType; +use Illuminate\Validation\Rules\Enum; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Contracts\Validation\Validator; use Illuminate\Http\Exceptions\HttpResponseException; class AgriculturalBaseRequest extends FormRequest @@ -16,9 +18,10 @@ class AgriculturalBaseRequest extends FormRequest public function rules() { return [ + 'type' => ['required', new Enum(BaseType::class)], 'name' => 'required|string|max:100', 'description' => 'nullable|string', - 'person' => 'required|string|max:100', + 'person' => 'required_if:type,1|string|max:100', 'crops_ids' => 'required|array|min:1', 'areas' => 'required|regex:/^\d+(\.\d{1,2})?$/', 'workforce' => 'required|integer|min:0', @@ -31,20 +34,19 @@ class AgriculturalBaseRequest extends FormRequest public function messages() { $messages = [ - 'name.required' => '请填写基地名称', - 'name.max' => '基地名称不能超过100字', - 'description.string' => '请正确填写基地介绍', - 'person.required' => '请填写基地负责人名称', - 'person.max' => '基地负责人名称不能超过100字', + 'type' => '请选择区域类别', + 'name.required' => '请填写名称', + 'name.max' => '名称不能超过100字', + 'description.string' => '请正确填写介绍', + 'person.required_if' => '请填写负责人名称', + 'person.max' => '负责人名称不能超过100字', 'crops_ids.required' => '请选择农作物', 'crops_ids.min' => '至少选择一种农作物', - 'areas.required' => '请填写基地面积', - 'areas.regex' => '请正确填写基地面积', - 'workforce.required' => '请填写就业人数', - 'workforce.min' => '就业人数最小为0', - 'address.string' => '请正确填写基地地址', - 'address_lat.regex' => '请正确填写经度', - 'address_lng.regex' => '请正确填写纬度', + 'areas.required' => '请填写面积', + 'areas.regex' => '请正确填写面积', + 'workforce.required' => '请填写人数', + 'workforce.min' => '人数最小为0', + 'address.string' => '请正确填写地址', ]; return $messages; diff --git a/app/Http/Requestes/CropRequest.php b/app/Http/Requestes/CropRequest.php new file mode 100644 index 0000000..8d534d6 --- /dev/null +++ b/app/Http/Requestes/CropRequest.php @@ -0,0 +1,50 @@ + 'required', + 'parent_id' => 'nullable|integer', + 'name' => 'required|string|max:100', + 'is_end' => 'required|boolean', + 'unit' => 'required|string|max:100', + 'extends' => 'nullable|array', + 'extends.*' => 'required_array_keys:name,unit', + 'sort' => 'integer', + ]; + } + + public function messages() + { + $messages = [ + 'category_id' => '请选择所属业', + 'parent_id' => '请选择上级', + 'name' => '请填写名称', + 'is_end' => '请选择是否结点', + 'unit' => '请填写单位', + 'extends' => '请正确填写扩展字段', + 'sort' => '请正确填写排序' + ]; + + return $messages; + } + + protected function failedValidation(Validator $validator) + { + $error = $validator->errors()->all(); + throw new HttpResponseException(response()->json(['data' => [], 'code' => 400, 'message' => $error[0]])); + } +} diff --git a/app/Http/Requestes/CropYieldRequest.php b/app/Http/Requestes/CropYieldRequest.php index 8305fc3..e561b78 100644 --- a/app/Http/Requestes/CropYieldRequest.php +++ b/app/Http/Requestes/CropYieldRequest.php @@ -17,9 +17,12 @@ class CropYieldRequest extends FormRequest { return [ 'time_year' => 'required|date_format:Y', + 'quarter' => 'required|integer|min:1|max:4', 'crop_id' => 'required|integer|min:0', - 'yields' => 'required|array|min:1', - 'yields.*' => 'required_array_keys:base_id,yield,cultivated,output', + 'base_id' => 'required|integer|min:0', + 'yield' => 'required|integer|min:0', + 'cultivated' => 'required|regex:/^\d+(\.\d{1,2})?$/', + 'output' => 'required|regex:/^\d+(\.\d{1,2})?$/', ]; } @@ -27,9 +30,12 @@ class CropYieldRequest extends FormRequest { $messages = [ 'time_year' => '请选择年份', + 'quarter' => '请选择季度', 'crop_id' => '请选择农作物', - 'yields' => '请填写基地以及产值信息', - 'yields.*.required_array_keys' => '请填写完整基地以及产值信息', + 'base_id' => '请选择地区', + 'yield' => '请填写产量', + 'cultivated' => '请填写种养殖面积', + 'output' => '请填写产值', ]; return $messages; diff --git a/app/Http/Resources/AgriculturalBaseResource.php b/app/Http/Resources/AgriculturalBaseResource.php index f698cbe..dbdaf45 100644 --- a/app/Http/Resources/AgriculturalBaseResource.php +++ b/app/Http/Resources/AgriculturalBaseResource.php @@ -25,7 +25,6 @@ class AgriculturalBaseResource extends JsonResource 'map' => $this->map ?? '', 'areas' => ($this->areas ?? 0.00).' 亩', 'workforce' => $this->workforce ?? 0, - 'crops' => KeywordResource::collection($this->whenLoaded('crops')), ]; } } diff --git a/app/Http/Resources/CropResource.php b/app/Http/Resources/CropResource.php new file mode 100644 index 0000000..f3c96a6 --- /dev/null +++ b/app/Http/Resources/CropResource.php @@ -0,0 +1,24 @@ + $this->id, + 'parent_id' => $this->parent_id, + 'name' => $this->name, + 'is_end' => $this->is_end, + ]; + } +} diff --git a/app/ModelFilters/AgriculturalBaseFilter.php b/app/ModelFilters/AgriculturalBaseFilter.php index f2f95a3..20a90a7 100644 --- a/app/ModelFilters/AgriculturalBaseFilter.php +++ b/app/ModelFilters/AgriculturalBaseFilter.php @@ -6,4 +6,7 @@ use EloquentFilter\ModelFilter; class AgriculturalBaseFilter extends ModelFilter { + public function type($type){ + return $this->where('type', $type); + } } diff --git a/app/ModelFilters/CropFilter.php b/app/ModelFilters/CropFilter.php new file mode 100644 index 0000000..f81bd81 --- /dev/null +++ b/app/ModelFilters/CropFilter.php @@ -0,0 +1,28 @@ +where('category_id', $categoryId); + } + + public function type($type) + { + $q = $this; + switch ($type) { + case "top": + $q->whereNull('parent_id'); + break; + case 'all': + break; + default: + break; + } + return $q; + } +} diff --git a/app/Models/AgriculturalBase.php b/app/Models/AgriculturalBase.php index ac4cc93..ec718d1 100644 --- a/app/Models/AgriculturalBase.php +++ b/app/Models/AgriculturalBase.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Enums\BaseType; use EloquentFilter\Filterable; use Illuminate\Database\Eloquent\Model; use Peidikeji\Keywords\Models\Keywords; @@ -10,11 +11,24 @@ class AgriculturalBase extends Model { use Filterable; + protected $casts = [ + 'type' => BaseType::class, + ]; + protected $fillable = [ + 'type', 'name', 'person', 'address', 'address_lat', 'address_lng', 'description', 'map', 'areas', 'workforce', ]; + public function scopeBase($q){ + return $q->where('type', BaseType::Base); + } + + public function scopeTown($q){ + return $q->where('type', BaseType::Town); + } + public function scopeSort($q) { return $q->orderBy('created_at', 'desc'); diff --git a/app/Models/Crop.php b/app/Models/Crop.php new file mode 100644 index 0000000..41df09f --- /dev/null +++ b/app/Models/Crop.php @@ -0,0 +1,23 @@ +orderBy('sort', 'desc')->orderBy('created_at', 'desc'); + } + + protected $fillable = [ + 'category_id', + 'name', 'parent_id', + 'path', 'is_end', + 'sort', + 'extends' + ]; +} diff --git a/app/Models/CropFlow.php b/app/Models/CropFlow.php index 0649073..498e00d 100644 --- a/app/Models/CropFlow.php +++ b/app/Models/CropFlow.php @@ -22,7 +22,7 @@ class CropFlow extends Model */ public function crop() { - return $this->belongsTo(Keywords::class, 'crop_id'); + return $this->belongsTo(Crop::class, 'crop_id'); } public function createdBy() diff --git a/app/Models/CropYield.php b/app/Models/CropYield.php index 12dd1ed..3303267 100644 --- a/app/Models/CropYield.php +++ b/app/Models/CropYield.php @@ -32,7 +32,7 @@ class CropYield extends Model */ public function crop() { - return $this->belongsTo(Keywords::class, 'crop_id'); + return $this->belongsTo(Crop::class, 'crop_id'); } public function createdBy() diff --git a/database/migrations/2022_10_11_025843_create_agricultural_bases_table.php b/database/migrations/2022_10_11_025843_create_agricultural_bases_table.php index c0ac331..4b430b1 100644 --- a/database/migrations/2022_10_11_025843_create_agricultural_bases_table.php +++ b/database/migrations/2022_10_11_025843_create_agricultural_bases_table.php @@ -15,27 +15,28 @@ return new class extends Migration { Schema::create('agricultural_bases', function (Blueprint $table) { $table->id(); - $table->string('name')->comment('基地名称'); - $table->string('person')->comment('基地负责人'); - $table->string('address')->nullable()->comment('基地地址'); + $table->string('name')->comment('名称'); + $table->unsignedTinyInteger('type')->default(1)->comment('类别:1基地,2城镇'); + $table->string('person')->nullable()->comment('负责人'); + $table->string('address')->nullable()->comment('地址'); $table->string('address_lat')->nullable()->comment('地址经度'); $table->string('address_lng')->nullable()->comment('地址维度'); $table->text('description')->nullable()->comment('基地描述'); $table->string('map')->nullable()->comment('基地地图'); $table->decimal('areas', 12, 2)->nullable()->comment('基地面积'); - $table->unsignedInteger('workforce')->nullable()->comment('职工数量'); + $table->unsignedInteger('workforce')->nullable()->comment('人员数量'); $table->timestamps(); - $table->comment('基地数据表'); + $table->comment('地区数据表'); }); Schema::create('base_crops', function (Blueprint $table) { $table->id(); - $table->unsignedBigInteger('base_id')->comment('基地ID'); + $table->unsignedBigInteger('base_id')->comment('地区ID'); $table->unsignedBigInteger('crop_id')->comment('农作物ID'); - $table->comment('基地农作物表'); + $table->comment('地区农作物表'); }); } diff --git a/database/migrations/2022_10_17_111601_create_crop_yields_table.php b/database/migrations/2022_10_17_111601_create_crop_yields_table.php index 708c204..b5a37df 100644 --- a/database/migrations/2022_10_17_111601_create_crop_yields_table.php +++ b/database/migrations/2022_10_17_111601_create_crop_yields_table.php @@ -15,12 +15,14 @@ return new class extends Migration { Schema::create('crop_yields', function (Blueprint $table) { $table->id(); - $table->unsignedBigInteger('base_id')->comment('基地ID'); + $table->unsignedBigInteger('base_id')->comment('地区ID'); $table->unsignedBigInteger('crop_id')->comment('农产品ID'); $table->unsignedInteger('time_year')->comment('年份'); - $table->unsignedDecimal('yield', 12, 2)->comment('产量(斤)'); + $table->unsignedInteger('quarter')->nullable()->comment('季度'); + $table->unsignedDecimal('yield', 12, 2)->comment('产量'); $table->unsignedDecimal('cultivated', 12, 2)->comment('耕地面积(亩)'); $table->unsignedDecimal('output', 12, 2)->comment('产值(元)'); + $table->text('extends')->nullable()->comment('扩展数据'); $table->unsignedBigInteger('created_by')->comment('创建人ID'); $table->unsignedBigInteger('updated_by')->comment('修改人ID'); $table->timestamps(); diff --git a/database/migrations/2022_10_21_105432_create_crops_table.php b/database/migrations/2022_10_21_105432_create_crops_table.php new file mode 100644 index 0000000..8529eb4 --- /dev/null +++ b/database/migrations/2022_10_21_105432_create_crops_table.php @@ -0,0 +1,39 @@ +id(); + $table->unsignedBigInteger('category_id')->comment('行业ID'); + $table->unsignedBigInteger('parent_id')->nullable()->comment('父级ID'); + $table->string('name')->comment('名称'); + $table->string('path')->nullable()->comment('路径'); + $table->unsignedTinyInteger('is_end')->default(0)->comment('是否结点'); + $table->string('unit')->nullable()->comment('单位'); + $table->unsignedInteger('sort')->default(0)->comment('排序'); + $table->text('extends')->nullable()->comment('扩展字段'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('crop_cates'); + } +}; diff --git a/routes/api.php b/routes/api.php index 7ff4c6f..0248100 100644 --- a/routes/api.php +++ b/routes/api.php @@ -28,6 +28,9 @@ Route::group(['middleware' => 'auth:sanctum'], function () { Route::get('citydata-statistics', [CityDataController::class, 'statistics'])->name('citydata_statistics.index'); //基地数据 Route::apiResource('agricultural-basic', AgriculturalBaseController::class)->names('agricultural_basic'); + //农作物 + Route::apiResource('crops', CropController::class)->names('crops'); + //农业结构 Route::apiResource('crop-structures', CropStructureController::class)->names('crops_build'); //产量