feat(acc-support): 实现动态获取并渲染联系我们条目

新增从后台获取管理员配置的联系我们数据的功能,支持邮箱和电话的跳转链接, fallback 到旧的固定链接配置
This commit is contained in:
Austin
2026-09-21 13:12:56 +08:00
parent 4dadb1bd5a
commit ca7af8baf9
2 changed files with 41 additions and 3 deletions
+3
View File
@@ -834,3 +834,6 @@ export const getAbuseReasons = (targetType = 'user') => imGet('/reports/abuse/re
export const submitAbuseReport = body => imPost('/reports/abuse', body); export const submitAbuseReport = body => imPost('/reports/abuse', body);
export const getFeedbackConfig = () => imGet('/feedback/config'); export const getFeedbackConfig = () => imGet('/feedback/config');
export const submitFeedback = body => imPost('/feedback', {client_context: clientContext(), ...body}); export const submitFeedback = body => imPost('/feedback', {client_context: clientContext(), ...body});
// -- Contact us (admin 字典 im_contact_us 透传,含邮箱/电话条目;后台修改后经缓存失效近实时生效). --
export const getContactUs = () => imGet('/contact-us');
+35
View File
@@ -3,6 +3,12 @@ import React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { APP_NAME, LINK_CONTACT_US, LINK_PRIVACY_POLICY, LINK_TERMS_OF_SERVICE } from '../config.js'; import { APP_NAME, LINK_CONTACT_US, LINK_PRIVACY_POLICY, LINK_TERMS_OF_SERVICE } from '../config.js';
import { getContactUs } from '../lib/im-api.js';
// Admin-managed "contact us" entries (dictionary type im_contact_us): emails get mailto:, phone
// numbers get tel:, anything else renders as plain (non-navigating) text.
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const PHONE_PATTERN = /^\+?[0-9][0-9\- ]{4,}$/;
// Renders as a real link when a destination is configured, or as inert (non-navigating) text // Renders as a real link when a destination is configured, or as inert (non-navigating) text
// otherwise -- same treatment auth-onboarding-view.jsx already gives its own placeholder // otherwise -- same treatment auth-onboarding-view.jsx already gives its own placeholder
@@ -14,13 +20,42 @@ function FlatLink({href, icon, children}) {
} }
export default class AccSupportView extends React.PureComponent { export default class AccSupportView extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
contactItems: []
};
}
componentDidMount() {
// Entries come from the im-server /contact-us endpoint (admin dictionary im_contact_us).
// On failure the static config fallback below stays in place; no toast for a support page.
getContactUs().then(data => {
const items = (data && Array.isArray(data.items)) ?
data.items.filter(it => it && it.label && it.value) : [];
this.setState({contactItems: items});
}).catch(() => {});
}
render() { render() {
const {contactItems} = this.state;
return ( return (
<div className="scrollable-panel"> <div className="scrollable-panel">
<div className="panel-form-column"> <div className="panel-form-column">
{contactItems.length > 0 ?
contactItems.map((item, idx) => {
const value = item.value;
const href = EMAIL_PATTERN.test(value) ? 'mailto:' + value :
(PHONE_PATTERN.test(value) ? 'tel:' + value.replace(/[^\d+]/g, '') : null);
return <FlatLink key={idx} href={href} icon={href && href.startsWith('tel:') ? 'call' : 'email'}>
{item.label}
</FlatLink>;
})
:
<FlatLink href={LINK_CONTACT_US} icon="email"> <FlatLink href={LINK_CONTACT_US} icon="email">
<FormattedMessage id="link_contact_us" defaultMessage="Contact Us" description="Ancor text for contacting us by email" /> <FormattedMessage id="link_contact_us" defaultMessage="Contact Us" description="Ancor text for contacting us by email" />
</FlatLink> </FlatLink>
}
<FlatLink href={LINK_TERMS_OF_SERVICE} icon="description"> <FlatLink href={LINK_TERMS_OF_SERVICE} icon="description">
<FormattedMessage id="link_terms_of_service" defaultMessage="Terms of Service" description="Ancor text for terms of service link" /> <FormattedMessage id="link_terms_of_service" defaultMessage="Terms of Service" description="Ancor text for terms of service link" />
</FlatLink> </FlatLink>