Ver código fonte

基础提交

aexiaoliou 1 ano atrás
pai
commit
82dcd5f978
54 arquivos alterados com 445 adições e 2193 exclusões
  1. 1 0
      .gitignore
  2. 0 1
      api/.gitignore
  3. 17 0
      api/.local.env
  4. 0 0
      api/.test.env
  5. 5 5
      api/README.md
  6. 1 8
      api/app/admin/controller/Admin.php
  7. 0 27
      api/app/admin/controller/Allocation.php
  8. 5 5
      api/app/admin/controller/Base.php
  9. 13 29
      api/app/admin/controller/BaseAuthorized.php
  10. 0 62
      api/app/admin/controller/Good.php
  11. 0 35
      api/app/admin/controller/GoodClass.php
  12. 1 15
      api/app/admin/controller/Index.php
  13. 0 40
      api/app/admin/controller/Io.php
  14. 0 16
      api/app/admin/controller/IoDetail.php
  15. 2 4
      api/app/admin/controller/Login.php
  16. 0 9
      api/app/admin/controller/Menu.php
  17. 0 4
      api/app/admin/controller/Message.php
  18. 97 0
      api/app/admin/controller/Project.php
  19. 0 33
      api/app/admin/controller/Repo.php
  20. 0 36
      api/app/admin/controller/Stock.php
  21. 4 5
      api/app/admin/controller/Test.php
  22. 0 1
      api/app/common/model/Admin.php
  23. 0 66
      api/app/common/model/Allocation.php
  24. 0 37
      api/app/common/model/AllocationDetail.php
  25. 0 24
      api/app/common/model/Check.php
  26. 0 25
      api/app/common/model/CheckDetail.php
  27. 21 0
      api/app/common/model/Contract.php
  28. 0 26
      api/app/common/model/Good.php
  29. 0 16
      api/app/common/model/GoodClass.php
  30. 0 84
      api/app/common/model/Io.php
  31. 0 94
      api/app/common/model/IoDetail.php
  32. 50 0
      api/app/common/model/Project.php
  33. 43 0
      api/app/common/model/ProjectSchedule.php
  34. 14 0
      api/app/common/model/ProjectStatus.php
  35. 0 33
      api/app/common/model/Repo.php
  36. 0 30
      api/app/common/model/Stock.php
  37. 0 30
      api/app/common/model/Transit.php
  38. 0 26
      api/app/common/model/TransitDetail.php
  39. 0 245
      api/app/common/service/AllocationService.php
  40. 0 15
      api/app/common/service/CheckService.php
  41. 21 0
      api/app/common/service/ContractService.php
  42. 0 79
      api/app/common/service/GoodClassService.php
  43. 0 286
      api/app/common/service/GoodService.php
  44. 0 51
      api/app/common/service/IoDetailService.php
  45. 0 420
      api/app/common/service/IoService.php
  46. 20 0
      api/app/common/service/ProjectScheduleService.php
  47. 57 0
      api/app/common/service/ProjectService.php
  48. 32 0
      api/app/common/service/ProjectStatusService.php
  49. 0 75
      api/app/common/service/RepoService.php
  50. 0 164
      api/app/common/service/StockService.php
  51. 29 29
      api/composer.lock
  52. 2 2
      api/generate-schema.py
  53. 0 1
      api/view/README.md
  54. 10 0
      docker/project-manager-backend.dockerfile

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+.vscode/settings.json

+ 0 - 1
api/.gitignore

@@ -1,5 +1,4 @@
 /.idea
-/.vscode
 /vendor
 *.log
 .env

+ 17 - 0
api/.local.env

@@ -0,0 +1,17 @@
+APP_DEBUG = true
+
+[APP]
+DEFAULT_TIMEZONE = Asia/Shanghai
+
+[DATABASE]
+TYPE = mysql
+HOSTNAME = 127.0.0.1
+DATABASE = project-manager
+USERNAME = root
+PASSWORD = root
+HOSTPORT = 3306
+CHARSET = utf8mb4
+DEBUG = true
+
+[LANG]
+default_lang = zh-cn

api/.example.env → api/.test.env


+ 5 - 5
api/README.md

@@ -3,19 +3,19 @@
 ### build 
 ```bash
 cd ../docker
-docker build -t lechang-storage-backend:8.0-apache -f ./lechang-storage-backend.dockerfile .
+docker build -t project-manager-backend:8.0-apache -f ./project-manager-backend.dockerfile .
 ```
 
 ### run
 ```bash
 cd api
 composer install
-docker run -d --rm -it -v $PWD:/var/www/html -p 8880:80 lechang-storage-backend:8.0-apache
+docker run -d --rm -it -v $PWD:/var/www/html -p 8880:80 project-manager-backend:8.0-apache
 
 # docker nginx-proxy env
 docker run -d --rm -it -v $PWD:/var/www/html -e VIRTUAL_HOST='~..*' \
-    -e VIRTUAL_PATH='/lechang-storage' \
+    -e VIRTUAL_PATH='/project-manager' \
     -e VIRTUAL_DEST='/public' \
-    --name lechang-storage \
-    --net use-proxy lechang-storage-backend:8.0-apache
+    --name project-manager \
+    --net use-proxy project-manager-backend:8.0-apache
 ```

+ 1 - 8
api/app/admin/controller/Admin.php

@@ -28,8 +28,6 @@ class Admin extends BaseAuthorized
             $this->error($res['msg'], $res["code"]);
         }
         return $this->success($res["data"]);
-
-//        abort(200,'aaa');
     }
 
 
@@ -77,20 +75,15 @@ class Admin extends BaseAuthorized
 
     /**
      * 删除
-     * @return void
      */
     public function delete()
     {
-        //第1段:校验输入
         $param = request()->param();
         $rules = [
             'ids|删除项' => 'require',
         ];
         $this->autoValid($rules, $param);
-        //第2段:执行业务
         $res = \app\common\model\Admin::del($param["ids"]);
-//        Log::record("res:" . print_r($res, true), "debug");
-        //第3段:格式化输出
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
         }
@@ -123,7 +116,7 @@ class Admin extends BaseAuthorized
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
         }
-        return $this->success($res["data"],"重置成功");
+        return $this->success($res["data"], "重置成功");
     }
 
 }

+ 0 - 27
api/app/admin/controller/Allocation.php

@@ -1,27 +0,0 @@
-<?php
-
-namespace app\admin\controller;
-use app\admin\attr\Permission;
-
-#[Permission('allocation')]
-class Allocation extends BaseAuthorized
-{
-    public function page()
-    {
-        return $this->AllocationService()->page();
-    }
-
-    public function info()
-    {
-        return $this->AllocationService()->info();
-    }
-    public function create()
-    {
-        return $this->AllocationService()->createTrans($this->admin);
-    }
-
-    public function revert()
-    {
-        return $this->AllocationService()->revertTrans($this->admin);
-    }
-}

+ 5 - 5
api/app/admin/controller/Base.php

@@ -4,22 +4,22 @@
 namespace app\admin\controller;
 
 
+use app\common\util\Result;
 use think\App;
 use think\Response;
 use think\facade\Log;
 use app\BaseController;
 use app\common\ErrorCode;
 use app\common\model\Admin;
-use app\middleware\AutoResult;
 use app\common\middleware\WriteLog;
 use think\annotation\route\Middleware;
 use think\exception\ValidateException;
 use think\exception\HttpResponseException;
 
-#[Middleware([AutoResult::class, WriteLog::class])]
+#[Middleware([WriteLog::class])]
 class Base extends BaseController
 {
-    protected $middleware = [AutoResult::class, WriteLog::class];
+    protected $middleware = [WriteLog::class];
 
     protected $checkTokenOpen = false; //是否校验token
     protected $checkApiSignOpen = false; //是否校验签名
@@ -53,7 +53,7 @@ class Base extends BaseController
             //from url
             $token = input("token");
         }
