master
lion 2 days ago
parent 5f377983f8
commit f472eec19d

@ -73,6 +73,10 @@ ARXIV_MIN_INTERVAL=4
# 天地图浏览器端 Key管理后台地图 + 小程序 web-view 雷达页,与 slake-school-web 的 VITE_TIANDITU_TK 一致)
TIANDITU_TK=cc3f61fa6cafe2f0ad440018d0f07b13
# 小程序 web-view 业务域名校验(微信公众平台下载校验文件后填写)
# WECHAT_MP_WEBVIEW_VERIFY_FILE=xxxxxxxx.txt
# WECHAT_MP_WEBVIEW_VERIFY_CONTENT=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Sanctum SPA 本地域名(管理后台 Vite 5173 需包含)
SANCTUM_STATEFUL_DOMAINS=localhost,localhost:5173,127.0.0.1,127.0.0.1:8000

@ -13,6 +13,7 @@ use App\Models\Teacher;
use App\Services\GridMemberScopeService;
use App\Services\TeacherFollowPlanService;
use App\Support\ApiResponse;
use App\Support\Miniapp\MiniappUserPermission;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@ -52,6 +53,15 @@ class MiniappUserController extends Controller
$query->whereNull('teacher_id');
}
if ($request->filled('identity_type')) {
$identityType = (string) $request->query('identity_type');
if ($identityType === 'none') {
$query->whereNull('identity_type');
} elseif (in_array($identityType, ['incubation', 'partner'], true)) {
$query->where('identity_type', $identityType);
}
}
$paginator = $query
->orderByDesc('id')
->paginate((int) $request->query('page_size', 20))
@ -80,18 +90,21 @@ class MiniappUserController extends Controller
$data = $request->validate([
'admin_user_id' => ['nullable', 'integer', 'exists:admin_users,id'],
'identity_type' => ['nullable', 'string', Rule::in(['incubation', 'partner'])],
]);
$adminUserId = $data['admin_user_id'] ?? null;
$identityType = $data['identity_type'] ?? null;
if ($adminUserId) {
$admin = AdminUser::query()->with('roles:id,code')->findOrFail($adminUserId);
$codes = $admin->roles->pluck('code')->all();
if (! in_array('super_admin', $codes, true) && ! in_array('grid_member', $codes, true)) {
return $this->fail('仅可绑定管理员或网格员账号', 422);
$admin = AdminUser::query()->with('roles:id,code,name')->findOrFail($adminUserId);
if ((int) $admin->status !== 1) {
return $this->fail('该后台账号已停用,无法绑定', 422);
}
}
$model->admin_user_id = $adminUserId;
$model->identity_type = $identityType;
$model->save();
$model->load([
@ -99,7 +112,7 @@ class MiniappUserController extends Controller
'adminUser.roles:id,code,name',
]);
return $this->ok($this->serializeDetail($model), $adminUserId ? '已绑定后台账号' : '已解除绑定');
return $this->ok($this->serializeDetail($model), '已保存');
}
public function convertToTeacher(Request $request, int $miniappUser): JsonResponse
@ -304,6 +317,8 @@ class MiniappUserController extends Controller
'teacher_name' => $u->teacher?->name,
'admin_user_id' => $u->admin_user_id,
'admin_user_name' => $u->adminUser?->real_name ?: $u->adminUser?->username,
'identity_type' => $u->identity_type,
'identity_label' => MiniappUserPermission::identityTypeLabel($u->identity_type),
'staff_role_label' => $this->staffRoleLabel($u),
'converted_at' => $u->converted_at?->toIso8601String(),
'course_titles' => $enrollments['course_titles'],
@ -334,15 +349,19 @@ class MiniappUserController extends Controller
return null;
}
$codes = $u->adminUser->roles->pluck('code')->all();
if (in_array('super_admin', $codes, true)) {
$roles = $u->adminUser->roles;
if ($roles->isEmpty()) {
return '后台账号';
}
if ($roles->contains(fn ($role) => $role->code === 'super_admin')) {
return '管理员';
}
if (in_array('grid_member', $codes, true)) {
if ($roles->contains(fn ($role) => $role->code === 'grid_member')) {
return '网格员';
}
return null;
return $roles->pluck('name')->filter()->unique()->implode('、') ?: '后台账号';
}
protected function loadEnrollments(MiniappUser $u, bool $detailed = false): array

@ -0,0 +1,97 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\PastReview;
use App\Support\ApiResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class PastReviewController extends Controller
{
use ApiResponse;
public function index(Request $request): JsonResponse
{
$query = PastReview::query();
if ($request->filled('status')) {
$query->where('status', (int) $request->query('status'));
}
if ($kw = $request->query('keyword')) {
$query->where('title', 'like', "%{$kw}%");
}
$paginator = $query
->orderBy('sort')
->orderByDesc('id')
->paginate((int) $request->query('page_size', 20))
->withQueryString();
$paginator->getCollection()->transform(fn (PastReview $row) => $this->serialize($row));
return $this->paginated($paginator);
}
public function show(int $pastReview): JsonResponse
{
$model = PastReview::query()->findOrFail($pastReview);
return $this->ok($this->serialize($model));
}
public function store(Request $request): JsonResponse
{
$data = $this->validated($request);
$row = PastReview::query()->create($data);
return $this->ok(['id' => $row->id], '已创建');
}
public function update(Request $request, int $pastReview): JsonResponse
{
$model = PastReview::query()->findOrFail($pastReview);
$data = $this->validated($request, $model);
$model->fill($data);
$model->save();
return $this->ok($this->serialize($model->fresh()), '已保存');
}
public function destroy(int $pastReview): JsonResponse
{
PastReview::query()->findOrFail($pastReview)->delete();
return $this->ok(null, '已删除');
}
/**
* @return array<string, mixed>
*/
protected function validated(Request $request, ?PastReview $existing = null): array
{
return $request->validate([
'title' => [$existing ? 'sometimes' : 'required', 'string', 'max:255'],
'cover_url' => ['nullable', 'string', 'max:512'],
'sort' => [$existing ? 'sometimes' : 'required', 'integer', 'min:0'],
'status' => ['sometimes', 'integer', 'in:0,1'],
]);
}
/**
* @return array<string, mixed>
*/
protected function serialize(PastReview $row): array
{
return [
'id' => $row->id,
'title' => $row->title,
'cover_url' => $row->cover_url,
'sort' => $row->sort,
'status' => $row->status,
'created_at' => $row->created_at?->toIso8601String(),
'updated_at' => $row->updated_at?->toIso8601String(),
];
}
}

@ -30,6 +30,26 @@ class RadarMapController extends Controller
$bounds = $this->resolveBounds($universities);
$schools = $universities->map(function (University $u) use ($bounds) {
$teachers = $u->teachers->map(fn ($t) => [
'id' => $t->id,
'name' => $t->name,
'department' => $t->department,
'bio' => $t->bio,
'title' => $t->title,
'research_direction' => $t->researchDirections->pluck('name')->join('、') ?: null,
'research_directions' => $t->researchDirections->map(fn ($d) => [
'id' => $d->id,
'name' => $d->name,
])->values()->all(),
'star_level_item' => $t->starLevelItem ? [
'id' => $t->starLevelItem->id,
'label' => $t->starLevelItem->label,
'value' => $t->starLevelItem->value,
] : null,
])->values();
$colleges = $this->buildColleges($teachers);
return [
'id' => $u->id,
'name' => $u->name,
@ -39,23 +59,8 @@ class RadarMapController extends Controller
'left_percent' => $this->toPercent($u->longitude, $bounds['min_lng'], $bounds['max_lng']),
'top_percent' => $this->toPercentInverted($u->latitude, $bounds['min_lat'], $bounds['max_lat']),
'teachers_count' => $u->teachers->count(),
'teachers' => $u->teachers->map(fn ($t) => [
'id' => $t->id,
'name' => $t->name,
'department' => $t->department,
'bio' => $t->bio,
'title' => $t->title,
'research_direction' => $t->researchDirections->pluck('name')->join('、') ?: null,
'research_directions' => $t->researchDirections->map(fn ($d) => [
'id' => $d->id,
'name' => $d->name,
])->values()->all(),
'star_level_item' => $t->starLevelItem ? [
'id' => $t->starLevelItem->id,
'label' => $t->starLevelItem->label,
'value' => $t->starLevelItem->value,
] : null,
])->values(),
'colleges' => $colleges,
'teachers' => $teachers,
];
})->values();
@ -261,4 +266,47 @@ class RadarMapController extends Controller
return round(10 + $ratio * 80, 2);
}
/**
* @param \Illuminate\Support\Collection<int, array<string, mixed>> $teachers
* @return list<array{key:string, name:string, teachers_count:int, teachers: \Illuminate\Support\Collection<int, array<string, mixed>>}>
*/
protected function buildColleges($teachers): array
{
$groups = [];
foreach ($teachers as $teacher) {
$department = trim((string) ($teacher['department'] ?? ''));
$key = $department !== '' ? $department : '__none__';
if (! isset($groups[$key])) {
$groups[$key] = [
'key' => $key,
'name' => $department !== '' ? $department : '暂无学院归属',
'teachers' => collect(),
];
}
$groups[$key]['teachers']->push($teacher);
}
$colleges = collect($groups)
->map(fn ($group) => [
'key' => $group['key'],
'name' => $group['name'],
'teachers_count' => $group['teachers']->count(),
'teachers' => $group['teachers']->values(),
])
->sort(function ($a, $b) {
if ($a['key'] === '__none__') {
return 1;
}
if ($b['key'] === '__none__') {
return -1;
}
return $b['teachers_count'] <=> $a['teachers_count'];
})
->values()
->all();
return $colleges;
}
}

