Files
OMS/app/ome/view/admin/refund/merchant_negotiation.html
2025-12-28 23:13:25 +08:00

846 lines
29 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
Copyright © ShopeX http://www.shopex.cn. All rights reserved.
See LICENSE file for license details.
-->
<style>
/* 商家协商页面样式 - 参考detail.html的左右布局 */
.merchant-negotiation {
display: flex;
gap: 20px;
height: 100%;
width: 100%;
max-width: 100%;
box-sizing: border-box;
overflow: hidden;
}
/* 强制所有子元素不撑开容器 */
.merchant-negotiation * {
max-width: 100%;
box-sizing: border-box;
}
.merchant-negotiation .main-container {
display: flex;
gap: 20px;
height: 100%;
width: 100%;
max-width: 100%;
box-sizing: border-box;
overflow: hidden;
}
.merchant-negotiation .left-panel {
flex: 3;
min-width: 0;
max-width: calc(100% - 350px);
overflow: hidden;
}
.merchant-negotiation .right-panel {
width: 330px;
flex-shrink: 0;
}
/* 左侧表单容器 */
.merchant-negotiation .form-container {
background: #fff;
border: 1px solid #e3e6f0;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
height: 100%;
display: flex;
flex-direction: column;
width: 100%;
max-width: 100%;
box-sizing: border-box;
}
.merchant-negotiation .form-header {
background: linear-gradient(135deg, #f8f9fc 0%, #f1f3f6 100%);
border-bottom: 1px solid #e3e6f0;
padding: 15px 20px;
text-align: center;
}
.merchant-negotiation .form-title {
font-size: 18px;
font-weight: 600;
color: #212529;
margin: 0;
}
.merchant-negotiation .form-content {
flex: 1;
padding: 15px 20px;
overflow-y: auto;
}
/* 表单字段样式 */
.merchant-negotiation .form-group {
margin-bottom: 20px;
}
.merchant-negotiation .form-label {
display: block;
font-weight: 600;
color: #495057;
margin-bottom: 6px;
font-size: 14px;
}
.merchant-negotiation .form-label.required::after {
content: " *";
color: #dc3545;
}
.merchant-negotiation .form-control {
width: 100%;
border: 1px solid #ced4da;
border-radius: 6px;
font-size: 14px;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
box-sizing: border-box;
}
.merchant-negotiation .form-control:not(.form-textarea) {
max-width: 400px;
}
.merchant-negotiation .form-control:focus {
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.merchant-negotiation .form-control[readonly] {
background-color: #f8f9fa;
color: #6c757d;
}
.merchant-negotiation .form-textarea {
min-height: 80px;
resize: vertical;
}
.merchant-negotiation .hint-box {
background: #e3f2fd;
border: 1px solid #bbdefb;
border-radius: 4px;
padding: 8px 12px;
margin-top: 5px;
font-size: 12px;
color: #1976d2;
line-height: 1.4;
}
/* 图片上传区域 - 使用系统组件,无需自定义样式 */
/* 表单备注样式 */
.merchant-negotiation .form-remark {
font-size: 12px;
color: #6c757d;
margin-top: 5px;
line-height: 1.4;
}
/* 错误信息标签样式 */
.merchant-negotiation .error-message {
display: none;
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
border-radius: 6px;
padding: 12px 16px;
margin: 0 0px 15px 0px;
font-size: 14px;
line-height: 1.4;
position: relative;
}
.merchant-negotiation .error-message.show {
display: block;
animation: slideDown 0.3s ease-out;
}
.merchant-negotiation .error-message::before {
content: "⚠️";
margin-right: 8px;
font-size: 16px;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 成功信息标签样式 */
.merchant-negotiation .success-message {
display: none;
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
border-radius: 6px;
padding: 12px 16px;
margin: 0 20px 15px 20px;
font-size: 14px;
line-height: 1.4;
position: relative;
}
.merchant-negotiation .success-message.show {
display: block;
animation: slideDown 0.3s ease-out;
}
.merchant-negotiation .success-message::before {
content: "✅";
margin-right: 8px;
font-size: 16px;
}
/* 按钮样式 */
.merchant-negotiation .btn-group {
display: flex;
gap: 12px;
justify-content: center;
margin-top: 0;
padding: 20px;
border-top: 1px solid #e3e6f0;
background: #f8f9fa;
}
.merchant-negotiation .btn {
padding: 12px 32px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 100px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
}
/* 右侧信息面板 */
.merchant-negotiation .info-panel {
background: #fff;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 20px;
height: 100%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
overflow-y: auto;
}
.merchant-negotiation .info-title {
font-size: 18px;
font-weight: 600;
color: #212529;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #007bff;
}
.merchant-negotiation .info-section {
margin-bottom: 25px;
}
.merchant-negotiation .info-section-title {
font-size: 16px;
font-weight: 600;
color: #495057;
margin-bottom: 15px;
padding-bottom: 8px;
border-bottom: 1px solid #e9ecef;
}
.merchant-negotiation .info-item {
display: flex;
margin-bottom: 12px;
align-items: flex-start;
}
.merchant-negotiation .info-label {
width: 100px;
font-weight: 600;
color: #6c757d;
font-size: 13px;
text-align: right;
margin-right: 15px;
flex-shrink: 0;
}
.merchant-negotiation .info-value {
flex: 1;
color: #212529;
word-break: break-all;
line-height: 1.4;
font-size: 13px;
}
/* 状态样式 */
.merchant-negotiation .status-applying {
color: #ffc107;
font-weight: bold;
background: #fff3cd;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.merchant-negotiation .left-panel {
flex: 2;
}
.merchant-negotiation .right-panel {
width: 320px;
}
}
@media (max-width: 768px) {
.merchant-negotiation .main-container {
flex-direction: column;
}
.merchant-negotiation .left-panel {
flex: 1;
}
.merchant-negotiation .right-panel {
width: 100%;
}
.merchant-negotiation .form-container {
height: 50%;
}
.merchant-negotiation .info-panel {
height: 50%;
}
}
</style>
<div class="merchant-negotiation" id="merchant-negotiation-container">
<div class="main-container">
<!-- 左侧:协商表单 -->
<div class="left-panel">
<div class="form-container">
<div class="form-header">
<h3 class="form-title">商家协商</h3>
</div>
<div class="form-content">
<!-- 消息提示区域 -->
<div class="error-message" id="error_message"></div>
<div class="success-message" id="success_message"></div>
<form id="negotiation-form" method="post" action="index.php?app=ome&ctl=admin_refund_apply&act=save_merchant_negotiation" enctype="multipart/form-data">
<input type="hidden" name="apply_id" value="<{$apply_id}>">
<input type="hidden" name="refund_version" value="<{$refund_version}>">
<!-- 协商类型 -->
<div class="form-group">
<label class="form-label required">协商类型</label>
<select class="form-control" name="negotiation_type" id="negotiation_type" required>
<option value="">请选择</option>
<{if $negotiate_types.negotiation_type}>
<{foreach from=$negotiate_types.negotiation_type item=type}>
<option value="<{$type.negotiate_code}>" <{if $negotiate_data.negotiate_type == $type.negotiate_code || (!$negotiate_data.negotiate_type && $negotiate_type_code == $type.negotiate_code)}>selected<{/if}>><{$type.negotiate_desc}></option>
<{/foreach}>
<{/if}>
</select>
</div>
<!-- 退款类型 -->
<div class="form-group">
<label class="form-label required">退款类型</label>
<select class="form-control" name="refund_type" id="refund_type" required>
<option value="">请选择</option>
<{if $refund_type_options}>
<{foreach from=$refund_type_options key=type_code item=type_name}>
<option value="<{$type_code}>" <{if $negotiate_data.refund_type_code == $type_code}>selected<{/if}>><{$type_name}></option>
<{/foreach}>
<{/if}>
</select>
</div>
<!-- 协商方案 -->
<div class="form-group">
<label class="form-label required">协商方案</label>
<textarea class="form-control form-textarea" name="negotiation_plan" id="negotiation_plan"
placeholder="请填写" required><{$negotiate_data.negotiate_desc}></textarea>
<div class="hint-box">
若消费者接受协商,则按协商方案执行,或消费者拒绝协商,需重新审核退款单,建议先与消费者协商一致
</div>
</div>
<!-- 收货地址 -->
<div class="form-group" id="return_address_group" style="display: none;">
<label class="form-label">收货地址</label>
<select class="form-control" name="return_address" id="return_address">
<option value="">请选择退货地址</option>
<{if $address_list.address}>
<{foreach from=$address_list.address item=address}>
<option value="<{$address.address_id}>" data-text="<{$address.receiver_name}> - <{$address.province_name}><{$address.city_name}><{$address.area_name}><{$address.town_name}><{$address.address_detail}>" <{if $negotiate_data.negotiate_address_id == $address.address_id}>selected<{/if}>>
<{$address.receiver_name}> - <{$address.province_name}><{$address.city_name}><{$address.area_name}><{$address.town_name}><{$address.address_detail}>
</option>
<{/foreach}>
<{/if}>
</select>
<input type="hidden" name="return_address_text" id="return_address_text">
</div>
<!-- 建议退款金额 -->
<div class="form-group">
<label class="form-label required">建议退款金额</label>
<input type="number" class="form-control" name="suggested_amount" id="suggested_amount"
placeholder="最大可退金额: <{$max_refund_fee.max_refund_fee|default:'0.00'}>元" step="0.01" min="0" max="<{$max_refund_fee.max_refund_fee|default:'0.00'}>" value="<{$negotiate_data.negotiate_refund_fee}>" required>
</div>
<!-- 建议原因 -->
<div class="form-group">
<label class="form-label required">建议原因</label>
<select class="form-control" name="suggested_reason" id="suggested_reason" required>
<option value="">请选择</option>
<{if $reason_list.reason}>
<{foreach from=$reason_list.reason item=reason}>
<option value="<{$reason.reason_id}>" data-text="<{$reason.reason_text}>" <{if $negotiate_data.negotiate_reason_id == $reason.reason_id}>selected<{/if}>><{$reason.reason_text}></option>
<{/foreach}>
<{/if}>
</select>
<input type="hidden" name="suggested_reason_text" id="suggested_reason_text">
</div>
<!-- 推荐协商话术 -->
<div class="form-group">
<label class="form-label">推荐协商话术</label>
<textarea class="form-control form-textarea" name="recommended_script" id="recommended_script"
placeholder="推荐协商话术将显示在这里"><{$negotiate_data.negotiate_text|default:'亲,很抱歉没有让您满意,我们愿意支持您的售后申请,请您补充下凭证。'}></textarea>
<div class="hint-box">
推荐话术可以修改,如不修改则按默认话术提交
</div>
</div>
<!-- 凭证图片上传 -->
<div class="form-group">
<label class="form-label">凭证图片上传</label>
<{input type="image_magnifier" name="proof_images" target_type="refund_nego" target_id="{$apply_id}" display_width="150" display_height="150" magnifier="true" border_style="2px dashed #ddd" border_radius="8px" cursor_style="pointer"}>
<div class="form-remark">支持上传1张图片支持放大镜预览</div>
</div>
</form>
</div>
<!-- 按钮组 -->
<div class="btn-group">
<button type="button" class="btn btn-primary" id="submit_btn">提交</button>
<button type="button" class="btn btn-secondary" id="cancel_btn">取消</button>
</div>
</div>
</div>
<!-- 右侧:退款申请单信息 -->
<div class="right-panel">
<div class="info-panel">
<div class="info-title">退款申请单</div>
<div class="info-section">
<div class="info-section-title">基本信息</div>
<div class="info-item">
<div class="info-label">订单编号</div>
<div class="info-value"><{$refund_info.order_id}></div>
</div>
<div class="info-item">
<div class="info-label">退款申请单号</div>
<div class="info-value"><{$refund_info.apply_bn}></div>
</div>
<div class="info-item">
<div class="info-label">订单状态</div>
<div class="info-value">
<span class="status-applying">申请中</span>
</div>
</div>
<div class="info-item">
<div class="info-label">申请时间</div>
<div class="info-value">2025-06-12 14:26:27</div>
</div>
</div>
<div class="info-section">
<div class="info-section-title">申请退款服务的商品</div>
<div class="info-item">
<div class="info-label">基础物料编码</div>
<div class="info-value"><{$refund_info.basic_material_code}></div>
</div>
<div class="info-item">
<div class="info-label">基础物料名称</div>
<div class="info-value"><{$refund_info.basic_material_name}></div>
</div>
<div class="info-item">
<div class="info-label">销售物料编码</div>
<div class="info-value"><{$refund_info.sales_material_code}></div>
</div>
<div class="info-item">
<div class="info-label">规格</div>
<div class="info-value"><{$refund_info.specification}></div>
</div>
<div class="info-item">
<div class="info-label">申请数量</div>
<div class="info-value"><{$refund_info.apply_quantity}></div>
</div>
<div class="info-item">
<div class="info-label">数量</div>
<div class="info-value"><{$refund_info.quantity}></div>
</div>
<div class="info-item">
<div class="info-label">单价</div>
<div class="info-value"><{$refund_info.unit_price}></div>
</div>
<div class="info-item">
<div class="info-label">小计</div>
<div class="info-value"><{$refund_info.subtotal}></div>
</div>
<div class="info-item">
<div class="info-label">店铺编码</div>
<div class="info-value"><{$refund_info.shop_bn}></div>
</div>
</div>
<div class="info-section">
<div class="info-section-title">其他信息</div>
<div class="info-item">
<div class="info-label">申请原因</div>
<div class="info-value"><{$refund_info.apply_reason}></div>
</div>
<div class="info-item">
<div class="info-label">申请备注</div>
<div class="info-value"><{$refund_info.apply_remarks}></div>
</div>
<div class="info-item">
<div class="info-label">售后答复</div>
<div class="info-value"><{$refund_info.after_sales_reply}></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
// 商家协商页面JavaScript
window.MerchantNegotiation = window.MerchantNegotiation || {};
(function(){
var domId = 'merchant-negotiation-container';
var instanceId = domId;
// 初始化
function init() {
bindEvents();
setupFormValidation();
initEditMode();
}
// 初始化编辑模式
function initEditMode() {
var container = document.getElementById(domId);
if (!container) return;
// 初始化协商类型变化事件(显示/隐藏收货地址)
var negotiationType = container.querySelector('#negotiation_type');
if (negotiationType && negotiationType.value) {
toggleReturnAddress(negotiationType.value);
}
// 初始化建议原因文本
var suggestedReason = container.querySelector('#suggested_reason');
var suggestedReasonText = container.querySelector('#suggested_reason_text');
if (suggestedReason && suggestedReasonText && suggestedReason.value) {
var selectedOption = suggestedReason.options[suggestedReason.selectedIndex];
if (selectedOption && selectedOption.dataset.text) {
suggestedReasonText.value = selectedOption.dataset.text;
}
}
// 初始化收货地址文本
var returnAddress = container.querySelector('#return_address');
var returnAddressText = container.querySelector('#return_address_text');
if (returnAddress && returnAddressText && returnAddress.value) {
var selectedOption = returnAddress.options[returnAddress.selectedIndex];
if (selectedOption && selectedOption.dataset.text) {
returnAddressText.value = selectedOption.dataset.text;
}
}
}
// 绑定事件
function bindEvents() {
var container = document.getElementById(domId);
if (!container) return;
// 协商类型变化事件
var negotiationType = container.querySelector('#negotiation_type');
if (negotiationType) {
negotiationType.addEventListener('change', function() {
toggleReturnAddress(this.value);
});
}
// 建议原因变化事件
var suggestedReason = container.querySelector('#suggested_reason');
var suggestedReasonText = container.querySelector('#suggested_reason_text');
if (suggestedReason && suggestedReasonText) {
suggestedReason.addEventListener('change', function() {
var selectedOption = this.options[this.selectedIndex];
if (selectedOption && selectedOption.dataset.text) {
suggestedReasonText.value = selectedOption.dataset.text;
} else {
suggestedReasonText.value = '';
}
});
}
// 收货地址变化事件
var returnAddress = container.querySelector('#return_address');
var returnAddressText = container.querySelector('#return_address_text');
if (returnAddress && returnAddressText) {
returnAddress.addEventListener('change', function() {
var selectedOption = this.options[this.selectedIndex];
if (selectedOption && selectedOption.dataset.text) {
returnAddressText.value = selectedOption.dataset.text;
} else {
returnAddressText.value = '';
}
});
}
// 图片上传功能由 image_magnifier 组件自动处理
// 提交按钮事件
var submitBtn = container.querySelector('#submit_btn');
if (submitBtn) {
submitBtn.addEventListener('click', function() {
submitNegotiation();
});
}
// 取消按钮事件
var cancelBtn = container.querySelector('#cancel_btn');
if (cancelBtn) {
cancelBtn.addEventListener('click', function() {
cancelNegotiation();
});
}
}
// 切换退货地址显示
function toggleReturnAddress(negotiationType) {
var returnAddressGroup = document.getElementById('return_address_group');
// 需要退货地址的协商类型:协商售后信息-退货退款(17)、补发商品(9)
var needReturnAddress = [17, 9];
if (needReturnAddress.indexOf(parseInt(negotiationType)) !== -1) {
returnAddressGroup.style.display = 'block';
} else {
returnAddressGroup.style.display = 'none';
}
}
// 处理图片上传
// 图片上传功能由 image_magnifier 组件自动处理
// 表单验证
function setupFormValidation() {
var form = document.getElementById('negotiation-form');
if (!form) return;
form.addEventListener('submit', function(e) {
e.preventDefault();
if (validateForm()) {
submitNegotiation();
}
});
}
// 验证表单
function validateForm() {
var container = document.getElementById(domId);
var requiredFields = container.querySelectorAll('[required]');
var isValid = true;
requiredFields.forEach(function(field) {
if (!field.value.trim()) {
field.style.borderColor = '#dc3545';
isValid = false;
} else {
field.style.borderColor = '#ced4da';
}
});
// 验证退款金额
var amountField = document.getElementById('suggested_amount');
if (amountField) {
var amount = parseFloat(amountField.value);
var maxAmount = parseFloat(amountField.getAttribute('max')) || 100.30;
if (amount > maxAmount) {
alert('退款金额不能超过' + maxAmount + '元');
amountField.style.borderColor = '#dc3545';
isValid = false;
}
}
if (!isValid) {
alert('请填写所有必填字段');
}
return isValid;
}
// 提交协商
function submitNegotiation() {
if (!validateForm()) {
return;
}
// 显示加载状态
var submitBtn = document.getElementById('submit_btn');
var originalText = submitBtn.textContent;
submitBtn.textContent = '提交中...';
submitBtn.disabled = true;
// 使用form.store方式提交参考add.html的提交方式
var form = $('negotiation-form');
form.store('target', {
onRequest: function() {
submitBtn.textContent = '提交中...';
submitBtn.disabled = true;
},
onComplete: function(jsontext) {
try {
var json = JSON.decode(jsontext);
if (json.rsp == 'fail') {
// 提交失败 - 显示错误信息标签
showErrorMessage('提交失败: ' + (json.msg || '操作失败'));
submitBtn.textContent = originalText;
submitBtn.disabled = false;
} else {
// 提交成功 - 显示成功信息标签
showSuccessMessage('提交成功: ' + (json.msg || '操作成功'));
// 恢复按钮状态
submitBtn.textContent = originalText;
submitBtn.disabled = false;
// 延迟关闭弹窗,让用户看到成功信息
setTimeout(function() {
var container = document.getElementById(domId);
if (container) {
container.getParent('.dialog').retrieve('instance').close();
}
}, 1500);
}
} catch (e) {
showErrorMessage('提交失败: 响应格式错误');
submitBtn.textContent = originalText;
submitBtn.disabled = false;
}
}
});
// 直接提交表单
form.fireEvent('submit');
}
// 取消协商
function cancelNegotiation() {
if (confirm('确定要取消协商吗?')) {
// 关闭弹窗
var container = document.getElementById(domId);
if (container) {
container.getParent('.dialog').retrieve('instance').close();
}
}
}
// 显示错误信息
function showErrorMessage(message) {
// 隐藏成功信息
var successMsg = document.getElementById('success_message');
if (successMsg) {
successMsg.classList.remove('show');
}
// 显示错误信息
var errorMsg = document.getElementById('error_message');
if (errorMsg) {
errorMsg.textContent = message;
errorMsg.classList.add('show');
}
}
// 显示成功信息
function showSuccessMessage(message) {
// 隐藏错误信息
var errorMsg = document.getElementById('error_message');
if (errorMsg) {
errorMsg.classList.remove('show');
}
// 显示成功信息
var successMsg = document.getElementById('success_message');
if (successMsg) {
successMsg.textContent = message;
successMsg.classList.add('show');
}
}
// 将函数绑定到全局对象
window.MerchantNegotiation[instanceId] = {
submitNegotiation: submitNegotiation,
cancelNegotiation: cancelNegotiation,
validateForm: validateForm,
showErrorMessage: showErrorMessage,
showSuccessMessage: showSuccessMessage
};
// 立即执行初始化
init();
})();
// 使用domready事件作为备用初始化
window.addEvent('domready', function(e){
var container = document.getElementById('merchant-negotiation-container');
if (container && !container.hasAttribute('data-initialized')) {
container.setAttribute('data-initialized', 'true');
}
});
</script>