-        return $token;
+        return Result::rest($token);
     }
 
     /**
@@ -98,7 +98,7 @@ class Base extends BaseController
     public function success($data, $msg = "")
     {
         Log::record("response:" . mb_substr(json_encode($data, JSON_UNESCAPED_UNICODE), 0, 1000) . ",code:0", "debug");
-        return $data;
+        return Result::rest($data);
     }
 
     /**

+ 13 - 29
api/app/admin/controller/BaseAuthorized.php

@@ -4,16 +4,13 @@
 namespace app\admin\controller;
 
 use app\middleware\AutoResult;
-use app\common\service\IoService;
 use app\common\middleware\WriteLog;
-use app\common\service\GoodService;
-use app\common\service\RepoService;
-use app\common\service\StockService;
-use app\common\service\IoDetailService;
+use app\common\service\ProjectService;
+use app\common\service\ContractService;
 use app\common\exception\CatchException;
-use app\common\service\GoodClassService;
-use app\common\service\AllocationService;
+use app\common\service\ProjectStatusService;
 use app\admin\middleware\CheckPermissionAttr;
+use app\common\service\ProjectScheduleService;
 
 /**
  * 需要登录 的基类
@@ -26,34 +23,21 @@ class BaseAuthorized extends Base
     
     protected $checkTokenOpen = true;
 
-    public function IoService(): IoService
+    protected function ProjectService(): ProjectService
     {
-        return (new IoService($this->app))->exceptionClass(CatchException::class);
+        return (new ProjectService($this->app))->exceptionClass(CatchException::class);
     }
-    public function IoDetailService(): IoDetailService
-    {
-        return (new IoDetailService($this->app))->exceptionClass(CatchException::class);
-    }
-    public function GoodClassService(): GoodClassService
-    {
-        return (new GoodClassService($this->app))->exceptionClass(CatchException::class);
-    }
-    public function GoodService(): GoodService
-    {
-        return (new GoodService($this->app))->exceptionClass(CatchException::class);
-    }
-    public function RepoService(): RepoService
+
+    protected function ProjectScheduleService(): ProjectScheduleService
     {
-        return (new RepoService($this->app))->exceptionClass(CatchException::class);
+        return (new ProjectScheduleService($this->app))->exceptionClass(CatchException::class);
     }
-
-    public function StockService(): StockService
+    protected function ProjectStatusService(): ProjectStatusService
     {
-        return (new StockService($this->app))->exceptionClass(CatchException::class);
+        return (new ProjectStatusService($this->app))->exceptionClass(CatchException::class);
     }
-
-    public function AllocationService(): AllocationService
+    protected function ContractService(): ContractService
     {
-        return (new AllocationService($this->app))->exceptionClass(CatchException::class);
+        return (new ContractService($this->app))->exceptionClass(CatchException::class);
     }
 }

+ 0 - 62
api/app/admin/controller/Good.php

@@ -1,62 +0,0 @@
-<?php
-
-namespace app\admin\controller;
-
-use app\admin\attr\Permission;
-use app\common\util\Result;
-use think\annotation\route\Get;
-use think\annotation\route\Group;
-use app\common\model\Good as GoodModel;
-use app\admin\controller\BaseAuthorized;
-
-#[Permission('good')]
-#[Group('good')]
-class Good extends BaseAuthorized
-{
-    public function page()
-    {
-        return $this->GoodService()->page();
-    }
-
-    #[Get(rule: 'get/name')]
-    public function getByName($name)
-    {
-        return GoodModel::getByName($name) ?? Result::failed('不存在的商品');
-    }
-
-    #[Get(rule: 'get/no')]
-    public function getByNo($no)
-    {
-        return GoodModel::getByNo($no) ?? Result::failed('不存在的商品');
-    }
-
-    public function create()
-    {
-        return $this->GoodService()->create();
-    }
-
-    public function delete()
-    {
-        return $this->GoodService()->delete();
-    }
-
-    public function update()
-    {
-        return $this->GoodService()->update();
-    }
-
-    public function template()
-    {
-        return download(public_path('static/execl') . 'GOOD_TEMPLATE.xlsx', '物品导入模板.xlsx');
-    }
-
-    public function import()
-    {
-        return $this->GoodService()->import();
-    }
-
-    public function export()
-    {
-        return $this->GoodService()->export();
-    }
-}

+ 0 - 35
api/app/admin/controller/GoodClass.php

@@ -1,35 +0,0 @@
-<?php
-
-namespace app\admin\controller;
-
-use app\admin\attr\Permission;
-use app\admin\controller\BaseAuthorized;
-
-#[Permission('good_class')]
-class GoodClass extends BaseAuthorized
-{
-    public function page()
-    {
-        return $this->GoodClassService()->page();
-    }
-
-    public function all()
-    {
-        return $this->GoodClassService()->all();
-    }
-
-    public function create()
-    {
-        return $this->GoodClassService()->create();
-    }
-
-    public function update()
-    {
-        return $this->GoodClassService()->update();
-    }
-
-    public function delete()
-    {
-        return $this->GoodClassService()->delete();
-    }
-}

+ 1 - 15
api/app/admin/controller/Index.php

@@ -10,19 +10,5 @@ use app\common\model\Allocation;
 #[Permission('index')]
 class Index extends BaseAuthorized
 {
-    public function statistics()
-    {
-        $ioCount = Io::count();
-        $checkCount = Io::where('change_type', '=', Io::CHANGE_TYPE_CHECK)->count();
-        $allcationCount = Allocation::count();
-        $goodTotal = Stock::sum('num');
-        $repoCount = Repo::count();
-        return [
-            'ioCount' => $ioCount,
-            'checkCount' => $checkCount,
-            'allcationCount' => $allcationCount,
-            'goodTotal' => $goodTotal,
-            'repoCount' => $repoCount
-        ];
-    }
+    
 }

+ 0 - 40
api/app/admin/controller/Io.php

@@ -1,40 +0,0 @@
-<?php
-
-namespace app\admin\controller;
-
-use app\admin\attr\Permission;
-use app\admin\controller\BaseAuthorized;
-
-#[Permission('io')]
-class Io extends BaseAuthorized
-{
-    public function page()
-    {
-        return $this->IoService()->page();
-    }
-
-    public function info()
-    {
-        return $this->IoService()->info();
-    }
-
-    public function create()
-    {
-        return $this->IoService()->createTrans(admin: $this->admin);
-    }
-
-    public function complete()
-    {
-        return $this->IoService()->completeTrans(admin: $this->admin);
-    }
-
-    public function revert()
-    {
-        return $this->IoService()->revertTrans(admin: $this->admin);
-    }
-
-    public function export()
-    {
-        return $this->IoService()->export();
-    }
-}

+ 0 - 16
api/app/admin/controller/IoDetail.php

@@ -1,16 +0,0 @@
-<?php
-
-namespace app\admin\controller;
-
-class IoDetail extends BaseAuthorized
-{
-    public function page()
-    {
-        return $this->IoDetailService()->page();
-    }
-
-    public function transits()
-    {
-        return $this->IoDetailService()->transits();
-    }
-}

+ 2 - 4
api/app/admin/controller/Login.php

@@ -1,20 +1,18 @@
 <?php
 
 namespace app\admin\controller;
+use app\common\model\Admin;
 
 class Login extends Base
 {
     public function doLogin(){
-        //第1段:校验输入
         $param = request()->param();
         $rules = [
             "phone|用户名" => "require",
             'password|密码' => 'require',
         ];
         $this->autoValid($rules, $param);
-        //第2段:执行业务
-        $res = \app\common\model\Admin::login($param["phone"], $param["password"]);
-        //第3段:格式化输出
+        $res = Admin::login($param["phone"], $param["password"]);
         if ($res["code"] != 0) {
             $this->error($res['msg'], $res["code"]);
         }

+ 0 - 9
api/app/admin/controller/Menu.php

@@ -9,31 +9,22 @@ class Menu extends Base
 {
     /**
      * 中间件校验
-     * 1.权限
      * @var array[]
      */
     protected $middleware = [
-        //except 除了某个方法不校验,其余校验
-        //only 仅仅校验某个方法
         Login::class => ['except' => ['']],
-//        Auth::class => ['except' => ['']],
     ];
 
     /**
      * 获取菜单
      * @param Request $request
-     * @return void
      */
     public function list(Request $request)
     {
         $menuJson = file_get_contents(root_path() . "config/json/menu.json");
         $menu = json_decode($menuJson, true);
 
-//        $admin = $request->admin;
         $role_codes = [];
-//        if ($admin->role && $admin->role->codes) {
-//            $role_codes = explode(',', $admin->role->codes);
-//        }
         $role_codes[] = 'home';
         $role_codes[] = 'admin';
         $fin_menu = $this->getFinMenu($menu, $role_codes,1);

+ 0 - 4
api/app/admin/controller/Message.php

@@ -11,12 +11,9 @@ class Message extends Base
 {
     /**
      * 中间件校验
-     * 1.权限
      * @var array[]
      */
     protected $middleware = [
-        //except 除了某个方法不校验,其余校验
-        //only 仅仅校验某个方法
         Login::class => ['except' => ['']],
         Auth::class => ['except' => ['']],
     ];
@@ -25,7 +22,6 @@ class Message extends Base
     /**
      * 列表
      * @param Request $request
-     * @return void
      */
     public function list(Request $request)
     {

+ 97 - 0
api/app/admin/controller/Project.php

@@ -0,0 +1,97 @@
+<?php
+
+namespace app\admin\controller;
+
+use app\admin\attr\Permission;
+use app\common\util\Result;
+use think\annotation\route\Get;
+use think\annotation\route\Group;
+use think\annotation\route\Post;
+
+#[Permission('project')]
+#[Group('project')]
+class ProjectController extends BaseAuthorized
+{
+    /*
+     * 基础接口 
+     */
+
+    public function page()
+    {
+        $res = $this->ProjectService()->page();
+        return Result::rest($res);
+    }
+
+    public function create()
+    {
+        $res = $this->ProjectService()->create();
+        return Result::rest($res);
+    }
+
+    public function update()
+    {
+        $res = $this->ProjectService()->update();
+        return Result::rest($res);
+    }
+
+    public function delete()
+    {
+        $res = $this->ProjectService()->delete();
+        return Result::rest($res);
+    }
+
+    /*
+    * 状态相关接口
+    */
+
+    #[Get('status/list')]
+    public function listStatus()
+    {
+        $res = $this->ProjectStatusService()->list();
+        return Result::rest($res);
+    }
+
+    #[Post('status/create')]
+    public function createStatus()
+    {
+        $res = $this->ProjectStatusService()->create();
+        return Result::rest($res);
+    }
+
+    #[Post('status/update')]
+    public function updateStatus()
+    {
+        $res = $this->ProjectStatusService()->update();
+        return Result::rest($res);
+    }
+
+    /*
+    * 进度相关接口
+    */
+
+    #[Post('schedule/create')]
+    public function createSchedule()
+    {
+        $res = $this->ProjectScheduleService()->create();
+        return Result::rest($res);
+    }
+
+    /*
+    * 合同相关接口
+    */
+
+    #[Post('contract/create')]
+    public function createContract()
+    {
+        $res = $this->ContractService()->create();
+        return Result::rest($res);
+    }
+
+    #[Post('contract/update')]
+    public function updateContract()
+    {
+        $res = $this->ContractService()->update();
+        return Result::rest($res);
+    }
+
+}

+ 0 - 33
api/app/admin/controller/Repo.php

@@ -1,33 +0,0 @@
-<?php
-
-namespace app\admin\controller;
-use app\admin\attr\Permission;
-
-#[Permission('repo')]
-class Repo extends BaseAuthorized
-{
-    public function page()
-    {
-        return $this->RepoService()->page();
-    }
-
-    public function all()
-    {
-        return $this->RepoService()->all();
-    }
-
-    public function create()
-    {
-        return $this->RepoService()->create();
-    }
-
-    public function update()
-    {
-        return $this->RepoService()->update();
-    }
-
-    public function delete()
-    {
-        return $this->RepoService()->delete();
-    }
-}

+ 0 - 36
api/app/admin/controller/Stock.php

@@ -1,36 +0,0 @@
-<?php
-
-namespace app\admin\controller;
-use app\admin\attr\Permission;
-use think\annotation\route\Get;
-use think\annotation\route\Group;
-
-#[Group('stock')]
-#[Permission('stock')]
-class Stock extends BaseAuthorized
-{
-    public function page()
-    {
-        return $this->StockService()->page();
-    }
-    public function allByRepo()
-    {
-        return $this->StockService()->allByRepo();
-    }
-
-    public function info()
-    {
-        return $this->StockService()->info();
-    }
-
-    #[Get('get/good-repo')]
-    public function getByGoodAndRepo()
-    {
-        return $this->StockService()->getByGoodAndRepo();
-    }
-
-    public function export()
-    {
-        return $this->StockService()->export();
-    }
-}

+ 4 - 5
api/app/admin/controller/Test.php

@@ -2,19 +2,18 @@
 
 namespace app\admin\controller;
 
-use app\common\model\Admin;
+use think\facade\Db;
 
 class Test extends Base
 {
     public function index()
     {
-        return $this->success([], "成功了");// returnFormat(0,"succ",[]);
+        return $this->success([], "成功了");
     }
 
-    public function page()
+    public function db()
     {
-        $list = Admin::where([])->paginate(10);
-        return $this->success($list);
+        return Db::execute('SELECT 1');
     }
 
 }

+ 0 - 1
api/app/common/model/Admin.php

@@ -129,7 +129,6 @@ class Admin extends Base
      * 获取管理员列表
      * @param $keyword
      * @param $listRow
-     * @return void
      * @throws \think\db\exception\DbException
      */
     public static function getList($keyword = "", $listRow = 20)

+ 0 - 66
api/app/common/model/Allocation.php

@@ -1,66 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-use app\common\model\Base;
-use app\common\model\AllocationDetail;
-
-/**
- * 物品调拨单
- * 
- * @property string $date 出入库日期
- * @property int $from_repo_id 调出仓库id
- * @property int $to_repo_id 调入仓库id
- * @property int $revert_id 回滚id
- * @property int $out_io_id 调出单ids
- * @property int $in_io_id 调入单id
- * @property array<AllocationDetail> $details 明细
- * @property Repo $from 调出仓库
- * @property Repo $to 调入仓库
- * @property Io $out_id 调出单
- * @property Io $in_io 调入单
- */
-class Allocation extends Base
-{
-    protected $schema = [
-        'id'         => 'int',       // id
-        'from_repo_id'       => 'int',       // 调出仓库ID
-        'to_repo_id'         => 'int',       // 调入仓库ID
-        'create_time'        => 'datetime',  // 创建时间
-        'update_time'        => 'datetime',  // 更新时间
-        'delete_time'        => 'datetime',  // 删除时间
-        'valid'      => 'tinyint',   // 状态,1启用,0禁用
-        'date'       => 'date',      // 出入库日期
-        'remark'     => 'varchar',   // 备注
-        'admin_id'   => 'int',       // 操作人ID
-        'revert_id'      => 'int',       // 回滚id
-        'out_io_id'      => 'int',       // 调出单id
-        'in_io_id'       => 'int',       // 调入单id
-    ];
-
-    public function details()
-    {
-        return $this->hasMany(AllocationDetail::class);
-    }
-
-    public function from()
-    {
-        return $this->belongsTo(Repo::class, 'from_repo_id', 'id');
-    }
-
-    public function to()
-    {
-        return $this->belongsTo(Repo::class, 'to_repo_id', 'id');
-    }
-
-    public function out_io()
-    {
-        return $this->belongsTo(Io::class, 'out_io_id', 'id');
-    }
-
-    public function in_io()
-    {
-        return $this->belongsTo(Io::class, 'in_io_id', 'id');
-    }
-
-}

+ 0 - 37
api/app/common/model/AllocationDetail.php

@@ -1,37 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-use app\common\model\Allocation;
-use app\common\model\Base;
-
-/**
- * 
- * @property int $good_id 物品id
- * @property number $num 数量
- */
-class AllocationDetail extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'good_id'        => 'int',       // 物品ID
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-        'num'    => 'float',     // 数量
-        'date'   => 'date',      // 出入库日期
-        'remark'         => 'varchar',   // 备注
-        'allocation_id'  => 'int',       // 调拔单订单ID
-    ];
-
-    public function allocation()
-    {
-        return $this->belongsTo(Allocation::class);
-    }
-
-    public function good()
-    {
-        return $this->belongsTo(Good::class);
-    }
-}

+ 0 - 24
api/app/common/model/Check.php

@@ -1,24 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-class Check extends Base
-{
-        protected $schema = [
-        'id'     => 'int',       // id
-        'repertory_id'   => 'int',       // 仓库ID
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-        'date'   => 'date',      // 出入库日期
-        'remark'         => 'varchar',   // 备注
-        'sn'     => 'varchar',   // 订单号
-        'admin_id'       => 'int',       // 操作人ID
-    ];
-
-    public function details()
-    {
-        return $this->hasMany(CheckDetail::class);
-    }
-}

+ 0 - 25
api/app/common/model/CheckDetail.php

@@ -1,25 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-class CheckDetail extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'good_id'        => 'int',       // 物品ID
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-        'origin_num'     => 'float',     // 原数量
-        'num'    => 'float',     // 数量
-        'date'   => 'date',      // 出入库日期
-        'remark'         => 'varchar',   // 备注
-        'check_id'       => 'int',       // 盘点单ID
-    ];
-
-    public function check()
-    {
-        return $this->belongsTo(Check::class);
-    }
-}