@ -32,7 +32,7 @@ class CrawlAddressController extends BaseController
}
$payload = MiniappPresenter::userPayload($user);
if (! ($payload['is_admin'] || $payload['is_grid_member'])) {
if (! ($payload['can_use_crawler'] ?? false)) {
abort(403, '无权使用数据爬虫');
}

@ -51,7 +51,7 @@ class CrawlJobController extends BaseController
}
$payload = MiniappPresenter::userPayload($user);
if (! ($payload['is_admin'] || $payload['is_grid_member'])) {
if (! ($payload['can_use_crawler'] ?? false)) {
abort(403, '无权使用数据爬虫');
}

@ -8,6 +8,7 @@ use App\Models\DictItem;
use App\Models\DictType;
use App\Models\MiniappUser;
use App\Support\ApiResponse;
use App\Support\Miniapp\MiniappUserPermission;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
@ -20,6 +21,11 @@ class DemandController extends Controller
{
/** @var MiniappUser $user */
$user = $request->user();
$permissions = MiniappUserPermission::resolve($user);
if (! ($permissions['can_access_demands'] ?? false)) {
return $this->fail('暂无相关权限', 403);
}
$items = Demand::query()
->with(['typeItem', 'statusItem'])
@ -38,6 +44,11 @@ class DemandController extends Controller
{
/** @var MiniappUser $user */
$user = $request->user();
$permissions = MiniappUserPermission::resolve($user);
if (! ($permissions['can_access_demands'] ?? false)) {
return $this->fail('暂无相关权限', 403);
}
$typeDictId = DictType::query()->where('code', 'demand_type')->where('status', 1)->value('id');
$statusDictId = DictType::query()->where('code', 'demand_status')->where('status', 1)->value('id');

@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
use App\Models\News;
use App\Support\ApiResponse;
use App\Support\Miniapp\MiniappPresenter;
use App\Support\News\UniversityNewsCategory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@ -22,6 +23,10 @@ class NewsController extends Controller
if ($request->filled('category_dict_item_id')) {
$query->where('category_dict_item_id', (int) $request->query('category_dict_item_id'));
} elseif ($request->boolean('university_news_only')) {
UniversityNewsCategory::applyUniversityNewsOnly($query);
} elseif ($request->boolean('exclude_university_news')) {
UniversityNewsCategory::applyExcludeUniversityNews($query);
}
$paginator = $query

@ -0,0 +1,35 @@
<?php
namespace App\Http\Controllers\Miniapp;
use App\Http\Controllers\Controller;
use App\Models\PastReview;
use App\Support\ApiResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class PastReviewController extends Controller
{
use ApiResponse;
public function index(Request $request): JsonResponse
{
$pageSize = min(50, max(1, (int) $request->query('page_size', 10)));
$items = PastReview::query()
->where('status', 1)
->orderBy('sort')
->orderByDesc('id')
->limit($pageSize)
->get()
->map(fn (PastReview $row) => [
'id' => $row->id,
'title' => $row->title,
'cover_url' => $row->cover_url,
])
->values()
->all();
return $this->ok(['items' => $items]);
}
}

@ -25,6 +25,7 @@ class MiniappUser extends Authenticatable
'job_title',
'teacher_id',
'admin_user_id',
'identity_type',
'converted_at',
'status',
];

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class PastReview extends Model
{
use SoftDeletes;
protected $fillable = [
'title',
'cover_url',
'sort',
'status',
];
protected $casts = [
'sort' => 'integer',
'status' => 'integer',
];
}

@ -481,18 +481,14 @@ class MiniappPresenter
]);
$directions = $user->researchDirections;
$isPartner = (bool) ($user->teacher?->is_partner ?? false);
$isAdmin = false;
$permissions = MiniappUserPermission::resolve($user);
$isGridMember = false;
if ($user->adminUser) {
if ($user->adminUser && (int) $user->adminUser->status === 1) {
$roleCodes = $user->adminUser->roles->pluck('code')->all();
$isAdmin = in_array('super_admin', $roleCodes, true);
$isGridMember = in_array('grid_member', $roleCodes, true);
}
$canSeePrivileged = $isAdmin || $isGridMember || $isPartner;
return [
'id' => $user->id,
'nickname' => $user->nickname,
@ -503,11 +499,18 @@ class MiniappPresenter
'job_title' => $user->job_title,
'research_direction' => $directions->pluck('name')->implode('、') ?: null,
'research_direction_ids' => $directions->pluck('id')->values()->all(),
'is_partner' => $isPartner,
'is_admin' => $isAdmin,
'identity_type' => $user->identity_type,
'role' => $permissions['role'],
'role_label' => $permissions['role_label'],
'is_partner' => $permissions['is_partner'],
'is_incubation' => $permissions['is_incubation'],
'is_admin' => $permissions['is_admin'],
'is_grid_member' => $isGridMember,
'can_see_radar' => $canSeePrivileged,
'can_see_papers' => $canSeePrivileged,
'is_staff' => $permissions['can_use_crawler'],
'can_see_radar' => $permissions['can_see_radar'],
'can_see_papers' => $permissions['can_see_papers'],
'can_access_demands' => $permissions['can_access_demands'],
'can_use_crawler' => $permissions['can_use_crawler'],
'admin_user_id' => $user->admin_user_id,
'teacher_id' => $user->teacher_id,
];

@ -0,0 +1,83 @@
<?php
namespace App\Support\Miniapp;
use App\Models\MiniappUser;
class MiniappUserPermission
{
public const ROLE_NORMAL = 'normal';
public const ROLE_INCUBATION = 'incubation';
public const ROLE_PARTNER = 'partner';
public const ROLE_ADMIN = 'admin';
/**
* @return array{
* role: string,
* role_label: string,
* is_admin: bool,
* is_partner: bool,
* is_incubation: bool,
* can_see_radar: bool,
* can_see_papers: bool,
* can_access_demands: bool,
* can_use_crawler: bool
* }
*/
public static function resolve(MiniappUser $user): array
{
$user->loadMissing([
'teacher:id,is_partner,name',
'adminUser.roles:id,code',
]);
$isAdmin = $user->adminUser && (int) $user->adminUser->status === 1;
$teacherPartner = (bool) ($user->teacher?->is_partner ?? false);
$identityType = $user->identity_type;
if ($isAdmin) {
$role = self::ROLE_ADMIN;
} elseif ($identityType === self::ROLE_PARTNER || $teacherPartner) {
$role = self::ROLE_PARTNER;
} elseif ($identityType === self::ROLE_INCUBATION) {
$role = self::ROLE_INCUBATION;
} else {
$role = self::ROLE_NORMAL;
}
return [
'role' => $role,
'role_label' => self::roleLabel($role),
'is_admin' => $isAdmin,
'is_partner' => $role === self::ROLE_PARTNER,
'is_incubation' => $role === self::ROLE_INCUBATION,
'can_see_radar' => in_array($role, [self::ROLE_ADMIN, self::ROLE_PARTNER], true),
'can_see_papers' => in_array($role, [self::ROLE_ADMIN, self::ROLE_PARTNER], true),
'can_access_demands' => in_array($role, [self::ROLE_ADMIN, self::ROLE_PARTNER, self::ROLE_INCUBATION], true),
'can_use_crawler' => $role === self::ROLE_ADMIN,
];
}
public static function roleLabel(string $role): string
{
return match ($role) {
self::ROLE_ADMIN => '管理员',
self::ROLE_PARTNER => '合作伙伴',
self::ROLE_INCUBATION => '入孵用户',
default => '普通用户',
};
}
public static function identityTypeLabel(?string $identityType): ?string
{
return match ($identityType) {
self::ROLE_INCUBATION => '入孵用户',
self::ROLE_PARTNER => '合作伙伴',
default => null,
};
}
}

@ -0,0 +1,169 @@
<?php
namespace App\Support\News;
use App\Models\CrawlAddress;
use App\Models\DictItem;
use App\Models\DictType;
use App\Models\News;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
class UniversityNewsCategory
{
public const LABEL = '高校要闻';
public const VALUE = 'university_news';
/**
* 合并重复的「高校要闻」字典项,保留已有数据引用最多的那条(通常即爬虫沿用的原始分类)。
*/
public static function consolidateDuplicates(): ?int
{
$typeId = DictType::query()->where('code', 'news_category')->where('status', 1)->value('id');
if (! $typeId) {
return null;
}
$items = DictItem::query()
->where('dict_type_id', $typeId)
->where(function ($q) {
$q->where('value', self::VALUE)
->orWhere('label', self::LABEL);
})
->orderBy('id')
->get();
if ($items->isEmpty()) {
return null;
}
if ($items->count() === 1) {
$item = $items->first();
$item->fill(['label' => self::LABEL, 'value' => self::VALUE, 'status' => 1]);
$item->save();
return (int) $item->id;
}
$keeper = $items->sort(function (DictItem $a, DictItem $b) {
$countA = self::referenceCount((int) $a->id);
$countB = self::referenceCount((int) $b->id);
if ($countA !== $countB) {
return $countB <=> $countA;
}
return $a->id <=> $b->id;
})->first();
if (! $keeper) {
return null;
}
return DB::transaction(function () use ($items, $keeper) {
$keeperId = (int) $keeper->id;
foreach ($items as $item) {
if ((int) $item->id === $keeperId) {
continue;
}
News::query()
->where('category_dict_item_id', $item->id)
->update(['category_dict_item_id' => $keeperId]);
CrawlAddress::query()
->where('category_dict_item_id', $item->id)
->update(['category_dict_item_id' => $keeperId]);
$item->delete();
}
$keeper->fill([
'label' => self::LABEL,
'value' => self::VALUE,
'status' => 1,
]);
$keeper->save();
return $keeperId;
});
}
public static function canonicalId(): ?int
{
$typeId = DictType::query()->where('code', 'news_category')->where('status', 1)->value('id');
if (! $typeId) {
return null;
}
$item = DictItem::query()
->where('dict_type_id', $typeId)
->where('status', 1)
->where('value', self::VALUE)
->orderBy('id')
->first();
if ($item) {
return (int) $item->id;
}
$item = DictItem::query()
->where('dict_type_id', $typeId)
->where('status', 1)
->where('label', self::LABEL)
->orderBy('id')
->first();
return $item ? (int) $item->id : null;
}
/**
* @return list<int>
*/
public static function categoryIds(): array
{
$id = self::canonicalId();
return $id ? [$id] : [];
}
public static function applyUniversityNewsOnly(Builder $query): Builder
{
$id = self::canonicalId();
return $query->where('category_dict_item_id', $id ?? -1);
}
public static function applyExcludeUniversityNews(Builder $query): Builder
{
$id = self::canonicalId();
if (! $id) {
return $query;
}
return $query->where(function ($q) use ($id) {
$q->whereNull('category_dict_item_id')
->orWhere('category_dict_item_id', '!=', $id);
});
}
public static function isUniversityNewsCategory(?DictItem $item): bool
{
if (! $item) {
return false;
}
$canonicalId = self::canonicalId();
return $canonicalId
? (int) $item->id === $canonicalId
: ($item->value === self::VALUE || $item->label === self::LABEL);
}
protected static function referenceCount(int $dictItemId): int
{
return News::query()->where('category_dict_item_id', $dictItemId)->count()
+ CrawlAddress::query()->where('category_dict_item_id', $dictItemId)->count();
}
}

@ -37,6 +37,9 @@ return [
'secret' => env('WX_SECRET'),
'env_version' => env('WX_MINIPROGRAM_ENV_VERSION', 'develop'),
'checkin_page' => 'subpkg/checkin/index',
// 小程序 web-view 业务域名校验文件(微信公众平台 → 开发设置 → 业务域名)
'webview_verify_file' => env('WECHAT_MP_WEBVIEW_VERIFY_FILE'),
'webview_verify_content' => env('WECHAT_MP_WEBVIEW_VERIFY_CONTENT'),
],
],

@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('past_reviews', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('cover_url', 512)->nullable();
$table->unsignedInteger('sort')->default(0);
$table->tinyInteger('status')->default(1)->comment('1=显示 0=隐藏');
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('past_reviews');
}
};

@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('miniapp_users', function (Blueprint $table) {
$table->string('identity_type', 32)->nullable()->after('admin_user_id')->comment('incubation=入孵用户 partner=合作伙伴');
});
}
public function down(): void
{
Schema::table('miniapp_users', function (Blueprint $table) {
$table->dropColumn('identity_type');
});
}
};

@ -0,0 +1,17 @@
<?php
use App\Support\News\UniversityNewsCategory;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
public function up(): void
{
UniversityNewsCategory::consolidateDuplicates();
}
public function down(): void
{
// 数据合并不可逆,回滚不做处理
}
};

@ -4,10 +4,11 @@ namespace Database\Seeders;
use App\Models\DictItem;
use App\Models\DictType;
use App\Support\News\UniversityNewsCategory;
use Illuminate\Database\Seeder;
/**
* 资讯分类下拉:政策信息 / 行业动态 / 活动通知(与 prototype news-create.html 一致)
* 资讯分类下拉:政策信息 / 行业动态 / 活动通知 / 高校要闻
*/
class NewsDictionarySeeder extends Seeder
{
@ -33,5 +34,19 @@ class NewsDictionarySeeder extends Seeder
['label' => $row['label'], 'sort' => $row['sort'], 'status' => 1]
);
}
// 先合并历史重复项,再按 value 唯一维护「高校要闻」(爬虫地址绑定沿用原 ID
UniversityNewsCategory::consolidateDuplicates();
DictItem::query()->updateOrCreate(
['dict_type_id' => $type->id, 'value' => UniversityNewsCategory::VALUE],
[
'label' => UniversityNewsCategory::LABEL,
'sort' => 40,
'status' => 1,
]
);
UniversityNewsCategory::consolidateDuplicates();
}
}

@ -39,6 +39,7 @@ class OperationsMenusSeeder extends Seeder
$opsChildren = [
['/courses', 'OperationsCourses', '课程管理', 'operations/courses/index', 10, 'Notebook'],
['/activities', 'OperationsActivities', '活动管理', 'operations/activities/index', 20, 'Calendar'],
['/past-reviews', 'OperationsPastReviews', '往期回顾', 'operations/past-reviews/index', 25, 'Picture'],
['/news', 'OperationsNews', '资讯管理', 'operations/news/index', 30, 'Reading'],
];

@ -0,0 +1,45 @@
<?php
namespace Database\Seeders;
use App\Models\Menu;
use App\Models\Role;
use Illuminate\Database\Seeder;
class PastReviewMenusSeeder extends Seeder
{
public function run(): void
{
$role = Role::query()->where('code', 'super_admin')->first();
if (! $role) {
$this->command?->warn('未找到 super_admin 角色,已跳过往期回顾菜单。');
return;
}
$opsRoot = Menu::query()->where('path', '/operations')->whereNull('parent_id')->first();
if (! $opsRoot) {
$this->command?->warn('未找到运营管理菜单,已跳过往期回顾菜单。');
return;
}
$menu = Menu::query()->firstOrCreate(
['path' => '/past-reviews', 'parent_id' => $opsRoot->id],
[
'name' => 'OperationsPastReviews',
'title' => '往期回顾',
'component' => 'operations/past-reviews/index',
'icon' => 'Picture',
'sort' => 25,
'visible' => 1,
'keep_alive' => 0,
'permission_code' => null,
'status' => 1,
]
);
$role->menus()->syncWithoutDetaching([$opsRoot->id, $menu->id]);
$this->command?->info('往期回顾菜单已挂载到运营管理。');
}
}

