跳到主要内容

配置和自定义指南

本综合指南涵盖了 OmniCRM 的所有配置和自定义选项,包括后端设置、前端品牌、视觉自定义和部署最佳实践。

概述

OmniCRM 使用两个主要的配置系统:

后端配置:

  • 文件: OmniCRM-API/crm_config.yaml
  • 格式: YAML
  • 要求: 更改后需要重启 API
  • 用于: 数据库、集成、安全、供应

前端配置:

  • 文件: OmniCRM-UI/.env
  • 格式: 环境变量
  • 要求: 更改后需要重建 UI
  • 用于: 品牌、功能、外部服务

后端配置 (crm_config.yaml)

crm_config.yaml 文件包含所有后端系统设置。

位置: /OmniCRM/OmniCRM-API/crm_config.yaml

数据库配置

database:
username: omnitouch
password: omnitouch2024
server: localhost

字段:

  • username - MySQL 数据库用户名
  • password - MySQL 数据库密码
  • server - 数据库服务器主机名或 IP(默认:localhost)

数据库连接:

  • 数据库名称硬编码为 omnicrm
  • 默认端口:3306(MySQL 默认)
  • 连接字符串:mysql+pymysql://username:password@server/omnicrm

安全提示: 永远不要将此文件与真实凭据提交到版本控制中。使用特定于环境的配置或秘密管理。

注意: 这应该与您的 .env 数据库凭据匹配。在容器化部署中,服务器通常是 db(Docker 服务名称)。

服务类型

service_types:
- omnicharge
- mobile
- fixed
- fixed-voice
- hotspot
- dongle

目的: 定义您部署的有效服务类型。

这些在系统中用于:

  • 产品分类
  • 附加组件过滤(附加组件与服务类型匹配)
  • 供应工作流
  • 报告和分析

在这里添加自定义服务类型以满足您的特定用例。

HSS 集成(家庭用户服务器)

对于具有 HSS 集成的移动网络运营商:

hss:
hss_peers:
- 'http://10.179.2.140:8080'
apn_list: "1,2,3,4,5,6"

配置:

  • hss_peers - 用户供应的 HSS 端点列表
  • apn_list - 可用于供应的 APN ID 的逗号分隔列表

用于: 移动网络供应和用户身份验证。

Mailjet 邮件模板配置

OmniCRM 使用 Mailjet 发送事务性电子邮件。每种电子邮件类型都有自己的模板配置:

mailjet:
api_key: your_mailjet_api_key
api_secret: your_mailjet_api_secret

# 客户欢迎邮件
api_crmCommunicationCustomerWelcome:
from_email: "support@yourcompany.com"
from_name: "Your Company Support"
template_id: 5977509
subject: "Welcome to YourCompany"

# 客户发票邮件
api_crmCommunicationCustomerInvoice:
from_email: "billing@yourcompany.com"
from_name: "Your Company Billing"
template_id: 6759851
subject: "Your Invoice - "

# 发票提醒
api_crmCommunicationCustomerInvoiceReminder:
from_email: "billing@yourcompany.com"
from_name: "Your Company Billing"
template_id: 5977570
subject: "Invoice Payment Reminder"

# 用户欢迎邮件(员工/管理员)
api_crmCommunicationUserWelcome:
from_email: "admin@yourcompany.com"
from_name: "Your Company Admin"
template_id: 6118112
subject: "Welcome to the Team"

# 密码重置请求
api_crmCommunicationUserPasswordReset:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6735666
subject: "Password Reset Request"

# 密码重置成功确认
api_crmCommunicationUserPasswordResetSuccess:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6118378
subject: "Password Reset Successful"

# 密码更改通知
api_crmCommunicationUserPasswordChange:
from_email: "security@yourcompany.com"
from_name: "Your Company Security"
template_id: 6118423
subject: "Password Changed"

# 邮件验证
api_crmCommunicationEmailVerification:
from_email: "verify@yourcompany.com"
from_name: "Your Company Verification"
template_id: 6267350
subject: "Verify Your Email Address"

# 余额过期通知
api_crmCommunicationsBalanceExpired:
from_email: "alerts@yourcompany.com"
from_name: "Your Company Alerts"
template_id: 7238252
subject: "Service Balance Expired"

# 余额不足警告
api_crmCommunicationsBalanceLow:
from_email: "alerts@yourcompany.com"
from_name: "Your Company Alerts"
template_id: 7238263
subject: "Low Balance Warning"