+ 21 - 0
api/app/common/model/Contract.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace app\common\model;
+
+class Contract extends Base
+{
+    protected $schema = [
+        'id'     => 'int',       // id
+        'create_time'    => 'datetime',  // 创建时间
+        'update_time'    => 'datetime',  // 更新时间
+        'delete_time'    => 'datetime',  // 删除时间
+        'project_id'     => 'int',       // 项目id
+        'client'         => 'varchar',   // 客户
+        'developer'      => 'varchar',   // 乙方
+        'title'  => 'varchar',   // 标题
+        'date'   => 'date',      // 合同签署日期
+        'start_date'     => 'date',      // 合同开始日期
+        'end_date'       => 'date',      // 合同结束日期
+        'amout'  => 'int',       // 合同金额,单位为分
+    ];
+}

+ 0 - 26
api/app/common/model/Good.php

@@ -1,26 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-class Good extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'no'     => 'varchar',   // 编号
-        'name'   => 'varchar',   // 物品名称
-        'desc'   => 'varchar',   // 物品介绍
-        'unit'   => 'varchar',   // 单位
-        'img'    => 'varchar',   // 图片
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-        'spec'   => 'varchar',   // 规格
-        'good_class_id'  => 'int',       // 类别
-    ];
-
-    public function goodClass()
-    {
-        return $this->belongsTo(GoodClass::class);
-    }
-}

+ 0 - 16
api/app/common/model/GoodClass.php

@@ -1,16 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-class GoodClass extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'name'   => 'varchar',   // 物品类别名称
-        'desc'   => 'varchar',   // 类别说明
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-    ];
-}

+ 0 - 84
api/app/common/model/Io.php

@@ -1,84 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-/**
- * 出入库
- * 
- * @property string $sn 编号
- * @property string $date 出入库日期
- * @property int $type 类型,1入库,2出库
- * @property int $repo_id 仓库id
- * @property int $change_type 变更原因,1出入库,2调拔,3.盘点
- * @property int $revert_id 回滚id
- * @property array<IoDetail>|\think\Collection<IoDetail> $details 出入库明细
- */
-class Io extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'repo_id'        => 'int',       // 仓库ID
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'date'   => 'date',      // 出入库日期
-        'type'   => 'tinyint',   // 类型,1入库,2出库
-        'remark'         => 'varchar',   // 备注
-        'sn'     => 'varchar',   // 订单号
-        'admin_id'       => 'int',       // 操作人ID
-        'change_type'    => 'tinyint',  // 变更原因,1出入库,2调拔,3.盘点
-        'source' => 'varchar',
-        'revert_id'      => 'int'       // 回滚id
-    ];
-
-    /**
-     * 入库
-     */
-    const TYPE_IN = 1;
-    /**
-     * 出库
-     */
-    const TYPE_OUT = 2;
-
-    
-    /**
-     * 出入库
-     */
-    const CHANGE_TYPE_IO = 1;
-    /**
-     * 调拨
-     */
-    const CHANGE_TYPE_ALLOCATION = 2;
-    /**
-     * 盘点
-     */
-    const CHANGE_TYPE_CHECK = 3;
-
-    const CHANGE_TYPE_MAP = [
-        self::CHANGE_TYPE_IO => ['text' => '出入库'],
-        self::CHANGE_TYPE_ALLOCATION => ['text' => '调拨'],
-        self::CHANGE_TYPE_CHECK => ['text' => '盘点']
-    ];
-
-
-    public function getChangeTypeTextAttr($value, $data)
-    {
-        $index = $data['change_type'];
-        return isset(self::CHANGE_TYPE_MAP[$index]) ? self::CHANGE_TYPE_MAP[$index]['text'] : '未知';
-    }
-
-    public function details()
-    {
-        return $this->hasMany(IoDetail::class);
-    }
-
-    public function repo()
-    {
-        return $this->belongsTo(Repo::class);
-    }
-
-    public function revert()
-    {
-        return $this->belongsTo(Io::class, 'revert_id', 'id');
-    }
-}

+ 0 - 94
api/app/common/model/IoDetail.php

@@ -1,94 +0,0 @@
-<?php
-
-namespace app\common\model;
-use app\common\exception\CatchException;
-use app\common\model\Good;
-use app\common\service\StockService;
-
-/**
- * 
- * @property int $good_id 物品ID
- * @property int $repo_id 仓库ID
- * @property number $num 数量,正数增加,负数减少
- * @property int $type 类型,1入库,2出库
- * @property string $transit_status 在途状态:"TRANSIT" 在途/借出 “COMPLETED” 完成/结束 ""/"NONE" 非在途/借出
- * @property number $transit_received 在途到达/归还数量
- * @property number $transit_lost 在途遗失数
- */
-class IoDetail extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'good_id'        => 'int',       // 物品ID
-        'repo_id'        => 'int',       // 仓库ID
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'num'    => 'float',     // 数量,正数增加,负数减少
-        'date'   => 'date',      // 出入库日期
-        'type'   => 'tinyint',   // 类型,1入库,2出库
-        'remark'         => 'varchar',   // 备注
-        'io_id'  => 'int',       // 出入库订单ID
-        'transit_status'         => 'varchar',   // 在途状态:"TRANSIT" 在途/借出 “COMPLETED” 完成/结束 ""/"NONE" 非在途/借出
-        'transit_received'       => 'float',     // 在途到达/归还数量
-        'transit_lost'   => 'float',     // 在途遗失数
-    ];
-
-    /**
-     * 入库
-     */
-    const TYPE_IN = 1;
-    /**
-     * 出库
-     */
-    const TYPE_OUT = 2;
-
-    /**
-     * 非在途/借出
-     */
-    const TRANSIT_STATUS_NONE = "NONE";
-    /**
-     * 在途/借出
-     */
-    const TRANSIT_STATUS_TRANSIT = 'TRANSIT';
-
-    /**
-     * 完成/结束
-     */
-    const TRANSIT_STATUS_COMPLETED = 'COMPLETED';
-
-    const TRANSIT_STATUS_MAP = [
-        self::TRANSIT_STATUS_NONE => ['text' => '非在途/借出'],
-        self::TRANSIT_STATUS_TRANSIT => ['text' => '在途/借出'],
-        self::TRANSIT_STATUS_COMPLETED => ['text' => '非在途/借出']
-    ];
-
-    public function io()
-    {
-        return $this->belongsTo(Io::class);
-    }
-
-    public function repo()
-    {
-        return $this->belongsTo(Repo::class);
-    }
-
-    public function good()
-    {
-        return $this->belongsTo(Good::class);
-    }
-
-    public function getTransitStatusTextAttr($value, $data)
-    {
-        return self::TRANSIT_STATUS_MAP[$data['transit_status']]['text'];
-    }
-
-    public static function onAfterInsert($detail)
-    {
-        static $service;
-        if (!$service) {
-            $service = (new StockService(app()))->exceptionClass(CatchException::class);
-        }
-        $service->chengeStockTrans($detail->repo, $detail->good, $detail->num);
-    }
-}

+ 50 - 0
api/app/common/model/Project.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace app\common\model;
+
+use app\common\model\Contract;
+use app\common\model\ProjectSchedule;
+
+/**
+ * @property array<ProjectSchedule> $schedules
+ * @property array<Contract> $contracts
+ */
+class Project extends Base
+{
+    protected $schema = [
+        'id'     => 'int',       // id
+        'create_time'    => 'datetime',  // 创建时间
+        'update_time'    => 'datetime',  // 更新时间
+        'delete_time'    => 'datetime',  // 删除时间
+        'name'   => 'varchar',   // 名称
+        'responsibility_person_id'    => 'int',       // 责任人id
+        'desc'   => 'text',      // 描述
+        'source'         => 'varchar',   // 来源
+        'estimated_amount'       => 'int',       // 预估金额, 分为单位
+        'status'         => 'varchar',   // 状态值
+        'project_start_date'     => 'date',      // 项目周期开始时间
+        'project_end_date'       => 'date',      // 项目周期结束时间
+        'dev_start_date'         => 'date',      // 开发开始时间
+        'dev_end_date'   => 'date',      // 开发结束时间
+        'pre_dev_time'   => 'int',       // 约定开发周期,单位为天
+        'maintain_start_date'    => 'date',      // 维护开始时间
+        'maintain_end_date'      => 'date',      // 维护结束时间
+        'pre_maintain_time'      => 'int',       // 约定维护周期,单位为天
+        'participants'   => 'json',      // 项目参与人员
+    ];
+
+    public function responsibilityPersonName()
+    {
+        return $this->belongsTo(Admin::class, 'responsibility_person_id', 'id');
+    }
+
+    public function contracts()
+    {
+        return $this->hasMany(Contract::class);
+    }
+
+    public function schedules()
+    {
+        return $this->hasMany(ProjectSchedule::class);
+    }
+}