@ -24,7 +24,7 @@ class TeacherDictionarySeeder extends Seeder
);
$status = DictType::query()->updateOrCreate(
['code' => 'teacher_status'],
['name' => '老师跟进状态', 'remark' => '伙伴/持续跟进/暂停跟进', 'status' => 1, 'sort' => 52]
['name' => '老师跟进状态', 'remark' => '入孵用户/持续跟进/暂停跟进', 'status' => 1, 'sort' => 52]
);
$method = DictType::query()->updateOrCreate(
['code' => 'follow_method'],
@ -97,7 +97,7 @@ class TeacherDictionarySeeder extends Seeder
}
foreach ([
['label' => '伙伴', 'value' => 'partner', 'sort' => 10],
['label' => '入孵用户', 'value' => 'partner', 'sort' => 10],
['label' => '持续跟进', 'value' => 'active', 'sort' => 20],
['label' => '暂停跟进', 'value' => 'paused', 'sort' => 30],
] as $row) {

@ -0,0 +1 @@
import{C as e,Ct as t,D as n,E as r,G as i,S as a,T as o,Y as s,Z as c,at as l,b as u,f as d,h as f,ht as p,m,q as h,tn as g,x as _,y as v}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{a as y,d as b,h as x,l as S,n as C,o as w,s as T,t as E,v as D}from"./index-CPrkFf57.js";var O={class:`user-link`},k=T(n({__name:`AdminLayout`,setup(n){let T=y(),k=w(),A=E(),j=v(()=>T.path),M=p(!1),N=p(!1),P=p({password:``,password_confirmation:``}),F=v(()=>A.user?.username||``);function I(e){return e&&x[e]||D}function L(e){e&&e!==T.path&&k.push(e)}async function R(e){e===`out`&&(await A.logout(),await k.replace({name:`login`})),e===`pwd`&&(P.value={password:``,password_confirmation:``},M.value=!0)}async function z(){N.value=!0;try{await C(P.value),S.success(`密码已更新`),M.value=!1}finally{N.value=!1}}return(n,p)=>{let v=s(`el-icon`),y=s(`el-dropdown-item`),x=s(`el-dropdown-menu`),S=s(`el-dropdown`),C=s(`el-header`),w=s(`el-menu-item`),E=s(`el-sub-menu`),D=s(`el-menu`),k=s(`el-aside`),B=s(`router-view`),V=s(`el-main`),H=s(`el-container`),U=s(`el-input`),W=s(`el-form-item`),G=s(`el-form`),K=s(`el-button`),q=s(`el-dialog`);return i(),e(m,null,[r(H,{class:`admin-layout`,direction:`vertical`},{default:l(()=>[r(C,{class:`layout-topbar`,height:`52px`},{default:l(()=>[p[7]||=u(`div`,{class:`brand`},`S-lake先进技术发展中心`,-1),p[8]||=u(`div`,{class:`spacer`},null,-1),r(S,{class:`topbar-user`,trigger:`click`,onCommand:R},{dropdown:l(()=>[r(x,null,{default:l(()=>[r(y,{command:`pwd`},{default:l(()=>[...p[5]||=[o(`修改密码`,-1)]]),_:1}),r(y,{command:`out`,divided:``,class:`dropdown-logout`},{default:l(()=>[...p[6]||=[o(` 退出登录 `,-1)]]),_:1})]),_:1})]),default:l(()=>[u(`span`,O,[o(g(t(A).user?.real_name||t(A).user?.username)+` `,1),r(v,{class:`el-icon--right`},{default:l(()=>[r(t(b))]),_:1})])]),_:1})]),_:1}),r(H,{class:`layout-body`},{default:l(()=>[r(k,{width:`260px`,class:`aside`},{default:l(()=>[r(D,{"default-active":j.value,class:`menu slake-menu`,"background-color":`#ffffff`,"text-color":`#495057`,"active-text-color":`#ffffff`},{default:l(()=>[(i(!0),e(m,null,h(t(A).menus,t=>(i(),e(m,{key:t.id},[t.children?.length?(i(),_(E,{key:0,index:String(t.id)},{title:l(()=>[r(v,null,{default:l(()=>[(i(),_(c(I(t.icon))))]),_:2},1024),u(`span`,null,g(t.title),1)]),default:l(()=>[(i(!0),e(m,null,h(t.children,e=>(i(),_(w,{key:e.id,index:e.path,onClick:t=>L(e.path)},{default:l(()=>[r(v,null,{default:l(()=>[(i(),_(c(I(e.icon))))]),_:2},1024),u(`span`,null,g(e.title),1)]),_:2},1032,[`index`,`onClick`]))),128))]),_:2},1032,[`index`])):(i(),_(w,{key:1,index:t.path,onClick:e=>L(t.path)},{default:l(()=>[r(v,null,{default:l(()=>[(i(),_(c(I(t.icon))))]),_:2},1024),u(`span`,null,g(t.title),1)]),_:2},1032,[`index`,`onClick`]))],64))),128))]),_:1},8,[`default-active`])]),_:1}),r(V,{class:`main`},{default:l(()=>[r(B,null,{default:l(({Component:e})=>[(i(),_(f,null,[t(T).meta.keepAlive&&e?(i(),_(c(e),{key:t(T).fullPath})):a(``,!0)],1024)),!t(T).meta.keepAlive&&e?(i(),_(c(e),{key:t(T).fullPath})):a(``,!0)]),_:1})]),_:1})]),_:1})]),_:1}),r(q,{modelValue:M.value,"onUpdate:modelValue":p[3]||=e=>M.value=e,class:`pwd-dialog`,title:`修改密码`,width:`480px`,"append-to-body":``,"destroy-on-close":``,onClosed:p[4]||=e=>P.value={password:``,password_confirmation:``}},{footer:l(()=>[r(K,{onClick:p[2]||=e=>M.value=!1},{default:l(()=>[...p[9]||=[o(`取消`,-1)]]),_:1}),r(K,{type:`primary`,loading:N.value,onClick:z},{default:l(()=>[...p[10]||=[o(`保存`,-1)]]),_:1},8,[`loading`])]),default:l(()=>[r(G,{class:`pwd-dialog-form`,"label-width":`100px`,onSubmit:d(z,[`prevent`])},{default:l(()=>[r(W,{label:`账号`},{default:l(()=>[r(U,{"model-value":F.value,readonly:``},null,8,[`model-value`])]),_:1}),r(W,{label:`新密码`,required:``},{default:l(()=>[r(U,{modelValue:P.value.password,"onUpdate:modelValue":p[0]||=e=>P.value.password=e,type:`password`,"show-password":``,placeholder:`至少 6 位`,autocomplete:`new-password`},null,8,[`modelValue`])]),_:1}),r(W,{label:`确认新密码`,required:``},{default:l(()=>[r(U,{modelValue:P.value.password_confirmation,"onUpdate:modelValue":p[1]||=e=>P.value.password_confirmation=e,type:`password`,"show-password":``,placeholder:`再次输入新密码`,autocomplete:`new-password`},null,8,[`modelValue`])]),_:1})]),_:1})]),_:1},8,[`modelValue`])],64)}}}),[[`__scopeId`,`data-v-a06bbc42`]]);export{k as default};

@ -1 +1 @@
.admin-layout[data-v-54fb5ddb]{height:100vh}.admin-layout[data-v-54fb5ddb] .layout-body{flex:1;min-height:0;overflow:hidden}.admin-layout[data-v-54fb5ddb] .layout-topbar.el-header{--el-header-height:52px;--el-header-padding:0 16px;--topbar-title-font-size:1rem;border-bottom:1px solid var(--slake-border);box-sizing:border-box;background:#fff;align-items:center;height:52px;padding:0 16px;display:flex}.brand[data-v-54fb5ddb]{font-weight:600;font-size:var(--topbar-title-font-size);color:#212529;letter-spacing:.02em;flex-shrink:0;line-height:1}.aside[data-v-54fb5ddb]{border-right:1px solid var(--slake-border);background:#fff;flex-direction:column;height:100%;display:flex;overflow:hidden}.menu[data-v-54fb5ddb]{border-right:none;flex:1;min-height:0;overflow-y:auto}.slake-menu[data-v-54fb5ddb] .el-menu-item{border-radius:6px;width:calc(100% - 16px);margin:0 8px 4px}.slake-menu[data-v-54fb5ddb] .el-sub-menu__title{border-radius:6px;margin:0 8px 4px}.slake-menu[data-v-54fb5ddb] .el-menu-item:hover,.slake-menu[data-v-54fb5ddb] .el-sub-menu__title:hover{color:var(--slake-brand)!important;background:#b11e230f!important}.slake-menu[data-v-54fb5ddb] .el-menu-item.is-active{color:#fff!important;background:var(--slake-brand)!important}.slake-menu[data-v-54fb5ddb] .el-sub-menu.is-active>.el-sub-menu__title{color:var(--slake-brand)!important}.spacer[data-v-54fb5ddb]{flex:1}.topbar-user[data-v-54fb5ddb] .user-link{cursor:pointer;font-size:var(--topbar-title-font-size);color:#212529;outline:none;align-items:center;gap:6px;font-weight:500;line-height:1;display:inline-flex}.topbar-user[data-v-54fb5ddb] .user-link:hover,.topbar-user[data-v-54fb5ddb] .user-link:focus{color:var(--slake-brand)}.topbar-user[data-v-54fb5ddb] .el-icon{font-size:var(--topbar-title-font-size)}.main[data-v-54fb5ddb]{background:var(--slake-bg-page);box-sizing:border-box;height:100%;padding:16px;overflow:auto}.admin-layout .layout-topbar .topbar-user .user-link{font-size:var(--topbar-title-font-size)!important;line-height:1!important}.el-overlay-dialog:has(.el-dialog.pwd-dialog){align-items:center}.el-overlay-dialog .el-dialog.pwd-dialog{flex-direction:column;align-self:center;width:480px;max-width:calc(100vw - 32px);display:flex;height:auto!important;max-height:none!important;margin:12vh auto 24px!important}.pwd-dialog .el-dialog__header{flex:none}.pwd-dialog .el-dialog__body{padding:12px 20px 4px;flex:none!important;min-height:0!important;overflow:visible!important}.pwd-dialog .el-dialog__footer{flex:none;padding:12px 20px 16px}.pwd-dialog-form .el-form-item{margin-bottom:14px}.pwd-dialog-form .el-form-item:last-child{margin-bottom:0}.pwd-dialog-form .el-form-item__label{white-space:nowrap;line-height:32px}.el-dropdown-menu__item.dropdown-logout{color:var(--slake-brand)!important}
.admin-layout[data-v-a06bbc42]{height:100vh}.admin-layout[data-v-a06bbc42] .layout-body{flex:1;min-height:0;overflow:hidden}.admin-layout[data-v-a06bbc42] .layout-topbar.el-header{--el-header-height:52px;--el-header-padding:0 16px;--topbar-title-font-size:1rem;border-bottom:1px solid var(--slake-border);box-sizing:border-box;background:#fff;align-items:center;height:52px;padding:0 16px;display:flex}.brand[data-v-a06bbc42]{font-weight:600;font-size:var(--topbar-title-font-size);color:#212529;letter-spacing:.02em;flex-shrink:0;line-height:1}.aside[data-v-a06bbc42]{border-right:1px solid var(--slake-border);background:#fff;flex-direction:column;height:100%;display:flex;overflow:hidden}.menu[data-v-a06bbc42]{border-right:none;flex:1;min-height:0;overflow-y:auto}.slake-menu[data-v-a06bbc42] .el-menu-item{border-radius:6px;width:calc(100% - 16px);margin:0 8px 4px}.slake-menu[data-v-a06bbc42] .el-sub-menu__title{border-radius:6px;margin:0 8px 4px}.slake-menu[data-v-a06bbc42] .el-menu-item:hover,.slake-menu[data-v-a06bbc42] .el-sub-menu__title:hover{color:var(--slake-brand)!important;background:#b11e230f!important}.slake-menu[data-v-a06bbc42] .el-menu-item.is-active{color:#fff!important;background:var(--slake-brand)!important}.slake-menu[data-v-a06bbc42] .el-sub-menu.is-active>.el-sub-menu__title{color:var(--slake-brand)!important}.spacer[data-v-a06bbc42]{flex:1}.topbar-user[data-v-a06bbc42] .user-link{cursor:pointer;font-size:var(--topbar-title-font-size);color:#212529;outline:none;align-items:center;gap:6px;font-weight:500;line-height:1;display:inline-flex}.topbar-user[data-v-a06bbc42] .user-link:hover,.topbar-user[data-v-a06bbc42] .user-link:focus{color:var(--slake-brand)}.topbar-user[data-v-a06bbc42] .el-icon{font-size:var(--topbar-title-font-size)}.main[data-v-a06bbc42]{background:var(--slake-bg-page);box-sizing:border-box;height:100%;padding:16px;overflow:auto}.admin-layout .layout-topbar .topbar-user .user-link{font-size:var(--topbar-title-font-size)!important;line-height:1!important}.el-overlay-dialog:has(.el-dialog.pwd-dialog){align-items:center}.el-overlay-dialog .el-dialog.pwd-dialog{flex-direction:column;align-self:center;width:480px;max-width:calc(100vw - 32px);display:flex;height:auto!important;max-height:none!important;margin:12vh auto 24px!important}.pwd-dialog .el-dialog__header{flex:none}.pwd-dialog .el-dialog__body{padding:12px 20px 4px;flex:none!important;min-height:0!important;overflow:visible!important}.pwd-dialog .el-dialog__footer{flex:none;padding:12px 20px 16px}.pwd-dialog-form .el-form-item{margin-bottom:14px}.pwd-dialog-form .el-form-item:last-child{margin-bottom:0}.pwd-dialog-form .el-form-item__label{white-space:nowrap;line-height:32px}.el-dropdown-menu__item.dropdown-logout{color:var(--slake-brand)!important}

@ -1 +0,0 @@
import{C as e,Ct as t,D as n,E as r,G as i,S as a,T as o,Y as s,Z as c,at as l,b as u,f as d,h as f,ht as p,m,q as h,tn as g,x as _,y as v}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{a as y,d as b,h as x,l as S,n as C,o as w,s as T,t as E,v as D}from"./index-DHoSHxJa.js";var O={class:`user-link`},k=T(n({__name:`AdminLayout`,setup(n){let T=y(),k=w(),A=E(),j=v(()=>T.path),M=p(!1),N=p(!1),P=p({password:``,password_confirmation:``}),F=v(()=>A.user?.username||``);function I(e){return e&&x[e]||D}function L(e){e&&e!==T.path&&k.push(e)}async function R(e){e===`out`&&(await A.logout(),await k.replace({name:`login`})),e===`pwd`&&(P.value={password:``,password_confirmation:``},M.value=!0)}async function z(){N.value=!0;try{await C(P.value),S.success(`密码已更新`),M.value=!1}finally{N.value=!1}}return(n,p)=>{let v=s(`el-icon`),y=s(`el-dropdown-item`),x=s(`el-dropdown-menu`),S=s(`el-dropdown`),C=s(`el-header`),w=s(`el-menu-item`),E=s(`el-sub-menu`),D=s(`el-menu`),k=s(`el-aside`),B=s(`router-view`),V=s(`el-main`),H=s(`el-container`),U=s(`el-input`),W=s(`el-form-item`),G=s(`el-form`),K=s(`el-button`),q=s(`el-dialog`);return i(),e(m,null,[r(H,{class:`admin-layout`,direction:`vertical`},{default:l(()=>[r(C,{class:`layout-topbar`,height:`52px`},{default:l(()=>[p[7]||=u(`div`,{class:`brand`},`S-lake高校雷达网`,-1),p[8]||=u(`div`,{class:`spacer`},null,-1),r(S,{class:`topbar-user`,trigger:`click`,onCommand:R},{dropdown:l(()=>[r(x,null,{default:l(()=>[r(y,{command:`pwd`},{default:l(()=>[...p[5]||=[o(`修改密码`,-1)]]),_:1}),r(y,{command:`out`,divided:``,class:`dropdown-logout`},{default:l(()=>[...p[6]||=[o(` 退出登录 `,-1)]]),_:1})]),_:1})]),default:l(()=>[u(`span`,O,[o(g(t(A).user?.real_name||t(A).user?.username)+` `,1),r(v,{class:`el-icon--right`},{default:l(()=>[r(t(b))]),_:1})])]),_:1})]),_:1}),r(H,{class:`layout-body`},{default:l(()=>[r(k,{width:`260px`,class:`aside`},{default:l(()=>[r(D,{"default-active":j.value,class:`menu slake-menu`,"background-color":`#ffffff`,"text-color":`#495057`,"active-text-color":`#ffffff`},{default:l(()=>[(i(!0),e(m,null,h(t(A).menus,t=>(i(),e(m,{key:t.id},[t.children?.length?(i(),_(E,{key:0,index:String(t.id)},{title:l(()=>[r(v,null,{default:l(()=>[(i(),_(c(I(t.icon))))]),_:2},1024),u(`span`,null,g(t.title),1)]),default:l(()=>[(i(!0),e(m,null,h(t.children,e=>(i(),_(w,{key:e.id,index:e.path,onClick:t=>L(e.path)},{default:l(()=>[r(v,null,{default:l(()=>[(i(),_(c(I(e.icon))))]),_:2},1024),u(`span`,null,g(e.title),1)]),_:2},1032,[`index`,`onClick`]))),128))]),_:2},1032,[`index`])):(i(),_(w,{key:1,index:t.path,onClick:e=>L(t.path)},{default:l(()=>[r(v,null,{default:l(()=>[(i(),_(c(I(t.icon))))]),_:2},1024),u(`span`,null,g(t.title),1)]),_:2},1032,[`index`,`onClick`]))],64))),128))]),_:1},8,[`default-active`])]),_:1}),r(V,{class:`main`},{default:l(()=>[r(B,null,{default:l(({Component:e})=>[(i(),_(f,null,[t(T).meta.keepAlive&&e?(i(),_(c(e),{key:t(T).fullPath})):a(``,!0)],1024)),!t(T).meta.keepAlive&&e?(i(),_(c(e),{key:t(T).fullPath})):a(``,!0)]),_:1})]),_:1})]),_:1})]),_:1}),r(q,{modelValue:M.value,"onUpdate:modelValue":p[3]||=e=>M.value=e,class:`pwd-dialog`,title:`修改密码`,width:`480px`,"append-to-body":``,"destroy-on-close":``,onClosed:p[4]||=e=>P.value={password:``,password_confirmation:``}},{footer:l(()=>[r(K,{onClick:p[2]||=e=>M.value=!1},{default:l(()=>[...p[9]||=[o(`取消`,-1)]]),_:1}),r(K,{type:`primary`,loading:N.value,onClick:z},{default:l(()=>[...p[10]||=[o(`保存`,-1)]]),_:1},8,[`loading`])]),default:l(()=>[r(G,{class:`pwd-dialog-form`,"label-width":`100px`,onSubmit:d(z,[`prevent`])},{default:l(()=>[r(W,{label:`账号`},{default:l(()=>[r(U,{"model-value":F.value,readonly:``},null,8,[`model-value`])]),_:1}),r(W,{label:`新密码`,required:``},{default:l(()=>[r(U,{modelValue:P.value.password,"onUpdate:modelValue":p[0]||=e=>P.value.password=e,type:`password`,"show-password":``,placeholder:`至少 6 位`,autocomplete:`new-password`},null,8,[`modelValue`])]),_:1}),r(W,{label:`确认新密码`,required:``},{default:l(()=>[r(U,{modelValue:P.value.password_confirmation,"onUpdate:modelValue":p[1]||=e=>P.value.password_confirmation=e,type:`password`,"show-password":``,placeholder:`再次输入新密码`,autocomplete:`new-password`},null,8,[`modelValue`])]),_:1})]),_:1})]),_:1},8,[`modelValue`])],64)}}}),[[`__scopeId`,`data-v-54fb5ddb`]]);export{k as default};

@ -1 +1 @@
import{C as e,Ct as t,D as n,E as r,G as i,T as a,Y as o,at as s,b as c,tn as l,y as u}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{g as d,s as f}from"./index-DHoSHxJa.js";var p={class:`page`},m={class:`card-head`},h=f(n({__name:`HomeView`,setup(n){let f=u(()=>`/api`);return(n,u)=>{let h=o(`el-icon`),g=o(`el-descriptions-item`),_=o(`el-descriptions`),v=o(`el-card`);return i(),e(`div`,p,[r(v,{class:`card`,shadow:`hover`},{header:s(()=>[c(`div`,m,[r(h,{size:22},{default:s(()=>[r(t(d))]),_:1}),u[0]||=c(`span`,null,`高校雷达网 · 管理后台`,-1)])]),default:s(()=>[u[2]||=c(`p`,{class:`desc`},[a(`技术栈Vue 3、Vite、TypeScript、Element Plus。本地已配置对接 `),c(`code`,null,`slake-school-service`),a(` 的 API 代理。`)],-1),r(_,{column:1,border:``},{default:s(()=>[r(g,{label:`VITE_API_BASE_URL`},{default:s(()=>[c(`code`,null,l(f.value),1)]),_:1}),r(g,{label:`说明`},{default:s(()=>[...u[1]||=[a(` 开发时请求 `,-1),c(`code`,null,`/api/*`,-1),a(` 由 Vite 转发至 `,-1),c(`code`,null,`VITE_PROXY_TARGET`,-1),a(`(默认 `,-1),c(`code`,null,`http://127.0.0.1:8000`,-1),a(`),与 Laravel 的 `,-1),c(`code`,null,`/api`,-1),a(` 前缀一致。 `,-1)]]),_:1})]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-436e6398`]]);export{h as default};
import{C as e,Ct as t,D as n,E as r,G as i,T as a,Y as o,at as s,b as c,tn as l,y as u}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{g as d,s as f}from"./index-CPrkFf57.js";var p={class:`page`},m={class:`card-head`},h=f(n({__name:`HomeView`,setup(n){let f=u(()=>`/api`);return(n,u)=>{let h=o(`el-icon`),g=o(`el-descriptions-item`),_=o(`el-descriptions`),v=o(`el-card`);return i(),e(`div`,p,[r(v,{class:`card`,shadow:`hover`},{header:s(()=>[c(`div`,m,[r(h,{size:22},{default:s(()=>[r(t(d))]),_:1}),u[0]||=c(`span`,null,`高校雷达网 · 管理后台`,-1)])]),default:s(()=>[u[2]||=c(`p`,{class:`desc`},[a(`技术栈Vue 3、Vite、TypeScript、Element Plus。本地已配置对接 `),c(`code`,null,`slake-school-service`),a(` 的 API 代理。`)],-1),r(_,{column:1,border:``},{default:s(()=>[r(g,{label:`VITE_API_BASE_URL`},{default:s(()=>[c(`code`,null,l(f.value),1)]),_:1}),r(g,{label:`说明`},{default:s(()=>[...u[1]||=[a(` 开发时请求 `,-1),c(`code`,null,`/api/*`,-1),a(` 由 Vite 转发至 `,-1),c(`code`,null,`VITE_PROXY_TARGET`,-1),a(`(默认 `,-1),c(`code`,null,`http://127.0.0.1:8000`,-1),a(`),与 Laravel 的 `,-1),c(`code`,null,`/api`,-1),a(` 前缀一致。 `,-1)]]),_:1})]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-436e6398`]]);export{h as default};

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/activities`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/activities/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/activities`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/activities/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/activities/${t}`);return n}async function o(t){let{data:n}=await e.get(`/admin/v1/activities/${t}/sessions`);return n.data.items}async function s(t,n){let{data:r}=await e.post(`/admin/v1/activities/${t}/sessions`,n);return r.data}async function c(t,n,r){let{data:i}=await e.put(`/admin/v1/activities/${t}/sessions/${n}`,r);return i}async function l(t,n){let{data:r}=await e.delete(`/admin/v1/activities/${t}/sessions/${n}`);return r}async function u(t,n){let{data:r}=await e.get(`/admin/v1/activities/${t}/signups`,{params:n});return r.data}async function d(e,t={}){let n=1,r=[];for(;;){let i=await u(e,{...t,page:n,page_size:200});if(r.push(...i.items),n>=i.meta.last_page||i.items.length===0)break;n+=1}return r}async function f(t,n){let{data:r}=await e.delete(`/admin/v1/activities/${t}/signups/${n}`);return r}async function p(t,n,r){let{data:i}=await e.post(`/admin/v1/activities/${t}/signups/${n}/checkin`,r);return i}export{l as a,n as c,d,i as f,a as i,o as l,r as n,f as o,c as p,s as r,t as s,p as t,u};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/activities`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/activities/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/activities`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/activities/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/activities/${t}`);return n}async function o(t){let{data:n}=await e.get(`/admin/v1/activities/${t}/sessions`);return n.data.items}async function s(t,n){let{data:r}=await e.post(`/admin/v1/activities/${t}/sessions`,n);return r.data}async function c(t,n,r){let{data:i}=await e.put(`/admin/v1/activities/${t}/sessions/${n}`,r);return i}async function l(t,n){let{data:r}=await e.delete(`/admin/v1/activities/${t}/sessions/${n}`);return r}async function u(t,n){let{data:r}=await e.get(`/admin/v1/activities/${t}/signups`,{params:n});return r.data}async function d(e,t={}){let n=1,r=[];for(;;){let i=await u(e,{...t,page:n,page_size:200});if(r.push(...i.items),n>=i.meta.last_page||i.items.length===0)break;n+=1}return r}async function f(t,n){let{data:r}=await e.delete(`/admin/v1/activities/${t}/signups/${n}`);return r}async function p(t,n,r){let{data:i}=await e.post(`/admin/v1/activities/${t}/signups/${n}/checkin`,r);return i}export{l as a,n as c,d,i as f,a as i,o as l,r as n,f as o,c as p,s as r,t as s,p as t,u};

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/universities`,{params:t});return n.data}async function n(t){let{data:n}=await e.post(`/admin/v1/universities`,t);return n.data}async function r(t,n){let{data:r}=await e.put(`/admin/v1/universities/${t}`,n);return r.data}async function i(t){let{data:n}=await e.delete(`/admin/v1/universities/${t}`);return n}async function a(t){let{data:n}=await e.get(`/admin/v1/papers`,{params:t});return n.data}async function o(){let{data:t}=await e.get(`/admin/v1/papers/filter-options`);return t.data}async function s(t){let{data:n}=await e.get(`/admin/v1/papers/${t}`);return n.data}async function c(t){let{data:n}=await e.delete(`/admin/v1/papers/${t}`);return n}async function l(t,n){let{data:r}=await e.post(`/admin/v1/papers/${t}/teachers`,{teacher_ids:n});return r}async function u(t){let{data:n}=await e.post(`/admin/v1/crawl-jobs/resolve-url`,t);return n.data}async function d(t){let{data:n}=await e.post(`/admin/v1/crawl-jobs`,t,{timeout:3e5});return n.data}async function f(t,n){let{data:r}=await e.get(`/admin/v1/crawl-jobs/${t}/items`,{params:n});return r.data}async function p(e,t){let n=[],r=1;for(;;){let i=await f(e,{...t,page:r,page_size:200});if(n.push(...i.items),r>=i.meta.last_page||i.items.length===0)break;r+=1}return n}async function m(){let{data:t}=await e.get(`/admin/v1/radar-map`);return t.data}async function h(t){let{data:n}=await e.get(`/admin/v1/weekly-briefs`,{params:t});return n.data}async function g(t){let{data:n}=await e.get(`/admin/v1/weekly-briefs/${t}`);return n.data}async function _(t={}){let{data:n}=await e.post(`/admin/v1/weekly-briefs/generate`,t);return n.data}export{p as a,a as c,g as d,h as f,r as g,d as h,i,m as l,u as m,n,s as o,_ as p,c as r,o as s,l as t,t as u};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/universities`,{params:t});return n.data}async function n(t){let{data:n}=await e.post(`/admin/v1/universities`,t);return n.data}async function r(t,n){let{data:r}=await e.put(`/admin/v1/universities/${t}`,n);return r.data}async function i(t){let{data:n}=await e.delete(`/admin/v1/universities/${t}`);return n}async function a(t){let{data:n}=await e.get(`/admin/v1/papers`,{params:t});return n.data}async function o(){let{data:t}=await e.get(`/admin/v1/papers/filter-options`);return t.data}async function s(t){let{data:n}=await e.get(`/admin/v1/papers/${t}`);return n.data}async function c(t){let{data:n}=await e.delete(`/admin/v1/papers/${t}`);return n}async function l(t,n){let{data:r}=await e.post(`/admin/v1/papers/${t}/teachers`,{teacher_ids:n});return r}async function u(t){let{data:n}=await e.post(`/admin/v1/crawl-jobs/resolve-url`,t);return n.data}async function d(t){let{data:n}=await e.post(`/admin/v1/crawl-jobs`,t,{timeout:3e5});return n.data}async function f(t,n){let{data:r}=await e.get(`/admin/v1/crawl-jobs/${t}/items`,{params:n});return r.data}async function p(e,t){let n=[],r=1;for(;;){let i=await f(e,{...t,page:r,page_size:200});if(n.push(...i.items),r>=i.meta.last_page||i.items.length===0)break;r+=1}return n}async function m(){let{data:t}=await e.get(`/admin/v1/radar-map`);return t.data}async function h(t){let{data:n}=await e.get(`/admin/v1/weekly-briefs`,{params:t});return n.data}async function g(t){let{data:n}=await e.get(`/admin/v1/weekly-briefs/${t}`);return n.data}async function _(t={}){let{data:n}=await e.post(`/admin/v1/weekly-briefs/generate`,t);return n.data}export{p as a,a as c,g as d,h as f,r as g,d as h,i,m as l,u as m,n,s as o,_ as p,c as r,o as s,l as t,t as u};

@ -1 +1 @@
import{C as e,D as t,E as n,G as r,T as i,X as a,Y as o,at as s,b as c,d as l,ht as u,ot as d,x as f}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{r as p}from"./index-DHoSHxJa.js";import{n as m,t as h}from"./usePageLoad-C9PEZ_Tm.js";async function g(e){let{data:t}=await p.get(`/admin/v1/operation-logs`,{params:e});return t.data}var _={class:`list-page`},v={class:`page-header`},y={class:`list-filter-bar`},b={class:`list-pager`},x=t({__name:`index`,setup(t){let p=u(!1),x=u([]),S=u({current_page:1,per_page:20,total:0}),C=u(1),w=u(``),T=u(``),E=u(``);async function D(){p.value=!0;try{let e=await g({page:C.value,page_size:S.value.per_page,keyword:w.value||void 0,from:T.value||void 0,to:E.value||void 0});x.value=e.items,S.value=e.meta}finally{p.value=!1}}function O(){C.value=1,D()}function k(){w.value=``,T.value=``,E.value=``,C.value=1,D()}return h(D),(t,u)=>{let h=o(`el-input`),g=o(`el-date-picker`),A=o(`el-button`),j=o(`el-table-column`),M=o(`el-table`),N=o(`el-pagination`),P=o(`el-card`),F=a(`loading`);return r(),e(`div`,_,[c(`div`,v,[n(m)]),n(P,{shadow:`never`,class:`admin-list-card`},{default:s(()=>[c(`div`,y,[n(h,{modelValue:w.value,"onUpdate:modelValue":u[0]||=e=>w.value=e,placeholder:`接口路径/操作人`,clearable:``,class:`filter-search`,onKeyup:l(O,[`enter`])},null,8,[`modelValue`]),n(g,{modelValue:T.value,"onUpdate:modelValue":u[1]||=e=>T.value=e,type:`datetime`,placeholder:`开始时间`,"value-format":`YYYY-MM-DD HH:mm:ss`,style:{width:`190px`}},null,8,[`modelValue`]),n(g,{modelValue:E.value,"onUpdate:modelValue":u[2]||=e=>E.value=e,type:`datetime`,placeholder:`结束时间`,"value-format":`YYYY-MM-DD HH:mm:ss`,style:{width:`190px`}},null,8,[`modelValue`]),n(A,{type:`primary`,onClick:O},{default:s(()=>[...u[4]||=[i(`搜索`,-1)]]),_:1}),n(A,{onClick:k},{default:s(()=>[...u[5]||=[i(`重置`,-1)]]),_:1})]),d((r(),f(M,{data:x.value,"row-key":`id`},{default:s(()=>[n(j,{prop:`operated_at`,label:`操作时间`,width:`180`}),n(j,{prop:`operator_name`,label:`操作人`,width:`120`}),n(j,{prop:`http_method`,label:`方法`,width:`80`}),n(j,{prop:`api_path`,label:`接口`,"min-width":`220`,"show-overflow-tooltip":``}),n(j,{prop:`action_label`,label:`操作项`,"min-width":`160`,"show-overflow-tooltip":``}),n(j,{prop:`ip`,label:`IP`,width:`140`}),n(j,{prop:`response_code`,label:`状态码`,width:`90`,align:`center`}),n(j,{prop:`duration_ms`,label:`耗时ms`,width:`90`,align:`center`})]),_:1},8,[`data`])),[[F,p.value]]),c(`div`,b,[n(N,{"current-page":C.value,"onUpdate:currentPage":u[3]||=e=>C.value=e,layout:`total, prev, pager, next`,total:S.value.total,"page-size":S.value.per_page,onCurrentChange:D},null,8,[`current-page`,`total`,`page-size`])])]),_:1})])}}});export{x as default};
import{C as e,D as t,E as n,G as r,T as i,X as a,Y as o,at as s,b as c,d as l,ht as u,ot as d,x as f}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{r as p}from"./index-CPrkFf57.js";import{n as m,t as h}from"./usePageLoad-B1L6ImD-.js";async function g(e){let{data:t}=await p.get(`/admin/v1/operation-logs`,{params:e});return t.data}var _={class:`list-page`},v={class:`page-header`},y={class:`list-filter-bar`},b={class:`list-pager`},x=t({__name:`index`,setup(t){let p=u(!1),x=u([]),S=u({current_page:1,per_page:20,total:0}),C=u(1),w=u(``),T=u(``),E=u(``);async function D(){p.value=!0;try{let e=await g({page:C.value,page_size:S.value.per_page,keyword:w.value||void 0,from:T.value||void 0,to:E.value||void 0});x.value=e.items,S.value=e.meta}finally{p.value=!1}}function O(){C.value=1,D()}function k(){w.value=``,T.value=``,E.value=``,C.value=1,D()}return h(D),(t,u)=>{let h=o(`el-input`),g=o(`el-date-picker`),A=o(`el-button`),j=o(`el-table-column`),M=o(`el-table`),N=o(`el-pagination`),P=o(`el-card`),F=a(`loading`);return r(),e(`div`,_,[c(`div`,v,[n(m)]),n(P,{shadow:`never`,class:`admin-list-card`},{default:s(()=>[c(`div`,y,[n(h,{modelValue:w.value,"onUpdate:modelValue":u[0]||=e=>w.value=e,placeholder:`接口路径/操作人`,clearable:``,class:`filter-search`,onKeyup:l(O,[`enter`])},null,8,[`modelValue`]),n(g,{modelValue:T.value,"onUpdate:modelValue":u[1]||=e=>T.value=e,type:`datetime`,placeholder:`开始时间`,"value-format":`YYYY-MM-DD HH:mm:ss`,style:{width:`190px`}},null,8,[`modelValue`]),n(g,{modelValue:E.value,"onUpdate:modelValue":u[2]||=e=>E.value=e,type:`datetime`,placeholder:`结束时间`,"value-format":`YYYY-MM-DD HH:mm:ss`,style:{width:`190px`}},null,8,[`modelValue`]),n(A,{type:`primary`,onClick:O},{default:s(()=>[...u[4]||=[i(`搜索`,-1)]]),_:1}),n(A,{onClick:k},{default:s(()=>[...u[5]||=[i(`重置`,-1)]]),_:1})]),d((r(),f(M,{data:x.value,"row-key":`id`},{default:s(()=>[n(j,{prop:`operated_at`,label:`操作时间`,width:`180`}),n(j,{prop:`operator_name`,label:`操作人`,width:`120`}),n(j,{prop:`http_method`,label:`方法`,width:`80`}),n(j,{prop:`api_path`,label:`接口`,"min-width":`220`,"show-overflow-tooltip":``}),n(j,{prop:`action_label`,label:`操作项`,"min-width":`160`,"show-overflow-tooltip":``}),n(j,{prop:`ip`,label:`IP`,width:`140`}),n(j,{prop:`response_code`,label:`状态码`,width:`90`,align:`center`}),n(j,{prop:`duration_ms`,label:`耗时ms`,width:`90`,align:`center`})]),_:1},8,[`data`])),[[F,p.value]]),c(`div`,b,[n(N,{"current-page":C.value,"onUpdate:currentPage":u[3]||=e=>C.value=e,layout:`total, prev, pager, next`,total:S.value.total,"page-size":S.value.per_page,onCurrentChange:D},null,8,[`current-page`,`total`,`page-size`])])]),_:1})])}}});export{x as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/courses`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/courses/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/courses`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/courses/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/courses/${t}`);return n}async function o(t){let{data:n}=await e.get(`/admin/v1/courses/${t}/checkin-days`);return n.data.items}async function s(t,n){let{data:r}=await e.get(`/admin/v1/courses/${t}/signups`,{params:n});return r.data}async function c(e,t={}){let n=1,r=[];for(;;){let i=await s(e,{...t,page:n,page_size:200});if(r.push(...i.items),n>=i.meta.last_page||i.items.length===0)break;n+=1}return r}async function l(t,n){let{data:r}=await e.delete(`/admin/v1/courses/${t}/signups/${n}`);return r}async function u(t,n,r){let{data:i}=await e.post(`/admin/v1/courses/${t}/signups/${n}/checkin`,r);return i}export{c as a,s as c,l as i,t as l,r as n,n as o,a as r,o as s,u as t,i as u};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/courses`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/courses/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/courses`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/courses/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/courses/${t}`);return n}async function o(t){let{data:n}=await e.get(`/admin/v1/courses/${t}/checkin-days`);return n.data.items}async function s(t,n){let{data:r}=await e.get(`/admin/v1/courses/${t}/signups`,{params:n});return r.data}async function c(e,t={}){let n=1,r=[];for(;;){let i=await s(e,{...t,page:n,page_size:200});if(r.push(...i.items),n>=i.meta.last_page||i.items.length===0)break;n+=1}return r}async function l(t,n){let{data:r}=await e.delete(`/admin/v1/courses/${t}/signups/${n}`);return r}async function u(t,n,r){let{data:i}=await e.post(`/admin/v1/courses/${t}/signups/${n}/checkin`,r);return i}export{c as a,s as c,l as i,t as l,r as n,n as o,a as r,o as s,u as t,i as u};

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/crawl-addresses`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/crawl-addresses/options`,{params:t?{target_type:t}:void 0});return n.data.items}async function r(t){let{data:n}=await e.post(`/admin/v1/crawl-addresses`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/crawl-addresses/${t}`,n);return r.data}async function a(t){let{data:n}=await e.delete(`/admin/v1/crawl-addresses/${t}`);return n}export{i as a,t as i,a as n,n as r,r as t};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/crawl-addresses`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/crawl-addresses/options`,{params:t?{target_type:t}:void 0});return n.data.items}async function r(t){let{data:n}=await e.post(`/admin/v1/crawl-addresses`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/crawl-addresses/${t}`,n);return r.data}async function a(t){let{data:n}=await e.delete(`/admin/v1/crawl-addresses/${t}`);return n}export{i as a,t as i,a as n,n as r,r as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/demands`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/demands/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/demands`,t);return n.data}async function i(t){let{data:n}=await e.delete(`/admin/v1/demands/${t}`);return n}async function a(t){let{data:n}=await e.get(`/admin/v1/demands/${t}/handle-logs`);return n.data.items}async function o(t,n){let{data:r}=await e.post(`/admin/v1/demands/${t}/handle-logs`,n);return r.data}function s(e){return e===`done`?`success`:e===`terminated`?`info`:`warning`}export{n as a,s as i,o as n,a as o,i as r,t as s,r as t};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/demands`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/demands/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/demands`,t);return n.data}async function i(t){let{data:n}=await e.delete(`/admin/v1/demands/${t}`);return n}async function a(t){let{data:n}=await e.get(`/admin/v1/demands/${t}/handle-logs`);return n.data.items}async function o(t,n){let{data:r}=await e.post(`/admin/v1/demands/${t}/handle-logs`,n);return r.data}function s(e){return e===`done`?`success`:e===`terminated`?`info`:`warning`}export{n as a,s as i,o as n,a as o,i as r,t as s,r as t};

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/dict-by-code/${encodeURIComponent(t)}/items`);return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/dict-types`,{params:t});return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/dict-types`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/dict-types/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/dict-types/${t}`);return n}async function o(t,n){let{data:r}=await e.get(`/admin/v1/dict-types/${t}/items`,{params:n});return r.data}async function s(t,n){let{data:r}=await e.post(`/admin/v1/dict-types/${t}/items`,n);return r.data}async function c(t,n,r){let{data:i}=await e.put(`/admin/v1/dict-types/${t}/items/${n}`,r);return i}async function l(t,n){let{data:r}=await e.delete(`/admin/v1/dict-types/${t}/items/${n}`);return r}export{t as a,c,a as i,i as l,r as n,o,l as r,n as s,s as t};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/dict-by-code/${encodeURIComponent(t)}/items`);return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/dict-types`,{params:t});return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/dict-types`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/dict-types/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/dict-types/${t}`);return n}async function o(t,n){let{data:r}=await e.get(`/admin/v1/dict-types/${t}/items`,{params:n});return r.data}async function s(t,n){let{data:r}=await e.post(`/admin/v1/dict-types/${t}/items`,n);return r.data}async function c(t,n,r){let{data:i}=await e.put(`/admin/v1/dict-types/${t}/items/${n}`,r);return i}async function l(t,n){let{data:r}=await e.delete(`/admin/v1/dict-types/${t}/items/${n}`);return r}export{t as a,c,a as i,i as l,r as n,o,l as r,n as s,s as t};

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/grid-members`,{params:t});return n.data}async function n(t){let{data:n}=await e.post(`/admin/v1/grid-members`,t);return n.data}async function r(t,n){let{data:r}=await e.put(`/admin/v1/grid-members/${t}`,n);return r}async function i(t,n){let{data:r}=await e.post(`/admin/v1/grid-members/${t}/password`,{password:n});return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/grid-members/${t}`);return n}export{r as a,i,a as n,t as r,n as t};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/grid-members`,{params:t});return n.data}async function n(t){let{data:n}=await e.post(`/admin/v1/grid-members`,t);return n.data}async function r(t,n){let{data:r}=await e.put(`/admin/v1/grid-members/${t}`,n);return r}async function i(t,n){let{data:r}=await e.post(`/admin/v1/grid-members/${t}/password`,{password:n});return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/grid-members/${t}`);return n}export{r as a,i,a as n,t as r,n as t};

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.login-split[data-v-feb9d828]{background:linear-gradient(#fdf8f8 0%,#fff 45%,#faf6f6 100%);min-height:100vh}.login-main[data-v-feb9d828]{justify-content:center;align-items:center;min-height:100vh;padding:2rem 1rem;display:flex}.login-container[data-v-feb9d828]{grid-template-columns:1fr;align-items:center;gap:2.5rem;width:100%;max-width:1060px;display:grid}@media (width>=992px){.login-container[data-v-feb9d828]{grid-template-columns:1fr 1fr;gap:3rem}}.login-hero[data-v-feb9d828]{text-align:center}@media (width>=992px){.login-hero[data-v-feb9d828]{text-align:left}}.login-hero-title[data-v-feb9d828]{color:#000;margin:0 0 1rem;font-size:clamp(1.35rem,2.5vw,1.85rem);font-weight:700;line-height:1.35}.login-hero-desc[data-v-feb9d828]{color:#868e96;max-width:26rem;margin:0 auto;font-size:.95rem;line-height:1.65}@media (width>=992px){.login-hero-desc[data-v-feb9d828]{margin:0}}.login-panel-wrap[data-v-feb9d828]{justify-content:center;display:flex}@media (width>=992px){.login-panel-wrap[data-v-feb9d828]{justify-content:flex-end}}.login-panel-card[data-v-feb9d828]{background:#fff;border-radius:12px;width:100%;max-width:420px;padding:2.25rem 2.5rem;box-shadow:0 8px 32px #0000000f,0 2px 8px #0000000a}@media (width>=992px){.login-panel-card[data-v-feb9d828]{padding:2.5rem 2.75rem}}.login-panel-title[data-v-feb9d828]{text-align:center;color:#212529;margin:0 0 1.75rem;font-size:1.25rem;font-weight:700}.login-form[data-v-feb9d828] .el-form-item__label{color:#212529;font-weight:400}.login-form[data-v-feb9d828] .el-input__wrapper{padding:.65rem .85rem;box-shadow:inset 0 0 0 1px #dee2e6}.login-form[data-v-feb9d828] .el-input__wrapper.is-focus{box-shadow:0 0 0 1px var(--slake-brand) inset}.login-btn[data-v-feb9d828]{width:100%;margin-top:.25rem;padding:.7rem 1rem;font-weight:600}

@ -1 +0,0 @@
import{C as e,D as t,E as n,G as r,T as i,Y as a,at as o,b as s,f as c,ht as l}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{a as u,l as d,o as f,s as p,t as m}from"./index-DHoSHxJa.js";var h={class:`login-split`},g={class:`login-main`},_={class:`login-container`},v={class:`login-panel-wrap`},y={class:`login-panel-card`},b=p(t({__name:`index`,setup(t){let p=f(),b=u(),x=m(),S=l(!1),C=l(!0),w=l({username:``,password:``});function T(){C.value=!1}async function E(){if(!w.value.username||!w.value.password){d.warning(`请输入账号和密码`);return}S.value=!0;try{await x.login(w.value.username,w.value.password);let e=b.query.redirect||`/dashboard`;await p.replace(e)}catch(e){let t=e?.response?.data?.message||`登录失败`;d.error(typeof t==`string`?t:`登录失败`)}finally{S.value=!1}}return(t,l)=>{let u=a(`el-input`),d=a(`el-form-item`),f=a(`el-button`),p=a(`el-form`);return r(),e(`div`,h,[s(`main`,g,[s(`div`,_,[l[4]||=s(`div`,{class:`login-hero`},[s(`h1`,{class:`login-hero-title`},`S-lake先进技术发展中心高校雷达网`),s(`p`,{class:`login-hero-desc`},`加强长三角高校顶尖科研人才的发现、跟踪与服务`)],-1),s(`div`,v,[s(`div`,y,[l[3]||=s(`h2`,{class:`login-panel-title`},`欢迎登录`,-1),n(p,{class:`login-form`,"label-position":`top`,size:`large`,autocomplete:`off`,onSubmit:c(E,[`prevent`])},{default:o(()=>[n(d,{label:`账号`},{default:o(()=>[n(u,{modelValue:w.value.username,"onUpdate:modelValue":l[0]||=e=>w.value.username=e,placeholder:`请输入账号`,autocomplete:`off`,name:`login-account`,readonly:C.value,onFocus:T},null,8,[`modelValue`,`readonly`])]),_:1}),n(d,{label:`密码`},{default:o(()=>[n(u,{modelValue:w.value.password,"onUpdate:modelValue":l[1]||=e=>w.value.password=e,type:`password`,placeholder:`请输入密码`,"show-password":``,autocomplete:`new-password`,name:`login-password`,readonly:C.value,onFocus:T},null,8,[`modelValue`,`readonly`])]),_:1}),n(d,null,{default:o(()=>[n(f,{type:`primary`,class:`login-btn`,loading:S.value,"native-type":`submit`,onClick:E},{default:o(()=>[...l[2]||=[i(` 登录 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])])])])])}}}),[[`__scopeId`,`data-v-bc69620b`]]);export{b as default};

@ -0,0 +1 @@
import{C as e,D as t,E as n,G as r,T as i,Y as a,at as o,b as s,f as c,ht as l}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{a as u,l as d,o as f,s as p,t as m}from"./index-CPrkFf57.js";var h={class:`login-split`},g={class:`login-main`},_={class:`login-container`},v={class:`login-panel-wrap`},y={class:`login-panel-card`},b=p(t({__name:`index`,setup(t){let p=f(),b=u(),x=m(),S=l(!1),C=l(!0),w=l({username:``,password:``});function T(){C.value=!1}async function E(){if(!w.value.username||!w.value.password){d.warning(`请输入账号和密码`);return}S.value=!0;try{await x.login(w.value.username,w.value.password);let e=b.query.redirect||`/dashboard`;await p.replace(e)}catch(e){let t=e?.response?.data?.message||`登录失败`;d.error(typeof t==`string`?t:`登录失败`)}finally{S.value=!1}}return(t,l)=>{let u=a(`el-input`),d=a(`el-form-item`),f=a(`el-button`),p=a(`el-form`);return r(),e(`div`,h,[s(`main`,g,[s(`div`,_,[l[4]||=s(`div`,{class:`login-hero`},[s(`h1`,{class:`login-hero-title`},`S-lake先进技术发展中心`),s(`p`,{class:`login-hero-desc`},`加强长三角高校顶尖科研人才的发现、跟踪与服务`)],-1),s(`div`,v,[s(`div`,y,[l[3]||=s(`h2`,{class:`login-panel-title`},`欢迎登录`,-1),n(p,{class:`login-form`,"label-position":`top`,size:`large`,autocomplete:`off`,onSubmit:c(E,[`prevent`])},{default:o(()=>[n(d,{label:`账号`},{default:o(()=>[n(u,{modelValue:w.value.username,"onUpdate:modelValue":l[0]||=e=>w.value.username=e,placeholder:`请输入账号`,autocomplete:`off`,name:`login-account`,readonly:C.value,onFocus:T},null,8,[`modelValue`,`readonly`])]),_:1}),n(d,{label:`密码`},{default:o(()=>[n(u,{modelValue:w.value.password,"onUpdate:modelValue":l[1]||=e=>w.value.password=e,type:`password`,placeholder:`请输入密码`,"show-password":``,autocomplete:`new-password`,name:`login-password`,readonly:C.value,onFocus:T},null,8,[`modelValue`,`readonly`])]),_:1}),n(d,null,{default:o(()=>[n(f,{type:`primary`,class:`login-btn`,loading:S.value,"native-type":`submit`,onClick:E},{default:o(()=>[...l[2]||=[i(` 登录 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])])])])])}}}),[[`__scopeId`,`data-v-feb9d828`]]);export{b as default};

@ -1 +0,0 @@
.login-split[data-v-bc69620b]{background:linear-gradient(#fdf8f8 0%,#fff 45%,#faf6f6 100%);min-height:100vh}.login-main[data-v-bc69620b]{justify-content:center;align-items:center;min-height:100vh;padding:2rem 1rem;display:flex}.login-container[data-v-bc69620b]{grid-template-columns:1fr;align-items:center;gap:2.5rem;width:100%;max-width:1060px;display:grid}@media (width>=992px){.login-container[data-v-bc69620b]{grid-template-columns:1fr 1fr;gap:3rem}}.login-hero[data-v-bc69620b]{text-align:center}@media (width>=992px){.login-hero[data-v-bc69620b]{text-align:left}}.login-hero-title[data-v-bc69620b]{color:#000;margin:0 0 1rem;font-size:clamp(1.35rem,2.5vw,1.85rem);font-weight:700;line-height:1.35}.login-hero-desc[data-v-bc69620b]{color:#868e96;max-width:26rem;margin:0 auto;font-size:.95rem;line-height:1.65}@media (width>=992px){.login-hero-desc[data-v-bc69620b]{margin:0}}.login-panel-wrap[data-v-bc69620b]{justify-content:center;display:flex}@media (width>=992px){.login-panel-wrap[data-v-bc69620b]{justify-content:flex-end}}.login-panel-card[data-v-bc69620b]{background:#fff;border-radius:12px;width:100%;max-width:420px;padding:2.25rem 2.5rem;box-shadow:0 8px 32px #0000000f,0 2px 8px #0000000a}@media (width>=992px){.login-panel-card[data-v-bc69620b]{padding:2.5rem 2.75rem}}.login-panel-title[data-v-bc69620b]{text-align:center;color:#212529;margin:0 0 1.75rem;font-size:1.25rem;font-weight:700}.login-form[data-v-bc69620b] .el-form-item__label{color:#212529;font-weight:400}.login-form[data-v-bc69620b] .el-input__wrapper{padding:.65rem .85rem;box-shadow:inset 0 0 0 1px #dee2e6}.login-form[data-v-bc69620b] .el-input__wrapper.is-focus{box-shadow:0 0 0 1px var(--slake-brand) inset}.login-btn[data-v-bc69620b]{width:100%;margin-top:.25rem;padding:.7rem 1rem;font-weight:600}

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(){let{data:t}=await e.get(`/admin/v1/menus`);return t.data}async function n(t){let{data:n}=await e.post(`/admin/v1/menus`,t);return n.data}async function r(t,n){let{data:r}=await e.put(`/admin/v1/menus/${t}`,n);return r}async function i(t){let{data:n}=await e.delete(`/admin/v1/menus/${t}`);return n}export{r as i,i as n,t as r,n as t};
import{r as e}from"./index-CPrkFf57.js";async function t(){let{data:t}=await e.get(`/admin/v1/menus`);return t.data}async function n(t){let{data:n}=await e.post(`/admin/v1/menus`,t);return n.data}async function r(t,n){let{data:r}=await e.put(`/admin/v1/menus/${t}`,n);return r}async function i(t){let{data:n}=await e.delete(`/admin/v1/menus/${t}`);return n}export{r as i,i as n,t as r,n as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/news`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/news/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/news`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/news/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/news/${t}`);return n}async function o(t,n){let{data:r}=await e.post(`/admin/v1/news/batch-publish`,{ids:t,published_at:n});return r.data}export{t as a,n as i,r as n,i as o,a as r,o as t};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/news`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/news/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/news`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/news/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/news/${t}`);return n}async function o(t,n){let{data:r}=await e.post(`/admin/v1/news/batch-publish`,{ids:t,published_at:n});return r.data}export{t as a,n as i,r as n,i as o,a as r,o as t};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.cover-upload-row[data-v-e560edfb]{align-items:center;gap:12px;display:flex}

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/research-directions`,{params:t});return n.data}async function n(){let{data:t}=await e.get(`/admin/v1/research-directions/options`);return t.data.items}async function r(t){let{data:n}=await e.post(`/admin/v1/research-directions`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/research-directions/${t}`,n);return r.data}async function a(t){let{data:n}=await e.delete(`/admin/v1/research-directions/${t}`);return n}export{i as a,t as i,a as n,n as r,r as t};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/research-directions`,{params:t});return n.data}async function n(){let{data:t}=await e.get(`/admin/v1/research-directions/options`);return t.data.items}async function r(t){let{data:n}=await e.post(`/admin/v1/research-directions`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/research-directions/${t}`,n);return r.data}async function a(t){let{data:n}=await e.delete(`/admin/v1/research-directions/${t}`);return n}export{i as a,t as i,a as n,n as r,r as t};

@ -1 +1 @@
import{C as e,Ct as t,D as n,E as r,G as i,T as a,X as o,Xt as s,Y as c,at as l,b as u,d,ht as f,m as p,ot as m,tn as h,x as g}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{c as _,l as v}from"./index-DHoSHxJa.js";import{n as y,t as b}from"./usePageLoad-C9PEZ_Tm.js";import{r as x}from"./admin-list-DjncsyJC.js";import{a as S,i as C,n as w,t as T}from"./research-directions-C0FNlolV.js";var E={class:`list-page`},D={class:`page-header`},O={class:`list-filter-bar`},k={class:`table-row-actions`},A={class:`list-pager`},j=n({__name:`index`,setup(n){let j=f(!1),M=f([]),N=f({current_page:1,per_page:20,total:0}),P=f(``),F=f(1),I=f(!1),L=f(null),R=f({name:``,sort:0,status:1,remark:``});async function z(){j.value=!0;try{let e=await C({page:F.value,page_size:N.value.per_page,keyword:P.value||void 0});M.value=e.items,N.value=e.meta}finally{j.value=!1}}function B(){L.value=null,R.value={name:``,sort:0,status:1,remark:``},I.value=!0}function V(e){L.value=e,R.value={name:e.name,sort:e.sort,status:e.status,remark:e.remark||``},I.value=!0}async function H(){if(!R.value.name.trim()){v.warning(`请填写研究方向名称`);return}let e={name:R.value.name.trim(),sort:R.value.sort,status:R.value.status,remark:R.value.remark||null};L.value?await S(L.value.id,e):await T(e),v.success(`已保存`),I.value=!1,await z()}async function U(e){await _.confirm(`确定删除研究方向「${e.name}」?`,`提示`,{type:`warning`}),await w(e.id),v.success(`已删除`),await z()}function W(){F.value=1,z()}function G(){P.value=``,F.value=1,z()}return b(z),(n,f)=>{let _=c(`el-button`),v=c(`el-input`),b=c(`el-table-column`),S=c(`el-table`),C=c(`el-pagination`),w=c(`el-card`),T=c(`el-form-item`),K=c(`el-input-number`),q=c(`el-switch`),J=c(`el-form`),Y=c(`el-dialog`),X=o(`loading`);return i(),e(p,null,[u(`div`,E,[u(`div`,D,[r(y),r(_,{type:`primary`,size:`small`,class:`btn-create`,onClick:B},{default:l(()=>[...f[8]||=[a(`新增`,-1)]]),_:1})]),r(w,{shadow:`never`,class:`admin-list-card`},{default:l(()=>[u(`div`,O,[r(v,{modelValue:P.value,"onUpdate:modelValue":f[0]||=e=>P.value=e,placeholder:`研究方向名称`,clearable:``,class:`filter-search`,onKeyup:d(W,[`enter`])},null,8,[`modelValue`]),r(_,{type:`primary`,onClick:W},{default:l(()=>[...f[9]||=[a(`搜索`,-1)]]),_:1}),r(_,{onClick:G},{default:l(()=>[...f[10]||=[a(`重置`,-1)]]),_:1})]),m((i(),g(S,{data:M.value,"row-key":`id`},{default:l(()=>[r(b,{prop:`name`,label:`名称`,"min-width":`180`}),r(b,{prop:`sort`,label:`排序`,width:`80`,align:`center`}),r(b,{prop:`teacher_count`,label:`关联老师数`,width:`110`,align:`center`}),r(b,{label:`状态`,width:`90`,align:`center`},{default:l(({row:e})=>[u(`span`,{class:s([`status-badge`,t(x)(e.status)])},h(e.status===1?`启用`:`停用`),3)]),_:1}),r(b,{prop:`remark`,label:`备注`,"min-width":`160`,"show-overflow-tooltip":``}),r(b,{label:`操作`,width:`160`,fixed:`right`},{default:l(({row:e})=>[u(`div`,k,[r(_,{class:`btn-action-primary`,onClick:t=>V(e)},{default:l(()=>[...f[11]||=[a(`编辑`,-1)]]),_:1},8,[`onClick`]),r(_,{class:`btn-action-brand`,onClick:t=>U(e)},{default:l(()=>[...f[12]||=[a(`删除`,-1)]]),_:1},8,[`onClick`])])]),_:1})]),_:1},8,[`data`])),[[X,j.value]]),u(`div`,A,[r(C,{"current-page":F.value,"onUpdate:currentPage":f[1]||=e=>F.value=e,layout:`total, prev, pager, next`,total:N.value.total,"page-size":N.value.per_page,onCurrentChange:z},null,8,[`current-page`,`total`,`page-size`])])]),_:1})]),r(Y,{modelValue:I.value,"onUpdate:modelValue":f[7]||=e=>I.value=e,title:L.value?`编辑研究方向`:`新增研究方向`,width:`480px`},{footer:l(()=>[r(_,{onClick:f[6]||=e=>I.value=!1},{default:l(()=>[...f[13]||=[a(`取消`,-1)]]),_:1}),r(_,{type:`primary`,onClick:H},{default:l(()=>[...f[14]||=[a(`保存`,-1)]]),_:1})]),default:l(()=>[r(J,{"label-width":`88px`},{default:l(()=>[r(T,{label:`名称`},{default:l(()=>[r(v,{modelValue:R.value.name,"onUpdate:modelValue":f[2]||=e=>R.value.name=e,maxlength:`255`},null,8,[`modelValue`])]),_:1}),r(T,{label:`排序`},{default:l(()=>[r(K,{modelValue:R.value.sort,"onUpdate:modelValue":f[3]||=e=>R.value.sort=e,min:0},null,8,[`modelValue`])]),_:1}),r(T,{label:`状态`},{default:l(()=>[r(q,{modelValue:R.value.status,"onUpdate:modelValue":f[4]||=e=>R.value.status=e,"active-value":1,"inactive-value":0},null,8,[`modelValue`])]),_:1}),r(T,{label:`备注`},{default:l(()=>[r(v,{modelValue:R.value.remark,"onUpdate:modelValue":f[5]||=e=>R.value.remark=e,type:`textarea`,rows:3},null,8,[`modelValue`])]),_:1})]),_:1})]),_:1},8,[`modelValue`,`title`])],64)}}});export{j as default};
import{C as e,Ct as t,D as n,E as r,G as i,T as a,X as o,Xt as s,Y as c,at as l,b as u,d,ht as f,m as p,ot as m,tn as h,x as g}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{c as _,l as v}from"./index-CPrkFf57.js";import{n as y,t as b}from"./usePageLoad-B1L6ImD-.js";import{r as x}from"./admin-list-dnDAubDa.js";import{a as S,i as C,n as w,t as T}from"./research-directions-BOEV4y5H.js";var E={class:`list-page`},D={class:`page-header`},O={class:`list-filter-bar`},k={class:`table-row-actions`},A={class:`list-pager`},j=n({__name:`index`,setup(n){let j=f(!1),M=f([]),N=f({current_page:1,per_page:20,total:0}),P=f(``),F=f(1),I=f(!1),L=f(null),R=f({name:``,sort:0,status:1,remark:``});async function z(){j.value=!0;try{let e=await C({page:F.value,page_size:N.value.per_page,keyword:P.value||void 0});M.value=e.items,N.value=e.meta}finally{j.value=!1}}function B(){L.value=null,R.value={name:``,sort:0,status:1,remark:``},I.value=!0}function V(e){L.value=e,R.value={name:e.name,sort:e.sort,status:e.status,remark:e.remark||``},I.value=!0}async function H(){if(!R.value.name.trim()){v.warning(`请填写研究方向名称`);return}let e={name:R.value.name.trim(),sort:R.value.sort,status:R.value.status,remark:R.value.remark||null};L.value?await S(L.value.id,e):await T(e),v.success(`已保存`),I.value=!1,await z()}async function U(e){await _.confirm(`确定删除研究方向「${e.name}」?`,`提示`,{type:`warning`}),await w(e.id),v.success(`已删除`),await z()}function W(){F.value=1,z()}function G(){P.value=``,F.value=1,z()}return b(z),(n,f)=>{let _=c(`el-button`),v=c(`el-input`),b=c(`el-table-column`),S=c(`el-table`),C=c(`el-pagination`),w=c(`el-card`),T=c(`el-form-item`),K=c(`el-input-number`),q=c(`el-switch`),J=c(`el-form`),Y=c(`el-dialog`),X=o(`loading`);return i(),e(p,null,[u(`div`,E,[u(`div`,D,[r(y),r(_,{type:`primary`,size:`small`,class:`btn-create`,onClick:B},{default:l(()=>[...f[8]||=[a(`新增`,-1)]]),_:1})]),r(w,{shadow:`never`,class:`admin-list-card`},{default:l(()=>[u(`div`,O,[r(v,{modelValue:P.value,"onUpdate:modelValue":f[0]||=e=>P.value=e,placeholder:`研究方向名称`,clearable:``,class:`filter-search`,onKeyup:d(W,[`enter`])},null,8,[`modelValue`]),r(_,{type:`primary`,onClick:W},{default:l(()=>[...f[9]||=[a(`搜索`,-1)]]),_:1}),r(_,{onClick:G},{default:l(()=>[...f[10]||=[a(`重置`,-1)]]),_:1})]),m((i(),g(S,{data:M.value,"row-key":`id`},{default:l(()=>[r(b,{prop:`name`,label:`名称`,"min-width":`180`}),r(b,{prop:`sort`,label:`排序`,width:`80`,align:`center`}),r(b,{prop:`teacher_count`,label:`关联老师数`,width:`110`,align:`center`}),r(b,{label:`状态`,width:`90`,align:`center`},{default:l(({row:e})=>[u(`span`,{class:s([`status-badge`,t(x)(e.status)])},h(e.status===1?`启用`:`停用`),3)]),_:1}),r(b,{prop:`remark`,label:`备注`,"min-width":`160`,"show-overflow-tooltip":``}),r(b,{label:`操作`,width:`160`,fixed:`right`},{default:l(({row:e})=>[u(`div`,k,[r(_,{class:`btn-action-primary`,onClick:t=>V(e)},{default:l(()=>[...f[11]||=[a(`编辑`,-1)]]),_:1},8,[`onClick`]),r(_,{class:`btn-action-brand`,onClick:t=>U(e)},{default:l(()=>[...f[12]||=[a(`删除`,-1)]]),_:1},8,[`onClick`])])]),_:1})]),_:1},8,[`data`])),[[X,j.value]]),u(`div`,A,[r(C,{"current-page":F.value,"onUpdate:currentPage":f[1]||=e=>F.value=e,layout:`total, prev, pager, next`,total:N.value.total,"page-size":N.value.per_page,onCurrentChange:z},null,8,[`current-page`,`total`,`page-size`])])]),_:1})]),r(Y,{modelValue:I.value,"onUpdate:modelValue":f[7]||=e=>I.value=e,title:L.value?`编辑研究方向`:`新增研究方向`,width:`480px`},{footer:l(()=>[r(_,{onClick:f[6]||=e=>I.value=!1},{default:l(()=>[...f[13]||=[a(`取消`,-1)]]),_:1}),r(_,{type:`primary`,onClick:H},{default:l(()=>[...f[14]||=[a(`保存`,-1)]]),_:1})]),default:l(()=>[r(J,{"label-width":`88px`},{default:l(()=>[r(T,{label:`名称`},{default:l(()=>[r(v,{modelValue:R.value.name,"onUpdate:modelValue":f[2]||=e=>R.value.name=e,maxlength:`255`},null,8,[`modelValue`])]),_:1}),r(T,{label:`排序`},{default:l(()=>[r(K,{modelValue:R.value.sort,"onUpdate:modelValue":f[3]||=e=>R.value.sort=e,min:0},null,8,[`modelValue`])]),_:1}),r(T,{label:`状态`},{default:l(()=>[r(q,{modelValue:R.value.status,"onUpdate:modelValue":f[4]||=e=>R.value.status=e,"active-value":1,"inactive-value":0},null,8,[`modelValue`])]),_:1}),r(T,{label:`备注`},{default:l(()=>[r(v,{modelValue:R.value.remark,"onUpdate:modelValue":f[5]||=e=>R.value.remark=e,type:`textarea`,rows:3},null,8,[`modelValue`])]),_:1})]),_:1})]),_:1},8,[`modelValue`,`title`])],64)}}});export{j as default};

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/roles`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/roles/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/roles`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/roles/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/roles/${t}`);return n}export{i as a,t as i,a as n,n as r,r as t};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/roles`,{params:t});return n.data}async function n(t){let{data:n}=await e.get(`/admin/v1/roles/${t}`);return n.data}async function r(t){let{data:n}=await e.post(`/admin/v1/roles`,t);return n.data}async function i(t,n){let{data:r}=await e.put(`/admin/v1/roles/${t}`,n);return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/roles/${t}`);return n}export{i as a,t as i,a as n,n as r,r as t};

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
.follow-teacher-summary[data-v-db5a27f0]{border-left:4px solid var(--brand-primary,#244e98);background:#edf2fb;border-radius:6px;padding:10px 12px;font-size:14px}.sub-title[data-v-db5a27f0]{margin:16px 0 8px;font-size:15px;font-weight:600}.star-preview[data-v-db5a27f0]{color:#e6a23c;margin-top:4px;font-size:13px;display:block}.form-small[data-v-db5a27f0] .el-form-item__label{padding-bottom:4px;font-size:13px}

@ -0,0 +1 @@
.follow-teacher-summary[data-v-b7849066]{border-left:4px solid var(--brand-primary,#244e98);background:#edf2fb;border-radius:6px;padding:10px 12px;font-size:14px}.sub-title[data-v-b7849066]{margin:16px 0 8px;font-size:15px;font-weight:600}.star-preview[data-v-b7849066]{color:#e6a23c;margin-top:4px;font-size:13px;display:block}.bind-hint[data-v-b7849066]{color:#909399;margin-top:6px;font-size:12px;line-height:1.5}.form-small[data-v-b7849066] .el-form-item__label{padding-bottom:4px;font-size:13px}

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(){let{data:t}=await e.get(`/admin/v1/teachers/filter-options`);return t.data}async function n(){let{data:t}=await e.get(`/admin/v1/teachers/stats`);return t.data}async function r(t){let{data:n}=await e.get(`/admin/v1/teachers`,{params:t});return n.data}async function i(t){let{data:n}=await e.get(`/admin/v1/teachers/${t}`);return n.data}async function a(t){let{data:n}=await e.post(`/admin/v1/teachers`,t);return n.data}async function o(t,n){let{data:r}=await e.put(`/admin/v1/teachers/${t}`,n);return r}async function s(t){let{data:n}=await e.patch(`/admin/v1/teachers/batch-star`,t);return n.data}async function c(t){let{data:n}=await e.get(`/admin/v1/teachers/${t}/follow-records`);return n.data.items}async function l(t,n){let{data:r}=await e.post(`/admin/v1/teachers/${t}/follow-records`,n);return r.data}async function u(t){let{data:n}=await e.get(`/admin/v1/teachers/${t}/papers`);return n.data.items}async function d(t,n){let{data:r}=await e.post(`/admin/v1/teachers/${t}/papers`,n);return r.data}async function f(t,n){let{data:r}=await e.post(`/admin/v1/teachers/${t}/papers/link`,{paper_id:n});return r}async function p(t,n){let{data:r}=await e.delete(`/admin/v1/teachers/${t}/papers/${n}`);return r}async function m(t){let{data:n}=await e.get(`/admin/v1/universities`,{params:t});return n.data}async function h(t){let{data:n}=await e.post(`/admin/v1/universities`,t);return n.data}export{h as a,t as c,n as d,r as f,o as h,d as i,c as l,f as m,a as n,p as o,m as p,l as r,i as s,s as t,u};
import{r as e}from"./index-CPrkFf57.js";async function t(){let{data:t}=await e.get(`/admin/v1/teachers/filter-options`);return t.data}async function n(){let{data:t}=await e.get(`/admin/v1/teachers/stats`);return t.data}async function r(t){let{data:n}=await e.get(`/admin/v1/teachers`,{params:t});return n.data}async function i(t){let{data:n}=await e.get(`/admin/v1/teachers/${t}`);return n.data}async function a(t){let{data:n}=await e.post(`/admin/v1/teachers`,t);return n.data}async function o(t,n){let{data:r}=await e.put(`/admin/v1/teachers/${t}`,n);return r}async function s(t){let{data:n}=await e.patch(`/admin/v1/teachers/batch-star`,t);return n.data}async function c(t){let{data:n}=await e.get(`/admin/v1/teachers/${t}/follow-records`);return n.data.items}async function l(t,n){let{data:r}=await e.post(`/admin/v1/teachers/${t}/follow-records`,n);return r.data}async function u(t){let{data:n}=await e.get(`/admin/v1/teachers/${t}/papers`);return n.data.items}async function d(t,n){let{data:r}=await e.post(`/admin/v1/teachers/${t}/papers`,n);return r.data}async function f(t,n){let{data:r}=await e.post(`/admin/v1/teachers/${t}/papers/link`,{paper_id:n});return r}async function p(t,n){let{data:r}=await e.delete(`/admin/v1/teachers/${t}/papers/${n}`);return r}async function m(t){let{data:n}=await e.get(`/admin/v1/universities`,{params:t});return n.data}async function h(t){let{data:n}=await e.post(`/admin/v1/universities`,t);return n.data}export{h as a,t as c,n as d,r as f,o as h,d as i,c as l,f as m,a as n,p as o,m as p,l as r,i as s,s as t,u};

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.teachers-page[data-v-c16cffd4]{--brand-primary:#244e98;--brand-primary-hover:#8b1519;--brand-bg-soft:#fdf3f3;flex-direction:column;gap:12px;display:flex}.talent-stat-grid[data-v-c16cffd4]{grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;display:grid}.teachers-list-card[data-v-c16cffd4]{margin-top:0}.teachers-filter-search[data-v-c16cffd4]{width:180px}.talent-stat-card[data-v-c16cffd4]{text-align:left;cursor:pointer;min-height:68px;font:inherit;background:#fff;border:1px solid #d8dde4;border-radius:8px;flex-direction:column;justify-content:center;align-items:flex-start;gap:6px;padding:10px 16px;display:flex;position:relative;box-shadow:0 2px 10px #0f172a14}.talent-stat-card[data-v-c16cffd4]:hover,.talent-stat-card.is-active[data-v-c16cffd4]{border-color:var(--brand-primary)}.talent-stat-card.is-active[data-v-c16cffd4]:before{content:"";background:var(--brand-primary);width:4px;position:absolute;top:0;bottom:0;left:0}.talent-stat-label[data-v-c16cffd4]{color:#6b7280;font-size:14px}.talent-stat-value[data-v-c16cffd4]{color:var(--brand-primary);font-size:24px;font-weight:600;line-height:1.1}.talent-stat-value.is-dark[data-v-c16cffd4]{color:#111827}.talent-stat-value.is-danger[data-v-c16cffd4]{color:var(--el-color-danger)}.talent-stat-value.is-success[data-v-c16cffd4]{color:var(--el-color-success)}.filter-source[data-v-c16cffd4]{width:132px}.filter-stars[data-v-c16cffd4]{width:100px}.filter-status[data-v-c16cffd4]{width:112px}.filter-school[data-v-c16cffd4]{width:184px}.filter-direction[data-v-c16cffd4]{width:146px}.name-link[data-v-c16cffd4]{color:inherit;text-decoration:none}.name-link[data-v-c16cffd4]:hover{color:var(--brand-primary)}.tag-overdue[data-v-c16cffd4]{vertical-align:middle;margin-left:4px}.star-text[data-v-c16cffd4]{color:#e6a23c;letter-spacing:1px}.source-tag[data-v-c16cffd4]{border:none;font-weight:500}.source-tag-manual[data-v-c16cffd4]{--el-tag-bg-color:#6c757d;--el-tag-border-color:#6c757d;--el-tag-text-color:#fff}.teachers-table-actions[data-v-c16cffd4]{flex-wrap:nowrap;gap:4px}.teachers-table-btn[data-v-c16cffd4]{min-height:22px;font-size:12px;padding:2px 6px!important}.follow-teacher-summary[data-v-c16cffd4]{border-left:4px solid var(--brand-primary);background:var(--brand-bg-soft);border-radius:6px;padding:10px 12px;font-size:14px}.text-brand[data-v-c16cffd4]{color:var(--brand-primary);font-weight:600}.names-muted[data-v-c16cffd4]{color:#6b7280;margin-left:8px;font-size:13px}.batch-rule[data-v-c16cffd4]{color:#6b7280;margin:0;font-size:12px}.follow-date-rule[data-v-c16cffd4]{color:#6b7280;margin:6px 0 0;font-size:12px;line-height:1.45}.follow-history-list[data-v-c16cffd4]{gap:14px;max-height:60vh;margin-top:12px;display:grid;overflow:auto}.follow-history-card[data-v-c16cffd4]{border:1px solid #dfe4eb;border-left:4px solid var(--brand-primary);background:#fff;border-radius:6px}.follow-history-head[data-v-c16cffd4]{border-bottom:1px solid #e6eaf1;justify-content:space-between;align-items:center;gap:12px;padding:12px 14px;display:flex}.follow-history-title[data-v-c16cffd4]{color:var(--brand-primary);font-weight:600}.follow-history-date[data-v-c16cffd4]{color:#6b7280;margin-left:14px;font-size:13px}.follow-history-body[data-v-c16cffd4]{padding:14px;font-size:13px}.follow-history-row[data-v-c16cffd4]{grid-template-columns:96px 1fr;gap:14px;margin-bottom:10px;display:grid}.follow-history-row>span[data-v-c16cffd4]{color:#6b7280}.follow-history-footer[data-v-c16cffd4]{color:#6b7280;padding:0 14px 14px;font-size:13px}.dot[data-v-c16cffd4]{color:#9ca3af;margin:0 6px}.uni-row[data-v-c16cffd4]{align-items:center;gap:8px;width:100%;display:flex}.teachers-primary-btn.el-button--primary{--el-button-text-color:#fff;--el-button-bg-color:#244e98;--el-button-border-color:#244e98;--el-button-hover-text-color:#fff;--el-button-hover-bg-color:#8b1519;--el-button-hover-border-color:#8b1519;--el-button-active-text-color:#fff;--el-button-active-bg-color:#8b1519;--el-button-active-border-color:#8b1519}.form-small[data-v-c16cffd4] .el-form-item__label{padding-bottom:4px;font-size:13px}@media (width<=992px){.talent-stat-grid[data-v-c16cffd4]{grid-template-columns:1fr 1fr}}

@ -1 +0,0 @@
.teachers-page[data-v-38f7d6f8]{--brand-primary:#244e98;--brand-primary-hover:#8b1519;--brand-bg-soft:#fdf3f3;flex-direction:column;gap:12px;display:flex}.talent-stat-grid[data-v-38f7d6f8]{grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;display:grid}.teachers-list-card[data-v-38f7d6f8]{margin-top:0}.teachers-filter-search[data-v-38f7d6f8]{width:180px}.talent-stat-card[data-v-38f7d6f8]{text-align:left;cursor:pointer;min-height:68px;font:inherit;background:#fff;border:1px solid #d8dde4;border-radius:8px;flex-direction:column;justify-content:center;align-items:flex-start;gap:6px;padding:10px 16px;display:flex;position:relative;box-shadow:0 2px 10px #0f172a14}.talent-stat-card[data-v-38f7d6f8]:hover,.talent-stat-card.is-active[data-v-38f7d6f8]{border-color:var(--brand-primary)}.talent-stat-card.is-active[data-v-38f7d6f8]:before{content:"";background:var(--brand-primary);width:4px;position:absolute;top:0;bottom:0;left:0}.talent-stat-label[data-v-38f7d6f8]{color:#6b7280;font-size:14px}.talent-stat-value[data-v-38f7d6f8]{color:var(--brand-primary);font-size:24px;font-weight:600;line-height:1.1}.talent-stat-value.is-dark[data-v-38f7d6f8]{color:#111827}.talent-stat-value.is-danger[data-v-38f7d6f8]{color:var(--el-color-danger)}.talent-stat-value.is-success[data-v-38f7d6f8]{color:var(--el-color-success)}.filter-source[data-v-38f7d6f8]{width:132px}.filter-stars[data-v-38f7d6f8]{width:100px}.filter-status[data-v-38f7d6f8]{width:112px}.filter-school[data-v-38f7d6f8]{width:184px}.filter-direction[data-v-38f7d6f8]{width:146px}.name-link[data-v-38f7d6f8]{color:inherit;text-decoration:none}.name-link[data-v-38f7d6f8]:hover{color:var(--brand-primary)}.tag-overdue[data-v-38f7d6f8]{vertical-align:middle;margin-left:4px}.star-text[data-v-38f7d6f8]{color:#e6a23c;letter-spacing:1px}.source-tag[data-v-38f7d6f8]{border:none;font-weight:500}.source-tag-manual[data-v-38f7d6f8]{--el-tag-bg-color:#6c757d;--el-tag-border-color:#6c757d;--el-tag-text-color:#fff}.teachers-table-actions[data-v-38f7d6f8]{flex-wrap:nowrap;gap:4px}.teachers-table-btn[data-v-38f7d6f8]{min-height:22px;font-size:12px;padding:2px 6px!important}.follow-teacher-summary[data-v-38f7d6f8]{border-left:4px solid var(--brand-primary);background:var(--brand-bg-soft);border-radius:6px;padding:10px 12px;font-size:14px}.text-brand[data-v-38f7d6f8]{color:var(--brand-primary);font-weight:600}.names-muted[data-v-38f7d6f8]{color:#6b7280;margin-left:8px;font-size:13px}.batch-rule[data-v-38f7d6f8]{color:#6b7280;margin:0;font-size:12px}.follow-date-rule[data-v-38f7d6f8]{color:#6b7280;margin:6px 0 0;font-size:12px;line-height:1.45}.follow-history-list[data-v-38f7d6f8]{gap:14px;max-height:60vh;margin-top:12px;display:grid;overflow:auto}.follow-history-card[data-v-38f7d6f8]{border:1px solid #dfe4eb;border-left:4px solid var(--brand-primary);background:#fff;border-radius:6px}.follow-history-head[data-v-38f7d6f8]{border-bottom:1px solid #e6eaf1;justify-content:space-between;align-items:center;gap:12px;padding:12px 14px;display:flex}.follow-history-title[data-v-38f7d6f8]{color:var(--brand-primary);font-weight:600}.follow-history-date[data-v-38f7d6f8]{color:#6b7280;margin-left:14px;font-size:13px}.follow-history-body[data-v-38f7d6f8]{padding:14px;font-size:13px}.follow-history-row[data-v-38f7d6f8]{grid-template-columns:96px 1fr;gap:14px;margin-bottom:10px;display:grid}.follow-history-row>span[data-v-38f7d6f8]{color:#6b7280}.follow-history-footer[data-v-38f7d6f8]{color:#6b7280;padding:0 14px 14px;font-size:13px}.dot[data-v-38f7d6f8]{color:#9ca3af;margin:0 6px}.uni-row[data-v-38f7d6f8]{align-items:center;gap:8px;width:100%;display:flex}.teachers-primary-btn.el-button--primary{--el-button-text-color:#fff;--el-button-bg-color:#244e98;--el-button-border-color:#244e98;--el-button-hover-text-color:#fff;--el-button-hover-bg-color:#8b1519;--el-button-hover-border-color:#8b1519;--el-button-active-text-color:#fff;--el-button-active-bg-color:#8b1519;--el-button-active-border-color:#8b1519}.form-small[data-v-38f7d6f8] .el-form-item__label{padding-bottom:4px;font-size:13px}@media (width<=992px){.talent-stat-grid[data-v-38f7d6f8]{grid-template-columns:1fr 1fr}}

@ -0,0 +1 @@
import{r as e}from"./index-CPrkFf57.js";async function t(t,n){let r=new FormData;r.append(`file`,t),r.append(`subdir`,n);let{data:i}=await e.post(`/admin/v1/uploads/course-asset`,r);return i.data}async function n(t){let n=new FormData;n.append(`file`,t);let{data:r}=await e.post(`/admin/v1/uploads/news-cover`,n);return r.data}async function r(t){let n=new FormData;n.append(`file`,t);let{data:r}=await e.post(`/admin/v1/uploads/banner-cover`,n);return r.data}async function i(t,n=`common`){let r=new FormData;r.append(`file`,t),r.append(`scope`,n);let{data:i}=await e.post(`/admin/v1/uploads/editor-image`,r);return i.data}export{n as i,t as n,i as r,r as t};

@ -1 +1 @@
import{C as e,D as t,G as n,H as r,L as i,Xt as a,tn as o,y as s}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{a as c}from"./index-DHoSHxJa.js";var l=t({__name:`PageTitle`,props:{variant:{default:`default`}},setup(t){let r=t,i=c(),l=s(()=>String(i.meta.title||``)),u=s(()=>r.variant===`dashboard`?`dashboard-page-title`:r.variant===`radar`?`radar-page-title`:`page-title`);return(t,r)=>(n(),e(`h1`,{class:a(u.value)},o(l.value),3))}});function u(e){let t=()=>{Promise.resolve(e())};r(t),i(t)}export{l as n,u as t};
import{C as e,D as t,G as n,H as r,L as i,Xt as a,tn as o,y as s}from"./vue.runtime.esm-bundler-DUiYyeqQ.js";import{a as c}from"./index-CPrkFf57.js";var l=t({__name:`PageTitle`,props:{variant:{default:`default`}},setup(t){let r=t,i=c(),l=s(()=>String(i.meta.title||``)),u=s(()=>r.variant===`dashboard`?`dashboard-page-title`:r.variant===`radar`?`radar-page-title`:`page-title`);return(t,r)=>(n(),e(`h1`,{class:a(u.value)},o(l.value),3))}});function u(e){let t=()=>{Promise.resolve(e())};r(t),i(t)}export{l as n,u as t};

@ -1 +1 @@
import{r as e}from"./index-DHoSHxJa.js";async function t(t){let{data:n}=await e.get(`/admin/v1/admin-users`,{params:t});return n.data}async function n(t){let{data:n}=await e.post(`/admin/v1/admin-users`,t);return n.data}async function r(t,n){let{data:r}=await e.put(`/admin/v1/admin-users/${t}`,n);return r}async function i(t,n){let{data:r}=await e.post(`/admin/v1/admin-users/${t}/password`,{password:n});return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/admin-users/${t}`);return n}export{r as a,i,a as n,t as r,n as t};
import{r as e}from"./index-CPrkFf57.js";async function t(t){let{data:n}=await e.get(`/admin/v1/admin-users`,{params:t});return n.data}async function n(t){let{data:n}=await e.post(`/admin/v1/admin-users`,t);return n.data}async function r(t,n){let{data:r}=await e.put(`/admin/v1/admin-users/${t}`,n);return r}async function i(t,n){let{data:r}=await e.post(`/admin/v1/admin-users/${t}/password`,{password:n});return r}async function a(t){let{data:n}=await e.delete(`/admin/v1/admin-users/${t}`);return n}export{r as a,i,a as n,t as r,n as t};

File diff suppressed because one or more lines are too long

@ -10,8 +10,8 @@
href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
<title>S-lake高校雷达网</title>
<script type="module" crossorigin src="/admin/assets/index-DHoSHxJa.js"></script>
<title>S-lake先进技术发展中心</title>
<script type="module" crossorigin src="/admin/assets/index-CPrkFf57.js"></script>
<link rel="modulepreload" crossorigin href="/admin/assets/rolldown-runtime-BYbx6iT9.js">
<link rel="modulepreload" crossorigin href="/admin/assets/vue.runtime.esm-bundler-DUiYyeqQ.js">
<link rel="stylesheet" crossorigin href="/admin/assets/index-BoedZQk5.css">

@ -30,6 +30,16 @@
.panel-title { color: #111827; font-size: 18px; font-weight: 600; }
.panel-sub { margin-top: 4px; color: #6b7280; font-size: 13px; }
.panel-scroll { max-height: 52vh; margin-top: 12px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.college-row {
display: flex; align-items: center; justify-content: space-between; gap: 12px;
padding: 12px 0; border-bottom: 1px solid #eef2f6; cursor: pointer;
}
.college-name { display: block; color: #111827; font-size: 15px; }
.college-count { display: block; margin-top: 4px; color: #6b7280; font-size: 12px; }
.panel-back {
display: inline-flex; align-items: center; gap: 4px; margin-bottom: 8px;
color: #244e98; font-size: 13px; cursor: pointer;
}
.teacher-row {
display: flex; align-items: center; justify-content: space-between; gap: 12px;
padding: 12px 0; border-bottom: 1px solid #eef2f6; cursor: pointer;
@ -79,7 +89,7 @@
const TIANDITU_TK = @json($tiandituTk);
const API_BASE = @json($apiBase);
const SUZHOU_CENTER = { lng: 120.585316, lat: 31.298886 };
const SUZHOU_ZOOM = 11;
const SUZHOU_ZOOM = 9;
const params = new URLSearchParams(window.location.search);
const token = params.get('token') || '';
@ -88,6 +98,8 @@
let schoolOverlays = [];
let schools = [];
let activeSchool = null;
let activeCollege = null;
let panelMode = 'colleges';
let unbindDragPan = null;
let schoolOverlayClass = null;
@ -241,19 +253,50 @@
function selectSchool(school) {
activeSchool = school;
activeCollege = null;
panelMode = 'colleges';
schoolOverlays.forEach(({ school: s, overlay }) => overlay.setActive(s.id === school.id));
openTeacherPanel(school);
openCollegePanel(school);
}
function openTeacherPanel(school) {
document.getElementById('panelTitle').textContent = school.name || '高校老师';
function openCollegePanel(school) {
document.getElementById('panelTitle').textContent = school.name || '高校学院';
document.getElementById('panelSub').textContent = (school.city || '') + ' · ' + (school.teachers_count || 0) + ' 位老师';
const scroll = document.getElementById('panelScroll');
const teachers = school.teachers || [];
const colleges = school.colleges || [];
if (!colleges.length) {
scroll.innerHTML = '<div class="panel-empty">该高校暂无学院数据</div>';
} else {
scroll.innerHTML = colleges.map((c) => (
'<div class="college-row" data-key="' + escapeHtml(c.key) + '">' +
'<div><span class="college-name">' + escapeHtml(c.name) + '</span>' +
'<span class="college-count">' + (c.teachers_count || 0) + ' 位老师</span></div>' +
'<span class="teacher-arrow"></span></div>'
)).join('');
scroll.querySelectorAll('.college-row').forEach((row) => {
row.addEventListener('click', () => {
const key = row.dataset.key;
const college = colleges.find((item) => item.key === key);
if (college) openTeacherPanel(school, college);
});
});
}
document.getElementById('panelMask').classList.add('visible');
document.getElementById('teacherPanel').classList.add('visible');
}
function openTeacherPanel(school, college) {
activeCollege = college;
panelMode = 'teachers';
document.getElementById('panelTitle').textContent = college.name || '学院老师';
document.getElementById('panelSub').textContent = (school.name || '') + ' · ' + (college.teachers_count || 0) + ' 位老师';
const scroll = document.getElementById('panelScroll');
const teachers = college.teachers || [];
const backHtml = '<div class="panel-back" id="panelBack"> 返回学院列表</div>';
if (!teachers.length) {
scroll.innerHTML = '<div class="panel-empty">该高校暂无老师数据</div>';
scroll.innerHTML = backHtml + '<div class="panel-empty">学院暂无老师数据</div>';
} else {
scroll.innerHTML = teachers.map((t) => (
scroll.innerHTML = backHtml + teachers.map((t) => (
'<div class="teacher-row" data-id="' + t.id + '">' +
'<div><span class="teacher-name">' + escapeHtml(t.name) + '</span>' +
'<span class="teacher-dir">' + escapeHtml(t.research_direction || '暂无研究方向') + '</span></div>' +
@ -263,11 +306,20 @@
row.addEventListener('click', () => openTeacher(Number(row.dataset.id)));
});
}
document.getElementById('panelMask').classList.add('visible');
document.getElementById('teacherPanel').classList.add('visible');
const backBtn = document.getElementById('panelBack');
if (backBtn) {
backBtn.addEventListener('click', (e) => {
e.stopPropagation();
openCollegePanel(school);
});
}
}
function closeTeacherPanel() {
activeSchool = null;
activeCollege = null;
panelMode = 'colleges';
schoolOverlays.forEach(({ overlay }) => overlay.setActive(false));
document.getElementById('panelMask').classList.remove('visible');
document.getElementById('teacherPanel').classList.remove('visible');
}

@ -21,6 +21,7 @@ use App\Http\Controllers\Admin\MiniappUserController;
use App\Http\Controllers\Admin\NewsController;
use App\Http\Controllers\Admin\OperationLogController;
use App\Http\Controllers\Admin\PaperController;
use App\Http\Controllers\Admin\PastReviewController;
use App\Http\Controllers\Admin\RadarMapController;
use App\Http\Controllers\Admin\GridMemberController;
use App\Http\Controllers\Admin\ResearchDirectionController;
@ -139,6 +140,12 @@ Route::prefix('admin/v1')->group(function () {
Route::delete('/news/{news}', [NewsController::class, 'destroy'])->name('admin.news.destroy');
Route::patch('/news/{news}/publish', [NewsController::class, 'publish'])->name('admin.news.publish');
Route::get('/past-reviews', [PastReviewController::class, 'index'])->name('admin.past-reviews.index');
Route::post('/past-reviews', [PastReviewController::class, 'store'])->name('admin.past-reviews.store');
Route::get('/past-reviews/{pastReview}', [PastReviewController::class, 'show'])->name('admin.past-reviews.show');
Route::put('/past-reviews/{pastReview}', [PastReviewController::class, 'update'])->name('admin.past-reviews.update');
Route::delete('/past-reviews/{pastReview}', [PastReviewController::class, 'destroy'])->name('admin.past-reviews.destroy');
Route::get('/banners', [BannerController::class, 'index'])->name('admin.banners.index');
Route::post('/banners', [BannerController::class, 'store'])->name('admin.banners.store');
Route::get('/banners/{banner}', [BannerController::class, 'show'])->name('admin.banners.show');

@ -11,6 +11,7 @@ use App\Http\Controllers\Miniapp\DemandController;
use App\Http\Controllers\Miniapp\DictController;
use App\Http\Controllers\Miniapp\NewsController;
use App\Http\Controllers\Miniapp\PaperController;
use App\Http\Controllers\Miniapp\PastReviewController;
use App\Http\Controllers\Miniapp\ProfileController;
use App\Http\Controllers\Miniapp\RadarMapController;
use App\Http\Controllers\Miniapp\ResearchDirectionController;
@ -24,6 +25,7 @@ Route::prefix('miniapp/v1')->group(function () {
Route::get('/banners', [BannerController::class, 'index']);
Route::get('/banners/{banner}', [BannerController::class, 'show'])->whereNumber('banner');
Route::get('/past-reviews', [PastReviewController::class, 'index']);
Route::get('/courses/hot', [CourseController::class, 'hot']);
Route::get('/courses/latest', [CourseController::class, 'latest']);
Route::get('/courses/calendar', [CourseController::class, 'calendar']);

@ -19,5 +19,13 @@ Route::redirect('/', '/admin/');
Route::get('/miniapp-radar', [MiniappRadarPageController::class, 'show']);
$webviewVerifyFile = config('services.wechat.mini_program.webview_verify_file');
$webviewVerifyContent = config('services.wechat.mini_program.webview_verify_content');
if ($webviewVerifyFile && $webviewVerifyContent) {
Route::get('/'.$webviewVerifyFile, static fn () => response($webviewVerifyContent, 200, [
'Content-Type' => 'text/plain; charset=UTF-8',
]));
}
// 管理后台 SPA入口返回 index.html历史深链 /admin/xxx 重定向到 /admin/#/xxx
Route::get('/admin/{path?}', AdminSpaController::class)->where('path', '.*');

Loading…
Cancel
Save