feat:新增意向产品,去掉试用时间

This commit is contained in:
hangyu.tao 2026-01-29 15:42:55 +08:00
parent df1be594ca
commit db7646dbb1
5 changed files with 925 additions and 1398 deletions

View File

@ -36,7 +36,7 @@ body {
/* Sidebar Styles */ /* Sidebar Styles */
.sidebar { .sidebar {
width: var(--sidebar-width); width: var(--sidebar-width);
background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%); background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%);
color: var(--white); color: var(--white);
position: fixed; position: fixed;
height: 100vh; height: 100vh;
@ -214,7 +214,7 @@ body {
transition: margin-left 0.3s ease; transition: margin-left 0.3s ease;
} }
.sidebar.collapsed ~ .main-content { .sidebar.collapsed~.main-content {
margin-left: 70px; margin-left: 70px;
} }
@ -649,7 +649,7 @@ body {
cursor: pointer; cursor: pointer;
} }
.checkbox-label input[type="checkbox"]:checked + span { .checkbox-label input[type="checkbox"]:checked+span {
color: var(--primary-orange); color: var(--primary-orange);
font-weight: 500; font-weight: 500;
} }
@ -1104,7 +1104,7 @@ td.overflow-cell {
flex-direction: column; flex-direction: column;
} }
.sidebar.collapsed ~ .main-content #editModal .modal-content { .sidebar.collapsed~.main-content #editModal .modal-content {
width: min(calc(100vw - 70px - 80px), 800px); width: min(calc(100vw - 70px - 80px), 800px);
} }
@ -1126,7 +1126,7 @@ td.overflow-cell {
flex-direction: column; flex-direction: column;
} }
.sidebar.collapsed ~ .main-content #createModal .modal-content { .sidebar.collapsed~.main-content #createModal .modal-content {
width: min(calc(100vw - 70px - 80px), 800px); width: min(calc(100vw - 70px - 80px), 800px);
} }
@ -1559,6 +1559,7 @@ td.overflow-cell {
} }
@keyframes pulse { @keyframes pulse {
0%, 0%,
100% { 100% {
opacity: 1; opacity: 1;
@ -2323,11 +2324,9 @@ tr:hover .action-cell {
} }
.customer-tab.active { .customer-tab.active {
background: linear-gradient( background: linear-gradient(135deg,
135deg, var(--primary-orange),
var(--primary-orange), var(--secondary-orange));
var(--secondary-orange)
);
color: var(--white); color: var(--white);
border-color: transparent; border-color: transparent;
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3); box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);

File diff suppressed because it is too large Load Diff

View File

@ -191,9 +191,9 @@ document.addEventListener("DOMContentLoaded", function () {
placement === "top" placement === "top"
? rect.top - tipHeight - offset ? rect.top - tipHeight - offset
: Math.min( : Math.min(
rect.bottom + offset, rect.bottom + offset,
window.innerHeight - viewportPadding - tipHeight, window.innerHeight - viewportPadding - tipHeight,
); );
cellTooltipEl.style.left = `${Math.round(left)}px`; cellTooltipEl.style.left = `${Math.round(left)}px`;
cellTooltipEl.style.top = `${Math.round(top)}px`; cellTooltipEl.style.top = `${Math.round(top)}px`;
@ -1410,7 +1410,7 @@ document.addEventListener("DOMContentLoaded", function () {
const ctx = document.getElementById("statusChart").getContext("2d"); const ctx = document.getElementById("statusChart").getContext("2d");
const selectedField = document.getElementById("chartFieldSelect").value; const selectedField = document.getElementById("chartFieldSelect").value;
const statusChartTitleEl = document.getElementById("statusChartTitle"); const statusChartTitleEl = document.getElementById("statusChartTitle");
const chartTitle = statusChartTitleEl ? statusChartTitleEl.value : "数据分布"; const chartTitle = statusChartTitleEl ? statusChartTitleEl.value : "模块分布";
const fieldCount = {}; const fieldCount = {};
customers.forEach((customer) => { customers.forEach((customer) => {
@ -1518,7 +1518,7 @@ document.addEventListener("DOMContentLoaded", function () {
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext("2d");
const typeChartTitleEl = document.getElementById("typeChartTitle"); const typeChartTitleEl = document.getElementById("typeChartTitle");
const chartTitle = typeChartTitleEl ? typeChartTitleEl.value : "客户类型"; const chartTitle = typeChartTitleEl ? typeChartTitleEl.value : "类型分布";
if (typeChartInstance) { if (typeChartInstance) {
typeChartInstance.destroy(); typeChartInstance.destroy();

View File

@ -83,7 +83,7 @@ function initTrialPeriodsPage() {
// 刷新按钮事件 // 刷新按钮事件
const refreshTrialPeriodsBtn = document.getElementById('refreshTrialPeriodsBtn'); const refreshTrialPeriodsBtn = document.getElementById('refreshTrialPeriodsBtn');
if (refreshTrialPeriodsBtn) { if (refreshTrialPeriodsBtn) {
refreshTrialPeriodsBtn.addEventListener('click', async function() { refreshTrialPeriodsBtn.addEventListener('click', async function () {
// 添加旋转动画 // 添加旋转动画
refreshTrialPeriodsBtn.classList.add('refreshing'); refreshTrialPeriodsBtn.classList.add('refreshing');
const table = document.querySelector('.trial-periods-container table'); const table = document.querySelector('.trial-periods-container table');
@ -109,6 +109,9 @@ function initTrialPeriodsPage() {
}); });
} }
// Setup trial time visibility based on intended product selection
setupTrialTimeVisibility();
// Load customers map for displaying customer names // Load customers map for displaying customer names
loadCustomersMap(); loadCustomersMap();
} }
@ -184,6 +187,38 @@ function setupIntendedProductCheckboxes(otherCheckboxId, otherInputId) {
}); });
} }
// Setup trial time visibility based on intended product selection
// When only "robogo" or "其他" is selected (no "数据闭环"), hide start/end time fields
function setupTrialTimeVisibility() {
const checkboxGroup = document.getElementById('trialIntendedProductGroup');
if (!checkboxGroup) return;
const checkboxes = checkboxGroup.querySelectorAll('input[type="checkbox"]');
const startTimeGroup = document.getElementById('trialStartTimeGroup');
const endTimeGroup = document.getElementById('trialEndTimeGroup');
if (!startTimeGroup || !endTimeGroup) return;
function updateTimeVisibility() {
const checkedBoxes = checkboxGroup.querySelectorAll('input[type="checkbox"]:checked');
const checkedValues = Array.from(checkedBoxes).map(cb => cb.value);
// Show time fields only if "数据闭环" is selected
const showTimeFields = checkedValues.includes('数据闭环');
startTimeGroup.style.display = showTimeFields ? 'block' : 'none';
endTimeGroup.style.display = showTimeFields ? 'block' : 'none';
}
// Add change listener to all checkboxes
checkboxes.forEach(checkbox => {
checkbox.addEventListener('change', updateTimeVisibility);
});
// Initial visibility check
updateTimeVisibility();
}
// Get intended product values from checkboxes (returns comma-separated string) // Get intended product values from checkboxes (returns comma-separated string)
function getIntendedProductValues(checkboxName, otherInputId) { function getIntendedProductValues(checkboxName, otherInputId) {
const checkboxes = document.querySelectorAll(`input[name="${checkboxName}"]:checked`); const checkboxes = document.querySelectorAll(`input[name="${checkboxName}"]:checked`);
@ -642,7 +677,9 @@ async function createTrialPeriodFromPage() {
return; return;
} }
if (!startTime || !endTime) { // Only require start/end time if "数据闭环" is selected
const requiresTimeFields = intendedProduct.includes('数据闭环');
if (requiresTimeFields && (!startTime || !endTime)) {
alert('请填写开始时间和结束时间'); alert('请填写开始时间和结束时间');
return; return;
} }
@ -652,8 +689,8 @@ async function createTrialPeriodFromPage() {
customerName: customerName, customerName: customerName,
source: source, source: source,
intendedProduct: intendedProduct, intendedProduct: intendedProduct,
startTime: new Date(startTime).toISOString(), startTime: startTime ? new Date(startTime).toISOString() : '',
endTime: new Date(endTime).toISOString(), endTime: endTime ? new Date(endTime).toISOString() : '',
isTrial: isTrial isTrial: isTrial
}; };

View File

@ -69,17 +69,24 @@ func (h *TrialPeriodHandler) CreateTrialPeriod(w http.ResponseWriter, r *http.Re
return return
} }
// Parse start and end times // Parse start and end times (optional - only required for 数据闭环)
startTime, err := time.Parse(time.RFC3339, req.StartTime) var startTime, endTime time.Time
if err != nil { var parseErr error
http.Error(w, "Invalid start time format", http.StatusBadRequest)
return if req.StartTime != "" {
startTime, parseErr = time.Parse(time.RFC3339, req.StartTime)
if parseErr != nil {
http.Error(w, "Invalid start time format", http.StatusBadRequest)
return
}
} }
endTime, err := time.Parse(time.RFC3339, req.EndTime) if req.EndTime != "" {
if err != nil { endTime, parseErr = time.Parse(time.RFC3339, req.EndTime)
http.Error(w, "Invalid end time format", http.StatusBadRequest) if parseErr != nil {
return http.Error(w, "Invalid end time format", http.StatusBadRequest)
return
}
} }
trialPeriod := models.TrialPeriod{ trialPeriod := models.TrialPeriod{