+ 43 - 0
api/app/common/model/ProjectSchedule.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace app\common\model;
+
+class ProjectSchedule extends Base
+{
+    // 状态值
+    /**
+     * 未开始
+     */
+    const STATUS_NOT_START = 'NOT_START';
+
+    /**
+     * 进行中
+     */
+    const STATUS_GOING = 'GOING';
+
+    /**
+     * 完成
+     */
+    const STATUS_FINISH = 'FINISH';
+
+    /**
+     * 跳过
+     */
+    const STATUS_SKIP = 'SKIP';
+
+    protected $schema = [
+        'id'     => 'int',       // id
+        'create_time'    => 'datetime',  // 创建时间
+        'update_time'    => 'datetime',  // 更新时间
+        'delete_time'    => 'datetime',  // 删除时间
+        'name'   => 'varchar',   // 名称
+        'start_date'     => 'date',      // 开始日期
+        'end_date'       => 'date',      // 结束日期
+        'desc'   => 'text',      // 描述
+        'project_id'     => 'int',       // 项目id
+        'is_update_project_status'       => 'tinyint',   // 是否更新项目状态
+        'going_project_status'   => 'varchar',   // 进行中项目状态
+        'finish_project_status'  => 'varchar',   // 结束项目状态(如果勾选更新项目状态为必填)
+        'status'         => 'varchar',   // "NOT_START"未开始 "GOING"进行中 "FINISH"完成 "SKIP"跳过
+    ];
+}

+ 14 - 0
api/app/common/model/ProjectStatus.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace app\common\model;
+use think\Model;
+
+class ProjectStatus extends Model
+{
+    protected $pk = 'key';
+    
+    protected $schema = [
+        'key'    => 'varchar',   // 键
+        'value'  => 'varchar',   // 值
+    ];
+}

+ 0 - 33
api/app/common/model/Repo.php

@@ -1,33 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-class Repo extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'name'   => 'varchar',   // 仓库名称
-        'desc'   => 'varchar',   // 仓库说明
-        'address'        => 'varchar',   // 仓库地址
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-        'parent' => 'int',  // 父仓库id
-    ];
-
-    public function logs()
-    {
-        return $this->hasMany(Repo::class);
-    }
-
-    public function parent()
-    {
-        return $this->belongsTo(Repo::class, 'id', 'parent');
-    }
-
-    public function children()
-    {
-        return $this->hasMany(Repo::class, 'parent', 'id');
-    }
-}

+ 0 - 30
api/app/common/model/Stock.php

@@ -1,30 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-/**
- * @property number $num
- */
-class Stock extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'repo_id'        => 'int',       // 仓库ID
-        'good_id'        => 'int',       // 物品ID
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-        'num'    => 'float',     // 数量
-    ];
-
-    public function repo()
-    {
-        return $this->belongsTo(Repo::class);
-    }
-
-    public function good()
-    {
-        return $this->belongsTo(Good::class);
-    }
-}

+ 0 - 30
api/app/common/model/Transit.php

@@ -1,30 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-class Transit extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-        'date'   => 'date',      // 出入库日期
-        'type'   => 'tinyint',   // 类型,1入库,2出库
-        'remark'         => 'varchar',   // 备注
-        'sn'     => 'varchar',   // 订单号
-        'admin_id'       => 'int',       // 操作人ID
-        'status'         => 'varchar',   // 状态值:IN_TRANSIT 在途(入库) ARRIVED 到达 LEND 借出 LOST 遗失 COMPENSATED 赔偿
-        'repo_id'        => 'int',       // 仓库id
-        'from'   => 'varchar',   // 来自?
-        'to'     => 'varchar',   // 前往?
-        'contact_name'   => 'varchar',   // 联系人
-        'contact_phone'  => 'varchar',   // 联系电话
-    ];
-
-    public function details()
-    {
-        return $this->hasMany(TransitDetail::class);
-    }
-}

+ 0 - 26
api/app/common/model/TransitDetail.php

@@ -1,26 +0,0 @@
-<?php
-
-namespace app\common\model;
-
-class TransitDetail extends Base
-{
-    protected $schema = [
-        'id'     => 'int',       // id
-        'good_id'        => 'int',       // 物品ID
-        'repo_id'        => 'int',       // 仓库ID
-        'create_time'    => 'datetime',  // 创建时间
-        'update_time'    => 'datetime',  // 更新时间
-        'delete_time'    => 'datetime',  // 删除时间
-        'valid'  => 'tinyint',   // 状态,1启用,0禁用
-        'num'    => 'float',     // 数量,正数增加,负数减少
-        'date'   => 'date',      // 出入库日期
-        'type'   => 'tinyint',   // 类型,1入库,2出库
-        'remark'         => 'varchar',   // 备注
-        'transit_id'     => 'int',       // 出入库订单ID
-    ];
-
-    public function transit()
-    {
-        return $this->belongsTo(Transit::class);
-    }
-}

+ 0 - 245
api/app/common/service/AllocationService.php

@@ -1,245 +0,0 @@
-<?php
-
-namespace app\common\service;
-
-use Carbon\Carbon;
-use think\Validate;
-use think\facade\Db;
-use app\common\model\Io;
-use app\common\model\Good;
-use app\common\model\Admin;
-use app\common\model\IoDetail;
-use app\common\model\Allocation;
-use app\common\util\WhereBuilder;
-use app\common\model\AllocationDetail;
-
-class AllocationService extends Service
-{
-    public function page($params = [])
-    {
-        // 自动处理传入的参数
-        $this->autoParams($params);
-
-        // 获取关键词
-        $keyword = $this->pg('keyword');
-
-        // 获取来源仓库ID
-        $from_repo_id = $this->pg('from_repo_id');
-
-        // 获取目标仓库ID
-        $to_repo_id = $this->pg('to_repo_id');
-
-        // 获取开始日期
-        $begin_date = $this->pg('begin_date');
-
-        // 获取结束日期
-        $end_date = $this->pg('end_date');
-
-        // 如果结束日期存在,则将其解析为 Carbon 对象并增加一天,并转换为日期字符串
-        if ($end_date) {
-            $end_date = Carbon::parse($end_date)->addDay()->toDateString();
-        }
-
-        // 构建查询条件
-        $where = WhereBuilder::builder()
-            ->like('a.id|from.name|to.name|a.remark', $keyword)
-            ->in('a.from_repo_id', $from_repo_id)
-            ->in('a.to_repo_id', $to_repo_id)
-            ->between('a.date', $begin_date, $end_date)
-            ->build();
-
-        // 执行查询,并返回分页结果
-        return (new Allocation)->alias('a')
-            ->field('a.*, from.name as from_repo_name, to.name as to_repo_name')
-            ->join('repo from', 'from.id = a.from_repo_id', 'LEFT')
-            ->join('repo to', 'to.id = a.to_repo_id', 'LEFT')
-            ->where($where)
-            ->order('a.create_time desc')
-            ->paginate($this->tp6Page());
-    }
-
-
-    public function info($params = [])
-    {
-        $this->autoParams($params);
-
-        $alloc = $this->one(Allocation::class);
-        $alloc->append(['from', 'to', 'details', 'details.good', 'details.good.goodClass']);
-
-        return $alloc;
-    }
-
-    /**
-     * 创建调拨单(事务处理)
-     *
-     * @param Admin $admin 管理员对象
-     * @param array $params 参数数组
-     * @return Allocation 创建的调拨单对象
-     */
-    public function createTrans(Admin $admin, $params = [])
-    {
-        // 使用事务处理创建调拨单
-        return Db::transaction(fn() => $this->create($admin, $params));
-    }
-
-    /**
-     * 创建调拨单
-     *
-     * @param Admin $admin 管理员对象
-     * @param array $params 参数数组
-     * @return Allocation 创建的调拨单对象
-     */
-    public function create(Admin $admin, $params = [])
-    {
-        // 自动处理参数
-        $params = $this->autoParams($params);
-
-        // 验证参数
-        $this->validate($params, new AllocateValidate);
-
-        // 获取调拨明细
-        $details = $this->pg('details');
-
-        // 设置管理员ID
-        $params['admin_id'] = $admin->id;
-
-        // 创建调拨单
-        $allocation = Allocation::create($params);
-
-        // 遍历调拨明细进行赋值和检查
-        foreach ($details as &$detail) {
-            // 设置调拨单ID和日期
-            $detail['allocation_id'] = $allocation->id;
-            $detail['date'] = isset($detail['date']) && $detail['date'] ? $detail['date'] : $allocation->date;
-
-            // 检查出入库数量
-            if ($detail['num'] == 0) {
-                $good = Good::find($detail['good_id']);
-                throw $this->exception("物品--{$good?->name}的出入库数量不能为0");
-            }
-            if ($detail['num'] > 0 && $allocation->type == Io::TYPE_OUT) {
-                $good = Good::find($detail['good_id']);
-                throw $this->exception("物品--{$good?->name}的出入库数量大于0但是类型为出库");
-            }
-            if ($detail['num'] < 0 && $allocation->type == Io::TYPE_IN) {
-                $good = Good::find($detail['good_id']);
-                throw $this->exception("物品--{$good?->name}的出入库数量小于0但是类型为入库");
-            }
-        }
-
-        // 保存调拨明细
-        $allocationDetails = (new AllocationDetail)->saveAll($details);
-
-        // 出库
-        $outIoData = [
-            'repo_id' => $allocation->from_repo_id,
-            'type' => Io::TYPE_OUT,
-            'change_type' => Io::CHANGE_TYPE_ALLOCATION,
-            'date' => $allocation->date,
-            'remark' => "自动生成自调拨单{$allocation->id}",
-            'sn' => "SYS_ALC_OUT_T" . hrtime(true) . '_SN' . rand(100000, 999999),
-            'admin_id' => $admin->id,
-            'source' => "调拨单{$allocation->id}"
-        ];
-        $outIo = Io::create($outIoData);
-
-        // 出库详情
-        foreach ($details as &$detail) {
-            $detail['type'] = Io::TYPE_OUT;
-            $detail['io_id'] = $outIo->id;
-            $detail['repo_id'] = $allocation->from_repo_id;
-            $detail['num'] = -$detail['num'];
-        }
-        $outDetails = (new IoDetail)->saveAll($details);
-
-        // 入库
-        $inIoData = [
-            'repo_id' => $allocation->to_repo_id,
-            'type' => Io::TYPE_IN,
-            'change_type' => Io::CHANGE_TYPE_ALLOCATION,
-            'date' => $allocation->date,
-            'remark' => "自动生成自调拨单{$allocation->id}",
-            'sn' => "SYS_ALC_IN_T" . hrtime(true) . '_SN' . rand(100000, 999999),
-            'admin_id' => $admin->id,
-            'source' => "调拨单{$allocation->id}"
-        ];
-        $inIo = Io::create($inIoData);
-
-        // 入库详情
-        foreach ($details as &$detail) {
-            $detail['type'] = Io::TYPE_IN;
-            $detail['io_id'] = $inIo->id;
-            $detail['repo_id'] = $allocation->to_repo_id;
-            $detail['num'] = -$detail['num'];
-        }
-        $inDetails = (new IoDetail)->saveAll($details);
-
-        $allocation->out_io_id = $outIo->id;
-        $allocation->in_io_id = $inIo->id;
-        $allocation->save();
-
-        // 返回创建的调拨单对象
-        return $allocation;
-    }
-
-    public function revertTrans(Admin $admin, $params = [])
-    {
-        return Db::transaction(fn() => $this->revert($admin, $params));
-    }
-    
-    public function revert(Admin $admin, $params = [])
-    {
-        $this->autoParams($params);
-        $allc = $this->one(Allocation::class);
-        if ($allc->revert_id) {
-            return true;
-        }
-        $service = (new IoService($this->app))->exceptionClass($this->exceptionClass);
-        $out_revert_to_in_io = $service->revertTrans($admin, ['id' => $allc->out_io_id]);
-        $in_revert_to_out_io = $service->revertTrans($admin, ['id' => $allc->in_io_id]);
-        // 创建调拨单
-        $revertData = [
-            'from_repo_id' => $allc->to_repo_id,
-            'to_repo_id' => $allc->from_repo_id,
-            'date' => date('Ymd'),
-            'remark' => "回滚自$allc->id",
-            'admin_id' => $admin->id,
-            'out_io_id' => $in_revert_to_out_io->id,
-            'in_io_id' => $out_revert_to_in_io->id
-        ];
-        $revert = Allocation::create($revertData);
-
-        $revertDetails = [];
-        // 遍历调拨明细进行赋值和检查
-        foreach ($allc->details as $detail) {
-            // 设置调拨单ID和日期
-            $revertDetail = [
-                'good_id' => $detail->good_id,
-                'num' => $detail->num,
-                'date' => date('Ymd'),
-                'remark' => '回滚',
-                'allocation_id' => $revert->id
-            ];
-            $revertDetails[] = $revertDetail;
-        }
-
-        // 保存调拨明细
-        $allocationDetails = (new AllocationDetail)->saveAll($revertDetails);
-
-        $allc->revert_id = $revert->id;
-        $allc->save();
-        return $revert;
-    }
-}
-
-
-class AllocateValidate extends Validate
-{
-    protected $rule = [
-        'from_repo_id' => 'require',
-        'to_repo_id' => 'require',
-        'date' => 'require',
-        'remark' => 'max:255',
-        'details' => 'require|array'
-    ];
-}

