diff --git a/app/Admin/Controllers/HomeController.php b/app/Admin/Controllers/HomeController.php
index 34bf37b..ab1a55f 100644
--- a/app/Admin/Controllers/HomeController.php
+++ b/app/Admin/Controllers/HomeController.php
@@ -20,6 +20,7 @@ class HomeController extends AdminController
public function index(): JsonResponse|JsonResource
{
$page = $this->basePage()->css($this->css())->body([
+ // amis()->IFrame()->src('')//数据驾驶仓地址-todo
Grid::make()->columns([
$this->frameworkInfo()->md(5),
Flex::make()->items([
diff --git a/app/Admin/Controllers/Plan/PlanController.php b/app/Admin/Controllers/Plan/PlanController.php
index e51793b..34cc2ec 100644
--- a/app/Admin/Controllers/Plan/PlanController.php
+++ b/app/Admin/Controllers/Plan/PlanController.php
@@ -5,6 +5,7 @@ namespace App\Admin\Controllers\Plan;
use App\Admin\Controllers\AdminController;
use App\Admin\Services\Plan\PlanService;
use App\Enums\PlanStatus;
+use App\Enums\TaskStatus;
use Illuminate\Support\Arr;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Renderers\Form;
@@ -161,6 +162,28 @@ class PlanController extends AdminController
public function detail(): Form
{
return $this->baseDetail()->title('')->body([
+ amis()->Property()->items([
+ ['label' => __('plan.plan.name'), 'content' => '${name}'],
+ ['label' => __('plan.plan.type'), 'content' => amis()->Mapping()->name('planable_type')->map($this->planableTypeLabelMap)],
+ ['label' => __('plan.plan.status'), 'content' => amis()->Mapping()->name('plan_status')->map(PlanStatus::labelMap())],
+ ]),
+
+ amis()->Divider(),
+
+ // 总账录入
+ amis()->CRUDTable()
+ ->api(admin_url('api/tasks?plan_id=${id}'))
+ ->columns([
+ amis()->TableColumn('id', __('plan.task.id')),
+ amis()->TableColumn('name', __('plan.task.name')),
+ amis()->TableColumn('taskable.date', __('plan.task_ledger.date')),
+ amis()->TableColumn('taskable.store.title', __('plan.task_ledger.store')),
+ amis()->TableColumn('taskable.store.master.name', __('plan.task_ledger.store_master')),
+ amis()->TableColumn('task_status', __('plan.task.status'))->type('mapping')->map(TaskStatus::labelMap()),
+ amis()->TableColumn('completed_at', __('plan.task.completed_at')),
+ amis()->TableColumn('created_at', __('plan.task.created_at')),
+ ])
+ ->visibleOn('${planable_type == "plan_ledgers"}'),
]);
}
}
diff --git a/app/Admin/Controllers/Plan/TaskController.php b/app/Admin/Controllers/Plan/TaskController.php
new file mode 100644
index 0000000..32298d6
--- /dev/null
+++ b/app/Admin/Controllers/Plan/TaskController.php
@@ -0,0 +1,35 @@
+input(), TaskFilter::class)
+ ->with([
+ 'taskable' => function (MorphTo $morphTo) {
+ $morphTo->morphWith([
+ TaskLedger::class => ['store.master'],
+ ]);
+ },
+ ])
+ ->latest('id')
+ ->get();
+
+ return $this->response()->success($tasks);
+ }
+}
diff --git a/app/Admin/Filters/TaskFilter.php b/app/Admin/Filters/TaskFilter.php
new file mode 100644
index 0000000..e33157a
--- /dev/null
+++ b/app/Admin/Filters/TaskFilter.php
@@ -0,0 +1,13 @@
+where('plan_id', $id);
+ }
+}
diff --git a/app/Admin/Services/Plan/TaskService.php b/app/Admin/Services/Plan/TaskService.php
new file mode 100644
index 0000000..9a839d6
--- /dev/null
+++ b/app/Admin/Services/Plan/TaskService.php
@@ -0,0 +1,19 @@
+post('workflow/success', [WorkflowController::class, 'success']);
$router->post('workflow/fail', [WorkflowController::class, 'fail']);
$router->get('workflow/logs', [WorkflowController::class, 'logs']);
+
+ $router->get('tasks', [TaskController::class, 'shareList']);
});
});
diff --git a/app/Console/Commands/TaskLedgerGenerateCommand.php b/app/Console/Commands/TaskLedgerGenerateCommand.php
new file mode 100644
index 0000000..aa01cbb
--- /dev/null
+++ b/app/Console/Commands/TaskLedgerGenerateCommand.php
@@ -0,0 +1,99 @@
+argument('date');
+
+ $this->generateTasks(
+ $date ? Carbon::parse($date) : today()
+ );
+ }
+
+ protected function generateTasks(Carbon $datetime): void
+ {
+ /** @var \App\Models\PlanLedger */
+ $planable = DB::transaction(function () use ($datetime) {
+ /** @var \App\Models\PlanLedger */
+ $planable = PlanLedger::firstOrNew([
+ 'date' => $datetime->format('Y-m-d'),
+ ]);
+
+ if ($planable->exists) {
+ return $planable;
+ }
+
+ $planable->save();
+
+ $plan = $planable->plan()->create([
+ 'name' => "{$planable->date} 总账录入",
+ 'plan_status' => PlanStatus::Published,
+ ]);
+
+ return $planable->setRelation('plan', $plan);
+ });
+
+ $stores = Store::all();
+
+ /** @var \App\Models\Store */
+ foreach ($stores as $store) {
+ DB::transaction(function () use ($store, $planable) {
+ $taskable = TaskLedger::firstOrNew([
+ 'store_id' => $store->id,
+ 'date' => $planable->date,
+ ]);
+
+ if ($taskable->exists) {
+ return;
+ }
+
+ $taskable->save();
+
+ $ledger = Ledger::where('store_id', $store->id)
+ ->where('date', $planable->date)
+ ->first();
+
+ $date = Carbon::parse($planable->date);
+
+ $taskable->task()->create([
+ 'plan_id' => $planable->plan->id,
+ 'name' => '总账录入',
+ 'start_at' => $date->copy()->startOfDay(),
+ 'end_at' => $date->copy()->endOfDay(),
+ 'task_status' => $ledger ? TaskStatus::Success : TaskStatus::Pending,
+ 'completed_at' => $ledger?->created_at,
+ ]);
+ });
+ }
+ }
+}
diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php
index e6b9960..5c2613a 100644
--- a/app/Console/Kernel.php
+++ b/app/Console/Kernel.php
@@ -12,7 +12,7 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule): void
{
- // $schedule->command('inspire')->hourly();
+ $schedule->command(Commands\TaskLedgerGenerateCommand::class)->dailyAt('01:00');
}
/**
diff --git a/app/Enums/TaskStatus.php b/app/Enums/TaskStatus.php
new file mode 100644
index 0000000..79b8399
--- /dev/null
+++ b/app/Enums/TaskStatus.php
@@ -0,0 +1,39 @@
+value];
+ }
+
+ public static function options(): array
+ {
+ return [
+ self::Pending->value => '待完成',
+ self::Processing->value => '进行中',
+ self::Success->value => '已完成',
+ self::Failed->value => '未完成',
+ self::Revoked->value => '已撤销',
+ ];
+ }
+
+ public static function labelMap(): array
+ {
+ return [
+ self::Pending->value => ''.self::Pending->text().'',
+ self::Processing->value => ''.self::Processing->text().'',
+ self::Success->value => ''.self::Success->text().'',
+ self::Failed->value => ''.self::Failed->text().'',
+ self::Revoked->value => ''.self::Revoked->text().'',
+ ];
+ }
+}
diff --git a/app/Models/PlanLedger.php b/app/Models/PlanLedger.php
index befaae7..c53ec6f 100644
--- a/app/Models/PlanLedger.php
+++ b/app/Models/PlanLedger.php
@@ -11,10 +11,6 @@ class PlanLedger extends Model
{
use HasFactory, HasDateTimeFormatter;
- protected $casts = [
- 'date' => 'date',
- ];
-
protected $fillable = [
'date',
];
diff --git a/app/Models/Task.php b/app/Models/Task.php
new file mode 100644
index 0000000..c95e87b
--- /dev/null
+++ b/app/Models/Task.php
@@ -0,0 +1,42 @@
+ TaskStatus::Pending,
+ ];
+
+ protected $casts = [
+ 'start_at' => 'datetime',
+ 'end_at' => 'datetime',
+ 'task_status' => TaskStatus::class,
+ 'completed_at' => 'datetime',
+ ];
+
+ protected $fillable = [
+ 'plan_id',
+ 'taskable_type',
+ 'taskable_id',
+ 'name',
+ 'start_at',
+ 'end_at',
+ 'task_status',
+ 'completed_at',
+ ];
+
+ public function taskable(): MorphTo
+ {
+ return $this->morphTo();
+ }
+}
diff --git a/app/Models/TaskLedger.php b/app/Models/TaskLedger.php
new file mode 100644
index 0000000..3bed357
--- /dev/null
+++ b/app/Models/TaskLedger.php
@@ -0,0 +1,29 @@
+morphOne(Task::class, 'taskable');
+ }
+
+ public function store(): BelongsTo
+ {
+ return $this->belongsTo(Store::class);
+ }
+}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index e3bfef3..c9fc7c3 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -45,6 +45,7 @@ class AppServiceProvider extends ServiceProvider
\App\Models\PlanPerformance::class,
\App\Models\Reimbursement::class,
\App\Models\StoreMasterCommission::class,
+ \App\Models\TaskLedger::class,
\App\Models\EmployeePromotion::class,
\App\Models\Agreement::class,
])->mapWithKeys(fn ($model) => [(new $model)->getTable() => $model])->all()
diff --git a/config/admin.php b/config/admin.php
index 7a63480..af01553 100644
--- a/config/admin.php
+++ b/config/admin.php
@@ -2,7 +2,7 @@
return [
// 应用名称
- 'name' => 'Owl Admin',
+ 'name' => '门店助手-管理后台',
// 应用 logo
'logo' => '/admin-assets/logo.png',
diff --git a/database/migrations/2024_04_08_223111_create_plans_table.php b/database/migrations/2024_04_08_223111_create_plans_table.php
index ac02e8a..18f17c3 100644
--- a/database/migrations/2024_04_08_223111_create_plans_table.php
+++ b/database/migrations/2024_04_08_223111_create_plans_table.php
@@ -13,10 +13,13 @@ return new class extends Migration
{
Schema::create('plans', function (Blueprint $table) {
$table->id();
+ $table->string('planable_type');
+ $table->unsignedBigInteger('planable_id');
$table->string('name')->comment('名称');
- $table->morphs('planable');
$table->tinyInteger('plan_status')->comment('状态');
$table->timestamps();
+
+ $table->unique(['planable_type', 'planable_id'], 'planable_type');
});
}
diff --git a/database/migrations/2024_04_15_075647_create_tasks_table.php b/database/migrations/2024_04_15_075647_create_tasks_table.php
new file mode 100644
index 0000000..8f552d0
--- /dev/null
+++ b/database/migrations/2024_04_15_075647_create_tasks_table.php
@@ -0,0 +1,37 @@
+id();
+ $table->string('taskable_type');
+ $table->unsignedBigInteger('taskable_id');
+ $table->foreignId('plan_id')->comment('任务计划');
+ $table->string('name')->comment('任务名称');
+ $table->dateTime('start_at')->nullable()->comment('开始时间');
+ $table->dateTime('end_at')->nullable()->comment('结束时间');
+ $table->tinyInteger('task_status')->comment('任务状态');
+ $table->dateTime('completed_at')->nullable()->comment('完成时间');
+ $table->timestamps();
+
+ $table->unique(['taskable_type', 'taskable_id'], 'taskable_type');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('tasks');
+ }
+};
diff --git a/database/migrations/2024_04_15_081617_create_task_ledgers_table.php b/database/migrations/2024_04_15_081617_create_task_ledgers_table.php
new file mode 100644
index 0000000..07b128e
--- /dev/null
+++ b/database/migrations/2024_04_15_081617_create_task_ledgers_table.php
@@ -0,0 +1,29 @@
+id();
+ $table->foreignId('store_id')->comment('门店ID');
+ $table->date('date')->comment('日期');
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('task_ledgers');
+ }
+};
diff --git a/database/seeders/AdminPermissionSeeder.php b/database/seeders/AdminPermissionSeeder.php
index 3ff14a3..926d563 100644
--- a/database/seeders/AdminPermissionSeeder.php
+++ b/database/seeders/AdminPermissionSeeder.php
@@ -27,7 +27,9 @@ class AdminPermissionSeeder extends Seeder
'name' => '主页',
'icon' => 'line-md:home-twotone-alt',
'uri' => '/dashboard',
+ 'is_home' => 1,
'children' => [],
+ 'order' => 1,
],
/*
@@ -37,50 +39,59 @@ class AdminPermissionSeeder extends Seeder
*/
'store' => [
'name' => '门店管理',
- 'icon' => 'material-symbols:store-rounded',
+ 'icon' => 'material-symbols:store-outline',
'uri' => '/store',
+ 'order' =>2,
'children' => [
'stores' => [
- 'name' => '门店管理',
- 'icon' => '',
+ 'name' => '门店列表',
+ 'icon' => 'ic:outline-storefront',
'uri' => '/store/stores',
'resource' => true,
+ 'order' => 1,
],
'employees' => [
'name' => '店员管理',
- 'icon' => '',
+ 'icon' => 'ic:baseline-people-outline',
'uri' => '/store/employees',
'resource' => ['list', 'create', 'delete'],
+ 'order' => 2,
],
'categories' => [
'name' => '门店分类',
- 'icon' => '',
+ 'icon' => 'tabler:category',
'uri' => '/store/categories?parent_key=store_category',
'resource' => true,
+ 'order' => 3,
],
'levels' => [
'name' => '门店等级',
- 'icon' => '',
+ 'icon' => 'carbon:skill-level',
'uri' => '/store/levels?parent_key=store_levels',
'resource' => true,
+ 'order' => 4,
+
],
'business' => [
'name' => '经营类别',
- 'icon' => '',
+ 'icon' => 'mingcute:certificate-line',
'uri' => '/store/business?parent_key=store_business',
'resource' => true,
+ 'order' => 5,
],
'devices' => [
'name' => '彩票机管理',
- 'icon' => '',
+ 'icon' => 'streamline:money-cashier-shop-shopping-pay-payment-cashier-store-cash-register-machine',
'uri' => '/store/devices',
'resource' => true,
+ 'order' => 6,
],
'lottery-types' => [
'name' => '彩种类型',
- 'icon' => '',
+ 'icon' => 'mingcute:sunflower-line',
'uri' => '/store/lottery-types?parent_key=lottery_type',
'resource' => true,
+ 'order' => 7,
],
],
],
@@ -92,65 +103,75 @@ class AdminPermissionSeeder extends Seeder
*/
'hr' => [
'name' => '人事管理',
- 'icon' => 'flowbite:user-settings-solid',
+ 'icon' => 'material-symbols:deployed-code-account-outline',
'uri' => '/hr',
+ 'order' => 3,
'children' => [
'employees' => [
'name' => '员工管理',
- 'icon' => '',
+ 'icon' => 'material-symbols:user-attributes-outline',
'uri' => '/hr/employees',
'resource' => true,
'children' => [
'leave' => '离职',
],
+ 'order' => 1,
],
'jobs' => [
'name' => '职位管理',
- 'icon' => '',
+ 'icon' => 'material-symbols:frame-person-outline-sharp',
'uri' => '/hr/jobs?parent_key=job',
'resource' => true,
+ 'order' => 2,
],
'rests' => [
- 'name' => '休息管理',
- 'icon' => '',
+ 'name' => '休息日管理',
+ 'icon' => 'material-symbols-light:timelapse-outline-rounded',
'uri' => '/hr/rests',
'resource' => ['list', 'create', 'delete'],
+ 'order' => 3,
],
'signs' => [
'name' => '考勤打卡',
- 'icon' => '',
+ 'icon' => 'material-symbols:calendar-clock-outline',
'uri' => '/hr/signs',
'resource' => ['list', 'view'],
+ 'order' => 4,
],
'repairs' => [
'name' => '补卡申请',
- 'icon' => '',
+ 'icon' => 'mdi:table-clock',
'uri' => '/hr/repairs',
'resource' => true,
+ 'order' => 5,
],
'holiday' => [
'name' => '请假申请',
- 'icon' => '',
+ 'icon' => 'ic:outline-more-time',
'uri' => '/hr/holiday',
'resource' => true,
+ 'order' => 6,
],
'overtime' => [
'name' => '加班申请',
- 'icon' => '',
+ 'icon' => 'ic:round-add-alarm',
'uri' => '/hr/overtime',
'resource' => true,
+ 'order' => 7,
],
'business' => [
'name' => '出差报备',
- 'icon' => '',
+ 'icon' => 'material-symbols:car-tag-outline',
'uri' => '/hr/business',
'resource' => true,
+ 'order' => 8,
],
'promotion' => [
'name' => '升职申请',
- 'icon' => '',
+ 'icon' => 'fluent:people-star-32-regular',
'uri' => '/hr/promotion',
'resource' => true,
+ 'order' => 9,
],
],
],
@@ -161,13 +182,14 @@ class AdminPermissionSeeder extends Seeder
|--------------------------------------------------------------------------
*/
'plan' => [
- 'name' => '任务计划',
- 'icon' => 'flowbite:user-settings-solid',
- 'uri' => '/hr',
+ 'name' => '任务管理',
+ 'icon' => 'mingcute:send-plane-line',
+ 'uri' => '/plan',
+ 'order' => 4,
'children' => [
'plans' => [
- 'name' => '任务计划',
- 'icon' => '',
+ 'name' => '任务列表',
+ 'icon' => 'tdesign:task',
'uri' => '/plan/plans',
'resource' => true,
'children' => [],
@@ -184,6 +206,7 @@ class AdminPermissionSeeder extends Seeder
'name' => '投诉意见',
'icon' => 'mdi:star-four-points-box-outline',
'uri' => '/complaint',
+ 'order' => 5,
'children' => [
'complaints' => [
'name' => '举报投诉',
@@ -214,6 +237,7 @@ class AdminPermissionSeeder extends Seeder
'name' => '财务报表',
'icon' => 'material-symbols:finance-mode',
'uri' => '/finance',
+ 'order' => 6,
'children' => [
'ledgers' => [
'name' => '上报数据',
@@ -270,24 +294,25 @@ class AdminPermissionSeeder extends Seeder
'train' => [
'name' => '培训管理',
- 'icon' => '',
+ 'icon' => 'solar:people-nearby-broken',
'uri' => '/train',
+ 'order' => 7,
'children' => [
'books' => [
'name' => '课件管理',
- 'icon' => '',
+ 'icon' => 'material-symbols:library-books-outline-rounded',
'uri' => '/train/books',
'resource' => true,
],
'questions' => [
'name' => '题库管理',
- 'icon' => '',
+ 'icon' => 'ph:books-duotone',
'uri' => '/train/questions',
'resource' => true,
],
'examinations' => [
'name' => '考试管理',
- 'icon' => '',
+ 'icon' => 'material-symbols:checkbook-outline',
'uri' => '/train/examinations',
'resource' => true,
],
@@ -295,7 +320,7 @@ class AdminPermissionSeeder extends Seeder
],
'agreement' => [
'name' => '合同管理',
- 'icon' => '',
+ 'icon' => 'flowbite:inbox-full-outline',
'uri' => '/agreement',
'resource' => true,
'children' => [
@@ -360,7 +385,7 @@ class AdminPermissionSeeder extends Seeder
],
'workflows' => [
'name' => '审核流程',
- 'icon' => '',
+ 'icon' => 'carbon:flow-data',
'uri' => '/system/workflows',
'resource' => true,
],
diff --git a/lang/zh_CN/plan.php b/lang/zh_CN/plan.php
index ec98acb..0e86ad2 100644
--- a/lang/zh_CN/plan.php
+++ b/lang/zh_CN/plan.php
@@ -14,4 +14,18 @@ return [
'store_level' => '门店等级',
'performance' => '业绩',
],
+
+ 'task' => [
+ 'id' => 'ID',
+ 'name' => '任务名称',
+ 'status' => '状态',
+ 'completed_at' => '完成时间',
+ 'created_at' => '创建时间',
+ ],
+
+ 'task_ledger' => [
+ 'date' => '日期',
+ 'store' => '门店',
+ 'store_master' => '店长',
+ ],
];
diff --git a/public/admin-assets/logo.png b/public/admin-assets/logo.png
index a46d3ef..38c5c3c 100644
Binary files a/public/admin-assets/logo.png and b/public/admin-assets/logo.png differ