如何在弹窗中显示关联任务的Technician与Tarification表格并填充表单?
实现基于Metier和Tache选择的技术人员与定价弹窗填充功能
我来帮你一步步实现这个需求,咱们从后端接口、前端视图到交互逻辑逐一处理:
一、后端:新增API接口获取关联数据
首先在InterventionController中添加一个方法,用于根据选中的任务(tache)ID获取对应的技术人员和定价信息:
use Illuminate\Http\Request; use App\Tarificationtache; public function getTechniciansByTache(Request $request) { $tacheId = $request->input('tache_id'); // 通过任务ID获取关联的定价记录,同时加载关联的技术人员 $tarifications = Tarificationtache::with('techniciens') ->where('tache_id', $tacheId) ->get(); // 整理返回数据,方便前端渲染 $data = []; foreach ($tarifications as $tarif) { foreach ($tarif->techniciens as $tech) { $data[] = [ 'technicien_id' => $tech->id, 'technicien_name' => $tech->nom . ' ' . $tech->prenom, // 假设技术人员表有nom和prenom字段 'tarification_id' => $tarif->id, 'tarif' => $tarif->tarif ]; } } return response()->json($data); }
别忘了在routes/web.php中添加对应的路由:
Route::get('/intervention/get-technicians-by-tache', [App\Http\Controllers\InterventionController::class, 'getTechniciansByTache'])->name('intervention.getTechnicians');
二、前端:修改表单视图(intervention/create.blade.php)
调整表单结构,添加模态弹窗,并优化下拉框的联动逻辑(假设你使用Bootstrap框架):
<div class="container mt-4"> <form action="{{ route('intervention.store') }}" method="POST"> @csrf <!-- Metier下拉框 --> <div class="mb-3"> <label for="metier_id" class="form-label">Metier</label> <select class="form-select" id="metier_id" name="metier_id"> <option value="">请选择职业</option> @foreach($metiers as $metier) <option value="{{ $metier->id }}">{{ $metier->nom }}</option> <!-- 假设metier表有nom字段 --> @endforeach </select> </div> <!-- Tache下拉框 --> <div class="mb-3"> <label for="tache_id" class="form-label">Tache</label> <select class="form-select" id="tache_id" name="tache_id" disabled> <option value="">请先选择职业</option> </select> </div> <!-- Technicien和Tarification字段(用隐藏域+显示文本) --> <div class="mb-3"> <label class="form-label">技术人员</label> <div id="technicien_display" class="form-control-plaintext text-muted">未选择</div> <input type="hidden" id="technicien_id" name="technicien_id"> </div> <div class="mb-3"> <label class="form-label">定价</label> <div id="tarification_display" class="form-control-plaintext text-muted">未选择</div> <input type="hidden" id="tarification_id" name="tarification_id"> </div> <!-- 其他表单字段 --> <div class="mb-3"> <label for="description" class="form-label">Description</label> <textarea class="form-control" id="description" name="description"></textarea> </div> <div class="mb-3"> <label for="duree_prevu" class="form-label">Durée prévue</label> <input type="datetime-local" class="form-control" id="duree_prevu" name="duree_prevu"> </div> <div class="mb-3"> <div class="form-check"> <input class="form-check-input" type="checkbox" id="statut" name="statut"> <label class="form-check-label" for="statut">Statut</label> </div> </div> <div class="mb-3"> <label for="client_id" class="form-label">Client</label> <select class="form-select" id="client_id" name="client_id"> @foreach($client as $c) <option value="{{ $c->id }}">{{ $c->nom }}</option> @endforeach </select> </div> <!-- 提交按钮 --> <button type="submit" class="btn btn-primary" disabled id="submit_btn">提交</button> </form> </div> <!-- 技术人员选择弹窗 --> <div class="modal fade" id="technicianModal" tabindex="-1" aria-labelledby="technicianModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="technicianModalLabel">选择技术人员与定价</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <table class="table table-striped"> <thead> <tr> <th>技术人员</th> <th>定价</th> </tr> </thead> <tbody id="technician_table_body"> <!-- 数据将通过JS动态渲染 --> </tbody> </table> </div> </div> </div> </div>
三、JavaScript:实现交互逻辑
添加以下JS代码(放在视图底部或外部JS文件):
// 监听Metier选择事件,动态加载对应的Tache选项 document.getElementById('metier_id').addEventListener('change', function() { const metierId = this.value; const tacheSelect = document.getElementById('tache_id'); tacheSelect.disabled = true; tacheSelect.innerHTML = '<option value="">加载中...</option>'; if (metierId) { // 调用后端接口获取该职业下的任务 fetch(`/intervention/get-taches-by-metier?metier_id=${metierId}`) .then(response => response.json()) .then(data => { tacheSelect.innerHTML = '<option value="">请选择任务</option>'; data.forEach(tache => { const option = document.createElement('option'); option.value = tache.id; option.textContent = tache.nom; // 假设tache表有nom字段 tacheSelect.appendChild(option); }); tacheSelect.disabled = false; }); } else { tacheSelect.innerHTML = '<option value="">请先选择职业</option>'; } }); // 监听Tache选择事件,弹窗显示技术人员列表 document.getElementById('tache_id').addEventListener('change', function() { const metierId = document.getElementById('metier_id').value; const tacheId = this.value; const modal = new bootstrap.Modal(document.getElementById('technicianModal')); const tableBody = document.getElementById('technician_table_body'); if (metierId && tacheId) { tableBody.innerHTML = '<tr><td colspan="2" class="text-center">加载中...</td></tr>'; fetch(`{{ route('intervention.getTechnicians') }}?tache_id=${tacheId}`) .then(response => response.json()) .then(data => { tableBody.innerHTML = ''; if (data.length === 0) { tableBody.innerHTML = '<tr><td colspan="2" class="text-center text-muted">暂无相关技术人员</td></tr>'; return; } data.forEach(item => { const row = document.createElement('tr'); row.style.cursor = 'pointer'; row.dataset.technicienId = item.technicien_id; row.dataset.technicienName = item.technicien_name; row.dataset.tarificationId = item.tarification_id; row.dataset.tarif = item.tarif; row.innerHTML = ` <td>${item.technicien_name}</td> <td>${item.tarif} €</td> `; // 点击行时填充表单并关闭弹窗 row.addEventListener('click', function() { document.getElementById('technicien_id').value = this.dataset.technicienId; document.getElementById('technicien_display').textContent = this.dataset.technicienName; document.getElementById('tarification_id').value = this.dataset.tarificationId; document.getElementById('tarification_display').textContent = `${this.dataset.tarif} €`; document.getElementById('submit_btn').disabled = false; bootstrap.Modal.getInstance(document.getElementById('technicianModal')).hide(); }); tableBody.appendChild(row); }); }); modal.show(); } });
四、补充说明
- Metier与Tache的联动接口:你需要补充一个
getTachesByMetier后端接口,逻辑类似getTechniciansByTache,根据职业ID返回对应的任务列表。 - 模型关系检查:确保
Tarificationtache和Technicien的多对多关系中间表technicien_tarificationtache字段(tarificationtache_id、technicien_id)配置正确。 - Store方法修正:你的原
store方法中$intervention ->tarification_id = $request->tarificationtache_id;应改为$request->input('tarification_id'),和前端隐藏域的name对应。 - 表单验证:在
InterventionRequest中添加technicien_id和tarification_id的必填规则,防止未选择提交。
内容的提问来源于stack exchange,提问作者IT2704
相关产品推荐
相关产品推荐