+ 0 - 15
api/app/common/service/CheckService.php

@@ -1,15 +0,0 @@
-<?php
-
-namespace app\common\service;
-use app\common\model\Check;
-
-class CheckService extends Service
-{
-    public function page($params = [])
-    {
-        $this->autoParams($params);
-
-        return (new Check)
-            ->paginate($this->tp6Page());
-    }
-}

+ 21 - 0
api/app/common/service/ContractService.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace app\common\service;
+use app\common\model\Contract;
+
+class ContractService extends Service
+{
+    public function create($param = [])
+    {
+        $this->autoParams($param);
+
+        return Contract::create($param);
+    }
+
+    public function update($param = [])
+    {
+        $this->autoParams($param);
+
+        return Contract::update($param);
+    }
+}

+ 0 - 79
api/app/common/service/GoodClassService.php

@@ -1,79 +0,0 @@
-<?php
-
-namespace app\common\service;
-
-use app\common\model\GoodClass;
-use app\common\util\WhereBuilder;
-
-class GoodClassService extends Service
-{
-    /**
-     * 分页
-     *
-     * @param array $params
-     */
-    public function page($params = [])
-    {
-        $this->autoParams($params);
-        $keyword = $this->pg('keyword');
-
-        $where = WhereBuilder::builder()
-            ->like('name', $keyword)
-            ->build();
-
-        return (new GoodClass)
-            ->where($where)
-            ->paginate($this->tp6Page());
-    }
-
-    public function all()
-    {
-        return (new GoodClass)->select();
-    }
-
-    /**
-     * 创建
-     *
-     * @param array $params
-     */
-    public function create($params = [])
-    {
-        $this->autoParams($params);
-        $name = $this->pg('name');
-        $desc = $this->pg('desc');
-        $class = (new GoodClass)->where('name', '=', $name)->find();
-        if ($class) {
-            throw $this->exception("名称为 $name 的类别已存在,id={$class->id}");
-        }
-        $classData = [
-            'name' => $name,
-            'desc' => $desc,
-        ];
-        $class = GoodClass::create($classData);
-        return $class;
-    }
-
-    /**
-     * 更新
-     *
-     * @param array $params
-     */
-    public function update($params = [])
-    {
-        $params = $this->autoParams($params);
-        return (new GoodClass)->allowField(['name', 'desc'])->update($params);
-    }
-
-    /**
-     * 删除
-     *
-     * @param array $params
-     */
-    public function delete($params = [])
-    {
-        $this->autoParams($params);
-        $class = $this->one(GoodClass::class);
-        return $class->delete();
-    }
-
-}

+ 0 - 286
api/app/common/service/GoodService.php

@@ -1,286 +0,0 @@
-<?php
-
-namespace app\common\service;
-
-use think\facade\Db;
-use app\common\model\Good;
-use think\facade\Validate;
-use app\common\model\Stock;
-use app\common\util\Result;
-use think\facade\Filesystem;
-use app\common\model\GoodClass;
-use app\common\service\Service;
-use app\common\util\WhereBuilder;
-use app\common\util\PhpSpreadsheetImport;
-use app\common\util\PhpSpreadsheetExportV2;
-
-class GoodService extends Service
-{
-    /**
-     * 分页查询商品列表
-     *
-     * @param array $params 参数数组
-     * @return \think\Paginator 分页对象,包含商品列表
-     */
-    public function page($params = [])
-    {
-        // 自动处理参数
-        $this->autoParams($params);
-
-        // 获取关键字和商品分类ID
-        $keyword = $this->pg('keyword');
-        $valid = $this->pgd([], 'valid');
-        $good_class_id = $this->pg('good_class_id');
-
-        // 构建查询条件
-        $where = WhereBuilder::builder()
-            ->like('no|name|desc|unit|spec', $keyword)
-            ->eq('good_class_id', $good_class_id)
-            ->in('valid', $valid)
-            ->build();
-
-        // 执行分页查询
-        $page = (new Good)
-            ->where($where)
-            ->paginate($this->tp6Page());
-
-        // 关联加载商品分类信息
-        $page->getCollection()->append(['goodClass']);
-
-        // 返回分页对象
-        return $page;
-    }
-
-
-    /**
-     * 创建商品(事务处理)
-     *
-     * @param array $params 参数数组
-     * @return Good 创建的商品对象
-     */
-    public function createTrans($params = [])
-    {
-        // 使用事务处理创建商品
-        return Db::transaction(fn() => $this->create($params));
-    }
-
-    /**
-     * 创建商品
-     *
-     * @param array $params 参数数组
-     * @return Good 创建的商品对象
-     * @throws \Exception 如果商品编号已存在,则抛出异常
-     */
-    public function create($params = [])
-    {
-        // 自动处理参数
-        $params = $this->autoParams($params);
-
-        // 获取商品编号
-        $no = $this->pg('no');
-
-        // 获取商品分类对象
-        $goodClass = $this->one(GoodClass::class, 'good_class_id');
-
-        // 根据编号查找商品
-        $good = Good::getByNo($no);
-        if ($good) {
-            throw $this->exception("编号 $no 已存在");
-        }
-
-        // 创建商品
-        return Good::create($params);
-    }
-
-
-    /**
-     * 更新商品信息
-     *
-     * @param array $params 参数数组
-     * @return array 更新成功的商品对象数组
-     * @throws \Exception 如果未选中任何商品进行更新,则抛出异常
-     */
-    public function update($params = [])
-    {
-        // 自动处理参数
-        $params = $this->autoParams($params);
-
-        if (!$params) {
-            throw $this->exception('未选中任何商品进行更新');
-        }
-
-        // 更新商品信息并返回更新成功的商品对象数组
-        return (new Good)->allowField(['name', 'unit', 'img', 'valid', 'spec', 'good_class_id'])->saveAll($params);
-    }
-
-    /**
-     * 删除商品
-     *
-     * @param array $params 参数数组
-     * @return int 删除的商品数量
-     * @throws \Exception 如果非强制删除商品时,存在库存未处理,则抛出异常
-     */
-    public function delete($params = [])
-    {
-        // 自动处理参数
-        $this->autoParams($params);
-
-        // 获取商品ID和是否强制删除标志
-        $id = $this->req('id');
-        $force = $this->pgd(false, 'force');
-
-        if (is_int($id)) {
-            $id = [$id];
-        }
-
-        // 非强制删除时,检查仓库库存
-        if (!$force) {
-            foreach ($id as $i) {
-                $num = (new Stock)->where('good_id', '=', $i)->sum('num');
-                if ($num > 0) {
-                    $good = (new Good)->find($id);
-                    throw $this->exception("商品{$good->name}仍有库存未处理,请使用调拨/出库清理库存", 1);
-                }
-            }
-        }
-
-        // 删除商品并返回删除的商品数量
-        return Good::destroy($id);
-    }
-
-
-    /**
-     * 导入商品数据
-     *
-     * @return \think\Response 导入结果的响应对象
-     * @throws \think\Exception\ValidateException 如果上传文件格式或大小不符合要求,则抛出验证异常
-     * @throws \think\Exception 如果上传图片失败,则抛出异常
-     */
-    public function import()
-    {
-        // 获取表单上传文件
-        $files = request()->file();
-
-        // 验证上传文件格式和大小
-        $this->validate($files, Validate::rule(['file' => 'fileSize:20480000|fileExt:csv,xlsx']));
-        $file = request()->file('file');
-
-        try {
-            $path = Filesystem::putFile('execl', $file);
-        } catch (\Exception $e) {
-            throw $this->warpException($e, '上传图片失败:\n');
-        }
-
-        // 读取导入的数据
-        $data = PhpSpreadsheetImport::readData(runtime_path('../storage') . $path);
-
-        static $MAP = [
-        'A' => 'no',
-        'B' => 'name',
-        'C' => 'desc',
-        'D' => 'unit',
-        'E' => 'img',
-        'F' => 'spec',
-        'G' => 'good_class_id'
-        ];
-
-        /**
-         * @var GoodClassService $service 
-         */
-        static $service;
-
-        if (!$service) {
-            $service = (new GoodClassService($this->app))->exceptionClass($this->exceptionClass);
-        }
-
-        $goods = [];
-
-        // 处理导入的每一行数据
-        foreach ($data as $row) {
-            $good = [];
-            foreach ($row as $key => $value) {
-                $newKey = $MAP[$key];
-
-                // 如果是分类字段,则替换为对应的ID,如果分类不存在则创建
-                if ($newKey == 'good_class_id') {
-                    $class = (new GoodClass)->cache()->where('name', '=', $value)->find();
-                    if (!$class) {
-                        $class = $service->create(['name' => $value]);
-                    }
-                    $value = $class->id;
-                }
-
-                $good[$newKey] = $value;
-            }
-            $goods[] = $good;
-        }
-
-        // 批量保存商品数据
-        $goods = (new Good)->saveAll($goods);
-
-        return Result::rest(true, 0, "成功{$goods->count()}个");
-    }
-
-
-
-    /**
-     * 导出商品数据
-     *
-     * @param array $params 导出参数
-     * @return mixed 导出结果
-     */
-    public function export($params = [])
-    {
-        $this->autoParams($params);
-        $keyword = $this->pg('name');
-        $repo_id = $this->pg('repo_id');
-
-        // 构建查询条件
-        $where = WhereBuilder::builder()
-            ->like('name', $keyword)
-            ->in('repo_id', $repo_id)
-            ->build();
-
-        $header = [
-            [
-                'id',
-                '序号',
-                '名称',
-                '介绍',
-                '单位',
-                '图片地址',
-                '创建时间',
-                '更新时间',
-                '删除时间',
-                '状态',
-                '规格',
-                '类别id',
-                '类别名称'
-            ]
-        ];
-
-        // 查询商品数据,并关联查询商品类别信息
-        $goods = (new Good)
-            ->field('g.*, c.name as class_name')
-            ->alias('g')
-            ->join('good_class c', 'c.id = g.good_class_id', 'LEFT')
-            ->where($where)
-            ->select()
-            ->map(fn(Good $good) => $good->getData())
-            ->each(function (array $good) {
-                // 格式化商品状态字段
-                $good['valid'] = $good['valid'] ? '启用' : '禁用';
-                return $good;
-            });
-
-        // 导出商品数据
-        $res = PhpSpreadsheetExportV2::outputFile(
-            $goods,
-            $header,
-            'good' . date('Ymdis'),
-            []
-        );
-
-        return $res;
-    }
-}

