id(); $table->string('name', 255); $table->string('province', 64)->nullable(); $table->string('city', 64)->nullable(); $table->decimal('latitude', 10, 7)->nullable(); $table->decimal('longitude', 10, 7)->nullable(); $table->string('address', 512)->nullable(); $table->text('remark')->nullable(); $table->tinyInteger('status')->default(1)->comment('1启用 0停用'); $table->timestamps(); $table->softDeletes(); $table->index(['city', 'status']); }); Schema::create('teachers', function (Blueprint $table) { $table->id(); $table->string('name', 64); $table->foreignId('university_id') ->nullable() ->constrained('universities') ->nullOnDelete(); $table->string('city', 64)->nullable(); $table->string('title', 64)->nullable()->comment('职称'); $table->string('research_direction', 255)->nullable()->comment('研究方向'); $table->string('phone', 32)->nullable(); $table->string('email', 128)->nullable(); $table->foreignId('source_dict_item_id') ->nullable() ->constrained('dict_items') ->restrictOnDelete() ->comment('来源,字典 teacher_source'); $table->foreignId('star_level_dict_item_id') ->nullable() ->constrained('dict_items') ->restrictOnDelete() ->comment('星级,字典 teacher_level'); $table->foreignId('status_dict_item_id') ->nullable() ->constrained('dict_items') ->restrictOnDelete() ->comment('跟进状态,字典 teacher_status'); $table->date('next_follow_date')->nullable()->comment('下次跟进日'); $table->string('next_follow_subject', 255)->nullable(); $table->boolean('is_partner')->default(false)->comment('是否转化伙伴'); $table->timestamp('converted_at')->nullable(); $table->text('remark')->nullable(); $table->integer('sort')->default(0); $table->timestamps(); $table->softDeletes(); $table->index(['university_id', 'status_dict_item_id']); $table->index(['next_follow_date', 'star_level_dict_item_id']); $table->index(['source_dict_item_id']); }); Schema::create('teacher_follow_records', function (Blueprint $table) { $table->id(); $table->foreignId('teacher_id')->constrained('teachers')->cascadeOnDelete(); $table->foreignId('admin_user_id') ->nullable() ->constrained('admin_users') ->nullOnDelete(); $table->string('subject', 255)->comment('跟进主题'); $table->text('content')->nullable()->comment('跟进记录'); $table->foreignId('follow_method_dict_item_id') ->nullable() ->constrained('dict_items') ->restrictOnDelete() ->comment('跟进方式,字典 follow_method'); $table->foreignId('urgency_dict_item_id') ->nullable() ->constrained('dict_items') ->restrictOnDelete() ->comment('紧急程度,字典 follow_urgency'); $table->string('next_follow_subject', 255)->nullable(); $table->date('next_follow_date')->nullable(); $table->date('followed_at')->comment('本次跟进日期'); $table->string('result', 64)->nullable()->comment('跟进结果,如成为伙伴'); $table->timestamps(); $table->index(['teacher_id', 'followed_at']); }); Schema::create('papers', function (Blueprint $table) { $table->id(); $table->string('title', 512); $table->string('authors', 512)->nullable(); $table->foreignId('university_id') ->nullable() ->constrained('universities') ->nullOnDelete(); $table->string('school_name', 255)->nullable()->comment('冗余学校名,便于展示'); $table->date('published_at')->nullable(); $table->string('url', 512)->nullable(); $table->text('summary')->nullable(); $table->string('source', 32)->default('manual')->comment('manual|crawl'); $table->timestamps(); $table->softDeletes(); }); Schema::create('teacher_papers', function (Blueprint $table) { $table->id(); $table->foreignId('teacher_id')->constrained('teachers')->cascadeOnDelete(); $table->foreignId('paper_id')->constrained('papers')->cascadeOnDelete(); $table->timestamps(); $table->unique(['teacher_id', 'paper_id']); }); } public function down(): void { Schema::dropIfExists('teacher_papers'); Schema::dropIfExists('papers'); Schema::dropIfExists('teacher_follow_records'); Schema::dropIfExists('teachers'); Schema::dropIfExists('universities'); } };