文件
yjyf/server/application/admin/view/service/edit.html
YuanWen 361dffc7d8 feat: 新增师傅端功能及服务增项管理模块
- 新增师傅端路由和页面配置,切换登录后默认跳转到师傅大厅
- 新增服务分类图标上传功能和增项服务管理模块
- 新增订单、申诉、结算等模型关联关系及后台控制器
- 新增师傅端TabBar组件和消息页面跳转逻辑
- 新增文件上传接口和服务计算逻辑
- 新增各类SVG图标和空状态提示
2026-11-03 15:45:21 +08:00

336 行
20 KiB
HTML

<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="nav-tabs-custom" style="box-shadow: none;">
<ul class="nav nav-tabs">
<li class="active"><a href="#tab-basic" data-toggle="tab"><i class="fa fa-info-circle text-primary"></i> 基础信息</a></li>
<li><a href="#tab-service-types" data-toggle="tab"><i class="fa fa-wrench text-warning"></i> 工项服务定价</a></li>
<li><a href="#tab-specs" data-toggle="tab"><i class="fa fa-cubes text-success"></i> 规格独立一口价</a></li>
<li><a href="#tab-addons" data-toggle="tab"><i class="fa fa-plus-square text-danger"></i> 增项施工服务绑定</a></li>
</ul>
<div class="tab-content" style="padding: 15px 0;">
<!-- Tab 1: 基础信息 -->
<div class="tab-pane active" id="tab-basic">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">所属类目:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-cat_id" data-rule="required" min="0" data-source="service/cat/index" class="form-control selectpage" name="row[cat_id]" type="text" value="{$row.cat_id|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">服务/商品名称:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-name" data-rule="required" class="form-control" name="row[name]" type="text" value="{$row.name|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">主图:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group">
<input id="c-image" class="form-control" size="50" name="row[image]" type="text" value="{$row.image|htmlentities}">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="faupload-image" class="btn btn-danger plupload" data-input-id="c-image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="false" data-preview-id="p-image"><i class="fa fa-upload"></i> 上传</button></span>
<span><button type="button" id="fachoose-image" class="btn btn-primary fachoose" data-input-id="c-image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> 选择</button></span>
</div>
<span class="msg-box n-right" for="c-image"></span>
</div>
<ul class="row list-inline plupload-preview" id="p-image"></ul>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">计价模式:</label>
<div class="col-xs-12 col-sm-8">
<select id="c-price_type" data-rule="required" class="form-control selectpicker" name="row[price_type]">
{foreach name="priceTypeList" item="vo"}
<option value="{$key}" {in name="key" value="$row.price_type"}selected{/in}>{$vo}</option>
{/foreach}
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">基准一口价/参考价(元):</label>
<div class="col-xs-12 col-sm-8">
<input id="c-base_price" data-rule="required" class="form-control" step="0.01" name="row[base_price]" type="number" value="{$row.base_price|htmlentities}">
<span class="help-block text-muted"><i class="fa fa-info-circle"></i> 作为该商品的通用基准价(若各工项未单独定价时默认采用此价)</span>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">计价单位:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-unit" data-rule="required" class="form-control" name="row[unit]" type="text" value="{$row.unit|htmlentities}" placeholder="如:件、台、套、次">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">步梯楼层费(元/层):</label>
<div class="col-xs-12 col-sm-8">
<input id="c-floor_fee" data-rule="required" class="form-control" step="0.01" name="row[floor_fee]" type="number" value="{$row.floor_fee|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">免费楼层数:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-free_floor" data-rule="required" class="form-control" name="row[free_floor]" type="number" value="{$row.free_floor|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">服务简介说明:</label>
<div class="col-xs-12 col-sm-8">
<textarea id="c-description" class="form-control" rows="3" name="row[description]">{$row.description|htmlentities}</textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">排序权重:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-weigh" data-rule="required" class="form-control" name="row[weigh]" type="number" value="{$row.weigh|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">状态:</label>
<div class="col-xs-12 col-sm-8">
<div class="radio">
{foreach name="statusList" item="vo"}
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="$row.status"}checked{/in} /> {$vo}</label>
{/foreach}
</div>
</div>
</div>
</div>
<!-- Tab 2: 工项服务定价 -->
<div class="tab-pane" id="tab-service-types">
<div class="alert alert-info-light">
<i class="fa fa-info-circle"></i> 勾选此商品支持的服务工项(如安装、维修、拆旧等),并可为每个工项设定独立一口价。
</div>
<table class="table table-bordered table-striped" id="service-types-table">
<thead>
<tr class="active">
<th style="width: 60px; text-align: center;">启用</th>
<th style="width: 120px;">工项标识</th>
<th style="width: 160px;">工项显示名称</th>
<th style="width: 140px;">工项一口价(元)</th>
<th style="width: 80px; text-align: center;">默认勾选</th>
</tr>
</thead>
<tbody>
<?php
$defaultTypes = [
'install' => ['name' => '安装', 'price' => $row['base_price'], 'default' => 1],
'repair' => ['name' => '维修', 'price' => round($row['base_price'] * 0.7, 2), 'default' => 0],
'remove' => ['name' => '拆旧', 'price' => round($row['base_price'] * 0.5, 2), 'default' => 0],
'deliver' => ['name' => '送货到家', 'price' => 50.00, 'default' => 0],
'deliver_install' => ['name' => '送货到家并安装', 'price' => $row['base_price'] + 50.00, 'default' => 0],
'measure' => ['name' => '坑距测量(含拆旧)', 'price' => 40.00, 'default' => 0],
'maintain' => ['name' => '保养', 'price' => 60.00, 'default' => 0],
];
$savedMap = [];
foreach ($serviceTypes as $st) {
if (isset($st['code'])) {
$savedMap[$st['code']] = $st;
}
}
?>
{foreach name="defaultTypes" item="cfg" key="code"}
<?php
$isCheck = !empty($savedMap) ? isset($savedMap[$code]) : true;
$curName = isset($savedMap[$code]['name']) ? $savedMap[$code]['name'] : $cfg['name'];
$curPrice = isset($savedMap[$code]['price']) ? $savedMap[$code]['price'] : $cfg['price'];
$isDef = isset($savedMap[$code]['is_default']) ? $savedMap[$code]['is_default'] : $cfg['default'];
?>
<tr>
<td style="text-align: center; vertical-align: middle;">
<input type="checkbox" class="st-enable" data-code="{$code}" {if $isCheck}checked{/if}>
</td>
<td style="vertical-align: middle;"><code>{$code}</code></td>
<td>
<input type="text" class="form-control input-sm st-name" data-code="{$code}" value="{$curName}">
</td>
<td>
<div class="input-group input-group-sm">
<span class="input-group-addon">¥</span>
<input type="number" step="0.01" class="form-control st-price" data-code="{$code}" value="{$curPrice}">
</div>
</td>
<td style="text-align: center; vertical-align: middle;">
<input type="radio" name="st_default_radio" class="st-default" data-code="{$code}" {if $isDef}checked{/if}>
</td>
</tr>
{/foreach}
</tbody>
</table>
<input type="hidden" name="row[service_types_raw]" id="service_types_raw" value="">
</div>
<!-- Tab 3: 规格独立定价 -->
<div class="tab-pane" id="tab-specs">
<div class="alert alert-success-light">
<i class="fa fa-info-circle"></i> 为该商品增设不同规格(如:单眼灶/双眼灶、普通坐便器/智能马桶),并分别设置规格基准一口价。
</div>
<table class="table table-bordered table-striped" id="specs-table">
<thead>
<tr class="active">
<th style="width: 200px;">规格名称</th>
<th style="width: 150px;">规格独立一口价(元)</th>
<th>规格施工描述</th>
<th style="width: 80px; text-align: center;">操作</th>
</tr>
</thead>
<tbody id="specs-tbody">
{foreach name="specs" item="sp" key="idx"}
<tr data-id="{$sp.id}">
<td>
<input type="hidden" name="specs[{$idx}][id]" value="{$sp.id}">
<input type="text" name="specs[{$idx}][name]" class="form-control input-sm" value="{$sp.name|htmlentities}" placeholder="如:智能一体机">
</td>
<td>
<div class="input-group input-group-sm">
<span class="input-group-addon">¥</span>
<input type="number" step="0.01" name="specs[{$idx}][base_price]" class="form-control" value="{$sp.base_price}">
</div>
</td>
<td>
<input type="text" name="specs[{$idx}][description]" class="form-control input-sm" value="{$sp.description|htmlentities}" placeholder="施工要求说明">
</td>
<td style="text-align: center;">
<button type="button" class="btn btn-xs btn-danger btn-del-spec"><i class="fa fa-trash"></i></button>
</td>
</tr>
{/foreach}
</tbody>
</table>
<button type="button" class="btn btn-sm btn-success" id="btn-add-spec"><i class="fa fa-plus"></i> 添加新规格</button>
</div>
<!-- Tab 4: 增项服务绑定 -->
<div class="tab-pane" id="tab-addons">
<div class="alert alert-danger-light">
<i class="fa fa-info-circle"></i> 从系统增项库中勾选该商品允许加选的增项服务(如马桶勾选拆旧/改坑距,油烟机勾选打孔),并可为该商品定制专属单价(留空则默认按全局价)。
</div>
<table class="table table-bordered table-striped" id="addons-table">
<thead>
<tr class="active">
<th style="width: 60px; text-align: center;">绑定</th>
<th style="width: 180px;">增项名称</th>
<th style="width: 90px; text-align: center;">单位</th>
<th style="width: 140px;">平台全局指导价</th>
<th style="width: 180px;">针对本商品专属单价(元)</th>
</tr>
</thead>
<tbody>
<?php
$assignedMap = [];
foreach ($assignedAddons as $ad) {
if (isset($ad['id'])) {
$assignedMap[$ad['id']] = $ad;
}
}
?>
{foreach name="addonsPool" item="ad"}
<?php
$isBind = isset($assignedMap[$ad['id']]);
$customPrice = $isBind && isset($assignedMap[$ad['id']]['price']) ? $assignedMap[$ad['id']]['price'] : $ad['default_price'];
?>
<tr>
<td style="text-align: center; vertical-align: middle;">
<input type="checkbox" class="ad-bind" data-id="{$ad.id}" data-name="{$ad.name}" data-unit="{$ad.unit}" {if $isBind}checked{/if}>
</td>
<td style="vertical-align: middle;">
<strong>{$ad.name}</strong>
</td>
<td style="text-align: center; vertical-align: middle;">
<span class="badge">{$ad.unit}</span>
</td>
<td style="vertical-align: middle; color: #888;">
¥{$ad.default_price}
</td>
<td>
<div class="input-group input-group-sm">
<span class="input-group-addon">¥</span>
<input type="number" step="0.01" class="form-control ad-price" data-id="{$ad.id}" value="{$customPrice}" placeholder="覆盖单价">
</div>
</td>
</tr>
{/foreach}
</tbody>
</table>
<input type="hidden" name="row[addons_raw]" id="addons_raw" value="">
</div>
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-primary btn-embossed disabled" id="btn-submit-service">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
<script>
// 动态组装工项与增项 JSON
function collectServiceConfig() {
// 1. 收集工项
var serviceTypes = [];
$('#service-types-table tbody tr').each(function () {
var $row = $(this);
var $enable = $row.find('.st-enable');
if ($enable.is(':checked')) {
var code = $enable.data('code');
var name = $row.find('.st-name').val();
var price = parseFloat($row.find('.st-price').val()) || 0;
var isDef = $row.find('.st-default').is(':checked') ? 1 : 0;
serviceTypes.push({
code: code,
name: name,
price: price,
is_default: isDef
});
}
});
$('#service_types_raw').val(JSON.stringify(serviceTypes));
// 2. 收集增项
var addons = [];
$('#addons-table tbody tr').each(function () {
var $row = $(this);
var $bind = $row.find('.ad-bind');
if ($bind.is(':checked')) {
var id = parseInt($bind.data('id'), 10);
var name = $bind.data('name');
var unit = $bind.data('unit');
var price = parseFloat($row.find('.ad-price').val()) || 0;
addons.push({
id: id,
name: name,
unit: unit,
price: price
});
}
});
$('#addons_raw').val(JSON.stringify(addons));
}
// 监听表单提交事件,在提交前组装 JSON
$(document).on('submit', '#edit-form', function () {
collectServiceConfig();
});
// 动态添加规格
var specIndex = 1000;
$(document).on('click', '#btn-add-spec', function () {
specIndex++;
var html = '<tr>' +
'<td><input type="text" name="specs[' + specIndex + '][name]" class="form-control input-sm" placeholder="规格名称(如:四眼炒灶)"></td>' +
'<td><div class="input-group input-group-sm"><span class="input-group-addon">¥</span><input type="number" step="0.01" name="specs[' + specIndex + '][base_price]" class="form-control" value="0.00"></div></td>' +
'<td><input type="text" name="specs[' + specIndex + '][description]" class="form-control input-sm" placeholder="施工说明"></td>' +
'<td style="text-align:center;"><button type="button" class="btn btn-xs btn-danger btn-del-spec"><i class="fa fa-trash"></i></button></td>' +
'</tr>';
$('#specs-tbody').append(html);
});
// 删除规格
$(document).on('click', '.btn-del-spec', function () {
$(this).closest('tr').remove();
});
</script>