+ 0 - 51
api/app/common/service/IoDetailService.php

@@ -1,51 +0,0 @@
-<?php
-
-namespace app\common\service;
-
-use app\admin\attr\Permission;
-use app\common\model\IoDetail;
-use app\common\util\WhereBuilder;
-
-#[Permission('io_detail')]
-class IoDetailService extends Service
-{
-    public function page($params = [])
-    {
-        $params = $this->autoParams($params);
-        $repo_id = $this->pg('repo_id');
-
-        $where = WhereBuilder::builder()
-            ->eq('d.repo_id', $repo_id)
-            ->build();
-
-        return (new IoDetail)->alias('d')
-            ->field('d.*, r.name as repo_name, g.name as good_name')
-            ->join('repo r', 'r.id = d.repo_id', 'LEFT')
-            ->join('good g', 'g.id = d.good_id', 'LEFT')
-            ->where($where)
-            ->order('d.create_time desc')
-            ->paginate($this->tp6Page());
-    }
-
-    public function transits($params = [])
-    {
-        $params = $this->autoParams($params);
-
-        $transit_status = $this->pg('transit_status');
-        $repo_id = $this->pg('repo_id');
-        $io_id = $this->pg('io_id');
-
-        $where = WhereBuilder::builder()
-            ->in('d.transit_status', $transit_status)
-            ->eq('d.repo_id', $repo_id)
-            ->eq('d.io_id', $io_id)
-            ->build();
-
-        return (new IoDetail)->alias('d')
-            ->field('d.*, r.name as repo_name, g.name as good_name, g.no as good_no')
-            ->join('repo r', 'r.id = d.repo_id', 'LEFT')
-            ->join('good g', 'g.id = d.good_id', 'LEFT')
-            ->where($where)
-            ->select();
-    }
-}

+ 0 - 420
api/app/common/service/IoService.php

@@ -1,420 +0,0 @@
-<?php
-
-namespace app\common\service;
-
-use Carbon\Carbon;
-use think\Validate;
-use think\facade\Db;
-use app\common\model\Io;
-use app\common\model\Good;
-use app\common\model\Repo;
-use app\common\model\Admin;
-use app\common\model\Stock;
-use app\common\model\IoDetail;
-use app\common\util\WhereBuilder;
-use app\common\util\PhpSpreadsheetExportV2;
-
-class IoService extends Service
-{
-    /**
-     * 处理分页请求
-     * 
-     * @param array $params 请求参数数组
-     * @return mixed 分页结果
-     */
-    public function page($params = [])
-    {
-        // 自动处理请求参数
-        $this->autoParams($params);
-
-        // 从请求参数中获取相关值
-        $type = $this->pg('type');
-        $change_type = $this->pg('change_type');
-        $keyword = $this->pg('keyword');
-        $repo_id = $this->pg('repo_id');
-        $begin_date = $this->pg('begin_date');
-        $end_date = $this->pg('end_date');
-
-        // 如果存在结束日期,则向后延长一天
-        if ($end_date) {
-            $end_date = Carbon::parse($end_date)->addDay()->toDateString();
-        }
-
-        // 获取是否包含运输状态参数
-        $contain_transit = $this->pgd(false, 'contain_transit');
-
-        // 构建查询条件
-        $where = WhereBuilder::builder()
-            ->like('io.sn|r.name|io.remark', $keyword)
-            ->in('io.type', $type)
-            ->in('io.change_type', $change_type)
-            ->in('io.repo_id', $repo_id)
-            ->between('io.date', $begin_date, $end_date)
-            ->where('d.transit_status', 'in', [IoDetail::TRANSIT_STATUS_TRANSIT, IoDetail::TRANSIT_STATUS_TRANSIT], $contain_transit)
-            ->build();
-
-        // 构建查询对象
-        $query = (new Io)
-            ->alias('io')
-            ->field('io.*, r.name as repo_name')
-            ->join('repo r', 'r.id = io.repo_id');
-
-        // 如果包含运输状态,则进行关联查询
-        if ($contain_transit) {
-            $query = $query->join('io_detail d', 'd.io_id = io.id');
-        }
-
-        // 执行分页查询
-        $page = $query->where($where)
-            ->order('io.create_time desc')
-            ->paginate($this->tp6Page());
-
-        // 添加附加字段到分页结果集
-        $page->getCollection()->append(['change_type_text']);
-
-        // 返回分页结果
-        return $page;
-    }
-
-    /**
-     * 获取Io信息
-     * 
-     * @param array $params 请求参数数组
-     * @return mixed Io对象
-     */
-    public function info($params = [])
-    {
-        // 自动处理请求参数
-        $this->autoParams($params);
-
-        // 查询单个Io对象
-        $io = $this->one(Io::class);
-
-        // 添加附加字段到Io对象
-        $io->append(['change_type_text', 'details', 'repo', 'details.good']);
-
-        // 返回Io对象
-        return $io;
-    }
-
-    /**
-     * 创建运输记录事务
-     * 
-     * @param Admin $admin 管理员对象
-     * @param array $params 请求参数数组
-     * @return mixed 运输记录创建结果
-     */
-    public function createTrans(Admin $admin, $params = [])
-    {
-        // 使用数据库事务执行创建操作
-        return Db::transaction(fn() => $this->create($admin, $params));
-    }
-
-    /**
-     * 创建运输记录
-     * 
-     * @param Admin $admin 管理员对象
-     * @param array $params 请求参数数组
-     * @return mixed 创建的Io对象
-     * @throws \Exception 创建失败时抛出异常
-     */
-    public function create(Admin $admin, $params = [])
-    {
-        // 自动处理请求参数
-        $params = $this->autoParams($params);
-
-        // 如果存在管理员对象,则将管理员ID赋值给参数数组
-        if ($admin) {
-            $params['admin_id'] = $admin->id;
-        }
-
-        // 查询Repo对象
-        $repo = $this->one(Repo::class, 'repo_id');
-
-        // 获取出入库明细
-        $details = $this->pg('details');
-        // 过滤掉数量为0的明细
-        $details = array_filter($details, fn($detail) => $detail['num']);
-
-        // 创建Io对象
-        $io = Io::create($params);
-
-        // 赋值并检查明细
-        foreach ($details as &$detail) {
-            $detail['io_id'] = $io->id;
-            $detail['date'] = isset($detail['date']) && $detail['date'] ? $detail['date'] : $io->date;
-            $detail['type'] = isset($detail['type']) && $detail['type'] ? $detail['type'] : $io->type;
-            $detail['repo_id'] = isset($detail['repo_id']) && $detail['repo_id'] ? $detail['repo_id'] : $io->repo_id;
-
-            // 检查出入库数量
-            if ($detail['num'] == 0) {
-                $good = Good::find($detail['good_id']);
-                throw $this->exception("物品--{$good?->name}的出入库数量不能为0");
-            }
-            if ($detail['num'] > 0 && $detail['type'] == Io::TYPE_OUT) {
-                $good = Good::find($detail['good_id']);
-                throw $this->exception("物品--{$good?->name}的出入库数量大于0但是类型为出库");
-            }
-            if ($detail['num'] < 0 && $detail['type'] == Io::TYPE_IN) {
-                $good = Good::find($detail['good_id']);
-                throw $this->exception("物品--{$good?->name}的出入库数量小于0但是类型为入库");
-            }
-        }
-
-        // 保存出入库明细
-        $details = (new IoDetail)->saveAll($details);
-
-        // 在oninsert事件中进行库存变更
-        $io->details = $details;
-
-        // 返回创建的Io对象
-        return $io;
-    }
-
-
-    /**
-     * 导出运输记录
-     * 
-     * @param array $params 请求参数数组
-     * @return mixed 导出结果
-     */
-    public function export($params = [])
-    {
-        // 自动处理请求参数
-        $this->autoParams($params);
-
-        $type = $this->pg('type');
-        // 获取起始日期和结束日期
-        $begin_date = $this->pg('begin_date');
-        $end_date = $this->pg('end_date');
-
-        // 如果存在结束日期,则向后延长一天
-        if ($end_date) {
-            $end_date = Carbon::parse($end_date)->addDay()->toDateString();
-        }
-
-        // 构建查询条件
-        $where = WhereBuilder::builder()
-            ->in('io.type', $type)
-            ->between('i.date', $begin_date, $end_date)
-            ->build();
-
-        // 导出表格的表头
-        $header = [
-            [
-                '编号',
-                '仓库名',
-                '出入库类型',
-                '变更原因',
-                '备注',
-                '来源',
-                '创建时间',
-                '日期',
-                '物品名',
-                '数量',
-                '明细备注',
-                '在途状态',
-                '归还数量',
-                '遗失数量'
-            ]
-        ];
-
-        // 构建查询字段中的change_type_export
-        $changeTypeField = <<<SQL
-            CASE i.change_type 
-                WHEN 1 THEN "出入库" 
-                WHEN 2 THEN "调拨" 
-                WHEN 3 THEN "盘点" 
-                ELSE "出入库" 
-            END as change_type_export
-        SQL;
-
-        // 构建查询字段中的transit_status_export
-        $transitStatusField = <<<SQL
-            CASE d.transit_status
-                WHEN "TRANSIT" THEN "在途"
-                WHEN "COMPLETED" THEN "完成"
-                ELSE ""
-            END as transit_status_export
-        SQL;
-
-        // 执行查询
-        $details = (new IoDetail)->alias('d')
-            ->field('i.sn, r.name as repo_name, if(i.type = 1, "入库", "出库")')
-            ->field($changeTypeField)
-            ->field('i.remark, i.source, i.create_time, i.date')
-            ->field('g.name as good_name, d.num, d.remark as detail_remark')
-            ->field($transitStatusField)
-            ->field('d.transit_received, d.transit_lost')
-            ->join('io i', 'i.id = d.io_id', 'LEFT')
-            ->join('repo r', 'r.id = i.repo_id', 'LEFT')
-            ->join('good g', 'g.id = d.good_id', 'LEFT')
-            ->where($where)
-            ->select()
-            ->toArray();
-
-        // 导出表格文件
-        $res = PhpSpreadsheetExportV2::outputFile(
-            $details,
-            $header,
-            'io' . date('Ymdis'),
-            []
-        );
-
-        // 返回导出结果
-        return $res;
-    }
-
-
-    public function completeTrans(Admin $admin, $params = [])
-    {
-        return Db::transaction(fn() => $this->complete($admin, $params));
-    }
-
-    public function complete(Admin $admin, $params = [])
-    {
-        $params = $this->autoParams($params);
-        $this->validate($params, new CompleteValidate);
-        $transits = $this->pg('transits');
-        foreach ($transits as &$transit) {
-            /**
-             * @var IoDetail
-             */
-            $detail = IoDetail::find($transit['id']);
-            $stock = (new Stock)
-                ->where('repo_id', '=', $detail->repo_id)
-                ->where('good_id', '=', $detail->good_id)
-                ->find();
-
-            // 检查数量
-            $num = abs($detail->num);
-            if ($transit['transit_received'] + $transit['transit_lost'] == $num) {
-                $transit['transit_status'] = IoDetail::TRANSIT_STATUS_COMPLETED;
-            } elseif ($transit['transit_received'] + $transit['transit_lost'] > $num) {
-                throw $this->exception("到达/归还数量{$transit['transit_received']} 加 在途遗失数{$transit['transit_lost']} 大于该出入库明细的数量:{$num}");
-            } elseif ($transit['transit_received'] < $detail->transit_received) {
-                throw $this->exception("到达/归还数量{$transit['transit_received']} 比原来还少了!(原数量:{$detail->transit_received}) 如发现归还数量错误,请使用盘点功能");
-            } elseif ($transit['transit_lost'] < $detail->transit_lost) {
-                throw $this->exception("在途遗失数量{$transit['transit_lost']} 比原来还少了!(原数量:{$detail->transit_lost}) 如发现遗失后又归还,请使用盘点功能");
-            } else {
-                $transit['transit_status'] = isset($transit['transit_status']) ? $transit['transit_status'] : IoDetail::TRANSIT_STATUS_TRANSIT;
-            }
-
-            $stock->num += self::getTypeMul($detail->type) * ($transit['transit_received'] - $detail->transit_received);
-            $stock->save();
-
-        }
-        (new IoDetail)->allowField(['transit_status', 'transit_received', 'transit_lost'])->saveAll($transits);
-        return true;
-    }
-
-    public function revertTrans(Admin $admin, $params = []) {
-        return Db::transaction(fn() => $this->revert($admin, $params));
-    }
-
-    protected function revert(Admin $admin, $params = [])
-    {
-        $this->autoParams($params);
-        $io = $this->one(Io::class);
-        if ($io->revert_id) {
-            return true;
-        }
-        $revertData = [
-            'repo_id' => $io->repo_id,
-            'date' => date('Ymd'),
-            'type' => self::inverseIoType($io['type']),
-            'sn' => 'REVERT_T' . hrtime(true) . '_SN' . rand(100000, 999999),
-            'remark' => "回滚自$io->sn",
-            'admin_id' => $admin->id,
-            'change_type' => $io->change_type,
-            'source' => "$io->sn"
-        ];
-        $revert = Io::create($revertData);
-
-        $revertDetails = [];
-        foreach ($io->details as $detail) {
-            $revertDetail = [
-                'repo_id' => $detail->repo_id,
-                'good_id' => $detail->good_id,
-                'num' => -$detail['num'],
-                'date' => date('Ymd'),
-                'type' => self::inverseIoType($detail['type']),
-                'remark' => '回滚',
-                'io_id' => $revert->id,
-            ];
-            $revertDetails[] = $revertDetail;
-        }
-        $details = (new IoDetail)->saveAll($revertDetails);
-
-        $io->revert_id = $revert->id;
-        $io->save();
-        return $revert;
-    }
-
-    /**
-     * 翻转出入库类型
-     *
-     * @param int $type 出入库类型
-     * @return int 翻转后的出入库类型
-     */
-    protected static function inverseIoType(int $type)
-    {
-        return $type == Io::TYPE_IN ? Io::TYPE_OUT : Io::TYPE_IN;
-    }
-
-    /**
-     * 获取出入库类型的乘数
-     *
-     * @param int $type 出入库类型
-     * @return int 出入库类型的乘数
-     */
-    protected static function getTypeMul(int $type)
-    {
-        return $type == Io::TYPE_IN ? 1 : -1;
-    }
-
-}
-
-class CreateIoValidate extends Validate
-{
-    protected $rule = [
-        'repo_id|仓库' => 'require',
-        'valid|状态' => 'require',
-        'type|出入库类型' => 'require',
-        'change_type|变更类型' => 'require',
-        'details|出入库内容' => 'checkDetails',
-    ];
-
-    protected function checkDetails($details)
-    {
-        if (!is_array($details)) {
-            return 'details必须为数组';
-        }
-        if (!$details) {
-            return '出入库内容不能为空';
-        }
-        $setAndNotEmpty = fn($item, $index) => isset($item[$index]) && $item[$index];
-        $requires = ['good_id', 'num', 'type', 'remark'];
-        foreach ($details as $index => $detail) {
-            foreach ($requires as $require) {
-                if (!$setAndNotEmpty($detail, $require)) {
-                    return "details[$index].$require 不能为空";
-                }
-            }
-            $good_id = $detail['good_id'];
-            $good = Good::find($good_id);
-            if (!$good) {
-                return "未找到物品对象, id={$good_id}";
-            }
-        }
-
-        return true;
-    }
-}
-
-class CompleteValidate extends Validate
-{
-    protected $rule = [
-        'transits' => 'array'
-    ];
-}

