Files
huayang/frontend/src/api/customer.js
T
liuwenxin 85083ab962 feat(site): integrate multilingual content management / 集成多语言内容管理
完善官网、管理后台与后端的多语言内容编辑和发布流程,调整站点页面及相关接口,并同步数据库脚本。

新增容器部署配置,改用环境变量注入数据库凭据;补充仓库忽略规则,并停止跟踪本地环境文件和 Maven 构建产物。
2026-09-10 14:46:06 +08:00

185 lines
5.5 KiB
JavaScript
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.
/**
* 门户客户服务(若依公开接口)- 在线留言、联系信息
*/
import { nextTick } from 'vue'
import i18n from '../i18n'
function ui(key, fallback = '') {
const v = i18n.global.t(key)
return v && v !== key ? v : fallback
}
function escapeHtml(text) {
if (text == null || text === '') {
return ''
}
return String(text)
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
}
/**
* 获取联系信息列表
* @returns {Promise<Array>}
*/
export async function fetchContactList() {
const base = (import.meta.env.VITE_SITE_API_BASE || '/site').replace(/\/$/, '')
const res = await fetch(`${base}/contact/list`, { credentials: 'omit', cache: 'no-store' })
if (!res.ok) {
throw new Error(`HTTP ${res.status}`)
}
const body = await res.json()
if (body.code !== 200) {
throw new Error(body.msg || '接口返回异常')
}
return Array.isArray(body.data) ? body.data : []
}
/**
* 提交在线留言
* @param {Object} data { messageName, messagePhone, messageEmail, messageContent }
* @returns {Promise<Object>}
*/
export async function submitMessage(data) {
const base = (import.meta.env.VITE_SITE_API_BASE || '/site').replace(/\/$/, '')
const inquiryPayload = {
inquiryName: data?.messageName || '',
inquiryPhone: data?.messagePhone || '',
inquiryProduct: data?.messageEmail || '',
inquiryMessage: data?.messageContent || ''
}
const res = await fetch(`${base}/product/inquiry`, {
method: 'POST',
credentials: 'omit',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(inquiryPayload)
})
if (!res.ok) {
throw new Error(`HTTP ${res.status}`)
}
return await res.json()
}
/**
* 注入联系信息并初始化留言表单
*/
export async function injectContactAndInitForms() {
await injectContactInfo()
initMessageForm()
}
* 注入目标:联系我们页面的联系信息展示区域
*/
export async function injectContactInfo() {
const contactHost = document.querySelector(
'.contact-info-container, .info-list, .contact-list, .contact-way-list'
)
if (!contactHost) {
return
}
contactHost.innerHTML = ''
const contacts = await fetchContactList()
if (!contacts || !contacts.length) {
return
}
const contactHtml = contacts.map(contact => {
const iconHtml = contact.contactIcon ? `<img src="${escapeHtml(contact.contactIcon)}" alt="">` : ''
const value = escapeHtml(contact.contactValue || '')
// 电话类型可点击
const isPhone = contact.contactType === 'phone'
const displayValue = isPhone
? `<a href="tel:${value.replace(/[^0-9-]/g, '')}">${value}</a>`
: value
return `
<div class="contact-item contact-${escapeHtml(contact.contactType)}">
${iconHtml ? `<div class="contact-icon">${iconHtml}</div>` : ''}
<div class="contact-content">
<span class="contact-label">${escapeHtml(contact.contactLabel || '')}:</span>
<span class="contact-value">${displayValue}</span>
</div>
</div>
`
}).join('')
contactHost.innerHTML = contactHtml
}
/**
* 初始化留言表单
* 给留言表单绑定提交事件
*/
export function initMessageForm() {
const form = resolveMessageForm()
if (!form) {
return
}
if (form.dataset.huayangBoundMessage === '1') {
return
}
form.dataset.huayangBoundMessage = '1'
const submitHandler = async (event) => {
event.preventDefault()
const data = {
messageName: pickFormValue(form, ['name', 'messageName'], ['姓名', '联系人']),
messagePhone: pickFormValue(form, ['phone', 'messagePhone'], ['电话', '手机', '联系方式']),
messageEmail: pickFormValue(form, ['email', 'messageEmail'], ['邮箱', 'email']),
messageContent: pickFormValue(form, ['message', 'messageContent'], ['留言', '内容', '需求'])
}
if (!data.messageName || !data.messagePhone || !data.messageContent) {
alert(ui('ui.form.contact_required'))
return
}
try {
const result = await submitMessage(data)
if (result.code === 200) {
alert(ui('ui.status.submit_ok_message'))
form.reset()
} else {
alert(result.msg || ui('ui.status.submit_fail_retry'))
}
} catch (error) {
alert(ui('ui.status.submit_fail_retry'))
}
}
form.addEventListener('submit', submitHandler)
const submitBtn = form.querySelector('.e_formBtn-16, .e_formBtn-96, .btn-primary')
submitBtn?.addEventListener('click', submitHandler)
}
function resolveMessageForm() {
const explicit = document.querySelector('.message-form, #messageForm')
if (explicit) return explicit
const isContactPage =
window.location.search.includes('page=contact') || window.location.pathname.toLowerCase().includes('contact')
if (!isContactPage) return null
return document.querySelector('.e_form-10, form.e_form-10, form.e_form-94')
}
function pickFormValue(form, nameCandidates, placeholderCandidates) {
const byName = nameCandidates
.map((name) => form.querySelector(`[name="${name}"]`))
.find(Boolean)
if (byName?.value) return String(byName.value).trim()
const controls = Array.from(form.querySelectorAll('input, textarea, select'))
for (const control of controls) {
const hint = `${control.placeholder || ''}${control.getAttribute('name') || ''}`.toLowerCase()
if (placeholderCandidates.some((keyword) => hint.includes(String(keyword).toLowerCase()))) {
return String(control.value || '').trim()
}
}
return ''
}