创建 Mailjet 模板:

  1. 登录 Mailjet 仪表板 (<https://app.mailjet.com>)
  2. 导航到 TransactionalTemplates
  3. 创建新模板或克隆现有模板
  4. 注意 Template ID(数字值)
  5. 添加与 OmniCRM 数据结构匹配的模板变量
  6. 更新 crm_config.yaml 中的模板 ID

可用模板变量:

每种电子邮件类型接收特定变量。常见示例:

  • {{customer_name}} - 客户或用户姓名
  • {{service_name}} - 服务或产品名称
  • {{invoice_id}} - 发票编号
  • {{invoice_amount}} - 发票总金额
  • {{due_date}} - 付款到期日
  • {{reset_link}} - 密码重置 URL
  • {{verification_link}} - 邮件验证 URL
  • {{balance}} - 当前账户余额
  • {{expiry_date}} - 余额或服务到期日

供应配置

provisioning:
failure_list: ['admin@yourcompany.com', 'ops@yourcompany.com']

目的:

  • failure_list - 当 Ansible 供应失败时通知的电子邮件地址
  • 通知包括剧本名称、错误详细信息和客户信息
  • 允许运维团队快速响应供应问题

发票配置

invoice:
template_filename: 'yourcompany_invoice_template.html'

目的:

指定用于 PDF 发票生成的 Jinja2 HTML 模板。

模板位置: /OmniCRM-API/invoice_templates/

有关创建自定义模板的详细信息,请参见下面的 发票 PDF 生成 部分。

CRM 基础 URL

crm:
base_url: 'http://localhost:5000'

目的:

  • 由 Ansible 剧本用于进行 API 回调
  • 在电子邮件模板中用于生成指向 CRM 的链接
  • 应该是您的 API 的公共可访问 URL(而不是内部容器名称)

示例:

  • 开发:http://localhost:5000
  • 生��:https://api.yourcompany.com
  • Docker:http://omnicrm-api:5000(内部容器通信)

重要:

  • 不要包含尾部斜杠
  • 如果剧本在不同服务器上运行,请使用公共可访问 URL
  • 部署到生产时更新

OCS 和 CGRates 配置

ocs:
ocsApi: 'http://10.179.2.142:8080/api'
ocsTenant: 'mnc380.mcc313.3gppnetwork.org'
cgrates: 'localhost:2080'

配置:

  • ocsApi - 用于用户管理的 OCS API 端点
  • ocsTenant - 多租户 OCS 部署的租户标识符
  • cgrates - CGRates JSON-RPC API 端点(主机:端口)

用于: 实时计费、余额管理、使用跟踪。

SMSC 配置(短信网关)

smsc:
source_msisdn: 'YourCompany'
smsc_url: 'http://10.179.2.216/SMSc/'
api_key: 'your_smsc_api_key'

目的:

  • 向客户发送 SMS 通知(余额不足、服务警报、2FA 代码)
  • source_msisdn - 显示给收件人的发件人 ID(字母数字或电话号码)
  • smsc_url - SMSC 网关 API 端点
  • api_key - SMSC API 的身份验证

小区广播配置

cbc_url: 'http://10.179.1.113:8080'

目的: 小区广播中心(CBC)API 端点,用于紧急警报。

有关使用详细信息,请参见 features_cell_broadcast

JWT 密钥

jwt_secret: 'CHANGE_ME_ON_DEPLOYMENT'  # 由 Ansible 自动生成

安全性:

  • 用于签署和验证身份验证令牌(JWT)
  • 对身份验证安全至关重要 - 像密码一样对待
  • 每个部署/环境必须具有唯一的密钥
  • 永远不要共享或提交到版本控制

自动化密钥管理(Ansible 部署):

使用 Ansible 部署时,JWT 密钥会自动管理:

  1. 第一次部署: Ansible 生成一个随机的 64 字符十六进制字符串(256 位熵)
  2. 后续部署: Ansible 保留服务器上现有的密钥
  3. 每个服务器都有自己唯一的密钥 - 会话在不同环境之间无法使用

这确保了:

  • Git 仓库中没有硬编码的密钥
  • 每个环境都是加密隔离的
  • 密钥在部署之间持续存在(会话在重新部署时不会失效)
  • 重新构建服务器会生成新的密钥(会话会正确失效)

手动密钥生成(非 Ansible 部署):

如果没有 Ansible 部署,您必须手动生成唯一的密钥:

# 生成一个加密安全的随机密钥
python3 -c "import secrets; print(secrets.token_hex(32))"
# 或
openssl rand -hex 32

然后更新 crm_config.yaml

jwt_secret: 'your_generated_secret_here'

重要:

  • 绝不要在生产中使用默认占位符值 CHANGE_ME_ON_DEPLOYMENT
  • 绝不要公开共享 - 任何拥有密钥的人都可以伪造身份验证令牌
  • 更改此项会使所有现有用户会话失效(用户必须重新登录)
  • 每个环境(开发、预发布、生产)必须具有不同的密钥

Stripe 支付配置

stripe:
secret_key: 'sk_live_xxxxxxxxxx'
publishable_key: 'pk_live_xxxxxxxxxx'
currency: 'aud'
statement_descriptor_suffix: 'YOURCOMPANY'

配置:

  • secret_key - Stripe 秘密 API 密钥(服务器端,保密)
  • publishable_key - Stripe 可发布密钥(客户端,安全暴露)
  • currency - ISO 4217 货币代码(aud、usd、gbp、eur 等)
  • statement_descriptor_suffix - 出现在客户信用卡账单上的描述

密钥类型:

  • 测试密钥:sk_test_...pk_test_...(用于开发)
  • 生产密钥:sk_live_...pk_live_...(用于生产)

账单描述符使用:

  • 在客户银行账单上显示为 "YOURCOMPANY"
  • 最大 22 个字符
  • 帮助客户识别费用
  • 也用于发票 PDF 文件名(例如,YOURCOMPANY_12345.pdf

有关设置详细信息,请参见 Payment Vendor Integrations <integrations_payment_vendors>

API 密钥和 IP 白名单

定义具有基于角色访问和 IP 限制的 API 密钥:

api_keys:
"YOUR_API_KEY_1":
roles: ["admin"]
ips: ["127.0.0.1", "::1"]
"YOUR_API_KEY_2":
roles: ["customer_service_agent_1"]
ips: ["127.0.0.1", "::1", "10.0.1.0/24"]

# IP 白名单(独立,无需 API 密钥)
ip_whitelist:
"10.179.2.142":
roles: ["admin"]

目的:

  • 允许外部系统通过 API 密钥进行身份验证
  • 按 IP 地址限制访问
  • 授予 API 消费者特定角色
  • 对于集成(计费系统、监控、自动化)非常有用

生成 API 密钥:

openssl rand -base64 48

角色:

  • admin - 对所有端点的完全访问
  • 在 RBAC 系统中定义的自定义角色

安全最佳实践:

  • 使用长且随机的 API 密钥(至少 32 个字符)
  • 将 IP 限制为已知来源
  • 授予最低必要角色
  • 定期轮换 API 密钥
  • 在日志中监控 API 密钥使用情况

安全警告:

  • 仅对受信任的内部网络使用 IP 白名单
  • 不得使用本地主机 IP(127.0.0.1、::1)
  • 对于外部访问,请使用 API 密钥
  • 考虑防火墙规则作为额外保护

有关详细信息,请参见 administration_api_keysconcepts_api


前端配置 (.env)

React UI 通过 OmniCRM-UI/.env 中的环境变量进行配置。

位置: /OmniCRM/OmniCRM-UI/.env

API 密钥和外部服务

# Google Maps API(用于地址自动完成和地理编码)
VITE_GOOGLE_API_KEY=your_google_api_key

# Stripe 支付网关
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx

# 禁用 npm start 时的浏览器自动启动
BROWSER=none

必须匹配:

VITE_STRIPE_PUBLISHABLE_KEY 必须与 crm_config.yaml 中的 stripe.publishable_key 匹配。

品牌和公司信息

# 公司品牌
VITE_COMPANY_NAME="ShellFone"
VITE_PORTAL_NAME="ShellManager"
VITE_SELF_CARE_NAME="ShellCare"
VITE_COMPANY_TAGLINE="Phones with Shells"

这些值出现在 UI 的各个地方:

  • COMPANY_NAME - 显示在页面标题、电子邮件和客户通信中
  • PORTAL_NAME - 管理员/员工门户的名称(例如,“ShellManager”)
  • SELF_CARE_NAME - 客户自助服务门户的名称(例如,“ShellCare”)
  • COMPANY_TAGLINE - 出现在登录屏幕和营销材料中

本地化和区域设置

# 语言和区域
# 支持的语言:ar、ch、en、fr、gr、it、ru、sp
VITE_DEFAULT_LANGUAGE=en
VITE_LOCALE="en-GB"

# 默认位置(用于地址自动完成)
VITE_DEFAULT_LOCATION="Sydney, Australia"
VITE_DEFAULT_COUNTRY="Australia"

# 货币设置
VITE_CURRENCY_CODE="GBP"
VITE_CURRENCY_SYMBOL="£"

支持���语言:

  • ar - 阿拉伯语
  • ch - 中文
  • en - 英语(默认)
  • fr - 法语
  • gr - 希腊语
  • it - 意大利语
  • ru - 俄语
  • sp - 西班牙语

常见货币:

  • USD - $(美元)
  • GBP - £(英镑)
  • EUR - €(欧元)
  • AUD - $(澳大利亚元)
  • CAD - $(加元)

注意: 必须与 crm_config.yaml 中的 stripe.currency 匹配。

颜色主题配置

# 主要颜色(主要品牌颜色)
VITE_PRIMARY_COLOR=#405189

# 其他颜色选项(注释示例)
# VITE_SECONDARY_COLOR=#2bFFcf
# VITE_TERTIARY_COLOR=#1a9fbf
# VITE_SUCCESS_COLOR=#28a745
# VITE_INFO_COLOR=#17a2b8
# VITE_WARNING_COLOR=#ffc107
# VITE_DANGER_COLOR=#dc3545

可用颜色:

  • VITE_PRIMARY_COLOR - 主要品牌颜色(按钮、链接、高亮)
  • VITE_SECONDARY_COLOR - 辅助颜色
  • VITE_TERTIARY_COLOR - 额外辅助颜色
  • VITE_SUCCESS_COLOR - 成功消息(#28a745)
  • VITE_INFO_COLOR - 信息消息(#17a2b8)
  • VITE_WARNING_COLOR - 警告(#ffc107)
  • VITE_DANGER_COLOR - 错误(#dc3545)
  • VITE_LIGHT_COLOR - 浅色背景(#f8f9fa)
  • VITE_DARK_COLOR - 深色文本(#343a40)
  • VITE_PRIMARY_DARK_COLOR - 主要颜色的深色变体

格式: 十六进制颜色代码(#RRGGBB)

主要颜色应用于:

  • 导航标题
  • 操作按钮
  • 链接和高亮
  • 活动状态
  • 品牌元素

字体配置

# 字体系列配置
# 无衬线:Inter、Roboto、Open Sans、Lato、Quicksand、Poppins、Nunito、Montserrat、Work Sans、Source Sans Pro、Raleway、Ubuntu、Josefin Sans、HKGrotesk
# 衬线:Merriweather、Lora、Playfair Display
# 系统:System(本地设备字体)
# 默认:Quicksand
VITE_FONT_FAMILY=Quicksand

重要: 所有字体都是在 OmniCRM-UI 应用程序中本地自托管。这意味着:

  • 没有外部字体加载 - 字体与应用程序捆绑在一起
  • 封闭花园兼容 - 不需要互联网访问字体
  • 离线操作 - 在隔离或受限网络环境中完全功能
  • 隐私 - 不会向 Google Fonts、Adobe Fonts 或其他 CDN 发送外部请求
  • 性能 - 加载更快,没有外部依赖
  • 安全性 - 不会通过字体请求进行第三方跟踪或数据泄漏

可用选项:

无衬线字体:

  • Inter、Roboto、Open Sans、Lato、Quicksand(默认)、Poppins、Nunito、Montserrat、Work Sans、Source Sans Pro、Raleway、Ubuntu、Josefin Sans、HKGrotesk

衬线字体:

  • Merriweather、Lora、Playfair Display

系统字体:

  • System - 使用本地设备字体以获得最佳性能和最小的捆绑大小

添加自定义字体:

是的,您可以添加额外的字体!所有字体都存储在应用程序中。

要添加新的自定义字体:

  1. 将字体文件添加到 OmniCRM-UI/src/assets/fonts/your-font-name/

    • 使用 WOFF2 格式以获得最佳压缩和浏览器支持
    • 包括多个字重(300、400、500、600、700)以确保正确呈现
    • 文件命名:your-font-name-300.woff2your-font-name-400.woff2
  2. OmniCRM-UI/src/assets/scss/fonts/_google-fonts.scss 中定义 @font-face 规则

    //
    // 您的自定义字体 - 描述
    //

    @font-face {
    font-family: 'Your Font Name';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../../fonts/your-font-name/your-font-name-400.woff2") format('woff2');
    }

    @font-face {
    font-family: 'Your Font Name';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../../fonts/your-font-name/your-font-name-700.woff2") format('woff2');
    }
  3. 在 .env 文件中设置:

    VITE_FONT_FAMILY=Your Font Name

字体粗细指南:

  • 300 - 轻(可选,用于细微标题)
  • 400 - 常规(必需,默认文本)
  • 500 - 中等(可选,强调)
  • 600 - 半粗体(可选���副标题)
  • 700 - 粗体(必需,标题和强文本)

Web 应用快速链接

配置最多 6 个快速访问的 Web 应用程序,这些应用程序出现在管理员仪表板中:

# Web 应用 1:GitHub
VITE_WEB_APP_1_NAME="GitHub"
VITE_WEB_APP_1_URL="https://github.com"
VITE_WEB_APP_1_ICON_PATH="resources/webapp_icons/github.png"

# Web 应用 2:Xero
VITE_WEB_APP_2_NAME="Xero"
VITE_WEB_APP_2_URL="https://go.xero.com/"
VITE_WEB_APP_2_ICON_PATH="resources/webapp_icons/xero.png"

# Web 应用 3-6:其他集成
# (使用 NAME、URL 和 ICON_PATH 进行类似配置)

模式:

  • VITE_WEB_APP_N_NAME - 显示名称
  • VITE_WEB_APP_N_URL - 目标 URL
  • VITE_WEB_APP_N_ICON_PATH - 图标文件路径(相对于 public/)

示例图标: GitHub、Xero、Monday.com、Gmail、MailJet、Slack

Grafana 仪表板集成

OmniCRM 与 Grafana 集成以提供分析仪表板。具有 grafana_access 权限的用户可以在 /grafana 访问 Grafana 创建自定义仪表板,这些仪表板可以嵌入到 OmniCRM 界面中。

# Grafana 仪表板集成
# 仪表板 ID(逗号分隔) - 从 /grafana/d/ID/name URL 获取
VITE_GRAFANA_DASHBOARD_IDS=abc123,def456,ghi789

# 仪表板标签(逗号分隔,必须与 ID 的顺序匹配)
VITE_GRAFANA_DASHBOARD_LABELS=System Metrics,User Analytics,Network Performance

字段:

  • VITE_GRAFANA_DASHBOARD_IDS - 从 URL 路径中获取的 Grafana 仪表板 ID 的逗号分隔列表
  • VITE_GRAFANA_DASHBOARD_LABELS - 仪表板显示名称的逗号分隔列表(必须与 ID 的顺序匹配)

如何查找仪表板 ID:

在 Grafana 中查看仪表板时,URL 将类似于 /grafana/d/abc123/dashboard-name。仪表板 ID 是 /d/ 后面和名称前面的部分(在此示例中为 abc123)。

用法:

配置后,仪表板会自动出现在 OmniCRM 侧边栏的“仪表板”菜单下。用户可以单击查看嵌入的仪表板,同时保持 OmniCRM 导航可见。

示例:

如果您的仪表板 URL 是 http://your-server/grafana/d/system-overview-123/system-metrics,那么:

  • 仪表板 ID:system-overview-123
  • 仪表板标签:选择任何友好的名称,例如“系统概述”

重要:

  • ID 的数量必须与标签的数量匹配
  • 仪表板按定义的顺序出现在侧边栏中
  • 只有具有 grafana_access 权限的用户才能查看仪表板
  • 更改需要重建前端 UI

支持和文档 URL

# 常见问题和支持 URL
VITE_FAQS_URL=https://support.yourcompany.com/faqs
VITE_SUPPORT_URL=https://support.yourcompany.com

目的: 在 UI 中显示的外部支持资源链接。

社交登录

# 允许社交登录(yes|no)
VITE_ALLOW_SOCIAL_LOGINS=yes

选项:

  • yes - 启用社交登录按钮(Google、Facebook 等)
  • no - 禁用社交登录

注意: 社交登录提供者必须单独配置。

分析和跟踪

# Google Analytics 4 或 Google Tag Manager(可选)
# 对于 GA4,使用格式:G-XXXXXXXXXX
# 对于 GTM,使用格式:GTM-XXXXXXX
VITE_GOOGLE_TAG_ID=G-XXXXXXXXXX

目的: 启用 Google Analytics 4(GA4)或 Google Tag Manager(GTM)跟踪,以监控用户行为和应用程序使用情况。

支持的格式:

  • GA4 测量 ID: G-XXXXXXXXXX - 用于 Google Analytics 4 跟踪
  • GTM 容器 ID: GTM-XXXXXXX - 用于 Google Tag Manager
  • 禁用: 留空或省略以禁用跟踪

工作原理:

系统会根据 ID 格式自动检测跟踪服务:

  • G- 开头的 ID 初始化 Google Analytics 4
  • GTM- 开头的 ID 初始化 Google Tag Manager
  • 空值或缺失值禁用所有跟踪

功能:

  • 自动页面跟踪 - 每次路由更改都被跟踪为页面视图
  • 自定义事件跟踪 - 跟踪用户交互、按钮点击、表单提交
  • 无需代码更改 - 只需设置环境变量并重建 UI

设置说明:

  1. 获取您的跟踪 ID:

    对于 Google Analytics 4:

    • 登录 Google Analytics
    • 创建或选择一个 GA4 属性
    • 转到 AdminData Streams
    • 选择您的 Web 流
    • 复制 Measurement ID(格式:G-XXXXXXXXXX

    对于 Google Tag Manager:

    • 登录 Google Tag Manager
    • 创建或选择一个容器
    • 复制 Container ID(格式:GTM-XXXXXXX
  2. 添加到 .env 文件:

    VITE_GOOGLE_TAG_ID=G-XXXXXXXXXX
  3. 重建 UI:

    cd OmniCRM-UI
    npm run build
  4. 验证跟踪:

    • 在浏览器中打开您的应用程序
    • 检查浏览器控制台以获取初始化消息
    • 使用 Google Analytics 实时报告查看活动用户

高级用法 - 自定义事件跟踪:

集成提供了用于在整个应用程序中跟踪自定义事件的实用程序函数。

示例 - 跟踪按钮点击:

import { trackEvent } from './utils/googleAnalytics';

// 在您的组件中
const handleCheckout = () => {
trackEvent('checkout_initiated', {
cart_value: 99.99,
item_count: 3,
page: '/cart'
});
// 继续结账逻辑
};

示例 - 跟踪表单提交��

import { trackEvent } from './utils/googleAnalytics';

const handleFormSubmit = (formType) => {
trackEvent('form_submission', {
form_type: formType,
timestamp: new Date().toISOString()
});
};

示例 - 跟踪自定义页面视图:

import { trackPageView } from './utils/googleAnalytics';

// 手动跟踪页面视图(对模态对话框、选项卡等有用)
trackPageView('/virtual/page-path', 'Page Title');

可用跟踪函数:

函数目的参数
initializeGoogleTracking()在应用启动时初始化跟踪无(自动调用)
trackEvent(eventName, eventParams)跟踪自定义事件事件名称(字符串)、参数(对象)
trackPageView(path, title)手动跟踪页面视图路径(字符串)、标题(字符串)

隐私和合规性:

Google Analytics 跟踪收集用户行为数据。确保遵守数据保护法规:

  • GDPR(欧洲) - 在跟踪之前获得用户同意,提供选择退出机制
  • CCPA(加利福尼亚) - 允许用户选择退出数据收集
  • 隐私政策 - 在您的隐私政策中披露使用 Google Analytics
  • Cookie 同意 - 如果当地法律要求,实施 Cookie 同意横幅
  • 数据保留 - 在 Google Analytics 设置中配置适当的数据保留期限

故障排除:

问题可能原因解决方案
GA 仪表板中没有数据跟踪 ID 不正确验证 ID 格式是否匹配 G-XXXXXXXXXX 或 GTM-XXXXXXX
页面加载时控制台错误无效的跟踪 ID检查 .env 文件中的拼写错误
页面视图未跟踪UI 在更改 .env 后未重建运行 npm run build 并重启 UI
事件未出现广告拦截器已启用在禁用广告拦截器的情况下测试
数据延迟GA 的正常行为使用实时报告进行即时验证

性能考虑:

  • 跟踪脚本异步加载,不会阻塞页面渲染
  • 对性能的影响最小(< 50KB 额外负载)
  • 脚本在首次加载后由浏览器缓存
  • 如果 VITE_GOOGLE_TAG_ID 为空,则不会发生跟踪

实现细节:

  • 跟踪代码:OmniCRM-UI/src/utils/googleAnalytics.js
  • 页面跟踪钩子:OmniCRM-UI/src/utils/usePageTracking.js
  • 初始化:在 App.jsindex.js 中自动启动

充值和充值配置

VITE_TOPUP_PRICE_PER_DAY=10

目的: 设置自助服务门户中充值/充值服务的每日价格。

字段:

  • VITE_TOPUP_PRICE_PER_DAY - 充值服务的每日价格(数值)

示例: 如果���置为 10,且货币为 USD,客户支付 $10 每天的服务费用。

注意: 此值必须与后端定价配置匹配。有关完整设置详细信息,请参见 features_topup_recharge


品牌和视觉自定义

OmniCRM 允许您在不修改代码的情况下用公司的徽标和启动画面替换默认品牌图像。

徽标文件和回退系统

徽标存储在 /OmniCRM-UI/src/assets/images/omnitouch/ 中,并使用回退系统:

默认徽标(始终存在):

  • DefaultLogoDark.png - 深色主题徽标(用于浅色背景)
  • DefaultLogoLight.png - 浅色主题徽标(用于深色背景)

自定义徽标(可选,存在时优先):

  • logoSm.png - 用于折叠侧边栏的小徽标(推荐:100x100px)
  • logoDark.png - 用于标题的全尺寸深色徽标(推荐:200x50px)
  • logoLight.png - 用于身份验证屏幕的全尺寸浅色徽标(推荐:200x50px)

徽标回退工作原理:

系统首先尝试加载自定义徽标。如果自定义徽标文件不存在,则回退到默认徽标:

// 来自 Header.js
const tryImport = (filename) => {
try {
return require(`../assets/images/omnitouch/${filename}`);
} catch (err) {
return null; // 回退到默认
}
};

const userLogoSm = tryImport("logoSm.png");
const userLogoDark = tryImport("logoDark.png");
const userLogoLight = tryImport("logoLight.png");

徽标出现的位置:

  • logoSm.png - 折叠侧边栏、移动导航、小标题显示
  • logoDark.png - 主标题栏(浅色模式)、管理员仪表板标题
  • logoLight.png - 登录/注册屏幕、深色背景、身份验证轮播

替换徽标:

  1. 创建您的徽标文件:

    • 使用 PNG 格式以支持透明度
    • 匹配上述推荐尺寸
    • 确保徽标在常规和视网膜分辨率下清晰可见
  2. 添加到 OmniCRM:

    # 将您的徽标文件复制到 omnitouch 图像目录
    cp /path/to/your/logoSm.png OmniCRM-UI/src/assets/images/omnitouch/
    cp /path/to/your/logoDark.png OmniCRM-UI/src/assets/images/omnitouch/
    cp /path/to/your/logoLight.png OmniCRM-UI/src/assets/images/omnitouch/
  3. 重建 UI:

    cd OmniCRM-UI
    npm run build
  4. 验证更改:

    • 检查浅色模式标题(应显示 logoDark.png
    • 检查深色模式标题(应显示 logoLight.png
    • 检查折叠侧边栏(应显示 logoSm.png
    • 检查登录屏幕(应显示 logoLight.png

徽标设计最佳实践:

  • 对比度 - 确保徽标在浅色和深色背景��可见
  • 简洁性 - 徽标在小尺寸下应易于识别
  • 格式 - 使用带透明背景的 PNG
  • 视网膜 - 为高 DPI 显示器提供 2 倍分辨率
  • 一致性 - 在所有徽标变体中使用相同的品牌颜色

启动画面和身份验证背景

身份验证屏幕(登录、注册、密码重置)使用带可自定义图像的轮播背景。

位置: /OmniCRM-UI/src/pages/AuthenticationInner/authCarousel.js

默认配置:

import logoLight from "../../assets/images/logo-light.png";

// 在身份验证屏幕上显示的徽标
<!-- ![Company Logo](../absolute/path/to/your-logo.png) -->
<h1>INVOICE</h1>
</div>

<div class="invoice-details">
<p><strong>Invoice Number:</strong> {{ invoice_number }}</p>
<p><strong>Date:</strong> {{ date }}</p>
<p><strong>Due Date:</strong> {{ due_date }}</p>
<p><strong>Billing Period:</strong> {{ start_date }} to {{ end_date }}</p>
</div>

<div class="customer-details">
<h3>Bill To:</h3>
<p>{{ client.name }}</p>
<p>{{ client.address.address_line_1 }}</p>
<p>{{ client.address.city }}, {{ client.address.state }} {{ client.address.zip_code }}</p>
<p>{{ client.address.country }}</p>
</div>

<table>
<thead>
<tr>
<th>Description</th>
<th>Date</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{% for transaction in transaction_list[0] %}
<tr>
<td>{{ transaction.title }}</td>
<td>{{ transaction.created }}</td>
<td>${{ "%.2f"|format(transaction.retail_cost) }}</td>
</tr>
{% endfor %}
</tbody>
</table>

<div class="total">
<p>Total Amount Due: ${{ "%.2f"|format(total_amount) }}</p>
</div>

{% if paid %}
<div style="text-align: center; color: green; font-weight: bold;">
PAID
</div>
{% endif %}

{% if void %}
<div style="text-align: center; color: red; font-weight: bold;">
VOID
</div>
{% endif %}
</body>
</html>

模板最佳实践:

  • 使用绝对路径的图像 - file:///absolute/path/to/image.png
  • 内联 CSS - WeasyPrint 不可靠地加载外部样式表
  • 使用示例数据进行测试 - 使用 invoice_templates/rendered/ 检查 HTML
  • 页面换行 - 使用 <div style="page-break-after: always;"></div> 进行多页发票
  • 页眉和页脚 - 使用 @page CSS 规则重复元素
  • 货币格式化 - 使用 Jinja2 ���滤器:{{ "%.2f"|format(amount) }}

创建自定义发票模板

  1. 复制示例模板:

    cd /OmniCRM/OmniCRM-API/invoice_templates
    cp norfone_invoice_template.html yourcompany_invoice_template.html
  2. 编辑模板:

    • 替换公司名称、徽标、联系信息
    • 调整样式(颜色、字体、布局)以匹配品牌
    • 根据需要添加或删除部分(税务明细、付款说明等)
  3. 更新配置:

    编辑 crm_config.yaml

    invoice:
    template_filename: 'yourcompany_invoice_template.html'
  4. 测试发票生成:

    • 在 CRM 中创建测试发票
    • 下载 PDF 并验证格式
    • 检查 invoice_templates/rendered/{invoice_id}.html 以进行调试
  5. 使旧缓存失效(如有需要):

    如果您更改了模板并希望重新生成现有发票:

    -- 清除所有缓存的 PDF(强制重新生成)
    DELETE FROM Invoice_PDF_Cache;

PDF 缓存系统

为了提高性能,OmniCRM 缓存生成的 PDF:

缓存行为:

  • 第一次请求 - 生成 PDF、缓存并返回
  • 后续请求 - 立即返回缓存的 PDF(无需重新生成)
  • 缓存失效 - 当发票被修改、作废或退款时发生
  • 缓存清理 - 在 30 天不活动后自动清除旧缓存

缓存存储:

  • Base64 编码的 PDF 存储在 Invoice_PDF_Cache 表中
  • SHA256 内容哈希用于完整性验证
  • 包括文件名、创建时间戳、最后访问时间戳

手动缓存管理:

# 在 OmniCRM API 或 Python shell 中
from services.invoice_service import cleanup_old_pdf_cache, invalidate_invoice_cache
from utils.db_helpers import get_db_session

session = get_db_session()

# 清理超过 30 天的缓存
result = cleanup_old_pdf_cache(session, days_old=30)
print(result) # {'status': 'success', 'deleted_count': 15}

# 使特定发票缓存失效
invalidate_invoice_cache(session, invoice_id='12345')

API 端点:

生成/下载发票 PDF:

GET /invoice/pdf/{invoice_id}

响应: PDF 文件下载,文件名来自 Stripe 账单描述符

缓存头:

  • 第一次请求:响应较慢(生成时间)
  • 缓存请求:即时响应
  • 缓存命中/未命中对用户是透明的

应用配置更改

后端 (crm_config.yaml)

  1. 编辑 OmniCRM-API/crm_config.yaml
  2. 保存更改
  3. 重启 API 服务:
cd OmniCRM-API
sudo systemctl restart omnicrm-api
# 或
./restart_api.sh

更改在重启后立即生效

前端 (.env)

  1. 编辑 OmniCRM-UI/.env
  2. ��存更改
  3. 重建 UI:
cd OmniCRM-UI
npm run build
  1. 重启 UI 服务或 Web 服务器

开发模式:

在使用 npm start 进行开发时,重启开发服务器以应用更改。


配置最佳实践

安全性

  • 绝不要提交秘密 - 对于包含凭据的配置文件使用 .gitignore
  • 使用强密码 - 至少 16 个字符,包含大小写、数字和符号
  • 定期轮换凭据 - 尤其是针对生产部署
  • 限制数据库访问 - 使用 IP 白名单和防火墙规则
  • 使用特定于环境的配置 - 分开开发/预发布/生产配置
  • 限制 API 密钥权限 - 分配最低必要角色
  • 谨慎使用 IP 白名单 - 优先使用 API 密钥以提高安全性

维护

  • 记录更改 - 保持配置修改的变更日志
  • 备份配置 - 在重大更改之前存储副本
  • 在预发布环境中测试 - 在生产部署之前验证配置更改
  • 版本控制 - 在 git 中跟踪配置模板(不包含秘密)

性能

  • 使用本地数据库 - 避免远程数据库以提高性能
  • 配置缓存 - 如果可用,启用 OCS 缓存
  • 优化 Grafana - 限制嵌入仪表板的数量

品牌

  • 匹配颜色 - 确保 UI 颜色与徽标相辅相成
  • 测试对比度 - 验证文本在彩色��景上的可读性
  • 移动测试 - 检查移动设备上的品牌
  • 徽标位置 - 在不同上下文中使用适当的徽标尺寸

故障排除

常见问题

更改未应用

  • 原因: 服务未重启或 UI 未重建
  • 修复: 在配置更改后重启 API/UI 服务

YAML 语法错误

  • 原因: 无效的 YAML 格式(缩进、引号等)
  • 修复: 在线验证 YAML 或使用 yamllint crm_config.yaml

数据库连接失败

  • 原因: 凭据错误或服务器无法访问
  • 修复: 验证数据库是否正在运行,凭据是否正确

Stripe 支付未工作

  • 原因: 后端和前端之间的密钥不匹配
  • 修复: 确保两个文件中的 publishable_key 匹配

电子邮件未发送

  • 原因: 无效的 Mailjet 凭据或模板 ID
  • 修复: 验证 Mailjet API 密钥/秘密,检查模板 ID 是否存在

PDF 生成失败:

  • 检查 WeasyPrint 是否已安装:pip install weasyprint
  • 验证模板文件名是否与 crm_config.yaml 匹配
  • 检查 invoice_templates/rendered/ 中的 HTML 渲染错误
  • 查看 API 日志以获取 Jinja2 模板错误

图像未出现在 PDF 中:

  • 使用绝对文件路径:file:///full/path/to/image.png
  • 确保图像文件存在且可读
  • 检查图像���式(PNG 和 JPEG 最佳)
  • 验证图像路径不包含特殊字符

样式问题:

  • 所有 CSS 都要内联(不支持外部样式表)
  • 避免复杂的 CSS 特性(flexbox、grid 可能无法正确渲染)
  • 首先测试简单布局,逐步添加复杂性
  • 尽可能使用表格而不是 div 进行布局

缓存未失效:

  • 验证在发票修改时是否调用了 invalidate_invoice_cache()
  • 检查事务更新是否触发缓存失效
  • 如有需要,手动从 Invoice_PDF_Cache 表中删除

配置清单

在部署 OmniCRM 时使用此清单:

后端配置

  • 复制 .env.example.env
  • 设置强数据库密码
  • 配置 CGRates 凭据
  • 更新 crm_config.yaml 以包含您的设置:
    • 数据库连接
    • 服务类型
    • Mailjet API 密钥和模板 ID
    • 供应失败通知电子邮件
    • 发票模板文件名
    • CRM 基础 URL(公共可访问)
    • OCS/CGRates 端点
    • SMSC 配置
    • 生成新的 JWT 密钥
    • Stripe 密钥(生产,不是测试)
    • API 密钥和 IP 白名单

前端配置

  • 复制 OmniCRM-UI/.env.exampleOmniCRM-UI/.env
  • 设置 Google Maps API 密钥
  • 设置 Stripe 可发布密钥
  • 更新公司品牌:
    • 公司名称
    • 门户名称
    • 自助服务名称
    • 公司标语
  • 配置本地化:
    • 默认语言
    • 区域
    • 默认位置和国家
    • 货币代码和符号
  • 设置主要品牌颜色
  • 配置 Web 应用集成(可选)
  • 添加支持和常见问题 URL(可选)
  • 设置 Google Analytics/Tag Manager 跟踪 ID(可选)

品牌资产

  • 创建徽标文件(logoSm.png、logoDark.png、logoLight.png)
  • 将徽标上传到 OmniCRM-UI/src/assets/images/omnitouch/
  • 创建自定义发票模板 HTML
  • 将发票模板上传到 OmniCRM-API/invoice_templates/
  • 更新 crm_config.yaml 以包含发票模板文件名
  • 测试发票 PDF 生成
  • 重建 UI:npm run build

安全性

  • 更改所有默认密码
  • 生成唯一的 JWT 密钥
  • 使用生产 Stripe 密钥(不是测试密钥)
  • 轮换 Mailjet API 密钥
  • 启用防火墙规则
  • 配置 API 访问的 IP 白名单
  • 设置 SSL/TLS 证书
  • 为所有端点启用 HTTPS
  • 审查 CORS 设置
  • 实施速率限制
  • 配置备份和恢复程序

测试

  • 测试客户注册流程
  • 测试服务供应端到端
  • 验证电子邮件通知是否正确发送
  • 测试发票生成和 PDF 下载
  • 验证支付处理(Stripe)
  • 检查用户身份验证和 2FA
  • 测试模拟和审计日志
  • 验证 OCS 的使用数据同步
  • 测试 ActionPlan 创建和续订
  • 确认库存分配正常工作

部署

  • 构建 Docker 镜像或部署到服务器
  • 启动数据库容器(MySQL、PostgreSQL)
  • 启动 CGRates
  • 启动 OmniCRM API
  • 启动 OmniCRM UI
  • 配置反向代理(nginx、traefik)
  • 设置监控(Grafana、Prometheus)
  • 配置日志聚合
  • 设置自动备份
  • 记录部署架构
  • 培训员工使用系统

相关文档

  • RBAC 和用户管理 </rbac>
  • 产品和服务 </concepts_products_and_services>
  • Ansible 供应 </concepts_ansible>
  • 库存管理 </administration_inventory>
  • 客户发票 </payments_invoices>
  • 双因素身份验证 </2fa>
  • 客户关怀和模拟 </customer_care>
  • 支付供应商集成 <integrations_payment_vendors>
  • administration_api_keys - API 密钥管理
  • integrations_mailjet - 电子邮件集成
  • concepts_api - API 身份验证