+ 20 - 0
api/app/common/service/ProjectScheduleService.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace app\common\service;
+
+use app\common\model\ProjectSchedule;
+
+class ProjectScheduleService extends Service
+{
+    public function create($param = [])
+    {
+        $param = $this->autoParams($param);
+        
+        return ProjectSchedule::create($param);
+    }
+
+    public function update($param = [])
+    {
+        
+    }
+}

+ 57 - 0
api/app/common/service/ProjectService.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace app\common\service;
+
+use app\common\model\Project;
+use app\common\service\Service;
+use app\common\util\WhereBuilder;
+
+class ProjectService extends Service
+{
+    public function page($param = [])
+    {
+        $this->autoParams($param);
+
+        $status = $this->pg('status');
+        $keyword = $this->pg('keyword');
+        
+        $where = WhereBuilder::builder()
+            ->like('keyword', $keyword)
+            ->in('status', $status)
+            ->build();
+
+        return (new Project)
+            ->with(['contracts', 'schedules'])
+            ->where($where)
+            ->paginate($this->tp6Page());
+    }
+
+    public function create($param = []) 
+    {
+        $param = $this->autoParams($param);
+
+        return Project::create($param);
+    }
+
+    public function info($param = [])
+    {
+        $this->autoParams($param);
+        $project = $this->one(Project::class);
+        $project->append(['contracts', 'schedules']);
+
+        return $project;
+    }
+
+    public function update($param = [])
+    {
+        $param = $this->autoParams($param);
+        return Project::update($param);
+    }
+
+    public function delete($param = [])
+    {
+        $this->autoParams($param);
+        $project = $this->one(Project::class);
+        return $project->delete();
+    }
+}

+ 32 - 0
api/app/common/service/ProjectStatusService.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace app\common\service;
+use app\common\model\ProjectStatus;
+
+class ProjectStatusService extends Service
+{
+    public function create($param = [])
+    {
+        $param = $this->autoParams($param);
+
+        $key = $this->req('key');
+        $status = (new ProjectStatus)->where('key', '=', $key)->findOrEmpty();
+        if ($status->isExists()) {
+            throw $this->exception("状态键($status->key)已存在,对应的值为$status->value");
+        }
+
+        return ProjectStatus::create($param);
+    }
+
+    public function update($param = [])
+    {
+        $param = $this->autoParams($param);
+
+        return ProjectStatus::update($param);
+    }
+
+    public function list()
+    {
+        return (new ProjectStatus)->select();
+    }
+}

+ 0 - 75
api/app/common/service/RepoService.php

@@ -1,75 +0,0 @@
-<?php
-
-namespace app\common\service;
-use app\common\model\Repo;
-use app\common\model\Stock;
-use app\common\util\WhereBuilder;
-use think\facade\Validate;
-
-class RepoService extends Service
-{
-    public function page($params = [])
-    {
-        $this->autoParams($params);
-
-        $keyword = $this->pg('keyword');
-        $valid = $this->pg('valid');
-
-        $where = WhereBuilder::builder()
-            ->like('name|address', $keyword)
-            ->eq('valid', $valid)
-            ->build();
-
-        $page = (new Repo)
-            ->where($where)
-            ->paginate($this->tp6Page());
-
-        return $page;
-    }
-
-    public function all($params = [])
-    {
-        return (new Repo)->select();
-    }
-
-    public function create($params = [])
-    {
-        $params = $this->autoParams($params);   
-
-        return Repo::create($params);
-    }
-
-    public function update($params = [])
-    {
-        $params = $this->autoParams($params);
-        if (!$params) {
-            throw $this->exception('未选中任何商品进行更新');
-        }
-        return (new Repo)->allowField(['name', 'desc', 'address', 'valid'])->update($params);
-    }
-
-    public function delete($params = [])
-    {
-        $params = $this->autoParams($params);
-        $this->validate($params, Validate::rule(['id' => 'array']));
-
-        $id = $this->req('id');
-        $force = $this->pgd(false, 'force');
-
-        if (is_int($id)) {
-            $id = [$id];
-        }
-        // 非强制删除检查仓库库存
-        if (!$force) {
-            foreach ($id as $i) {
-                $sum = (new Stock)->where('repo_id', '=', $i)->sum('num');
-                if ($sum > 0) {
-                    $repo = (new Repo)->find($id);
-                    throw $this->exception("仓库{$repo->name}仍有库存未处理,请使用调拨/出库清理库存,或使用强制删除", 1);
-                }
-            }
-        }
-
-        return Repo::destroy($id);
-    }
-}

+ 0 - 164
api/app/common/service/StockService.php

