2343 lines
90 KiB
XML
2343 lines
90 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<odoo>
|
|
<template id="financial_form_template" name="Financial Form Template">
|
|
<style>
|
|
/* 财务表单CSS */
|
|
:root {
|
|
--primary-color: #3498db;
|
|
--primary-light: #e3f2fd;
|
|
--secondary-color: #6c757d;
|
|
--success-color: #2ecc71;
|
|
--warning-color: #f39c12;
|
|
--danger-color: #e74c3c;
|
|
--info-color: #17a2b8;
|
|
--light-bg: #f8f9fa;
|
|
--border-color: #dee2e6;
|
|
--card-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
--transition: all 0.3s ease;
|
|
--table-header-gradient: linear-gradient(135deg, var(--primary-color) 0%, #2980b9 100%);
|
|
}
|
|
|
|
/* 容器样式 */
|
|
.financial-form-container {
|
|
max-width: 1200px;
|
|
margin: 20px auto;
|
|
padding: 20px;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
}
|
|
|
|
/* 表单头部 */
|
|
.form-header {
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
padding: 25px;
|
|
background: var(--table-header-gradient);
|
|
border-radius: 12px;
|
|
color: white;
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.form-title {
|
|
font-size: 28px;
|
|
font-weight: 700;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.form-description {
|
|
font-size: 16px;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* 大项样式 */
|
|
.form-section {
|
|
background: white;
|
|
border-radius: 12px;
|
|
padding: 25px;
|
|
margin-bottom: 20px;
|
|
box-shadow: var(--card-shadow);
|
|
border-left: 4px solid var(--primary-color);
|
|
}
|
|
|
|
.section-header {
|
|
margin-bottom: 25px;
|
|
padding-bottom: 15px;
|
|
border-bottom: 2px solid var(--light-bg);
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
margin: 0;
|
|
}
|
|
|
|
/* 字段组样式 */
|
|
.section-fields {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 25px;
|
|
}
|
|
|
|
.field-group {
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
/* 字段标签样式 */
|
|
.field-label-row {
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.field-label {
|
|
display: block;
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
font-size: 16px;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.field-label .required {
|
|
color: var(--danger-color);
|
|
margin-left: 3px;
|
|
}
|
|
|
|
.field-help {
|
|
display: block;
|
|
margin-top: 5px;
|
|
font-size: 14px;
|
|
color: #7f8c8d;
|
|
font-style: italic;
|
|
}
|
|
|
|
/* 字段输入样式 */
|
|
.field-input-row {
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.form-control {
|
|
width: 100%;
|
|
padding: 12px 16px;
|
|
font-size: 16px;
|
|
line-height: 1.5;
|
|
color: #495057;
|
|
background-color: #fff;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 8px;
|
|
transition: var(--transition);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: var(--primary-color);
|
|
outline: none;
|
|
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
|
|
}
|
|
|
|
.form-control::placeholder {
|
|
color: #adb5bd;
|
|
}
|
|
|
|
/* 表格容器样式 */
|
|
.table-container {
|
|
background: white;
|
|
border-radius: 12px;
|
|
padding: 0;
|
|
margin: 25px 0;
|
|
box-shadow: var(--card-shadow);
|
|
border: 1px solid #e1e4e8;
|
|
overflow: hidden;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.table-container:hover {
|
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
|
|
}
|
|
|
|
.table-header {
|
|
background: var(--table-header-gradient);
|
|
padding: 20px 25px;
|
|
color: white;
|
|
}
|
|
|
|
.table-title-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.table-title {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.table-title .required {
|
|
color: #ffd700;
|
|
font-size: 20px;
|
|
}
|
|
|
|
.table-help-text {
|
|
font-size: 14px;
|
|
opacity: 0.9;
|
|
font-weight: normal;
|
|
}
|
|
|
|
.table-content {
|
|
padding: 25px;
|
|
}
|
|
|
|
.table-rows {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
}
|
|
|
|
.table-row {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 16px 0;
|
|
border-bottom: 1px solid #f0f2f5;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.table-row:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.table-row:hover {
|
|
background-color: #f8f9fa;
|
|
border-radius: 8px;
|
|
padding: 16px 20px;
|
|
margin: 0 -20px;
|
|
}
|
|
|
|
.table-label-cell {
|
|
flex: 0 0 200px;
|
|
padding-right: 30px;
|
|
min-width: 200px;
|
|
}
|
|
|
|
.table-label {
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
font-size: 15px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.table-label .required {
|
|
color: var(--danger-color);
|
|
font-size: 16px;
|
|
}
|
|
|
|
.table-column-help {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 18px;
|
|
height: 18px;
|
|
background: var(--light-bg);
|
|
color: var(--secondary-color);
|
|
border-radius: 50%;
|
|
font-size: 12px;
|
|
cursor: help;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.table-column-help:hover {
|
|
background: var(--primary-color);
|
|
color: white;
|
|
}
|
|
|
|
.table-input-cell {
|
|
flex: 1;
|
|
}
|
|
|
|
.table-input-wrapper {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.table-input {
|
|
width: 100%;
|
|
padding: 12px 16px;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 8px;
|
|
font-size: 15px;
|
|
transition: var(--transition);
|
|
background: white;
|
|
color: #4a5568;
|
|
}
|
|
|
|
.table-input:focus {
|
|
outline: none;
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.15);
|
|
}
|
|
|
|
.table-number-input {
|
|
padding-right: 50px;
|
|
}
|
|
|
|
.input-unit {
|
|
position: absolute;
|
|
right: 16px;
|
|
color: var(--secondary-color);
|
|
font-size: 14px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.table-select-wrapper {
|
|
position: relative;
|
|
}
|
|
|
|
.table-select-input {
|
|
appearance: none;
|
|
padding-right: 50px;
|
|
cursor: pointer;
|
|
background: white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'
|
|
fill='%234a5568' viewBox='0 0 16 16'%3E%3Cpath d='M7.247 11.14L2.451 5.658C1.885 5.013 2.345 4 3.204
|
|
4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/%3E%3C/svg%3E") no-repeat right 16px center;
|
|
background-size: 12px;
|
|
}
|
|
|
|
.select-arrow {
|
|
position: absolute;
|
|
right: 16px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
color: var(--secondary-color);
|
|
font-size: 12px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* 按钮容器 */
|
|
.button-container {
|
|
display: flex;
|
|
gap: 15px;
|
|
justify-content: center;
|
|
margin-top: 30px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.action-btn {
|
|
padding: 15px 30px;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
min-width: 160px;
|
|
justify-content: center;
|
|
}
|
|
|
|
.action-btn:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.action-btn:active {
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.btn-primary {
|
|
background: var(--table-header-gradient);
|
|
color: white;
|
|
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
box-shadow: 0 6px 16px rgba(52, 152, 219, 0.4);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: var(--secondary-color);
|
|
color: white;
|
|
}
|
|
|
|
.btn-warning {
|
|
background: var(--warning-color);
|
|
color: white;
|
|
}
|
|
|
|
.btn-danger {
|
|
background: var(--danger-color);
|
|
color: white;
|
|
}
|
|
|
|
/* 加载状态 */
|
|
.loading-container {
|
|
display: none;
|
|
text-align: center;
|
|
padding: 20px;
|
|
width: 100%;
|
|
}
|
|
|
|
.loading-spinner {
|
|
display: inline-block;
|
|
width: 24px;
|
|
height: 24px;
|
|
border: 3px solid rgba(52, 152, 219, 0.3);
|
|
border-radius: 50%;
|
|
border-top-color: var(--primary-color);
|
|
animation: spin 1s ease-in-out infinite;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
.loading-container p {
|
|
color: var(--secondary-color);
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* 成功提示 */
|
|
.success-message {
|
|
display: none;
|
|
background: linear-gradient(135deg, var(--success-color) 0%, #27ae60 100%);
|
|
color: white;
|
|
padding: 25px;
|
|
border-radius: 12px;
|
|
text-align: center;
|
|
margin: 20px 0;
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.success-message h3 {
|
|
font-size: 24px;
|
|
font-weight: 700;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.success-message p {
|
|
font-size: 16px;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* 错误提示 */
|
|
.error-message {
|
|
color: var(--danger-color);
|
|
font-size: 14px;
|
|
margin-top: 8px;
|
|
display: none;
|
|
padding: 10px 15px;
|
|
background: #fff5f5;
|
|
border: 1px solid #fc8181;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.field-error .form-control {
|
|
border-color: var(--danger-color);
|
|
}
|
|
|
|
.field-error .error-message {
|
|
display: block;
|
|
}
|
|
|
|
.table-error {
|
|
margin: 15px 25px 20px;
|
|
}
|
|
|
|
/* 下拉框样式 */
|
|
select.form-control {
|
|
appearance: none;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'
|
|
fill='%23333' viewBox='0 0 16 16'%3E%3Cpath d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1
|
|
1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/%3E%3C/svg%3E");
|
|
background-repeat: no-repeat;
|
|
background-position: right 16px center;
|
|
background-size: 12px;
|
|
padding-right: 40px;
|
|
}
|
|
|
|
/* 文本域样式 */
|
|
textarea.form-control {
|
|
min-height: 120px;
|
|
resize: vertical;
|
|
}
|
|
|
|
/* 动画效果 */
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(-10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.table-row {
|
|
animation: fadeIn 0.3s ease-out forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
.table-row:nth-child(1) { animation-delay: 0.1s; }
|
|
.table-row:nth-child(2) { animation-delay: 0.2s; }
|
|
.table-row:nth-child(3) { animation-delay: 0.3s; }
|
|
.table-row:nth-child(4) { animation-delay: 0.4s; }
|
|
.table-row:nth-child(5) { animation-delay: 0.5s; }
|
|
|
|
/* 响应式调整 */
|
|
@media (max-width: 768px) {
|
|
.financial-form-container {
|
|
padding: 15px;
|
|
}
|
|
|
|
.form-header {
|
|
padding: 20px;
|
|
}
|
|
|
|
.form-title {
|
|
font-size: 24px;
|
|
}
|
|
|
|
.form-section {
|
|
padding: 20px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 18px;
|
|
}
|
|
|
|
.table-row {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 10px;
|
|
padding: 20px 0;
|
|
}
|
|
|
|
.table-row:hover {
|
|
padding: 20px 15px;
|
|
margin: 0 -15px;
|
|
}
|
|
|
|
.table-label-cell {
|
|
flex: none;
|
|
width: 100%;
|
|
padding-right: 0;
|
|
min-width: auto;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.table-input-cell {
|
|
width: 100%;
|
|
}
|
|
|
|
.table-label {
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.button-container {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.action-btn {
|
|
width: 100%;
|
|
padding: 12px 20px;
|
|
}
|
|
|
|
.table-header {
|
|
padding: 15px 20px;
|
|
}
|
|
|
|
.table-content {
|
|
padding: 20px;
|
|
}
|
|
|
|
.table-rows {
|
|
gap: 15px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.form-title {
|
|
font-size: 22px;
|
|
}
|
|
|
|
.table-title {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.table-help-text {
|
|
font-size: 12px;
|
|
}
|
|
|
|
.table-label {
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div class="financial-form-container">
|
|
<!-- 表单头部 -->
|
|
<div class="form-header">
|
|
<h1 class="form-title">财务数据收集表</h1>
|
|
<p class="form-description">请根据实际情况填写以下财务数据</p>
|
|
</div>
|
|
<!-- 主表单 -->
|
|
<form id="financialForm" method="post" action="/financial/form/submit">
|
|
|
|
<!-- 动态生成大项 -->
|
|
<t t-foreach="form_config.get('sections', [])" t-as="section">
|
|
<div class="form-section" t-att-id="'section_' + section['id']">
|
|
<div class="section-header">
|
|
<h3 class="section-title" t-esc="section['label']"></h3>
|
|
</div>
|
|
|
|
<div class="section-fields">
|
|
<!-- 生成字段 -->
|
|
<t t-foreach="section.get('fields', [])" t-as="field">
|
|
<div class="field-group" t-att-id="'field_group_' + field['id']">
|
|
|
|
<t t-if="field['field_type'] in ['text', 'number', 'select', 'textarea']">
|
|
<!-- 第一行:标签 -->
|
|
<div class="field-label-row">
|
|
<label class="field-label" t-att-for="field['id']">
|
|
<span t-esc="field['label']"></span>
|
|
<t t-if="field.get('required', False)">
|
|
<span class="required">*</span>
|
|
</t>
|
|
</label>
|
|
|
|
<t t-if="field.get('help_text')">
|
|
<small class="field-help" t-esc="field.get('help_text')"></small>
|
|
</t>
|
|
</div>
|
|
|
|
<!-- 第二行:输入框 -->
|
|
<div class="field-input-row">
|
|
<!-- 文本字段 -->
|
|
<t t-if="field['field_type'] == 'text'">
|
|
<span t-if="field.get('readonly', False)"
|
|
t-esc="field.get('value', '')"></span>
|
|
<input t-else="not field.get('readonly', False)" t-att-id="field['id']"
|
|
t-att-name="field['id']"
|
|
type="text" class="form-control text-field"
|
|
t-att-placeholder="field.get('placeholder', '')"
|
|
t-att-maxlength="field.get('max_length', 100)"
|
|
t-att-required="'required' if field.get('required', False) else None"
|
|
t-att-readonly="field.get('readonly', False)"
|
|
t-att-value="field.get('value', '')"
|
|
/>
|
|
</t>
|
|
|
|
<!-- 数字字段 -->
|
|
<t t-elif="field['field_type'] == 'number'">
|
|
<span t-if="field.get('readonly', False)"
|
|
t-esc="field.get('value', '')"></span>
|
|
<input t-else="not field.get('readonly', False)" t-att-id="field['id']"
|
|
t-att-name="field['id']"
|
|
type="number" class="form-control number-field"
|
|
t-att-placeholder="field.get('placeholder', '')"
|
|
t-att-min="field.get('min_value', 0)"
|
|
t-att-step="field.get('step', 'any')"
|
|
t-att-required="'required' if field.get('required', False) else None"
|
|
t-att-readonly="field.get('readonly', False)"
|
|
t-att-value="field.get('value', '')"
|
|
/>
|
|
</t>
|
|
|
|
<!-- 下拉框 -->
|
|
<t t-elif="field['field_type'] == 'select'">
|
|
<!-- 下拉框模板 -->
|
|
<div class="form-group">
|
|
<t t-if="field.get('readonly', False)">
|
|
<p class="form-control-static">
|
|
<t t-esc="field.get('display_value', field.get('value', ''))"/>
|
|
</p>
|
|
<input type="hidden" t-att-name="field['id']"
|
|
t-att-value="field.get('value', '')"/>
|
|
</t>
|
|
<t t-else="">
|
|
<select t-att-name="field['id']" class="form-control"
|
|
t-att-required="field.get('required', False)">
|
|
<option value="">
|
|
<t t-esc="field.get('placeholder', '请选择')"/>
|
|
</option>
|
|
<t t-foreach="field.get('options', [])" t-as="opt">
|
|
<option t-att-value="opt.value"
|
|
t-attf-selected="{{ 'selected' if opt.value == field.get('value') else '' }}">
|
|
<t t-esc="opt.label"/>
|
|
</option>
|
|
</t>
|
|
</select>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- 多行文本 -->
|
|
<t t-elif="field['field_type'] == 'textarea'">
|
|
<textarea t-att-id="field['id']" t-att-name="field['id']"
|
|
class="form-control textarea-field"
|
|
t-att-placeholder="field.get('placeholder', '')"
|
|
t-att-rows="field.get('rows', 4)"
|
|
t-att-maxlength="field.get('max_length', 500)"
|
|
t-att-required="'required' if field.get('required', False) else None"
|
|
t-att-readonly="field.get('readonly', False)"
|
|
>
|
|
<t t-esc="field.get('value', '')"/>
|
|
</textarea>
|
|
</t>
|
|
</div>
|
|
|
|
<!-- 错误提示 -->
|
|
<div t-att-id="'error_' + field['id']" class="error-message"></div>
|
|
</t>
|
|
|
|
<t t-elif="field['field_type'] == 'table'">
|
|
<div class="table-container">
|
|
<div class="table-header">
|
|
<div class="table-title-row">
|
|
<h4 class="table-title" t-esc="field['label']">
|
|
<t t-if="field.get('required', False)">
|
|
<span class="required">*</span>
|
|
</t>
|
|
</h4>
|
|
<t t-if="field.get('help_text')">
|
|
<small class="table-help-text"
|
|
t-esc="field.get('help_text')"></small>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-content">
|
|
<!-- 先获取列配置 -->
|
|
<t t-set="columns" t-value="field['table_config']['columns']"/>
|
|
|
|
<div class="table-rows">
|
|
<t t-foreach="columns" t-as="col">
|
|
<div class="table-row" t-att-data-column="col['name']">
|
|
<!-- 左列:标签 -->
|
|
<div class="table-label-cell">
|
|
<label t-att-for="field['id'] + '_' + col['name']"
|
|
class="table-label">
|
|
<span t-esc="col['label']"></span>
|
|
<t t-if="col.get('required', False)">
|
|
<span class="required">*</span>
|
|
</t>
|
|
<t t-if="col.get('help_text')">
|
|
<span class="table-column-help"
|
|
t-att-title="col.get('help_text')">?
|
|
</span>
|
|
</t>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- 右列:输入框 -->
|
|
<div class="table-input-cell">
|
|
<!-- 数字输入框 -->
|
|
<t t-if="col['type'] == 'number'">
|
|
<div class="table-input-wrapper">
|
|
<input type="number"
|
|
t-att-id="field['id'] + '_' + col['name']"
|
|
t-att-name="field['id'] + '[' + col['name'] + ']'"
|
|
class="form-control table-input table-number-input"
|
|
t-att-min="col.get('min_value', 0)"
|
|
step="any"
|
|
t-att-placeholder="col.get('placeholder', '')"
|
|
t-att-required="'required' if col.get('required', False) else None"/>
|
|
<t t-if="col.get('unit')">
|
|
<span class="input-unit"
|
|
t-esc="col.get('unit')"></span>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- 文本输入框 -->
|
|
<t t-elif="col['type'] == 'text'">
|
|
<input type="text"
|
|
t-att-id="field['id'] + '_' + col['name']"
|
|
t-att-name="field['id'] + '[' + col['name'] + ']'"
|
|
class="form-control table-input table-text-input"
|
|
t-att-placeholder="col.get('placeholder', '')"
|
|
t-att-maxlength="col.get('max_length', 100)"
|
|
t-att-required="'required' if col.get('required', False) else None"/>
|
|
</t>
|
|
|
|
<!-- 下拉框 -->
|
|
<t t-elif="col['type'] == 'select'">
|
|
<div class="table-select-wrapper">
|
|
<select t-att-id="field['id'] + '_' + col['name']"
|
|
t-att-name="field['id'] + '[' + col['name'] + ']'"
|
|
class="form-control table-input table-select-input"
|
|
t-att-required="'required' if col.get('required', False) else None">
|
|
<option value=""
|
|
t-esc="col.get('placeholder', '请选择')"></option>
|
|
<t t-if="col.get('options_source')">
|
|
<t t-set="options_source"
|
|
t-value="col.get('options_source')"/>
|
|
<t t-foreach="dropdown_options.get(options_source, [])"
|
|
t-as="option">
|
|
<option t-att-value="option['value']"
|
|
t-esc="option['label']"></option>
|
|
</t>
|
|
</t>
|
|
</select>
|
|
<span class="select-arrow">▼</span>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 表格错误提示 -->
|
|
<div t-att-id="'error_' + field['id']"
|
|
class="error-message table-error"></div>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
|
|
<div class="btn-section">
|
|
<div class="btn-wrapper">
|
|
<button type="submit" id="submit_form" class="modern-submit-btn"
|
|
onclick="submitFinancialForm()">
|
|
<span class="btn-content">
|
|
<svg class="btn-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
|
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
|
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
|
</svg>
|
|
<span class="btn-text">提交财务数据</span>
|
|
</span>
|
|
<span class="btn-shimmer"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<style>
|
|
/* 彻底重置原有按钮样式 */
|
|
#submit_form,
|
|
#submit_form.action-btn,
|
|
#submit_form.btn-primary,
|
|
.action-btn,
|
|
.btn-primary,
|
|
.button-container button,
|
|
.button-container .action-btn,
|
|
.button-container .btn-primary {
|
|
all: unset !important;
|
|
box-sizing: border-box !important;
|
|
}
|
|
|
|
/* 移除原有按钮容器样式 */
|
|
.button-container {
|
|
display: none !important;
|
|
}
|
|
|
|
/* 新的按钮区域样式 */
|
|
.btn-section {
|
|
display: flex !important;
|
|
justify-content: center !important;
|
|
align-items: center !important;
|
|
margin: 50px 0 30px !important;
|
|
padding: 40px 0 !important;
|
|
width: 100% !important;
|
|
position: relative !important;
|
|
background: linear-gradient(to bottom,
|
|
transparent 0%,
|
|
rgba(52, 152, 219, 0.03) 50%,
|
|
transparent 100%) !important;
|
|
overflow: hidden !important;
|
|
}
|
|
|
|
.btn-section::before {
|
|
content: '' !important;
|
|
position: absolute !important;
|
|
top: 0 !important;
|
|
left: 50% !important;
|
|
transform: translateX(-50%) !important;
|
|
width: 80% !important;
|
|
height: 1px !important;
|
|
background: linear-gradient(to right,
|
|
transparent 0%,
|
|
rgba(52, 152, 219, 0.3) 50%,
|
|
transparent 100%) !important;
|
|
}
|
|
|
|
.btn-section::after {
|
|
content: '' !important;
|
|
position: absolute !important;
|
|
bottom: 0 !important;
|
|
left: 50% !important;
|
|
transform: translateX(-50%) !important;
|
|
width: 60% !important;
|
|
height: 1px !important;
|
|
background: linear-gradient(to right,
|
|
transparent 0%,
|
|
rgba(52, 152, 219, 0.2) 50%,
|
|
transparent 100%) !important;
|
|
}
|
|
|
|
.btn-wrapper {
|
|
display: flex !important;
|
|
justify-content: center !important;
|
|
align-items: center !important;
|
|
padding: 20px !important;
|
|
position: relative !important;
|
|
z-index: 10 !important;
|
|
}
|
|
|
|
/* 现代按钮样式 - 高优先级 */
|
|
#submit_form.modern-submit-btn,
|
|
.modern-submit-btn {
|
|
position: relative !important;
|
|
padding: 18px 50px !important;
|
|
border: none !important;
|
|
border-radius: 16px !important;
|
|
font-size: 18px !important;
|
|
font-weight: 700 !important;
|
|
cursor: pointer !important;
|
|
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important;
|
|
display: inline-flex !important;
|
|
align-items: center !important;
|
|
justify-content: center !important;
|
|
gap: 15px !important;
|
|
min-width: 220px !important;
|
|
overflow: hidden !important;
|
|
box-shadow:
|
|
0 8px 32px rgba(52, 152, 219, 0.3),
|
|
0 4px 12px rgba(0, 0, 0, 0.1),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
|
|
z-index: 1 !important;
|
|
color: white !important;
|
|
text-align: center !important;
|
|
line-height: 1.5 !important;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
|
letter-spacing: 0.5px !important;
|
|
text-transform: none !important;
|
|
outline: none !important;
|
|
text-decoration: none !important;
|
|
background: linear-gradient(135deg,
|
|
#3498db 0%,
|
|
#2980b9 25%,
|
|
#2c80b9 50%,
|
|
#2980b9 75%,
|
|
#3498db 100%) !important;
|
|
background-size: 200% 200% !important;
|
|
}
|
|
|
|
.modern-submit-btn::before {
|
|
content: '' !important;
|
|
position: absolute !important;
|
|
top: 0 !important;
|
|
left: -100% !important;
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
background: linear-gradient(90deg,
|
|
transparent,
|
|
rgba(255, 255, 255, 0.3),
|
|
transparent) !important;
|
|
transition: left 0.8s ease !important;
|
|
z-index: 1 !important;
|
|
}
|
|
|
|
.modern-submit-btn:hover {
|
|
transform: translateY(-6px) scale(1.03) !important;
|
|
box-shadow:
|
|
0 20px 50px rgba(52, 152, 219, 0.4),
|
|
0 10px 30px rgba(0, 0, 0, 0.15),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
|
|
background-position: 100% 100% !important;
|
|
color: white !important;
|
|
}
|
|
|
|
.modern-submit-btn:hover::before {
|
|
left: 100% !important;
|
|
}
|
|
|
|
.modern-submit-btn:active {
|
|
transform: translateY(-2px) scale(1.01) !important;
|
|
box-shadow:
|
|
0 10px 30px rgba(52, 152, 219, 0.3),
|
|
0 5px 15px rgba(0, 0, 0, 0.1),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
|
|
}
|
|
|
|
.btn-content {
|
|
display: flex !important;
|
|
align-items: center !important;
|
|
justify-content: center !important;
|
|
gap: 12px !important;
|
|
position: relative !important;
|
|
z-index: 2 !important;
|
|
}
|
|
|
|
.btn-icon {
|
|
width: 20px !important;
|
|
height: 20px !important;
|
|
stroke: currentColor !important;
|
|
stroke-width: 2.5px !important;
|
|
transition: transform 0.4s ease !important;
|
|
flex-shrink: 0 !important;
|
|
}
|
|
|
|
.modern-submit-btn:hover .btn-icon {
|
|
transform: translateX(8px) rotate(5deg) !important;
|
|
}
|
|
|
|
.btn-text {
|
|
position: relative !important;
|
|
z-index: 2 !important;
|
|
white-space: nowrap !important;
|
|
}
|
|
|
|
.btn-shimmer {
|
|
position: absolute !important;
|
|
top: -2px !important;
|
|
left: -2px !important;
|
|
right: -2px !important;
|
|
bottom: -2px !important;
|
|
background: linear-gradient(45deg,
|
|
transparent 30%,
|
|
rgba(255, 255, 255, 0.2) 50%,
|
|
transparent 70%) !important;
|
|
border-radius: 18px !important;
|
|
z-index: 0 !important;
|
|
opacity: 0 !important;
|
|
transition: opacity 0.3s ease !important;
|
|
}
|
|
|
|
.modern-submit-btn:hover .btn-shimmer {
|
|
opacity: 1 !important;
|
|
animation: shimmer 1.5s ease-in-out infinite !important;
|
|
}
|
|
|
|
@keyframes shimmer {
|
|
0% {
|
|
transform: translateX(-100%) !important;
|
|
}
|
|
100% {
|
|
transform: translateX(100%) !important;
|
|
}
|
|
}
|
|
|
|
/* 点击波纹效果 */
|
|
.ripple-effect {
|
|
position: absolute !important;
|
|
border-radius: 50% !important;
|
|
background: rgba(255, 255, 255, 0.6) !important;
|
|
transform: scale(0) !important;
|
|
animation: ripple 0.8s linear !important;
|
|
pointer-events: none !important;
|
|
z-index: 1 !important;
|
|
}
|
|
|
|
@keyframes ripple {
|
|
to {
|
|
transform: scale(4) !important;
|
|
opacity: 0 !important;
|
|
}
|
|
}
|
|
|
|
/* 响应式调整 */
|
|
@media (max-width: 768px) {
|
|
.btn-section {
|
|
margin: 30px 0 20px !important;
|
|
padding: 30px 0 !important;
|
|
}
|
|
|
|
.modern-submit-btn {
|
|
padding: 16px 35px !important;
|
|
font-size: 16px !important;
|
|
min-width: 200px !important;
|
|
gap: 10px !important;
|
|
}
|
|
|
|
.btn-icon {
|
|
width: 18px !important;
|
|
height: 18px !important;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.modern-submit-btn {
|
|
padding: 14px 30px !important;
|
|
font-size: 15px !important;
|
|
min-width: 180px !important;
|
|
gap: 8px !important;
|
|
border-radius: 14px !important;
|
|
}
|
|
|
|
.btn-content {
|
|
gap: 8px !important;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
// 确保在DOM完全加载后添加事件
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const submitBtn = document.getElementById('submit_form');
|
|
|
|
if (submitBtn) {
|
|
// 移除所有可能冲突的类名
|
|
submitBtn.classList.remove('action-btn', 'btn-primary');
|
|
|
|
// 添加点击波纹效果
|
|
submitBtn.addEventListener('click', function(e) {
|
|
// 移除已有的波纹效果
|
|
const existingRipples = this.querySelectorAll('.ripple-effect');
|
|
existingRipples.forEach(ripple => ripple.remove());
|
|
|
|
// 创建新的波纹效果
|
|
const ripple = document.createElement('span');
|
|
ripple.className = 'ripple-effect';
|
|
|
|
const rect = this.getBoundingClientRect();
|
|
const size = Math.max(rect.width, rect.height);
|
|
const x = e.clientX - rect.left - size / 2;
|
|
const y = e.clientY - rect.top - size / 2;
|
|
|
|
ripple.style.width = ripple.style.height = size + 'px';
|
|
ripple.style.left = x + 'px';
|
|
ripple.style.top = y + 'px';
|
|
|
|
this.appendChild(ripple);
|
|
|
|
// 动画结束后移除元素
|
|
setTimeout(() => {
|
|
if (ripple.parentNode === this) {
|
|
this.removeChild(ripple);
|
|
}
|
|
}, 800);
|
|
});
|
|
|
|
// 添加键盘支持
|
|
submitBtn.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
this.click();
|
|
}
|
|
});
|
|
|
|
// 添加焦点样式
|
|
submitBtn.addEventListener('focus', function() {
|
|
this.style.outline = '2px solid rgba(52, 152, 219, 0.5)';
|
|
this.style.outlineOffset = '4px';
|
|
});
|
|
|
|
submitBtn.addEventListener('blur', function() {
|
|
this.style.outline = 'none';
|
|
});
|
|
}
|
|
});
|
|
|
|
// 如果你的页面已经加载完成,也可以直接执行
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initButton);
|
|
} else {
|
|
initButton();
|
|
}
|
|
|
|
function initButton() {
|
|
const submitBtn = document.getElementById('submit_form');
|
|
if (submitBtn) {
|
|
// 确保按钮有正确的类名
|
|
if (!submitBtn.classList.contains('modern-submit-btn')) {
|
|
submitBtn.classList.add('modern-submit-btn');
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</template>
|
|
|
|
<template id="information_form_template" name="Information Form Template">
|
|
<style>
|
|
/* 财务表单CSS */
|
|
:root {
|
|
--primary-color: #3498db;
|
|
--primary-light: #e3f2fd;
|
|
--secondary-color: #6c757d;
|
|
--success-color: #2ecc71;
|
|
--warning-color: #f39c12;
|
|
--danger-color: #e74c3c;
|
|
--info-color: #17a2b8;
|
|
--light-bg: #f8f9fa;
|
|
--border-color: #dee2e6;
|
|
--card-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
--transition: all 0.3s ease;
|
|
--table-header-gradient: linear-gradient(135deg, var(--primary-color) 0%, #2980b9 100%);
|
|
}
|
|
|
|
/* 容器样式 */
|
|
.financial-form-container {
|
|
max-width: 1200px;
|
|
margin: 20px auto;
|
|
padding: 20px;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
}
|
|
|
|
/* 表单头部 */
|
|
.form-header {
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
padding: 25px;
|
|
background: var(--table-header-gradient);
|
|
border-radius: 12px;
|
|
color: white;
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.form-title {
|
|
font-size: 28px;
|
|
font-weight: 700;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.form-description {
|
|
font-size: 16px;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* 大项样式 */
|
|
.form-section {
|
|
background: white;
|
|
border-radius: 12px;
|
|
padding: 25px;
|
|
margin-bottom: 20px;
|
|
box-shadow: var(--card-shadow);
|
|
border-left: 4px solid var(--primary-color);
|
|
}
|
|
|
|
.section-header {
|
|
margin-bottom: 25px;
|
|
padding-bottom: 15px;
|
|
border-bottom: 2px solid var(--light-bg);
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
margin: 0;
|
|
}
|
|
|
|
/* 字段组样式 */
|
|
.section-fields {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 25px;
|
|
}
|
|
|
|
.field-group {
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
/* 字段标签样式 */
|
|
.field-label-row {
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.field-label {
|
|
display: block;
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
font-size: 16px;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.field-label .required {
|
|
color: var(--danger-color);
|
|
margin-left: 3px;
|
|
}
|
|
|
|
.field-help {
|
|
display: block;
|
|
margin-top: 5px;
|
|
font-size: 14px;
|
|
color: #7f8c8d;
|
|
font-style: italic;
|
|
}
|
|
|
|
/* 字段输入样式 */
|
|
.field-input-row {
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.form-control {
|
|
width: 100%;
|
|
padding: 12px 16px;
|
|
font-size: 16px;
|
|
line-height: 1.5;
|
|
color: #495057;
|
|
background-color: #fff;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 8px;
|
|
transition: var(--transition);
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: var(--primary-color);
|
|
outline: none;
|
|
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1);
|
|
}
|
|
|
|
.form-control::placeholder {
|
|
color: #adb5bd;
|
|
}
|
|
|
|
/* 表格容器样式 */
|
|
.table-container {
|
|
background: white;
|
|
border-radius: 12px;
|
|
padding: 0;
|
|
margin: 25px 0;
|
|
box-shadow: var(--card-shadow);
|
|
border: 1px solid #e1e4e8;
|
|
overflow: hidden;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.table-container:hover {
|
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
|
|
}
|
|
|
|
.table-header {
|
|
background: var(--table-header-gradient);
|
|
padding: 20px 25px;
|
|
color: white;
|
|
}
|
|
|
|
.table-title-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.table-title {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.table-title .required {
|
|
color: #ffd700;
|
|
font-size: 20px;
|
|
}
|
|
|
|
.table-help-text {
|
|
font-size: 14px;
|
|
opacity: 0.9;
|
|
font-weight: normal;
|
|
}
|
|
|
|
.table-content {
|
|
padding: 25px;
|
|
}
|
|
|
|
.table-rows {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
}
|
|
|
|
.table-row {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 16px 0;
|
|
border-bottom: 1px solid #f0f2f5;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.table-row:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.table-row:hover {
|
|
background-color: #f8f9fa;
|
|
border-radius: 8px;
|
|
padding: 16px 20px;
|
|
margin: 0 -20px;
|
|
}
|
|
|
|
.table-label-cell {
|
|
flex: 0 0 200px;
|
|
padding-right: 30px;
|
|
min-width: 200px;
|
|
}
|
|
|
|
.table-label {
|
|
font-weight: 600;
|
|
color: #2c3e50;
|
|
font-size: 15px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.table-label .required {
|
|
color: var(--danger-color);
|
|
font-size: 16px;
|
|
}
|
|
|
|
.table-column-help {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 18px;
|
|
height: 18px;
|
|
background: var(--light-bg);
|
|
color: var(--secondary-color);
|
|
border-radius: 50%;
|
|
font-size: 12px;
|
|
cursor: help;
|
|
transition: var(--transition);
|
|
}
|
|
|
|
.table-column-help:hover {
|
|
background: var(--primary-color);
|
|
color: white;
|
|
}
|
|
|
|
.table-input-cell {
|
|
flex: 1;
|
|
}
|
|
|
|
.table-input-wrapper {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.table-input {
|
|
width: 100%;
|
|
padding: 12px 16px;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 8px;
|
|
font-size: 15px;
|
|
transition: var(--transition);
|
|
background: white;
|
|
color: #4a5568;
|
|
}
|
|
|
|
.table-input:focus {
|
|
outline: none;
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.15);
|
|
}
|
|
|
|
.table-number-input {
|
|
padding-right: 50px;
|
|
}
|
|
|
|
.input-unit {
|
|
position: absolute;
|
|
right: 16px;
|
|
color: var(--secondary-color);
|
|
font-size: 14px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.table-select-wrapper {
|
|
position: relative;
|
|
}
|
|
|
|
.table-select-input {
|
|
appearance: none;
|
|
padding-right: 50px;
|
|
cursor: pointer;
|
|
background: white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'
|
|
fill='%234a5568' viewBox='0 0 16 16'%3E%3Cpath d='M7.247 11.14L2.451 5.658C1.885 5.013 2.345 4 3.204
|
|
4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/%3E%3C/svg%3E") no-repeat right 16px center;
|
|
background-size: 12px;
|
|
}
|
|
|
|
.select-arrow {
|
|
position: absolute;
|
|
right: 16px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
color: var(--secondary-color);
|
|
font-size: 12px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* 按钮容器 */
|
|
.button-container {
|
|
display: flex;
|
|
gap: 15px;
|
|
justify-content: center;
|
|
margin-top: 30px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.action-btn {
|
|
padding: 15px 30px;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: var(--transition);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
min-width: 160px;
|
|
justify-content: center;
|
|
}
|
|
|
|
.action-btn:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.action-btn:active {
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.btn-primary {
|
|
background: var(--table-header-gradient);
|
|
color: white;
|
|
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
box-shadow: 0 6px 16px rgba(52, 152, 219, 0.4);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: var(--secondary-color);
|
|
color: white;
|
|
}
|
|
|
|
.btn-warning {
|
|
background: var(--warning-color);
|
|
color: white;
|
|
}
|
|
|
|
.btn-danger {
|
|
background: var(--danger-color);
|
|
color: white;
|
|
}
|
|
|
|
/* 加载状态 */
|
|
.loading-container {
|
|
display: none;
|
|
text-align: center;
|
|
padding: 20px;
|
|
width: 100%;
|
|
}
|
|
|
|
.loading-spinner {
|
|
display: inline-block;
|
|
width: 24px;
|
|
height: 24px;
|
|
border: 3px solid rgba(52, 152, 219, 0.3);
|
|
border-radius: 50%;
|
|
border-top-color: var(--primary-color);
|
|
animation: spin 1s ease-in-out infinite;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
.loading-container p {
|
|
color: var(--secondary-color);
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* 成功提示 */
|
|
.success-message {
|
|
display: none;
|
|
background: linear-gradient(135deg, var(--success-color) 0%, #27ae60 100%);
|
|
color: white;
|
|
padding: 25px;
|
|
border-radius: 12px;
|
|
text-align: center;
|
|
margin: 20px 0;
|
|
box-shadow: var(--card-shadow);
|
|
}
|
|
|
|
.success-message h3 {
|
|
font-size: 24px;
|
|
font-weight: 700;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.success-message p {
|
|
font-size: 16px;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* 错误提示 */
|
|
.error-message {
|
|
color: var(--danger-color);
|
|
font-size: 14px;
|
|
margin-top: 8px;
|
|
display: none;
|
|
padding: 10px 15px;
|
|
background: #fff5f5;
|
|
border: 1px solid #fc8181;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.field-error .form-control {
|
|
border-color: var(--danger-color);
|
|
}
|
|
|
|
.field-error .error-message {
|
|
display: block;
|
|
}
|
|
|
|
.table-error {
|
|
margin: 15px 25px 20px;
|
|
}
|
|
|
|
/* 下拉框样式 */
|
|
select.form-control {
|
|
appearance: none;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12'
|
|
fill='%23333' viewBox='0 0 16 16'%3E%3Cpath d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1
|
|
1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/%3E%3C/svg%3E");
|
|
background-repeat: no-repeat;
|
|
background-position: right 16px center;
|
|
background-size: 12px;
|
|
padding-right: 40px;
|
|
}
|
|
|
|
/* 文本域样式 */
|
|
textarea.form-control {
|
|
min-height: 120px;
|
|
resize: vertical;
|
|
}
|
|
|
|
/* 动画效果 */
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(-10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.table-row {
|
|
animation: fadeIn 0.3s ease-out forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
.table-row:nth-child(1) { animation-delay: 0.1s; }
|
|
.table-row:nth-child(2) { animation-delay: 0.2s; }
|
|
.table-row:nth-child(3) { animation-delay: 0.3s; }
|
|
.table-row:nth-child(4) { animation-delay: 0.4s; }
|
|
.table-row:nth-child(5) { animation-delay: 0.5s; }
|
|
|
|
/* 响应式调整 */
|
|
@media (max-width: 768px) {
|
|
.financial-form-container {
|
|
padding: 15px;
|
|
}
|
|
|
|
.form-header {
|
|
padding: 20px;
|
|
}
|
|
|
|
.form-title {
|
|
font-size: 24px;
|
|
}
|
|
|
|
.form-section {
|
|
padding: 20px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 18px;
|
|
}
|
|
|
|
.table-row {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 10px;
|
|
padding: 20px 0;
|
|
}
|
|
|
|
.table-row:hover {
|
|
padding: 20px 15px;
|
|
margin: 0 -15px;
|
|
}
|
|
|
|
.table-label-cell {
|
|
flex: none;
|
|
width: 100%;
|
|
padding-right: 0;
|
|
min-width: auto;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.table-input-cell {
|
|
width: 100%;
|
|
}
|
|
|
|
.table-label {
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.button-container {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.action-btn {
|
|
width: 100%;
|
|
padding: 12px 20px;
|
|
}
|
|
|
|
.table-header {
|
|
padding: 15px 20px;
|
|
}
|
|
|
|
.table-content {
|
|
padding: 20px;
|
|
}
|
|
|
|
.table-rows {
|
|
gap: 15px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.form-title {
|
|
font-size: 22px;
|
|
}
|
|
|
|
.table-title {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.table-help-text {
|
|
font-size: 12px;
|
|
}
|
|
|
|
.table-label {
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<div class="financial-form-container">
|
|
<!-- 表单头部 -->
|
|
<div class="form-header">
|
|
<h1 class="form-title">财务数据收集表</h1>
|
|
<p class="form-description">请根据实际情况填写以下财务数据</p>
|
|
</div>
|
|
<!-- 主表单 -->
|
|
<form id="financialForm" method="post" action="/information/form/submit">
|
|
|
|
<!-- 动态生成大项 -->
|
|
<t t-foreach="form_config.get('sections', [])" t-as="section">
|
|
<div class="form-section" t-att-id="'section_' + section['id']">
|
|
<div class="section-header">
|
|
<h3 class="section-title" t-esc="section['label']"></h3>
|
|
</div>
|
|
|
|
<div class="section-fields">
|
|
<!-- 生成字段 -->
|
|
<t t-foreach="section.get('fields', [])" t-as="field">
|
|
<div class="field-group" t-att-id="'field_group_' + field['id']">
|
|
|
|
<t t-if="field['field_type'] in ['text', 'number', 'select', 'textarea']">
|
|
<!-- 第一行:标签 -->
|
|
<div class="field-label-row">
|
|
<label class="field-label" t-att-for="field['id']">
|
|
<span t-esc="field['label']"></span>
|
|
<t t-if="field.get('required', False)">
|
|
<span class="required">*</span>
|
|
</t>
|
|
</label>
|
|
|
|
<t t-if="field.get('help_text')">
|
|
<small class="field-help" t-esc="field.get('help_text')"></small>
|
|
</t>
|
|
</div>
|
|
|
|
<!-- 第二行:输入框 -->
|
|
<div class="field-input-row">
|
|
<!-- 文本字段 -->
|
|
<t t-if="field['field_type'] == 'text'">
|
|
<input t-att-id="field['id']" t-att-name="field['id']"
|
|
type="text" class="form-control text-field"
|
|
t-att-placeholder="field.get('placeholder', '')"
|
|
t-att-maxlength="field.get('max_length', 100)"
|
|
t-att-required="'required' if field.get('required', False) else None"
|
|
t-att-readonly="field.get('readonly', False)"
|
|
t-att-value="field.get('value', '')"
|
|
/>
|
|
</t>
|
|
|
|
<!-- 数字字段 -->
|
|
<t t-elif="field['field_type'] == 'number'">
|
|
<input t-att-id="field['id']" t-att-name="field['id']"
|
|
type="number" class="form-control number-field"
|
|
t-att-placeholder="field.get('placeholder', '')"
|
|
t-att-min="field.get('min_value', 0)"
|
|
t-att-step="field.get('step', 'any')"
|
|
t-att-required="'required' if field.get('required', False) else None"
|
|
t-att-readonly="field.get('readonly', False)"
|
|
t-att-value="field.get('value', '')"
|
|
/>
|
|
</t>
|
|
|
|
<!-- 下拉框 -->
|
|
<t t-elif="field['field_type'] == 'select'">
|
|
<div class="form-group">
|
|
<t t-if="field.get('readonly', False)">
|
|
<p class="form-control-static">
|
|
<t t-esc="field.get('display_value', field.get('value', ''))"/>
|
|
</p>
|
|
<input type="hidden" t-att-name="field['id']"
|
|
t-att-value="field.get('value', '')"/>
|
|
</t>
|
|
<t t-else="">
|
|
<select t-att-name="field['id']" class="form-control"
|
|
t-att-required="field.get('required', False)">
|
|
<option value="">
|
|
<t t-esc="field.get('placeholder', '请选择')"/>
|
|
</option>
|
|
<t t-foreach="field.get('options', [])" t-as="opt">
|
|
<option t-att-value="opt.value"
|
|
t-attf-selected="{{ 'selected' if opt.value == field.get('value') else '' }}">
|
|
<t t-esc="opt.label"/>
|
|
</option>
|
|
</t>
|
|
</select>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- 多行文本 -->
|
|
<t t-elif="field['field_type'] == 'textarea'">
|
|
<textarea t-att-id="field['id']" t-att-name="field['id']"
|
|
class="form-control textarea-field"
|
|
t-att-placeholder="field.get('placeholder', '')"
|
|
t-att-rows="field.get('rows', 4)"
|
|
t-att-maxlength="field.get('max_length', 500)"
|
|
t-att-required="'required' if field.get('required', False) else None"
|
|
t-att-readonly="field.get('readonly', False)"
|
|
>
|
|
<t t-esc="field.get('value', '')"/>
|
|
</textarea>
|
|
</t>
|
|
</div>
|
|
|
|
<!-- 错误提示 -->
|
|
<div t-att-id="'error_' + field['id']" class="error-message"></div>
|
|
</t>
|
|
|
|
<t t-elif="field['field_type'] == 'table'">
|
|
<div class="table-container">
|
|
<div class="table-header">
|
|
<div class="table-title-row">
|
|
<h4 class="table-title" t-esc="field['label']">
|
|
<t t-if="field.get('required', False)">
|
|
<span class="required">*</span>
|
|
</t>
|
|
</h4>
|
|
<t t-if="field.get('help_text')">
|
|
<small class="table-help-text"
|
|
t-esc="field.get('help_text')"></small>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-content">
|
|
<!-- 先获取列配置 -->
|
|
<t t-set="columns" t-value="field['table_config']['columns']"/>
|
|
|
|
<div class="table-rows">
|
|
<t t-foreach="columns" t-as="col">
|
|
<div class="table-row" t-att-data-column="col['name']">
|
|
<!-- 左列:标签 -->
|
|
<div class="table-label-cell">
|
|
<label t-att-for="field['id'] + '_' + col['name']"
|
|
class="table-label">
|
|
<span t-esc="col['label']"></span>
|
|
<t t-if="col.get('required', False)">
|
|
<span class="required">*</span>
|
|
</t>
|
|
<t t-if="col.get('help_text')">
|
|
<span class="table-column-help"
|
|
t-att-title="col.get('help_text')">?
|
|
</span>
|
|
</t>
|
|
</label>
|
|
</div>
|
|
|
|
<!-- 右列:输入框 -->
|
|
<div class="table-input-cell">
|
|
<!-- 数字输入框 -->
|
|
<t t-if="col['type'] == 'number'">
|
|
<div class="table-input-wrapper">
|
|
<input type="number"
|
|
t-att-id="field['id'] + '_' + col['name']"
|
|
t-att-name="field['id'] + '[' + col['name'] + ']'"
|
|
class="form-control table-input table-number-input"
|
|
t-att-min="col.get('min_value', 0)"
|
|
step="any"
|
|
t-att-placeholder="col.get('placeholder', '')"
|
|
t-att-required="'required' if col.get('required', False) else None"/>
|
|
<t t-if="col.get('unit')">
|
|
<span class="input-unit"
|
|
t-esc="col.get('unit')"></span>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- 文本输入框 -->
|
|
<t t-elif="col['type'] == 'text'">
|
|
<input type="text"
|
|
t-att-id="field['id'] + '_' + col['name']"
|
|
t-att-name="field['id'] + '[' + col['name'] + ']'"
|
|
class="form-control table-input table-text-input"
|
|
t-att-placeholder="col.get('placeholder', '')"
|
|
t-att-maxlength="col.get('max_length', 100)"
|
|
t-att-required="'required' if col.get('required', False) else None"/>
|
|
</t>
|
|
|
|
<!-- 下拉框 -->
|
|
<t t-elif="col['type'] == 'select'">
|
|
<div class="table-select-wrapper">
|
|
<select t-att-id="field['id'] + '_' + col['name']"
|
|
t-att-name="field['id'] + '[' + col['name'] + ']'"
|
|
class="form-control table-input table-select-input"
|
|
t-att-required="'required' if col.get('required', False) else None">
|
|
<option value=""
|
|
t-esc="col.get('placeholder', '请选择')"></option>
|
|
<t t-if="col.get('options_source')">
|
|
<t t-set="options_source"
|
|
t-value="col.get('options_source')"/>
|
|
<t t-foreach="dropdown_options.get(options_source, [])"
|
|
t-as="option">
|
|
<option t-att-value="option['value']"
|
|
t-esc="option['label']"></option>
|
|
</t>
|
|
</t>
|
|
</select>
|
|
<span class="select-arrow">▼</span>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 表格错误提示 -->
|
|
<div t-att-id="'error_' + field['id']"
|
|
class="error-message table-error"></div>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
|
|
<div class="btn-section">
|
|
<div class="btn-wrapper">
|
|
<button type="submit" id="submit_form" class="modern-submit-btn"
|
|
onclick="submitFinancialForm()">
|
|
<span class="btn-content">
|
|
<svg class="btn-icon" xmlns="http://www.w3.org/2000/svg" width="20" height="20"
|
|
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
|
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
|
</svg>
|
|
<span class="btn-text">提交财务数据</span>
|
|
</span>
|
|
<span class="btn-shimmer"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<style>
|
|
/* 彻底重置原有按钮样式 */
|
|
#submit_form,
|
|
#submit_form.action-btn,
|
|
#submit_form.btn-primary,
|
|
.action-btn,
|
|
.btn-primary,
|
|
.button-container button,
|
|
.button-container .action-btn,
|
|
.button-container .btn-primary {
|
|
all: unset !important;
|
|
box-sizing: border-box !important;
|
|
}
|
|
|
|
/* 移除原有按钮容器样式 */
|
|
.button-container {
|
|
display: none !important;
|
|
}
|
|
|
|
/* 新的按钮区域样式 */
|
|
.btn-section {
|
|
display: flex !important;
|
|
justify-content: center !important;
|
|
align-items: center !important;
|
|
margin: 50px 0 30px !important;
|
|
padding: 40px 0 !important;
|
|
width: 100% !important;
|
|
position: relative !important;
|
|
background: linear-gradient(to bottom,
|
|
transparent 0%,
|
|
rgba(52, 152, 219, 0.03) 50%,
|
|
transparent 100%) !important;
|
|
overflow: hidden !important;
|
|
}
|
|
|
|
.btn-section::before {
|
|
content: '' !important;
|
|
position: absolute !important;
|
|
top: 0 !important;
|
|
left: 50% !important;
|
|
transform: translateX(-50%) !important;
|
|
width: 80% !important;
|
|
height: 1px !important;
|
|
background: linear-gradient(to right,
|
|
transparent 0%,
|
|
rgba(52, 152, 219, 0.3) 50%,
|
|
transparent 100%) !important;
|
|
}
|
|
|
|
.btn-section::after {
|
|
content: '' !important;
|
|
position: absolute !important;
|
|
bottom: 0 !important;
|
|
left: 50% !important;
|
|
transform: translateX(-50%) !important;
|
|
width: 60% !important;
|
|
height: 1px !important;
|
|
background: linear-gradient(to right,
|
|
transparent 0%,
|
|
rgba(52, 152, 219, 0.2) 50%,
|
|
transparent 100%) !important;
|
|
}
|
|
|
|
.btn-wrapper {
|
|
display: flex !important;
|
|
justify-content: center !important;
|
|
align-items: center !important;
|
|
padding: 20px !important;
|
|
position: relative !important;
|
|
z-index: 10 !important;
|
|
}
|
|
|
|
/* 现代按钮样式 - 高优先级 */
|
|
#submit_form.modern-submit-btn,
|
|
.modern-submit-btn {
|
|
position: relative !important;
|
|
padding: 18px 50px !important;
|
|
border: none !important;
|
|
border-radius: 16px !important;
|
|
font-size: 18px !important;
|
|
font-weight: 700 !important;
|
|
cursor: pointer !important;
|
|
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important;
|
|
display: inline-flex !important;
|
|
align-items: center !important;
|
|
justify-content: center !important;
|
|
gap: 15px !important;
|
|
min-width: 220px !important;
|
|
overflow: hidden !important;
|
|
box-shadow:
|
|
0 8px 32px rgba(52, 152, 219, 0.3),
|
|
0 4px 12px rgba(0, 0, 0, 0.1),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
|
|
z-index: 1 !important;
|
|
color: white !important;
|
|
text-align: center !important;
|
|
line-height: 1.5 !important;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
|
letter-spacing: 0.5px !important;
|
|
text-transform: none !important;
|
|
outline: none !important;
|
|
text-decoration: none !important;
|
|
background: linear-gradient(135deg,
|
|
#3498db 0%,
|
|
#2980b9 25%,
|
|
#2c80b9 50%,
|
|
#2980b9 75%,
|
|
#3498db 100%) !important;
|
|
background-size: 200% 200% !important;
|
|
}
|
|
|
|
.modern-submit-btn::before {
|
|
content: '' !important;
|
|
position: absolute !important;
|
|
top: 0 !important;
|
|
left: -100% !important;
|
|
width: 100% !important;
|
|
height: 100% !important;
|
|
background: linear-gradient(90deg,
|
|
transparent,
|
|
rgba(255, 255, 255, 0.3),
|
|
transparent) !important;
|
|
transition: left 0.8s ease !important;
|
|
z-index: 1 !important;
|
|
}
|
|
|
|
.modern-submit-btn:hover {
|
|
transform: translateY(-6px) scale(1.03) !important;
|
|
box-shadow:
|
|
0 20px 50px rgba(52, 152, 219, 0.4),
|
|
0 10px 30px rgba(0, 0, 0, 0.15),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.3) !important;
|
|
background-position: 100% 100% !important;
|
|
color: white !important;
|
|
}
|
|
|
|
.modern-submit-btn:hover::before {
|
|
left: 100% !important;
|
|
}
|
|
|
|
.modern-submit-btn:active {
|
|
transform: translateY(-2px) scale(1.01) !important;
|
|
box-shadow:
|
|
0 10px 30px rgba(52, 152, 219, 0.3),
|
|
0 5px 15px rgba(0, 0, 0, 0.1),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.2) !important;
|
|
}
|
|
|
|
.btn-content {
|
|
display: flex !important;
|
|
align-items: center !important;
|
|
justify-content: center !important;
|
|
gap: 12px !important;
|
|
position: relative !important;
|
|
z-index: 2 !important;
|
|
}
|
|
|
|
.btn-icon {
|
|
width: 20px !important;
|
|
height: 20px !important;
|
|
stroke: currentColor !important;
|
|
stroke-width: 2.5px !important;
|
|
transition: transform 0.4s ease !important;
|
|
flex-shrink: 0 !important;
|
|
}
|
|
|
|
.modern-submit-btn:hover .btn-icon {
|
|
transform: translateX(8px) rotate(5deg) !important;
|
|
}
|
|
|
|
.btn-text {
|
|
position: relative !important;
|
|
z-index: 2 !important;
|
|
white-space: nowrap !important;
|
|
}
|
|
|
|
.btn-shimmer {
|
|
position: absolute !important;
|
|
top: -2px !important;
|
|
left: -2px !important;
|
|
right: -2px !important;
|
|
bottom: -2px !important;
|
|
background: linear-gradient(45deg,
|
|
transparent 30%,
|
|
rgba(255, 255, 255, 0.2) 50%,
|
|
transparent 70%) !important;
|
|
border-radius: 18px !important;
|
|
z-index: 0 !important;
|
|
opacity: 0 !important;
|
|
transition: opacity 0.3s ease !important;
|
|
}
|
|
|
|
.modern-submit-btn:hover .btn-shimmer {
|
|
opacity: 1 !important;
|
|
animation: shimmer 1.5s ease-in-out infinite !important;
|
|
}
|
|
|
|
@keyframes shimmer {
|
|
0% {
|
|
transform: translateX(-100%) !important;
|
|
}
|
|
100% {
|
|
transform: translateX(100%) !important;
|
|
}
|
|
}
|
|
|
|
/* 点击波纹效果 */
|
|
.ripple-effect {
|
|
position: absolute !important;
|
|
border-radius: 50% !important;
|
|
background: rgba(255, 255, 255, 0.6) !important;
|
|
transform: scale(0) !important;
|
|
animation: ripple 0.8s linear !important;
|
|
pointer-events: none !important;
|
|
z-index: 1 !important;
|
|
}
|
|
|
|
@keyframes ripple {
|
|
to {
|
|
transform: scale(4) !important;
|
|
opacity: 0 !important;
|
|
}
|
|
}
|
|
|
|
/* 响应式调整 */
|
|
@media (max-width: 768px) {
|
|
.btn-section {
|
|
margin: 30px 0 20px !important;
|
|
padding: 30px 0 !important;
|
|
}
|
|
|
|
.modern-submit-btn {
|
|
padding: 16px 35px !important;
|
|
font-size: 16px !important;
|
|
min-width: 200px !important;
|
|
gap: 10px !important;
|
|
}
|
|
|
|
.btn-icon {
|
|
width: 18px !important;
|
|
height: 18px !important;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 480px) {
|
|
.modern-submit-btn {
|
|
padding: 14px 30px !important;
|
|
font-size: 15px !important;
|
|
min-width: 180px !important;
|
|
gap: 8px !important;
|
|
border-radius: 14px !important;
|
|
}
|
|
|
|
.btn-content {
|
|
gap: 8px !important;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
// 确保在DOM完全加载后添加事件
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const submitBtn = document.getElementById('submit_form');
|
|
|
|
if (submitBtn) {
|
|
// 移除所有可能冲突的类名
|
|
submitBtn.classList.remove('action-btn', 'btn-primary');
|
|
|
|
// 添加点击波纹效果
|
|
submitBtn.addEventListener('click', function(e) {
|
|
// 移除已有的波纹效果
|
|
const existingRipples = this.querySelectorAll('.ripple-effect');
|
|
existingRipples.forEach(ripple => ripple.remove());
|
|
|
|
// 创建新的波纹效果
|
|
const ripple = document.createElement('span');
|
|
ripple.className = 'ripple-effect';
|
|
|
|
const rect = this.getBoundingClientRect();
|
|
const size = Math.max(rect.width, rect.height);
|
|
const x = e.clientX - rect.left - size / 2;
|
|
const y = e.clientY - rect.top - size / 2;
|
|
|
|
ripple.style.width = ripple.style.height = size + 'px';
|
|
ripple.style.left = x + 'px';
|
|
ripple.style.top = y + 'px';
|
|
|
|
this.appendChild(ripple);
|
|
|
|
// 动画结束后移除元素
|
|
setTimeout(() => {
|
|
if (ripple.parentNode === this) {
|
|
this.removeChild(ripple);
|
|
}
|
|
}, 800);
|
|
});
|
|
|
|
// 添加键盘支持
|
|
submitBtn.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
this.click();
|
|
}
|
|
});
|
|
|
|
// 添加焦点样式
|
|
submitBtn.addEventListener('focus', function() {
|
|
this.style.outline = '2px solid rgba(52, 152, 219, 0.5)';
|
|
this.style.outlineOffset = '4px';
|
|
});
|
|
|
|
submitBtn.addEventListener('blur', function() {
|
|
this.style.outline = 'none';
|
|
});
|
|
}
|
|
});
|
|
|
|
// 如果你的页面已经加载完成,也可以直接执行
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initButton);
|
|
} else {
|
|
initButton();
|
|
}
|
|
|
|
function initButton() {
|
|
const submitBtn = document.getElementById('submit_form');
|
|
if (submitBtn) {
|
|
// 确保按钮有正确的类名
|
|
if (!submitBtn.classList.contains('modern-submit-btn')) {
|
|
submitBtn.classList.add('modern-submit-btn');
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</template>
|
|
|
|
<!-- 简洁版成功页面 -->
|
|
<template id="simple_success_page" name="成功页面">
|
|
<t t-call="web.minimal_layout">
|
|
<t t-set="title">操作成功</t>
|
|
<div class="container mt-5">
|
|
<div class="row justify-content-center">
|
|
<div class="col-md-5 text-center">
|
|
<div class="mb-4">
|
|
<i class="fa fa-check-circle fa-5x text-success"></i>
|
|
</div>
|
|
<h2 class="text-success mb-3">
|
|
<t t-esc="title"/>
|
|
</h2>
|
|
<p class="lead mb-4">
|
|
<t t-if="message">
|
|
<t t-esc="message"/>
|
|
</t>
|
|
<t t-else="">
|
|
操作已成功完成!
|
|
</t>
|
|
</p>
|
|
<div class="d-grid gap-2">
|
|
<a t-att-href="redirect_url" class="btn btn-primary btn-lg">
|
|
<i class="fa fa-arrow-left me-2"></i>
|
|
返回
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
</odoo>
|