@@ -1,164 +0,0 @@
-<?php
-
-namespace app\common\service;
-
-use app\common\util\Result;
-use think\annotation\route\Group;
-use think\facade\Db;
-use app\common\model\Good;
-use app\common\model\Repo;
-use app\common\model\Stock;
-use app\common\util\WhereBuilder;
-use app\common\util\PhpSpreadsheetExportV2;
-
-class StockService extends Service
-{
-    public function page($params = [])
-    {
-        $this->autoParams($params);
-        $keyword = $this->pg('keyword');
-        $repo_id = $this->pg('repo_id');
-        $good_id = $this->pg('good_id');
-        $filter_zero_transit = $this->pgd(false, 'filter_zero_transit');
-        if ($repo_id && !Repo::find($repo_id)) {
-            throw $this->exception('仓库不存在');
-        }
-        if ($good_id && !Good::find($good_id)) {
-            throw $this->exception('物品不存在');
-        }
-
-        $where = WhereBuilder::builder()
-            ->like('g.no|g.name|r.name', $keyword)
-            ->in('s.repo_id', $repo_id)
-            ->build();
-
-        $transit_filter_symbol = '>=';
-        if ($filter_zero_transit) {
-            $transit_filter_symbol = '>';
-        }
-
-        $page = (new Stock)
-            ->alias('s')
-            ->field('s.*, g.name as good_name, g.no as good_no, r.name as repo_name, IFNULL(sum(abs(d.num) - d.transit_received), 0) as sum_transit')
-            ->join('good g', 'g.id = s.good_id', 'LEFT')
-            ->join('repo r', 'r.id = s.repo_id', 'LEFT')
-            ->join('io_detail d', 'd.good_id = s.good_id AND d.repo_id = s.repo_id AND d.transit_status = "TRANSIT"', 'LEFT')
-            ->where($where)
-            ->whereRaw("IFNULL(abs(d.num) - d.transit_received, 0) $transit_filter_symbol 0")
-            ->group('s.id')
-            ->paginate($this->tp6Page(PHP_INT_MAX));
-
-        return $page;
-    }
-
-    public function allByRepo($params = [])
-    {
-        $this->autoParams($params);
-
-        $repo = $this->one(Repo::class);
-
-        return (new Stock)->where('repo_id', '=', $repo->id)->select();
-    }
-
-    public function info($params = [])
-    {
-        $this->autoParams($params);
-
-        $stock = $this->one(Stock::class);
-        $stock->append(['good']);
-
-        return $stock;
-    }
-
-    public function getByGoodAndRepo($params = [])
-    {
-        $this->autoParams($params);
-        $good = $this->one(Good::class, 'good_id');
-        $repo = $this->one(Repo::class, 'repo_id');
-        return (new Stock)
-            ->with(['good'])
-            ->where('good_id', '=', $good->id)
-            ->where('repo_id', '=', $repo->id)
-            ->find()
-            ?? Result::rest(['repo_id' => $repo->id, 'good_id' => $good->id, 'num' => 0]);
-    }
-
-    /**
-     * tp6是支持事务嵌套的,为了保证修改库存时数据不出现问题,请无脑使用该事务方法
-     */
-    public function chengeStockTrans(Repo $repo, Good $good, $change)
-    {
-        // tp6是支持事务嵌套的,所有修改可以直接用事务
-        return Db::transaction(fn() => $this->changeStock($repo, $good, $change));
-    }
-
-    protected function changeStock(Repo $repo, Good $good, $change)
-    {
-        if (!$repo) {
-            throw $this->exception('致命错误,$repo为空');
-        }
-        if (!$good) {
-            throw $this->exception('致命错误,$good为空');
-        }
-        /**
-         * @var Stock
-         */
-        $stock = (new Stock)
-            ->lock(true)
-            ->where('good_id', '=', $good->id)
-            ->where('repo_id', '=', $repo->id)
-            ->find();
-        if (!$stock) {
-            $stock = Stock::create([
-                'repo_id' => $repo->id,
-                'good_id' => $good->id,
-                'num' => 0
-            ]);
-        }
-        if ($change < 0 && $stock->num < abs($change)) {
-            $info = <<<EOF
-            物品{$good->name}库存不足,当前库存为{$stock->num},出库数量为{$change}
-            出现这种情况可能有以下原因:
-            - 在该操作前,该物品已由另一名操作员出库,导致库存不足
-            - 多个相同商品出库相加库存不足
-            - 库存不足
-            - 库存低于0.01,此时系统会认为没有库存,请避免此类情况的发生
-            - 出库数量/库存数量过高导致溢出,如出现此类情况请联系开发人员解决
-            EOF;
-            throw $this->exception($info);
-        }
-        $stock->num += $change;
-        $stock->save();
-    }
-
-    public function export($params = [])
-    {
-        $params = $this->autoParams($params);
-        $params['pageParams']['size'] = PHP_INT_MAX;
-        $stocks = $this->page($params)->getCollection();
-        $stocks = $stocks->map(fn(Stock $stock) => $stock->getData());
-        $header = [
-            [
-                'id',
-                '仓库id',
-                '商品id',
-                '创建时间',
-                '更新时间',
-                '删除时间',
-                '数量',
-                '商品名',
-                '编号',
-                '仓库名',
-                '在途数量'
-            ]
-        ];
-        $res = PhpSpreadsheetExportV2::outputFile(
-            $stocks,
-            $header,
-            '仓储管理系统' . date('Ymdis'),
-            []
-        );
-        return $res;
-    }
-
-}

+ 29 - 29
api/composer.lock

@@ -200,16 +200,16 @@
         },
         {
             "name": "firebase/php-jwt",
-            "version": "v6.4.0",
+            "version": "v6.7.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/firebase/php-jwt.git",
-                "reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224"
+                "reference": "71278f20b0a623389beefe87a641d03948a38870"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/4dd1e007f22a927ac77da5a3fbb067b42d3bc224",
-                "reference": "4dd1e007f22a927ac77da5a3fbb067b42d3bc224",
+                "url": "https://api.github.com/repos/firebase/php-jwt/zipball/71278f20b0a623389beefe87a641d03948a38870",
+                "reference": "71278f20b0a623389beefe87a641d03948a38870",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -219,12 +219,12 @@
                 ]
             },
             "require": {
-                "php": "^7.1||^8.0"
+                "php": "^7.4||^8.0"
             },
             "require-dev": {
                 "guzzlehttp/guzzle": "^6.5||^7.4",
-                "phpspec/prophecy-phpunit": "^1.1",
-                "phpunit/phpunit": "^7.5||^9.5",
+                "phpspec/prophecy-phpunit": "^2.0",
+                "phpunit/phpunit": "^9.5",
                 "psr/cache": "^1.0||^2.0",
                 "psr/http-client": "^1.0",
                 "psr/http-factory": "^1.0"
@@ -263,9 +263,9 @@
             ],
             "support": {
                 "issues": "https://github.com/firebase/php-jwt/issues",
-                "source": "https://github.com/firebase/php-jwt/tree/v6.4.0"
+                "source": "https://github.com/firebase/php-jwt/tree/v6.7.0"
             },
-            "time": "2023-02-09T21:01:23+00:00"
+            "time": "2023-06-14T15:29:26+00:00"
         },
         {
             "name": "guzzlehttp/guzzle",
@@ -762,7 +762,7 @@
         },
         {
             "name": "maennchen/zipstream-php",
-            "version": "v2.4.0",
+            "version": "2.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/maennchen/ZipStream-PHP.git",
@@ -830,7 +830,7 @@
             ],
             "support": {
                 "issues": "https://github.com/maennchen/ZipStream-PHP/issues",
-                "source": "https://github.com/maennchen/ZipStream-PHP/tree/v2.4.0"
+                "source": "https://github.com/maennchen/ZipStream-PHP/tree/2.4.0"
             },
             "funding": [
                 {
@@ -965,16 +965,16 @@
         },
         {
             "name": "monolog/monolog",
-            "version": "2.9.0",
+            "version": "2.9.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Seldaek/monolog.git",
-                "reference": "e1c0ae1528ce313a450e5e1ad782765c4a8dd3cb"
+                "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/e1c0ae1528ce313a450e5e1ad782765c4a8dd3cb",
-                "reference": "e1c0ae1528ce313a450e5e1ad782765c4a8dd3cb",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
+                "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -1057,7 +1057,7 @@
             ],
             "support": {
                 "issues": "https://github.com/Seldaek/monolog/issues",
-                "source": "https://github.com/Seldaek/monolog/tree/2.9.0"
+                "source": "https://github.com/Seldaek/monolog/tree/2.9.1"
             },
             "funding": [
                 {
@@ -1069,7 +1069,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-02-05T13:07:32+00:00"
+            "time": "2023-02-06T13:44:46+00:00"
         },
         {
             "name": "myclabs/php-enum",
@@ -2094,16 +2094,16 @@
         },
         {
             "name": "symfony/cache",
-            "version": "v5.4.23",
+            "version": "v5.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/cache.git",
-                "reference": "983c79ff28612cdfd66d8e44e1a06e5afc87e107"
+                "reference": "e2013521c0f07473ae69a01fce0af78fc3ec0f23"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/cache/zipball/983c79ff28612cdfd66d8e44e1a06e5afc87e107",
-                "reference": "983c79ff28612cdfd66d8e44e1a06e5afc87e107",
+                "url": "https://api.github.com/repos/symfony/cache/zipball/e2013521c0f07473ae69a01fce0af78fc3ec0f23",
+                "reference": "e2013521c0f07473ae69a01fce0af78fc3ec0f23",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -2177,7 +2177,7 @@
                 "psr6"
             ],
             "support": {
-                "source": "https://github.com/symfony/cache/tree/v5.4.23"
+                "source": "https://github.com/symfony/cache/tree/v5.4.25"
             },
             "funding": [
                 {
@@ -2193,7 +2193,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-04-21T15:38:51+00:00"
+            "time": "2023-06-22T08:06:06+00:00"
         },
         {
             "name": "symfony/cache-contracts",
@@ -2531,16 +2531,16 @@
         },
         {
             "name": "symfony/http-foundation",
-            "version": "v5.4.24",
+            "version": "v5.4.25",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "3c59f97f6249ce552a44f01b93bfcbd786a954f5"
+                "reference": "f66be2706075c5f6325d2fe2b743a57fb5d23f6b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3c59f97f6249ce552a44f01b93bfcbd786a954f5",
-                "reference": "3c59f97f6249ce552a44f01b93bfcbd786a954f5",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f66be2706075c5f6325d2fe2b743a57fb5d23f6b",
+                "reference": "f66be2706075c5f6325d2fe2b743a57fb5d23f6b",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -2593,7 +2593,7 @@
             "description": "Defines an object-oriented layer for the HTTP specification",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-foundation/tree/v5.4.24"
+                "source": "https://github.com/symfony/http-foundation/tree/v5.4.25"
             },
             "funding": [
                 {
@@ -2609,7 +2609,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-05-19T07:21:23+00:00"
+            "time": "2023-06-22T08:06:06+00:00"
         },
         {
             "name": "symfony/polyfill-mbstring",

+ 2 - 2
api/generate-schema.py

@@ -17,8 +17,8 @@ def underscore_to_camelcase(text):
 table_name = sys.argv[1]
 
 # 连接MySQL数据库
-cnx = mysql.connector.connect(user='yfb', password='yfb123#',
-                              host='qqyun.ycxxkj.com', database='lechang_storage_dev', port='38006')
+cnx = mysql.connector.connect(user='root', password='root',
+                              host='localhost', database='project-manager', port='3306')
 cursor = cnx.cursor()
 
 # 定义SQL语句,获取表格列名、数据类型和注释

+ 0 - 1
api/view/README.md

@@ -1 +0,0 @@
-如果不使用模板,可以删除该目录

+ 10 - 0
docker/project-manager-backend.dockerfile

@@ -0,0 +1,10 @@
+FROM php:8.0-apache
+
+# 使用镜像
+RUN sed -i "s@http://.*archive.ubuntu.com@https://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list
+RUN sed -i "s@http://.*security.ubuntu.com@https://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list
+
+ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
+
+RUN chmod +x /usr/local/bin/install-php-extensions 
+RUN install-php-extensions gd pdo_mysql zip