Fan преди 1 месец
родител
ревизия
d24b53caa8

+ 6 - 0
ui/smarttrade-platform/src/api/emails/index.js

@@ -0,0 +1,6 @@
+import { get, post, put, remove, upload } from '@/utils/request'
+
+export const getMailsPort = (mailAccount) => post('/router/rest/mail/mail_port_config', { mailAccount })
+export const emailsTest = (data) => post('/router/rest/smtp/pop/setting/test_connect', data)
+export const addEmailsSetting = (data) => post('/router/rest/smtp/pop/setting/save', data)
+export const getUserEmails = () => post('/router/rest/smtp/pop/setting/personal_mail_account')

+ 7 - 0
ui/smarttrade-platform/src/api/layout/index.js

@@ -0,0 +1,7 @@
+import { get, post, put, remove, upload } from '@/utils/request'
+
+export const getNoReadCount = () => post('/router/rest/sys/message/getNoReadCountByApp', {appId: 7})
+export const getUserInfo = () => post('/router/rest/sys/auth/getCurrentUserInfo')
+export const updateUserPwd = (data) => post('/router/rest/sys/auth/modifyPass', data)
+export const updateRemark = (data) => post('/router/rest/sys/auth/updateRemark', data)
+export const getLoginData = (data) => post('/router/rest/sys/login/log/pageList', data)

+ 5 - 1
ui/smarttrade-platform/src/api/marketing/index.js

@@ -1,5 +1,9 @@
 import { get, post, put, remove, upload } from '@/utils/request'
 
 export const getMarketingList = (data = {}) => post('/router/rest/marketing/list', data)
-export const getSopList = (data = {}) => post('/router/rest/api/sop', data)
+export const getSopList = (data = {}) => post('/router/rest/api/sop/list', data)
+export const addSop = (data = {}) => post('/router/rest/api/sop/create', data)
+export const editSop = (id, data = {}) => put(`/router/rest/api/sop/${id}`, data)
+export const getSopById = (id) => get(`/router/rest/api/sop/${id}`)
 export const addMarketing = (data = {}) => post('/router/rest/marketing/add', data)
+export const editMarketing = (data = {}) => post('/router/rest/marketing/edit', data)

+ 0 - 4
ui/smarttrade-platform/src/assets/styles/main.css

@@ -1447,10 +1447,6 @@ body {
   border-bottom: none;
 }
 
-.settings-item:hover {
-  background: var(--bg-hover);
-}
-
 .settings-item-info h4 {
   font-size: 13px;
   font-weight: 500;

+ 1 - 0
ui/smarttrade-platform/src/assets/styles/marketing.css

@@ -325,6 +325,7 @@
 .card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
 .card-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 16px; }
 .status-badge { font-size: 10px; padding: 3px 8px; border-radius: 10px; }
+.status-badge.info { background: rgba(10, 10, 10, 0.2); color: white; }
 .status-badge.active { background: rgba(16, 185, 129, 0.2); color: var(--success); }
 .status-badge.paused { background: rgba(245, 158, 11, 0.2); color: var(--warning); }
 .card-title { font-size: 15px; font-weight: 600; margin-bottom: 6px; }

+ 714 - 0
ui/smarttrade-platform/src/assets/styles/settings.css

@@ -0,0 +1,714 @@
+/* Modal Styles */
+.modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.6); display: flex; align-items: center; justify-content: center; z-index: 1000; }
+.modal { background: var(--bg-card); border-radius: 16px; width: 90%; max-width: 480px; max-height: 80vh; display: flex; flex-direction: column; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); }
+.modal.wide { max-width: 700px; }
+.modal.extra-wide { max-width: 1000px; }
+
+.modal-header { display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; border-bottom: 1px solid var(--border); }
+.modal-title { font-size: 16px; font-weight: 600; display: flex; align-items: center; gap: 10px; }
+.modal-title i { color: var(--primary); }
+.modal-close { width: 32px; height: 32px; background: var(--bg-hover); border: none; border-radius: 8px; color: var(--text-secondary); cursor: pointer; display: flex; align-items: center; justify-content: center; }
+.modal-close:hover { background: var(--danger); color: white; }
+.modal-body { flex: 1; overflow-y: auto; padding: 24px; }
+.modal-footer { display: flex; justify-content: flex-end; gap: 12px; padding: 16px 24px; border-top: 1px solid var(--border); }
+
+.form-group { margin-bottom: 16px; }
+.form-label { display: block; font-size: 13px; font-weight: 500; margin-bottom: 8px; color: var(--text-primary); }
+.form-input, .form-select, .form-textarea { width: 100%; padding: 10px 14px; background: var(--bg-dark); border: 1px solid var(--border); border-radius: 8px; color: var(--text-primary); font-size: 13px; }
+.form-input:focus, .form-select:focus, .form-textarea:focus { outline: none; border-color: var(--primary); }
+.form-textarea { resize: vertical; min-height: 80px; }
+
+.password-hint { font-size: 12px; color: var(--text-muted); padding: 12px; background: var(--bg-hover); border-radius: 8px; display: flex; align-items: center; gap: 8px; }
+.password-hint i { color: var(--primary); }
+
+/* Model Fine Tune Modal */
+.model-info-card { padding: 20px; background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(139, 92, 246, 0.1)); border-radius: 12px; margin-bottom: 20px; }
+.model-header { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
+.model-icon { width: 48px; height: 48px; background: var(--primary); border-radius: 12px; display: flex; align-items: center; justify-content: center; color: white; font-size: 20px; }
+.model-title h4 { font-size: 16px; margin-bottom: 4px; }
+.model-status { font-size: 11px; padding: 2px 8px; background: var(--success); color: white; border-radius: 10px; }
+.model-stats { display: flex; gap: 24px; }
+.model-stat { display: flex; flex-direction: column; }
+.model-stat .stat-label { font-size: 11px; color: var(--text-muted); }
+.model-stat .stat-value { font-size: 14px; font-weight: 600; }
+
+.fine-tune-section { padding: 16px; background: var(--bg-hover); border-radius: 10px; }
+.fine-tune-section h5 { font-size: 14px; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
+.fine-tune-section h5 i { color: var(--primary); }
+
+/* Data Source Modal */
+.data-source-list { display: flex; flex-direction: column; gap: 10px; }
+.data-source-item { display: flex; align-items: center; gap: 14px; padding: 14px; background: var(--bg-hover); border-radius: 10px; cursor: pointer; transition: all 0.2s; }
+.data-source-item:hover { background: rgba(99, 102, 241, 0.1); }
+.source-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 16px; }
+.source-icon.trade { background: rgba(99, 102, 241, 0.2); color: var(--primary); }
+.source-icon.linkedin { background: rgba(10, 102, 194, 0.2); color: #0A66C2; }
+.source-icon.maps { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+.source-icon.company { background: rgba(139, 92, 246, 0.2); color: var(--secondary); }
+.source-icon.exhibition { background: rgba(245, 158, 11, 0.2); color: var(--warning); }
+.source-icon.procurement { background: rgba(6, 182, 212, 0.2); color: var(--info); }
+.source-icon.social { background: rgba(236, 72, 153, 0.2); color: #EC4899; }
+.source-icon.association { background: rgba(107, 114, 128, 0.2); color: var(--text-muted); }
+.source-info { flex: 1; }
+.source-name { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
+.source-meta { display: flex; gap: 16px; font-size: 12px; color: var(--text-muted); }
+.source-meta i { margin-right: 4px; }
+.source-desc { font-size: 11px; color: var(--text-muted); margin-top: 6px; }
+.source-status i { margin-right: 4px; }
+
+/* Overview Cards */
+.sources-overview, .email-overview { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 24px; }
+.overview-card { display: flex; align-items: center; gap: 14px; padding: 18px; background: var(--bg-hover); border-radius: 12px; }
+.overview-icon { width: 48px; height: 48px; background: rgba(99, 102, 241, 0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 20px; color: var(--primary); }
+.overview-icon.email { background: rgba(99, 102, 241, 0.2); }
+.overview-info { flex: 1; }
+.overview-value { font-size: 22px; font-weight: 700; }
+.overview-label { font-size: 12px; color: var(--text-muted); }
+
+/* Quick Source Grid */
+.foreign-trade-section { margin-top: 24px; padding: 20px; background: linear-gradient(135deg, rgba(99, 102, 241, 0.05), rgba(139, 92, 246, 0.05)); border-radius: 12px; border: 1px solid rgba(99, 102, 241, 0.1); }
+.foreign-trade-section h4 { font-size: 14px; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
+.foreign-trade-section h4 i { color: var(--primary); }
+.quick-source-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
+.quick-source-card { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 16px; background: var(--bg-card); border-radius: 10px; text-align: center; }
+.quick-source-card i { font-size: 24px; color: var(--primary); }
+.quick-source-card span { font-size: 12px; font-weight: 500; }
+.quick-source-card .btn { margin-top: auto; }
+
+/* Add Data Source & Quick Source Modal */
+.required { color: var(--danger); margin-left: 4px; }
+.test-connection { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border); }
+.test-connection .btn { width: 100%; justify-content: center; }
+
+.quick-config-section { margin-bottom: 20px; padding: 16px; background: var(--bg-hover); border-radius: 10px; }
+.quick-config-section h5 { font-size: 14px; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
+.quick-config-section h5 i { color: var(--primary); }
+
+.checkbox-group { display: flex; flex-wrap: wrap; gap: 12px; }
+.checkbox-item { display: flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; }
+.checkbox-item input { width: 16px; height: 16px; }
+
+/* Email Tab Content */
+.email-tab-content { padding: 16px 0; }
+.stats-overview { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 20px; }
+.stat-card { display: flex; align-items: center; gap: 14px; padding: 18px; background: var(--bg-hover); border-radius: 12px; }
+.stat-card .stat-icon { width: 44px; height: 44px; background: rgba(99, 102, 241, 0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 18px; }
+.stat-card .stat-info { flex: 1; }
+.stat-card .stat-value { font-size: 22px; font-weight: 700; }
+.stat-card .stat-label { font-size: 12px; color: var(--text-muted); }
+
+.chart-section, .top-performers { margin-top: 20px; }
+.chart-section h5, .top-performers h5 { font-size: 14px; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
+.chart-section h5 i, .top-performers h5 i { color: var(--primary); }
+
+.simple-chart { display: flex; align-items: flex-end; gap: 12px; height: 160px; padding: 30px 20px; background: var(--bg-hover); border-radius: 12px; }
+.chart-bar { flex: 1; background: linear-gradient(to top, var(--primary), var(--secondary)); border-radius: 6px 6px 0 0; position: relative; min-height: 20px; display: flex; align-items: flex-end; justify-content: center; padding-bottom: 8px; }
+.chart-bar span { font-size: 11px; color: var(--text-muted); position: absolute; bottom: -24px; }
+
+.template-list { display: flex; flex-direction: column; gap: 10px; }
+.template-item { display: flex; justify-content: space-between; align-items: center; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
+.template-name { font-size: 14px; font-weight: 500; }
+.template-stats { font-size: 12px; color: var(--text-muted); }
+
+/* Domain Config */
+.domain-config-section { margin-bottom: 20px; }
+.domain-config-section h5 { font-size: 14px; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
+.domain-config-section h5 i { color: var(--primary); }
+
+.domain-list { display: flex; flex-direction: column; gap: 10px; }
+.domain-item { display: flex; align-items: center; gap: 14px; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
+.domain-icon { width: 44px; height: 44px; background: rgba(99, 102, 241, 0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 18px; }
+.domain-info { flex: 1; }
+.domain-name { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
+.domain-meta { display: flex; gap: 16px; font-size: 12px; color: var(--text-muted); }
+.domain-status { display: inline-flex; align-items: center; gap: 4px; }
+.domain-status.active { color: var(--success); }
+
+.config-guide { display: flex; flex-direction: column; gap: 14px; }
+.guide-step { display: flex; gap: 14px; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
+.step-num { width: 28px; height: 28px; background: var(--primary); color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; flex-shrink: 0; }
+.step-content { flex: 1; }
+.step-title { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
+.step-desc { font-size: 12px; color: var(--text-muted); }
+
+/* Security */
+.security-overview { margin-bottom: 20px; }
+.security-card { padding: 24px; background: linear-gradient(135deg, rgba(16, 185, 129, 0.1), rgba(99, 102, 241, 0.1)); border-radius: 12px; text-align: center; }
+.security-header { display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 12px; font-size: 14px; color: var(--text-secondary); }
+.security-header i { color: var(--success); }
+.security-score { font-size: 36px; font-weight: 700; color: var(--success); margin-bottom: 8px; }
+.security-desc { font-size: 13px; color: var(--text-muted); }
+
+.security-section { margin-bottom: 20px; }
+.security-section h5 { font-size: 14px; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
+.security-section h5 i { color: var(--primary); }
+
+.security-list { display: flex; flex-direction: column; gap: 10px; }
+.security-item { display: flex; justify-content: space-between; align-items: center; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
+.security-item-info { display: flex; flex-direction: column; }
+.security-item-title { font-size: 14px; font-weight: 500; }
+.security-item-desc { font-size: 12px; color: var(--text-muted); }
+
+.security-logs { display: flex; flex-direction: column; gap: 8px; }
+.log-item { display: flex; align-items: center; gap: 16px; padding: 10px; background: var(--bg-hover); border-radius: 8px; font-size: 12px; }
+.log-item .log-time { color: var(--text-muted); min-width: 120px; }
+.log-item .log-event { flex: 1; }
+.log-item .log-status { padding: 2px 8px; border-radius: 10px; }
+.log-status.success { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+
+/* Email Enhanced */
+.email-account-item.selected { border: 2px solid var(--primary); background: rgba(99, 102, 241, 0.05); }
+.account-auth { display: flex; flex-direction: column; gap: 4px; }
+.auth-badge { display: inline-flex; align-items: center; gap: 4px; font-size: 10px; padding: 2px 6px; background: var(--bg-dark); border-radius: 4px; color: var(--text-muted); }
+.auth-badge.active { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+
+.detail-tabs { display: flex; gap: 8px; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
+.detail-tab { padding: 8px 14px; background: transparent; border: none; color: var(--text-secondary); font-size: 12px; cursor: pointer; border-radius: 8px; }
+.detail-tab:hover { background: var(--bg-hover); }
+.detail-tab.active { background: var(--primary); color: white; }
+
+.config-grid-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
+.config-card { background: var(--bg-card); border-radius: 10px; overflow: hidden; }
+.config-card-header { padding: 12px 16px; background: var(--bg-hover); font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 8px; }
+.config-card-body { padding: 16px; }
+.config-card-body .config-row { background: var(--bg-hover); padding: 10px; border-radius: 6px; margin-bottom: 8px; }
+.config-card-body .config-row:last-child { margin-bottom: 0; }
+
+.auth-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
+.auth-card { display: flex; align-items: center; gap: 12px; padding: 16px; background: var(--bg-card); border-radius: 10px; border: 1px solid var(--border); }
+.auth-card.pass { border-color: rgba(16, 185, 129, 0.3); }
+.auth-card.fail { border-color: rgba(239, 68, 68, 0.3); }
+.auth-card .auth-icon { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; }
+.auth-card.pass .auth-icon { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+.auth-card.fail .auth-icon { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
+.auth-card .auth-info { flex: 1; }
+.auth-card .auth-name { font-size: 14px; font-weight: 600; }
+.auth-card .auth-desc { font-size: 11px; color: var(--text-muted); }
+.auth-card .auth-status { font-size: 11px; padding: 3px 8px; border-radius: 10px; }
+.auth-card.pass .auth-status { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+.auth-card.fail .auth-status { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
+
+.config-row-flex { display: flex; gap: 24px; margin-bottom: 16px; }
+.config-row-flex .config-item { flex: 1; }
+
+.signature-preview { margin-bottom: 12px; padding: 16px; background: var(--bg-card); border-radius: 10px; border-left: 4px solid var(--primary); }
+.signature-label { font-size: 11px; color: var(--text-muted); margin-bottom: 8px; }
+.signature-content pre { font-size: 12px; white-space: pre-wrap; font-family: inherit; margin: 0; }
+.usage-label { font-size: 11px; color: var(--text-muted); margin-bottom: 4px; }
+
+/* Email Modal */
+.email-accounts-list { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
+.email-account-item { display: flex; align-items: center; gap: 14px; padding: 16px; background: var(--bg-hover); border-radius: 10px; }
+.account-icon { width: 44px; height: 44px; background: rgba(99, 102, 241, 0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 18px; }
+.account-info { flex: 1; }
+.account-email { font-size: 14px; font-weight: 500; margin-bottom: 2px; }
+.account-name { font-size: 12px; color: var(--text-muted); margin-bottom: 6px; }
+.account-stats { display: flex; gap: 16px; font-size: 11px; color: var(--text-muted); }
+.add-account-btn { width: 100%; }
+
+/* LinkedIn & WeChat Modal */
+.connect-prompt { text-align: center; padding: 40px 20px; }
+.connect-icon { width: 80px; height: 80px; background: rgba(10, 102, 194, 0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px; font-size: 36px; color: #0A66C2; }
+.connect-icon.wechat { background: rgba(7, 193, 96, 0.2); color: #07C160; }
+.connect-prompt h4 { font-size: 18px; margin-bottom: 10px; }
+.connect-prompt p { font-size: 13px; color: var(--text-muted); margin-bottom: 24px; }
+.wechat-btn { background: #07C160; }
+
+.linkedin-connected, .wechat-connected { padding: 20px; background: var(--bg-hover); border-radius: 12px; }
+.linkedin-stats, .wechat-stats { display: flex; gap: 24px; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }
+.stat-item { display: flex; flex-direction: column; align-items: center; flex: 1; }
+.stat-item .stat-label { font-size: 11px; color: var(--text-muted); margin-bottom: 4px; }
+.stat-item .stat-value { font-size: 18px; font-weight: 600; }
+
+/* Data Source Detail Modal */
+.source-detail-header { margin-bottom: 20px; }
+.source-detail-status { margin-bottom: 10px; }
+.status-badge { display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border-radius: 20px; font-size: 13px; }
+.status-badge.active { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+.status-badge.inactive { background: rgba(107, 114, 128, 0.2); color: var(--text-muted); }
+.source-description { font-size: 13px; color: var(--text-muted); }
+
+.source-stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 24px; }
+.source-stat-card { display: flex; align-items: center; gap: 12px; padding: 16px; background: var(--bg-hover); border-radius: 10px; }
+.source-stat-card .stat-icon { width: 40px; height: 40px; background: rgba(99, 102, 241, 0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 16px; }
+.source-stat-card .stat-info { flex: 1; }
+.source-stat-card .stat-value { font-size: 16px; font-weight: 600; }
+.source-stat-card .stat-label { font-size: 11px; color: var(--text-muted); }
+
+.detail-section { margin-bottom: 20px; }
+.detail-section h5 { font-size: 14px; margin-bottom: 12px; display: flex; align-items: center; gap: 8px; }
+.detail-section h5 i { color: var(--primary); }
+
+.config-grid { display: flex; gap: 16px; flex-wrap: wrap; }
+.config-item { display: flex; flex-direction: column; gap: 6px; min-width: 120px; }
+.config-item label { font-size: 12px; color: var(--text-muted); }
+.config-item .form-select { padding: 8px 12px; font-size: 12px; }
+
+.fields-list { display: flex; flex-direction: column; gap: 8px; }
+.field-item { display: flex; align-items: center; gap: 12px; padding: 10px; background: var(--bg-hover); border-radius: 8px; font-size: 13px; }
+.field-name { color: var(--primary); font-weight: 500; }
+.field-item i { color: var(--text-muted); }
+.field-target { color: var(--text-secondary); font-family: monospace; }
+
+.sync-logs { display: flex; flex-direction: column; gap: 8px; }
+.sync-log-item { display: flex; align-items: center; gap: 16px; padding: 10px; background: var(--bg-hover); border-radius: 8px; font-size: 12px; }
+.log-time { color: var(--text-muted); min-width: 140px; }
+.log-status { padding: 2px 8px; border-radius: 10px; }
+.log-status.success { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+.log-count { color: var(--text-secondary); }
+
+/* Email Modal Enhanced */
+.email-tabs { display: flex; gap: 8px; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
+.email-tab { padding: 8px 16px; background: transparent; border: none; color: var(--text-secondary); font-size: 13px; cursor: pointer; border-radius: 8px; }
+.email-tab:hover { background: var(--bg-hover); }
+.email-tab.active { background: var(--primary); color: white; }
+
+.account-usage { display: flex; flex-direction: column; gap: 4px; min-width: 100px; }
+.usage-bar { height: 6px; background: var(--bg-dark); border-radius: 3px; overflow: hidden; }
+.usage-fill { height: 100%; background: var(--primary); border-radius: 3px; }
+.usage-text { font-size: 10px; color: var(--text-muted); text-align: right; }
+
+.email-detail-panel { margin-top: 20px; padding: 20px; background: var(--bg-hover); border-radius: 12px; }
+.email-detail-panel .detail-header { margin-bottom: 16px; }
+.email-detail-panel .detail-header h4 { font-size: 14px; display: flex; align-items: center; gap: 8px; }
+
+.config-table { display: flex; flex-direction: column; gap: 8px; }
+.config-row { display: flex; justify-content: space-between; padding: 10px; background: var(--bg-card); border-radius: 8px; font-size: 12px; }
+.config-label { color: var(--text-muted); }
+.config-value { font-weight: 500; }
+
+.auth-status-grid { display: flex; gap: 12px; }
+.auth-status-item { display: flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--bg-card); border-radius: 8px; font-size: 12px; }
+.auth-status-item.active { color: var(--success); }
+.auth-status-item.inactive { color: var(--danger); }
+.auth-status-item i { font-size: 16px; }
+
+.auto-reply-config { display: flex; flex-direction: column; gap: 12px; }
+.auto-reply-config .config-item { flex-direction: row; align-items: center; justify-content: space-between; }
+.auto-reply-config textarea { min-height: 60px; }
+
+.signature-textarea { font-family: monospace; font-size: 12px; }
+
+.toggle-switch { width: 44px; height: 24px; background: var(--bg-dark); border-radius: 12px; position: relative; cursor: pointer; transition: all 0.2s; }
+.toggle-switch.active { background: var(--primary); }
+.toggle-slider { width: 20px; height: 20px; background: white; border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: all 0.2s; }
+.toggle-switch.active .toggle-slider { left: 22px; }
+
+.settings-page {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  padding: 24px;
+  overflow-y: auto;
+  background: var(--bg-dark);
+}
+
+.settings-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  margin-bottom: 24px;
+}
+
+.header-left {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+}
+
+.data-title {
+  font-size: 20px;
+  font-weight: 600;
+}
+
+.header-desc {
+  font-size: 13px;
+  color: var(--text-secondary);
+}
+
+.header-actions {
+  display: flex;
+  gap: 12px;
+}
+
+/* Settings Grid */
+.settings-grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 24px;
+}
+
+.settings-column {
+  display: flex;
+  flex-direction: column;
+  gap: 24px;
+}
+
+/* Settings Section */
+.settings-section {
+  background: var(--bg-card);
+  border: 1px solid var(--border);
+  border-radius: 16px;
+  overflow: hidden;
+}
+
+.section-header {
+  display: flex;
+  align-items: center;
+  gap: 14px;
+  padding: 20px;
+  background: var(--bg-hover);
+  border-bottom: 1px solid var(--border);
+}
+
+.section-icon {
+  width: 44px;
+  height: 44px;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 18px;
+}
+
+.section-title h3 {
+  font-size: 15px;
+  font-weight: 600;
+  margin-bottom: 2px;
+}
+
+.section-title p {
+  font-size: 12px;
+  color: var(--text-secondary);
+}
+
+/* Settings List */
+.settings-list {
+  padding: 8px;
+}
+
+.settings-item {
+  display: flex;
+  align-items: center;
+  gap: 14px;
+  padding: 14px;
+  border-radius: 10px;
+  cursor: pointer;
+  transition: background 0.2s;
+}
+
+.settings-item:hover {
+  background: var(--bg-hover);
+}
+
+.item-icon {
+  width: 40px;
+  height: 40px;
+  border-radius: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 16px;
+  flex-shrink: 0;
+}
+
+.item-content {
+  flex: 1;
+  min-width: 0;
+}
+
+.item-title {
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 2px;
+}
+
+.item-desc {
+  font-size: 12px;
+  color: var(--text-secondary);
+}
+
+.item-action {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  flex-shrink: 0;
+}
+
+.item-value {
+  font-size: 13px;
+  color: var(--text-secondary);
+}
+
+.item-value.success {
+  color: var(--success);
+}
+
+.item-value.warning {
+  color: var(--warning);
+}
+
+.item-action i {
+  color: var(--text-muted);
+  font-size: 12px;
+}
+
+/* Profile Card */
+.profile-card {
+  display: flex;
+  align-items: center;
+  gap: 16px;
+  padding: 20px;
+  margin: 8px;
+  background: var(--bg-hover);
+  border-radius: 12px;
+}
+
+.profile-avatar {
+  width: 64px;
+  height: 64px;
+  background: var(--gradient-1);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 24px;
+  font-weight: 600;
+  color: white;
+  position: relative;
+}
+
+.avatar-edit {
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  width: 24px;
+  height: 24px;
+  background: var(--primary);
+  border: 2px solid var(--bg-hover);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 10px;
+  color: white;
+  cursor: pointer;
+}
+
+.profile-info {
+  flex: 1;
+}
+
+.profile-name {
+  font-size: 16px;
+  font-weight: 600;
+  margin-bottom: 2px;
+}
+
+.profile-role {
+  font-size: 13px;
+  color: var(--text-secondary);
+  margin-bottom: 2px;
+}
+
+.profile-email {
+  font-size: 12px;
+  color: var(--text-muted);
+}
+
+/* Toggle Switch */
+.toggle-switch {
+  width: 44px;
+  height: 24px;
+  background: var(--bg-dark);
+  border-radius: 12px;
+  position: relative;
+  cursor: pointer;
+  transition: all 0.2s;
+  flex-shrink: 0;
+}
+.toggle-switch.active {
+  background: var(--primary);
+}
+.toggle-slider {
+  position: absolute;
+  top: 2px;
+  left: 2px;
+  width: 20px;
+  height: 20px;
+  background: white;
+  border-radius: 50%;
+  transition: all 0.2s;
+  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
+}
+.toggle-switch.active .toggle-slider {
+  transform: translateX(20px);
+}
+
+/* Global Toggle Fix - Override inline styles */
+.settings-item .toggle-switch,
+.channel-item .toggle-switch,
+.item-action .toggle-switch,
+.settings-modal .toggle-switch,
+.modal .toggle-switch,
+.detail-section .toggle-switch,
+.config-item .toggle-switch,
+.auto-reply-config .toggle-switch { 
+  margin-left: auto; 
+  background: var(--bg-dark) !important;
+}
+
+.settings-item .toggle-switch.active,
+.channel-item .toggle-switch.active,
+.item-action .toggle-switch.active,
+.settings-modal .toggle-switch.active,
+.modal .toggle-switch.active,
+.detail-section .toggle-switch.active,
+.config-item .toggle-switch.active,
+.auto-reply-config .toggle-switch.active {
+  background: var(--primary) !important;
+}
+
+/* Mini Select */
+.mini-select {
+  padding: 6px 12px;
+  background: var(--bg-hover);
+  border: 1px solid var(--border);
+  border-radius: 8px;
+  color: var(--text-primary);
+  font-size: 13px;
+  cursor: pointer;
+}
+
+.mini-select:focus {
+  outline: none;
+  border-color: var(--primary);
+}
+
+/* Channel List */
+.channel-list {
+  padding: 8px;
+}
+
+.channel-item {
+  display: flex;
+  align-items: center;
+  gap: 14px;
+  padding: 14px;
+  border-radius: 10px;
+  border: 1px solid var(--border);
+  margin-bottom: 8px;
+  background: var(--bg-dark);
+  transition: all 0.2s;
+}
+
+.channel-item:last-child {
+  margin-bottom: 0;
+}
+
+.channel-item.connected {
+  border-color: rgba(16, 185, 129, 0.3);
+}
+
+.channel-icon {
+  width: 40px;
+  height: 40px;
+  border-radius: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 18px;
+  flex-shrink: 0;
+}
+
+.channel-content {
+  flex: 1;
+}
+
+.channel-title {
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 2px;
+}
+
+.channel-desc {
+  font-size: 12px;
+  color: var(--text-secondary);
+}
+
+.channel-action {
+  flex-shrink: 0;
+}
+
+.status-badge {
+  display: inline-flex;
+  align-items: center;
+  gap: 4px;
+  padding: 4px 10px;
+  border-radius: 12px;
+  font-size: 11px;
+  font-weight: 500;
+}
+
+.status-badge.success {
+  background: rgba(16, 185, 129, 0.2);
+  color: var(--success);
+}
+
+/* Toast */
+.toast {
+  position: fixed;
+  bottom: 24px;
+  right: 24px;
+  padding: 12px 20px;
+  background: var(--bg-card);
+  border: 1px solid var(--border);
+  border-radius: 10px;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  font-size: 13px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
+  z-index: 2000;
+}
+
+.toast.success {
+  border-color: var(--success);
+}
+
+.toast.success i {
+  color: var(--success);
+}
+
+.toast-enter-active,
+.toast-leave-active {
+  transition: all 0.3s ease;
+}
+
+.toast-enter-from,
+.toast-leave-to {
+  opacity: 0;
+  transform: translateY(20px);
+}
+
+/* Responsive */
+@media (max-width: 1200px) {
+  .settings-grid {
+    grid-template-columns: 1fr;
+  }
+}
+
+@media (max-width: 768px) {
+  .settings-header {
+    flex-direction: column;
+    gap: 16px;
+  }
+  
+  .header-actions {
+    width: 100%;
+  }
+  
+  .header-actions .btn {
+    flex: 1;
+  }
+}

+ 3 - 3
ui/smarttrade-platform/src/components/PreviewCustomerModal.vue

@@ -17,15 +17,15 @@
         <div v-if="customers && customers.length" class="customer-list">
           <div v-for="customer in customers" :key="customer.id" class="customer-card">
             <div class="customer-card-left">
-              <div class="customer-logo">{{ customer.logoText || customer.name.charAt(0) }}</div>
+              <div class="customer-logo">{{ customer.logoText || customer.customerName.charAt(0) }}</div>
               <div class="customer-meta">
                 <div class="customer-name-row">
-                  <div class="customer-name">{{ customer.name }}</div>
+                  <div class="customer-name">{{ customer.customerName }}</div>
                   <span class="customer-badge">{{ customer.tag || '潜客' }}</span>
                 </div>
                 <div class="customer-subtitle">{{ customer.role || '采购总监' }} · {{ customer.company }}</div>
                 <div class="customer-info-row">
-                  <span><i class="fas fa-map-marker-alt"></i> {{ customer.location }}</span>
+                  <span><i class="fas fa-map-marker-alt"></i> {{ customer.continent }} - {{ customer.country }}</span>
                   <span><i class="fas fa-dollar-sign"></i> {{ customer.annualPurchase }}</span>
                 </div>
               </div>

+ 295 - 214
ui/smarttrade-platform/src/components/addMarketing.vue

@@ -3,7 +3,7 @@
         <div class="modal create-modal">
             <div class="modal-header">
                 <div class="modal-title">
-                    <i class="fas fa-plus-circle"></i> 创建营销活动
+                    <i class="fas fa-plus-circle"></i> {{ modalTitle }}
                 </div>
                 <button class="modal-close" @click="closeCreateModal">
                     <i class="fas fa-times"></i>
@@ -58,20 +58,21 @@
                         <div class="form-group">
                             <label class="form-label">活动类型</label>
                             <el-select v-model="newCampaign.type" placeholder="请选择活动类型">
-                                <el-option label="潜客开发" value="潜客开发" />
-                                <el-option label="客户培育" value="客户培育" />
-                                <el-option label="客户唤醒" value="客户唤醒" />
-                                <el-option label="产品推广" value="产品推广" />
-                                <el-option label="节日营销" value="节日营销" />
-                                <el-option label="展会跟进" value="展会跟进" />
+                                <el-option value="prospect" label="潜客开发"></el-option>
+                                <el-option value="nurture" label="客户培育"></el-option>
+                                <el-option value="reactivate" label="客户唤醒"></el-option>
+                                <el-option value="promote" label="产品推广"></el-option>
+                                <el-option value="seasonal" label="节日营销"></el-option>
+                                <el-option value="exhibition" label="展会跟进"></el-option>
                             </el-select>
                         </div>
                         <div class="form-group">
                             <label class="form-label">优先级</label>
                             <el-select v-model="newCampaign.priority" placeholder="请选择优先级">
-                                <el-option label="高" value="高" />
-                                <el-option label="中" value="中" />
-                                <el-option label="低" value="低" />
+                                <el-option label="紧急" value="urgent" />
+                                <el-option label="高优先" value="high" />
+                                <el-option label="中等" value="medium" />
+                                <el-option label="低优先" value="low" />
                             </el-select>
                         </div>
                     </div>
@@ -80,9 +81,9 @@
                             <label class="form-label">开始日期</label>
                             <el-date-picker
                                 v-model="newCampaign.startDate"
-                                type="datetime"
-                                format="YYYY-MM-DD HH:mm"
-                                value-format="YYYY-MM-DD HH:mm:ss"
+                                type="date"
+                                format="YYYY-MM-DD"
+                                value-format="YYYY-MM-DD"
                                 placeholder="选择开始时间"
                             />
                         </div>
@@ -90,9 +91,9 @@
                             <label class="form-label">结束日期</label>
                             <el-date-picker
                                 v-model="newCampaign.endDate"
-                                type="datetime"
-                                format="YYYY-MM-DD HH:mm"
-                                value-format="YYYY-MM-DD HH:mm:ss"
+                                type="date"
+                                format="YYYY-MM-DD"
+                                value-format="YYYY-MM-DD"
                                 placeholder="选择结束时间"
                             />
                         </div>
@@ -205,14 +206,8 @@
                         <div class="filter-row">
                             <div class="form-group">
                                 <label class="form-label">地区</label>
-                                <el-select v-model="newCampaign.filters.region" clearable placeholder="全部地区">
-                                    <el-option label="中东" value="middle-east" />
-                                    <el-option label="欧洲" value="europe" />
-                                    <el-option label="北美" value="north-america" />
-                                    <el-option label="东南亚" value="southeast-asia" />
-                                    <el-option label="非洲" value="africa" />
-                                    <el-option label="南美" value="south-america" />
-                                </el-select>
+                                <el-cascader style="width: 100%" placeholder="区域名称" :options="region"
+                                    v-model="regionValue" clearable filterable @change="getRegion" />
                             </div>
                             <div class="form-group">
                                 <label class="form-label">行业</label>
@@ -247,8 +242,8 @@
                         <div class="form-group">
                             <label class="form-label">关键词搜索</label>
                             <div class="keyword-search">
-                                <el-input v-model="newCampaign.filters.keyword" placeholder="搜索公司名、联系人、产品关键词..." clearable />
-                                <button class="btn btn-secondary">
+                                <el-input v-model="customerParams.blurry" placeholder="搜索公司名、联系人、产品关键词..." clearable />
+                                <button class="btn btn-secondary" @click="getCustomerData">
                                     <i class="fas fa-search"></i>
                                 </button>
                             </div>
@@ -266,46 +261,25 @@
                         <i class="fas fa-users"></i>
                         <div class="count-info">
                             <div class="count-value">
-                                已选择 <strong>{{ selectedCustomerCount }}</strong> 位客户
+                                已选择 <strong>{{ customerList.length }}</strong> 位客户
                             </div>
                             <div class="count-detail">基于当前筛选条件</div>
                         </div>
-                        <button class="btn btn-sm btn-outline" @click="showCustomerPreview = true">
+                        <button class="btn btn-sm btn-outline" @click="showCustomerPreview = true" v-if="customerList.length != 0">
                             <i class="fas fa-eye"></i> 预览客户
                         </button>
                     </div>
 
                     <!-- 客户来源分布 -->
-                    <div class="customer-source">
+                    <div class="customer-source" v-if="customerList.length != 0">
                         <h5><i class="fas fa-chart-pie"></i> 客户来源分布</h5>
                         <div class="source-bars">
-                            <div class="source-item">
-                                <span class="source-label">AI推荐</span>
-                                <div class="source-bar">
-                                    <div class="source-fill" style="width: 45%; background: var(--primary)"></div>
-                                </div>
-                                <span class="source-value">45%</span>
-                            </div>
-                            <div class="source-item">
-                                <span class="source-label">展会获取</span>
-                                <div class="source-bar">
-                                    <div class="source-fill" style="width: 25%; background: var(--success)"></div>
-                                </div>
-                                <span class="source-value">25%</span>
-                            </div>
-                            <div class="source-item">
-                                <span class="source-label">官网注册</span>
+                            <div class="source-item" v-for="(value, item) in sourceData">
+                                <span class="source-label">{{ item }}</span>
                                 <div class="source-bar">
-                                    <div class="source-fill" style="width: 20%; background: var(--info)"></div>
+                                    <div class="source-fill" :style="{ width: (value / customerList.length) * 100 + '%', background: 'var(--success)' }"></div>
                                 </div>
-                                <span class="source-value">20%</span>
-                            </div>
-                            <div class="source-item">
-                                <span class="source-label">转介绍</span>
-                                <div class="source-bar">
-                                    <div class="source-fill" style="width: 10%; background: var(--warning)"></div>
-                                </div>
-                                <span class="source-value">10%</span>
+                                <span class="source-value">{{ (value / customerList.length * 100).toFixed(2) }}%</span>
                             </div>
                         </div>
                     </div>
@@ -344,9 +318,7 @@
                             <div class="form-group">
                                 <label class="form-label">发件邮箱</label>
                                 <el-select v-model="newCampaign.emailSender" placeholder="请选择发件邮箱">
-                                    <el-option label="sales@company.com" value="sales@company.com" />
-                                    <el-option label="marketing@company.com" value="marketing@company.com" />
-                                    <el-option label="support@company.com" value="support@company.com" />
+                                    <el-option v-for="item in emailList" :label="item.mailAccount" :value="item.mailAccount" :key="item.id"></el-option>
                                 </el-select>
                             </div>
                             <div class="form-group">
@@ -460,11 +432,11 @@
                             <div v-for="sop in sopTemplates" :key="sop.id" class="sop-card"
                                 :class="{ selected: newCampaign.sopTemplate === sop.id }"
                                 @click="newCampaign.sopTemplate = sop.id">
-                                <div class="sop-icon">{{ sop.icon }}</div>
+                                <!-- <div class="sop-icon">{{ sop.icon }}</div> -->
                                 <div class="sop-info">
                                     <div class="sop-name">{{ sop.name }}</div>
-                                    <div class="sop-steps">{{ sop.steps }} 步序列</div>
-                                    <div class="sop-desc">{{ sop.description }}</div>
+                                    <div class="sop-steps">{{ sop.details.length }} 步序列</div>
+                                    <!-- <div class="sop-desc">{{ sop.description }}</div> -->
                                 </div>
                                 <div class="sop-check" v-if="newCampaign.sopTemplate === sop.id">
                                     <i class="fas fa-check-circle"></i>
@@ -480,14 +452,14 @@
                                 </button>
                             </div>
                             <div class="sop-timeline">
-                                <div v-for="(step, idx) in selectedSopTemplate.stepsDetail" :key="idx" class="sop-step">
+                                <div v-for="(step, idx) in selectedSopTemplate.details" :key="idx" class="sop-step">
                                     <div class="sop-step-marker">{{ idx + 1 }}</div>
                                     <div class="sop-step-content">
-                                        <div class="sop-step-title">{{ step.title }}</div>
+                                        <div class="sop-step-title">{{ step.name }}</div>
                                         <div class="sop-step-meta">
-                                            <span><i class="fas fa-clock"></i> 第{{ step.day }}天</span>
+                                            <span><i class="fas fa-clock"></i> 第{{ step.days }}天</span>
                                             <span><i :class="step.channelIcon"></i>
-                                                {{ step.channel }}</span>
+                                                {{ getChannelName(step.type) }}</span>
                                         </div>
                                     </div>
                                 </div>
@@ -508,7 +480,7 @@
                                 <div class="rule-desc">3天后发送提醒邮件,更换主题行</div>
                             </div>
                             <div class="rule-config" v-if="newCampaign.rules.noOpenFollowup">
-                                <el-select class="mini-select" v-model="newCampaign.rules.noOpenFollowupDays" placeholder="请选择">
+                                <el-select style="width: 90px;" v-model="newCampaign.rules.noOpenFollowupDays" placeholder="请选择">
                                     <el-option label="2天后" value="2" />
                                     <el-option label="3天后" value="3" />
                                     <el-option label="5天后" value="5" />
@@ -526,7 +498,7 @@
                                 <div class="rule-desc">7天后跟进</div>
                             </div>
                             <div class="rule-config" v-if="newCampaign.rules.noReplyFollowup">
-                                <el-select class="mini-select" v-model="newCampaign.rules.noReplyFollowupDays" placeholder="请选择">
+                                <el-select style="width: 90px;" v-model="newCampaign.rules.noReplyFollowupDays" placeholder="请选择">
                                     <el-option label="5天后" value="5" />
                                     <el-option label="7天后" value="7" />
                                     <el-option label="10天后" value="10" />
@@ -591,7 +563,7 @@
                                 </div>
                                 <div class="ab-variant">
                                     <span class="variant-label">B 版本</span>
-                                    <el-input v-model="newCampaign.abTest.variantB" class="variant-input" placeholder="输入测试主题..." />
+                                    <el-input v-model="newCampaign.abTest.variantB" placeholder="输入测试主题..." />
                                 </div>
                             </div>
                         </div>
@@ -803,8 +775,8 @@
                 <button v-if="currentStep < 5" class="btn btn-primary" @click="currentStep++">
                     下一步 <i class="fas fa-arrow-right"></i>
                 </button>
-                <button v-else class="btn btn-primary" :disabled="!canCreate || isSubmitting" @click="createCampaign">
-                    <i class="fas fa-rocket"></i> 创建活动
+                <button v-else class="btn btn-primary" @click="createCampaign">
+                    <i class="fas fa-rocket"></i> {{ isEditMode ? "编辑活动" : "创建活动" }}
                 </button>
             </div>
         </div>
@@ -834,40 +806,36 @@
                     </div>
 
                     <div class="custom-steps-list">
-                        <div v-for="(step, index) in customSopData.steps" :key="index" class="custom-step-item">
+                        <div v-for="(step, index) in customSopData.details" :key="index" class="custom-step-item">
                             <div class="step-number">{{ index + 1 }}</div>
                             <div class="step-fields">
                                 <div class="step-row">
                                     <div class="form-group">
                                         <label class="form-label">步骤名称</label>
-                                        <el-input v-model="step.title" placeholder="例如:发送产品介绍" />
+                                        <el-input v-model="step.name" placeholder="例如:发送产品介绍" />
                                     </div>
                                     <div class="form-group">
                                         <label class="form-label">间隔天数</label>
-                                        <el-input-number v-model="step.day" :controls="false" :min="1" :max="30" />
+                                        <el-input-number v-model="step.days" :controls="false" :min="1" :max="30" />
                                     </div>
                                 </div>
                                 <div class="step-row">
                                     <div class="form-group">
                                         <label class="form-label">触达渠道</label>
-                                        <el-select v-model="step.channel" placeholder="请选择渠道" @change="updateChannelIcon(index)">
+                                        <el-select v-model="step.type" placeholder="请选择渠道">
                                             <el-option label="邮件" value="email" />
-                                            <el-option label="WhatsApp" value="whatsapp" />
-                                            <el-option label="LinkedIn" value="linkedin" />
-                                            <el-option label="电话" value="phone" />
-                                            <el-option label="微信" value="wechat" />
                                         </el-select>
                                     </div>
                                     <div class="channel-preview">
-                                        <div class="preview-badge" :class="step.channel">
-                                            <i :class="step.channelIcon"></i> {{ getChannelName(step.channel) }}
+                                        <div class="preview-badge" :class="step.type">
+                                            {{ getChannelName(step.type) }}
                                         </div>
                                     </div>
                                 </div>
                             </div>
                             <div class="step-actions">
                                 <button class="btn-icon" @click="removeCustomSopStep(index)"
-                                    :disabled="customSopData.steps.length <= 1" title="删除步骤">
+                                    :disabled="customSopData.details.length <= 1" title="删除步骤">
                                     <i class="fas fa-trash"></i>
                                 </button>
                             </div>
@@ -879,17 +847,14 @@
                 <div class="custom-sop-preview">
                     <h5><i class="fas fa-eye"></i> 效果预览</h5>
                     <div class="preview-timeline">
-                        <div v-for="(step, index) in customSopData.steps.filter(s => s.title)" :key="index"
+                        <div v-for="(step, index) in customSopData.details.filter(s => s.name)" :key="index"
                             class="preview-step">
-                            <div class="preview-marker">
-                                <i :class="step.channelIcon"></i>
-                            </div>
                             <div class="preview-content">
-                                <div class="preview-title">{{ step.title }}</div>
-                                <div class="preview-meta">第{{ step.day }}天 · {{ getChannelName(step.channel) }}</div>
+                                <div class="preview-title">{{ step.name }}</div>
+                                <div class="preview-meta">第{{ step.days }}天 · {{ getChannelName(step.type) }}</div>
                             </div>
                         </div>
-                        <div v-if="customSopData.steps.filter(s => s.title).length === 0" class="preview-empty">
+                        <div v-if="customSopData.details.filter(s => s.name).length === 0" class="preview-empty">
                             <i class="fas fa-info-circle"></i> 请填写步骤内容以预览效果
                         </div>
                     </div>
@@ -897,7 +862,7 @@
             </div>
             <div class="modal-footer">
                 <button class="btn btn-secondary" @click="showCustomSopModal = false">取消</button>
-                <button class="btn btn-primary">
+                <button class="btn btn-primary" @click="addNewSop">
                     <i class="fas fa-save"></i> 保存为新序列
                 </button>
                 <button class="btn btn-primary" @click="saveCustomSop">
@@ -909,7 +874,7 @@
 
     <PreviewCustomerModal
       :visible="showCustomerPreview"
-      :customers="previewCustomers"
+      :customers="customerList"
       @close="showCustomerPreview = false"
     />
 </template>
@@ -917,19 +882,20 @@
 <script setup>
     import { ref, computed } from 'vue'
     import PreviewCustomerModal from './PreviewCustomerModal.vue'
-    import { getSopList, addMarketing } from '@/api/marketing'
+    import { getSopList, addMarketing, editMarketing, addSop, editSop } from '@/api/marketing'
+    import { getCustomerList } from '@/api/customer'
+    import { getUserEmails } from '@/api/emails'
+    import { region } from '@/utils/region';
+
+    const emits = defineEmits(['refresh'])
 
     const showCreateModal = ref(false)
     const currentStep = ref(1)
-    const toast = (message, type = 'success') => {
-        if (typeof window !== 'undefined' && typeof window.toast === 'function') {
-            window.toast(message, type)
-            return
-        }
-        console[type === 'success' ? 'log' : 'warn'](`[toast] ${message}`)
-    }
-    const newCampaign = ref({
-        name: '', type: '潜客开发', priority: '中', description: '',
+    const isEditMode = ref(false)
+    const editingCampaignId = ref(null)
+    const modalTitle = computed(() => isEditMode.value ? '编辑营销活动' : '创建营销活动')
+    const getDefaultCampaign = () => ({
+        name: '', type: 'prospect', priority: 'medium', description: '',
         startDate: '', endDate: '', owner: [], relatedOpportunity: '',
         segment: 'all', aiRecommend: 'high-value',
         filters: {
@@ -938,21 +904,114 @@
         },
         goals: { sent: 500, openRate: 40, replyRate: 10, opportunities: 15 },
         channels: ['email'],
-        emailSender: 'sales@company.com', emailSendTime: 'optimal',
+        emailSender: '', emailSendTime: 'optimal',
         emailTemplate: 'AI自主', batchSize: '100',
         emailSubject: '', emailPreviewText: '',
         trackOpen: true, trackClick: true, trackReply: true,
         whatsappAccount: '业务账号1', whatsappInterval: '60', whatsappTemplate: '',
         linkedinAction: 'message', linkedinLimit: '30',
-        sopTemplate: 'standard',
+        sopTemplate: '',
         rules: {
             noOpenFollowup: true, noReplyFollowup: true, noClickFollowup: false,
             stopOnReply: true, stopOnBooking: true,
-            noOpenFollowupDays: '3', noReplyFollowupDays: '7'
+            noOpenFollowupDays: '3', noReplyFollowupDays: '7', noClickFollowupDays: '7'
         },
         abTest: { enabled: false, variable: 'subject', ratio: '50', winnerCriteria: 'openRate', variantB: '' },
         scheduleMode: 'optimal', scheduledDate: '', scheduledTime: ''
     })
+    const newCampaign = ref(getDefaultCampaign())
+
+    const resetCampaignForm = () => {
+        newCampaign.value = getDefaultCampaign()
+    }
+
+    const populateCampaignForm = (data = {}) => {
+        const defaults = getDefaultCampaign()
+        const campaign = data || {}
+        const typeMap = { 1: 'prospect', 2: 'nurture', 3: 'reactivate', 4: 'promote', 5: 'seasonal', 6: 'exhibition' }
+        const priorityMap = { 1: 'urgent', 2: 'high', 3: 'medium', 4: 'low' }
+        const channelConfig = Number(campaign.channelConfiguration || 0)
+        const channels = []
+        if (channelConfig & 1) channels.push('email')
+        if (channelConfig & 2) channels.push('whatsapp')
+        if (channelConfig & 4) channels.push('linkedin')
+
+        const formData = {
+            name: campaign.name || '',
+            type: typeMap[campaign.type] || campaign.type || defaults.type,
+            priority: priorityMap[campaign.priority] || campaign.priority || defaults.priority,
+            description: campaign.description || '',
+            startDate: campaign.beginData || campaign.startDate || '',
+            endDate: campaign.endDate || '',
+            owner: Array.isArray(campaign.owner)
+                ? campaign.owner.map(item => String(item))
+                : campaign.supervisor ? [String(campaign.supervisor)] : [],
+            relatedOpportunity: campaign.linkToOpportunity || '',
+            segment: campaign.segment || defaults.segment,
+            aiRecommend: campaign.aiRecommend || defaults.aiRecommend,
+            filters: {
+                region: campaign.region || '',
+                industry: campaign.industry || '',
+                scoreRange: campaign.scoreRange || '',
+                stage: campaign.stage || '',
+                companySize: campaign.companySize || '',
+                purchaseCycle: campaign.purchaseCycle || '',
+                keyword: campaign.keyword || '',
+                selectedTags: Array.isArray(campaign.selectedTags) ? campaign.selectedTags : []
+            },
+            goals: {
+                sent: Number(campaign.sendVolume) || defaults.goals.sent,
+                openRate: Number(campaign.openRate) || defaults.goals.openRate,
+                replyRate: Number(campaign.replyRate) || defaults.goals.replyRate,
+                opportunities: Number(campaign.opportunityCount) || defaults.goals.opportunities
+            },
+            channels: channels.length ? channels : defaults.channels,
+            emailSender: campaign.emailAddress || defaults.emailSender,
+            emailSendTime: campaign.emailSentTime || defaults.emailSendTime,
+            emailTemplate: campaign.emailTemplate || defaults.emailTemplate,
+            batchSize: campaign.emailBatchSize ? String(campaign.emailBatchSize) : defaults.batchSize,
+            emailSubject: campaign.emailSubject || '',
+            emailPreviewText: campaign.emailPreviewText || '',
+            trackOpen: campaign.trackConfigOpen === 1 || campaign.trackConfigOpen === true || campaign.trackConfigOpen === '1',
+            trackClick: campaign.trackConfigClick === 1 || campaign.trackConfigClick === true || campaign.trackConfigClick === '1',
+            trackReply: campaign.trackConfigReply === 1 || campaign.trackConfigReply === true || campaign.trackConfigReply === '1',
+            whatsappAccount: campaign.whatsappAccount || defaults.whatsappAccount,
+            whatsappInterval: campaign.whatsappInterval || defaults.whatsappInterval,
+            whatsappTemplate: campaign.whatsappTemplate || '',
+            linkedinAction: campaign.linkedinAction || defaults.linkedinAction,
+            linkedinLimit: campaign.linkedinLimit || defaults.linkedinLimit,
+            sopTemplate: campaign.sopId || '',
+            rules: {
+                noOpenFollowup: campaign.followUpRulesNotOpened === 1 || campaign.followUpRulesNotOpened === true || campaign.followUpRulesNotOpened === '1',
+                noReplyFollowup: campaign.followUpRulesNotReplied === 1 || campaign.followUpRulesNotReplied === true || campaign.followUpRulesNotReplied === '1',
+                noClickFollowup: campaign.followUpRulesLinkNotClicked === 1 || campaign.followUpRulesLinkNotClicked === true || campaign.followUpRulesLinkNotClicked === '1',
+                stopOnReply: campaign.followUpRulesReplied === 1 || campaign.followUpRulesReplied === true || campaign.followUpRulesReplied === '1',
+                stopOnBooking: campaign.followUpRulesAppointmentBooked === 1 || campaign.followUpRulesAppointmentBooked === true || campaign.followUpRulesAppointmentBooked === '1',
+                noOpenFollowupDays: campaign.followUpRulesNotOpenedDays || defaults.rules.noOpenFollowupDays,
+                noReplyFollowupDays: campaign.followUpRulesNotRepliedDays || defaults.rules.noReplyFollowupDays,
+                noClickFollowupDays: campaign.followUpRulesLinkNotClickedDays || defaults.rules.noClickFollowupDays
+            },
+            abTest: {
+                enabled: campaign.aBTesting === 1 || campaign.aBTesting === true || campaign.aBTesting === '1',
+                variable: campaign.abTestVariable || defaults.abTest.variable,
+                ratio: campaign.abTestRatio || defaults.abTest.ratio,
+                winnerCriteria: campaign.abTestWinnerCriteria || defaults.abTest.winnerCriteria,
+                variantB: campaign.abTestVariantB || defaults.abTest.variantB
+            },
+            scheduleMode: campaign.smartSchedulingType || defaults.scheduleMode,
+            scheduledDate: campaign.smartSchedulingStartDate || '',
+            scheduledTime: campaign.smartSchedulingStartTime || ''
+        }
+
+        newCampaign.value = {
+            ...defaults,
+            ...formData,
+            filters: { ...defaults.filters, ...formData.filters },
+            goals: { ...defaults.goals, ...formData.goals },
+            rules: { ...defaults.rules, ...formData.rules },
+            abTest: { ...defaults.abTest, ...formData.abTest }
+        }
+    }
     const segmentOptions = [
         { id: 'all', name: '全部潜客', count: 847, icon: 'fas fa-globe' },
         { id: 'new', name: '本周新增', count: 56, icon: 'fas fa-star' },
@@ -968,45 +1027,13 @@
     })
     const showCustomerPreview = ref(false)
     const previewCustomers = ref([
-        { id: 1, name: 'Riyadh Tech Distribution', company: 'Riyadh Tech Distribution', role: '采购总监', location: '沙特 · 利雅得', annualPurchase: '年采购约$1.5M', score: 92, tag: '潜客', logoText: 'RT' },
-        { id: 2, name: 'Riyadh Tech Distribution', company: 'Riyadh Tech Distribution', role: '采购总监', location: '沙特 · 利雅得', annualPurchase: '年采购约$1.5M', score: 92, tag: '潜客', logoText: 'RT' },
-        { id: 3, name: 'Riyadh Tech Distribution', company: 'Riyadh Tech Distribution', role: '采购总监', location: '沙特 · 利雅得', annualPurchase: '年采购约$1.5M', score: 92, tag: '潜客', logoText: 'RT' },
-        { id: 4, name: 'Riyadh Tech Distribution', company: 'Riyadh Tech Distribution', role: '采购总监', location: '沙特 · 利雅得', annualPurchase: '年采购约$1.5M', score: 92, tag: '潜客', logoText: 'RT' }
+        // { id: 1, name: 'Riyadh Tech Distribution', company: 'Riyadh Tech Distribution', role: '采购总监', location: '沙特 · 利雅得', annualPurchase: '年采购约$1.5M', score: 92, tag: '潜客', logoText: 'RT' },
+        // { id: 2, name: 'Riyadh Tech Distribution', company: 'Riyadh Tech Distribution', role: '采购总监', location: '沙特 · 利雅得', annualPurchase: '年采购约$1.5M', score: 92, tag: '潜客', logoText: 'RT' },
+        // { id: 3, name: 'Riyadh Tech Distribution', company: 'Riyadh Tech Distribution', role: '采购总监', location: '沙特 · 利雅得', annualPurchase: '年采购约$1.5M', score: 92, tag: '潜客', logoText: 'RT' },
+        // { id: 4, name: 'Riyadh Tech Distribution', company: 'Riyadh Tech Distribution', role: '采购总监', location: '沙特 · 利雅得', annualPurchase: '年采购约$1.5M', score: 92, tag: '潜客', logoText: 'RT' }
     ])
     const showSubjectSuggestions = ref(false)
-    const sopTemplates = [
-        {
-            id: 'standard', name: '标准开发序列', icon: '📧', steps: 4, description: '适合初次触达客户', stepsDetail: [
-                { title: '首封介绍邮件', day: 1, channel: '邮件', channelIcon: 'fas fa-envelope' },
-                { title: '产品优势介绍', day: 3, channel: '邮件', channelIcon: 'fas fa-envelope' },
-                { title: '案例分享', day: 7, channel: 'LinkedIn', channelIcon: 'fab fa-linkedin' },
-                { title: '电话跟进', day: 14, channel: '电话', channelIcon: 'fas fa-phone' }
-            ]
-        },
-        {
-            id: 'aggressive', name: '快速跟进序列', icon: '⚡', steps: 3, description: '快速转化意向客户', stepsDetail: [
-                { title: '个性化介绍', day: 1, channel: '邮件', channelIcon: 'fas fa-envelope' },
-                { title: 'WhatsApp跟进', day: 2, channel: 'WhatsApp', channelIcon: 'fab fa-whatsapp' },
-                { title: '报价发送', day: 5, channel: '邮件', channelIcon: 'fas fa-envelope' }
-            ]
-        },
-        {
-            id: 'nurture', name: '培育序列', icon: '🌱', steps: 5, description: '长期培育潜在客户', stepsDetail: [
-                { title: '欢迎邮件', day: 1, channel: '邮件', channelIcon: 'fas fa-envelope' },
-                { title: '行业报告', day: 7, channel: '邮件', channelIcon: 'fas fa-envelope' },
-                { title: '产品更新', day: 14, channel: '邮件', channelIcon: 'fas fa-envelope' },
-                { title: '案例研究', day: 21, channel: 'LinkedIn', channelIcon: 'fab fa-linkedin' },
-                { title: '优惠促销', day: 30, channel: '邮件', channelIcon: 'fas fa-envelope' }
-            ]
-        },
-        {
-            id: 'reactivate', name: '唤醒序列', icon: '🔄', steps: 3, description: '重新激活沉睡客户', stepsDetail: [
-                { title: '想念你邮件', day: 1, channel: '邮件', channelIcon: 'fas fa-envelope' },
-                { title: '新产品推荐', day: 5, channel: '邮件', channelIcon: 'fas fa-envelope' },
-                { title: '特别优惠', day: 10, channel: 'WhatsApp', channelIcon: 'fab fa-whatsapp' }
-            ]
-        }
-    ]
+    const sopTemplates = ref([])
     const getTypeLabel = (type) => ({ prospect: '潜客开发', nurture: '客户培育', reactivate: '客户唤醒', promote: '产品推广', seasonal: '节日营销', exhibition: '展会跟进' }[type] || type)
     const getPriorityLabel = (priority) => ({ urgent: '紧急', high: '高优先', medium: '中等', low: '低优先' }[priority] || priority)
     const getOwnerName = (owner) => ({ sales1: '张经理', sales2: '李主管', sales3: '王小明' }[owner] || '')
@@ -1029,7 +1056,6 @@
     const getChannelIconById = (id) => ({ email: 'fas fa-envelope', whatsapp: 'fab fa-whatsapp', linkedin: 'fab fa-linkedin', wechat: 'fab fa-weixin' }[id] || 'fas fa-comment')
     const hasWarnings = computed(() => selectedCustomerCount.value > 500 || !newCampaign.value.emailSubject || newCampaign.value.channels.length === 0)
     const confirmChecks = ref({ content: false, schedule: false, compliance: false, unsubscribe: true })
-    const isSubmitting = ref(false)
     const canCreate = computed(() => confirmChecks.value.content && confirmChecks.value.schedule && confirmChecks.value.compliance)
 
     const goToStep = (step) => { currentStep.value = step }
@@ -1037,19 +1063,18 @@
     const createCampaign = async () => {
         if (!newCampaign.value.name) {
             currentStep.value = 1
-            toast('请填写活动名称', 'error')
+            ElMessage.error('请填写活动名称')
             return
         }
         if (newCampaign.value.channels.includes('email') && !newCampaign.value.emailSubject) {
             currentStep.value = 3
-            toast('请设置邮件主题', 'error')
+            ElMessage.error('请设置邮件主题')
             return
         }
         if (!canCreate.value) {
-            toast('请完成确认事项后创建活动', 'error')
+            ElMessage.error('请完成确认事项后创建活动')
             return
         }
-        isSubmitting.value = true
         try {
             const typeMap = { prospect: 1, nurture: 2, reactivate: 3, promote: 4, seasonal: 5, exhibition: 6 }
             const priorityMap = { urgent: 1, high: 2, medium: 3, low: 4 }
@@ -1057,7 +1082,6 @@
             const selectedOwners = Array.isArray(newCampaign.value.owner)
                 ? newCampaign.value.owner.filter(Boolean)
                 : [newCampaign.value.owner].filter(Boolean)
-            const sopIdMap = { standard: 1, aggressive: 2, nurture: 3, reactivate: 4, custom: 0 }
             const channelConfig = newCampaign.value.channels.reduce((acc, channel) => {
                 if (channel === 'email') return acc + 1
                 if (channel === 'whatsapp') return acc + 2
@@ -1065,6 +1089,7 @@
                 return acc
             }, 0)
             const payload = {
+                id: editingCampaignId.value || undefined,
                 name: newCampaign.value.name,
                 type: typeMap[newCampaign.value.type] || 1,
                 priority: priorityMap[newCampaign.value.priority] || 3,
@@ -1086,7 +1111,7 @@
                 trackConfigOpen: newCampaign.value.trackOpen ? 1 : 0,
                 trackConfigClick: newCampaign.value.trackClick ? 1 : 0,
                 trackConfigReply: newCampaign.value.trackReply ? 1 : 0,
-                sopId: sopIdMap[newCampaign.value.sopTemplate] || 0,
+                sopId: newCampaign.value.sopTemplate,
                 followUpRulesNotOpened: newCampaign.value.rules.noOpenFollowup ? 1 : 0,
                 followUpRulesNotOpenedDays: newCampaign.value.rules.noOpenFollowupDays,
                 followUpRulesNotReplied: newCampaign.value.rules.noReplyFollowup ? 1 : 0,
@@ -1102,16 +1127,20 @@
                 hasContentCompliant: confirmChecks.value.content ? 1 : 0,
                 hasScheduleApproved: confirmChecks.value.schedule ? 1 : 0,
                 hasGdprCompliant: confirmChecks.value.compliance ? 1 : 0,
-                hasUnsubscribeLink: confirmChecks.value.unsubscribe ? 1 : 0
+                hasUnsubscribeLink: confirmChecks.value.unsubscribe ? 1 : 0,
+                customerAnalysisIdList: customerList.value.map(c => c.id)
             }
-            console.log(payload)
-            await addMarketing(payload)
-            toast('营销活动已创建', 'success')
+            if (isEditMode.value) {
+                await editMarketing(payload)
+                ElMessage.success('营销活动已更新')
+            } else {
+                await addMarketing(payload)
+                ElMessage.success('营销活动已创建')
+            }
+            emits('refresh')
             closeCreateModal()
         } catch (error) {
-            toast(error?.message || '创建营销活动失败', 'error')
-        } finally {
-            isSubmitting.value = false
+            ElMessage.error(error?.message || '创建营销活动失败')
         }
     }
 
@@ -1136,19 +1165,19 @@
             const regions = ['中东', '欧洲', '北美', '东南亚']
             const region = regions[Math.floor(Math.random() * regions.length)]
             newCampaign.value.name = `2026春季${region}${typeNames[newCampaign.value.type] || '营销'}活动`
-            toast('活动名称已生成', 'success')
+            ElMessage.success('活动名称已生成')
         } else if (type === 'desc') {
             newCampaign.value.description = `本次活动旨在通过多渠道触达目标客户群体,提升品牌知名度并获取高质量商机。主要策略包括:
             1. 针对目标客户发送个性化邮件内容
             2. 结合WhatsApp/LinkedIn进行多渠道跟进
             3. 设置自动化SOP序列持续培育客户
             预期目标:打开率45%+,回复率10%+,转化商机15+`
-            toast('活动描述已生成', 'success')
+            ElMessage.success('活动描述已生成')
         }
     }
 
     const duplicateCampaign = (campaign) => {
-        toast(`已复制活动"${campaign.name}"`, 'success')
+        ElMessage.success(`已复制活动"${campaign.name}"`)
         showHistoryModal.value = false
         setTimeout(() => {
             openCreateModal()
@@ -1157,91 +1186,143 @@
     }
 
     const showCustomSopModal = ref(false)
-    const selectedSopTemplate = computed(() => sopTemplates.find(s => s.id === newCampaign.value.sopTemplate))
-    const customSopData = ref({
-        name: '',
-        steps: [
-            { title: '', day: 1, channel: 'email', channelIcon: 'fas fa-envelope' },
-            { title: '', day: 3, channel: 'email', channelIcon: 'fas fa-envelope' },
-            { title: '', day: 7, channel: 'linkedin', channelIcon: 'fab fa-linkedin' },
-            { title: '', day: 14, channel: 'phone', channelIcon: 'fas fa-phone' }
-        ]
-    })
+    const selectedSopTemplate = computed(() => sopTemplates.value.find(s => s.id === newCampaign.value.sopTemplate))
+    const customSopData = ref({})
     const editSopTemplate = () => {
-        customSopData.value = {
-            name: selectedSopTemplate.value?.name || '',
-            steps: selectedSopTemplate.value?.stepsDetail?.map(s => ({
-                title: s.title,
-                day: s.day,
-                channel: s.channel.toLowerCase().replace('邮件', 'email').replace('linkedin', 'linkedin').replace('电话', 'phone').replace('whatsapp', 'whatsapp'),
-                channelIcon: s.channelIcon
-            })) || [
-                    { title: '', day: 1, channel: 'email', channelIcon: 'fas fa-envelope' },
-                    { title: '', day: 3, channel: 'email', channelIcon: 'fas fa-envelope' },
-                    { title: '', day: 7, channel: 'linkedin', channelIcon: 'fab fa-linkedin' },
-                    { title: '', day: 14, channel: 'phone', channelIcon: 'fas fa-phone' }
-                ]
-        }
+        customSopData.value = JSON.parse(JSON.stringify(selectedSopTemplate.value))
         showCustomSopModal.value = true
     }
 
     const addCustomSopStep = () => {
-        const lastDay = customSopData.value.steps[customSopData.value.steps.length - 1]?.day || 0
-        customSopData.value.steps.push({
-            title: '',
-            day: lastDay + 3,
-            channel: 'email',
-            channelIcon: 'fas fa-envelope'
+        const lastDay = customSopData.value.details[customSopData.value.details.length - 1]?.days || 0
+        customSopData.value.details.push({
+            name: '',
+            days: lastDay + 3,
+            type: 'email',
         })
     }
 
     const removeCustomSopStep = (index) => {
-        if (customSopData.value.steps.length > 1) {
-            customSopData.value.steps.splice(index, 1)
+        if (customSopData.value.details.length > 1) {
+            customSopData.value.details.splice(index, 1)
         }
     }
 
-    const updateChannelIcon = (index) => {
-        const channel = customSopData.value.steps[index].channel
-        const icons = {
-            email: 'fas fa-envelope',
-            whatsapp: 'fab fa-whatsapp',
-            linkedin: 'fab fa-linkedin',
-            phone: 'fas fa-phone',
-            wechat: 'fab fa-weixin'
-        }
-        customSopData.value.steps[index].channelIcon = icons[channel] || 'fas fa-envelope'
-    }
+    // const updateChannelIcon = (index) => {
+    //     const channel = customSopData.value.steps[index].type
+    //     const icons = {
+    //         email: 'fas fa-envelope',
+    //         whatsapp: 'fab fa-whatsapp',
+    //         linkedin: 'fab fa-linkedin',
+    //         phone: 'fas fa-phone',
+    //         wechat: 'fab fa-weixin'
+    //     }
+    //     customSopData.value.steps[index].channelIcon = icons[channel] || 'fas fa-envelope'
+    // }
 
     const saveCustomSop = () => {
         if (!customSopData.value.name) {
-            toast('请输入SOP名称', 'error')
+            ElMessage.error('请输入SOP名称')
             return
         }
-        const validSteps = customSopData.value.steps.filter(s => s.title)
+        const validSteps = customSopData.value.details.filter(s => s.name)
         if (validSteps.length === 0) {
-            toast('请至少填写一个步骤', 'error')
+            ElMessage.error('请至少填写一个步骤')
             return
         }
-        // 将自定义SOP应用到活动
-        newCampaign.value.sopTemplate = 'custom'
-        newCampaign.value.customSOP = { ...customSopData.value }
-        showCustomSopModal.value = false
-        toast('自定义SOP已保存', 'success')
+        editSop(customSopData.value.id, customSopData.value).then(res => {
+            if(res.code === 200) {
+                ElMessage.success('保存成功')
+                getSop()
+                showCustomSopModal.value = false
+            } else {
+                ElMessage.error(res.message || '保存失败')
+            }
+        })
     }
 
-    const getSop = () => {
+    const getSop = (defaultSopId = '') => {
         getSopList({ pageIndex: 1, pageSize: 100 }).then(res => {
-            console.log('res :>> ', res);
+            sopTemplates.value = res.result.records || []
+            newCampaign.value.sopTemplate = defaultSopId || sopTemplates.value[0]?.id || ''
+        })
+    }
+
+    const addNewSop = () => {
+        let datas = customSopData.value.details.map((step, index) => ({
+            step: index + 1,
+            name: step.name,
+            days: step.days,
+            type: step.type
+        }))
+        let params = {
+            name: customSopData.value.name,
+            details: datas
+        }
+        addSop(params).then(res => {
+            if(res.code === 200) {
+                ElMessage.success('已保存新SOP序列')
+                getSop()
+                showCustomSopModal.value = false
+            } else {
+                ElMessage.error(res.message || '保存失败')
+            }
+        })
+    }
+
+    const open = (data) => {
+        currentStep.value = 1
+        isEditMode.value = !!data
+        editingCampaignId.value = data?.id || data?.campaignId || data?.marketingId || null
+        showCreateModal.value = true
+        resetCampaignForm()
+        if (data) {
+            populateCampaignForm(data)
+        }
+        getSop(data?.sopId || '')
+        customerList.value = []
+        getEmails()
+    }
+
+    const regionValue = ref([])
+    const getRegion = (value) => {
+        customerParams.value.country = value ? value[1] : ''
+    }
+    const customerParams = ref({
+        country: ''
+    })
+    const customerList = ref([])
+    const sourceData = ref({})
+    const getCustomerData = () => {
+        getCustomerList({ pageIndex: 1, pageSize: 10000, ...customerParams.value }).then(res => {
+            customerList.value = res.result.records || []
+            sourceData.value = {}
+            customerList.value.map(item => {
+                if(!item.customerSourceName) return
+                if(sourceData.value[item.customerSourceName]){
+                    sourceData.value[item.customerSourceName] += 1
+                }else{
+                    sourceData.value[item.customerSourceName] = 1
+                }
+            })
+            console.log('sourceData.value :>> ', sourceData.value);
+        })
+    }
+
+    const emailList = ref([])
+    const getEmails = () => {
+        getUserEmails().then(res => {
+            emailList.value = res.result || []
         })
     }
 
-    const open = () => {
-        currentStep.value = 1;
-        showCreateModal.value = true;
-        getSop()
+    const closeCreateModal = () => {
+        showCreateModal.value = false
+        currentStep.value = 1
+        isEditMode.value = false
+        editingCampaignId.value = null
+        resetCampaignForm()
     }
-    const closeCreateModal = () => { showCreateModal.value = false; currentStep.value = 1 }
 
     defineExpose({
         open,

+ 224 - 0
ui/smarttrade-platform/src/components/email/addEmail.vue

@@ -0,0 +1,224 @@
+<template>
+    <!-- 添加邮箱账号弹窗 -->
+    <div v-if="showAddEmailModal" class="modal-overlay" @click.self="showAddEmailModal = false">
+      <div class="modal settings-modal" style="max-width: 640px;">
+        <div class="modal-header">
+          <div class="modal-title"><i class="fas fa-plus-circle"></i> 添加邮箱账号</div>
+          <button class="modal-close" @click="showAddEmailModal = false"><i class="fas fa-times"></i></button>
+        </div>
+        <div class="modal-body">
+          <el-form ref="settingsFormRef" :model="form" :rules="rules" label-width="120px">
+            <el-form-item label="邮件地址:" prop="emailAddress">
+                <el-input :disabled="isEdit" autocomplete="off" v-model="form.emailAddress" @blur="getPort" />
+            </el-form-item>
+            <el-form-item label="密码:" prop="emailPassword">
+                <el-input type="password" autocomplete="off" show-password :readonly="isReadonly" v-model="form.emailPassword" />
+            </el-form-item>
+            <el-form-item label="邮箱类型:" prop="protocolType">
+                <el-radio-group v-model="form.protocolType" @change="changeType">
+                    <el-radio value="IMAP" label="IMAP" />
+                    <el-radio value="POP3" label="POP3" />
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item class="senior-item" :label="emailTypeName + ':'" prop="receiveServer">
+                <el-input v-model="form.receiveServer" />
+                <el-checkbox v-model="form.receiveSsl" value="IMAP" label="SSL" @change="changePort"></el-checkbox>
+                <label class="el-form-item__label">端口:</label>
+                <el-input v-model="form.receivePort" />
+            </el-form-item>
+            <el-form-item class="senior-item" label="SMTP服务器:" prop="smtpServer">
+                <el-input v-model="form.smtpServer" />
+                <el-checkbox v-model="form.smtpSsl" value="IMAP" label="SSL" @change="changePort('smtp')"></el-checkbox>
+                <label class="el-form-item__label">端口:</label>
+                <el-input v-model="form.smtpPort" />
+            </el-form-item>
+            <el-form-item class="senior-item" label="只收取:" prop="pullDay">
+                <el-input v-model="form.pullDay" />
+                <span>天内的邮件</span>
+            </el-form-item>
+            <el-form-item label="邮件发件人:" prop="senderNickName">
+                <el-input v-model="form.senderNickName" />
+            </el-form-item>
+            <el-form-item label="" prop="useDefault">
+                <el-checkbox v-model="form.useDefault" :value="1" label="设为默认发件箱"></el-checkbox>
+            </el-form-item>
+        </el-form>
+        </div>
+        <div class="modal-footer">
+            <el-button class="btn btn-secondary" @click="showAddEmailModal = false">取消</el-button>
+            <el-button class="btn btn-primary" :loading="buttonLoading" type="primary" @click="submitForm('test')">检 测</el-button>
+            <el-button class="btn btn-primary" :disabled="submitDisabled" :loading="buttonLoading" type="primary" @click="submitForm('save')">确认提交</el-button>
+        </div>
+      </div>
+    </div>
+</template>
+
+<script setup>
+    import { ref, nextTick } from 'vue'
+    import { getMailsPort, emailsTest, addEmailsSetting } from '@/api/emails'
+
+    const emits = defineEmits(['refresh'])
+    const showAddEmailModal = ref(false)
+
+    const isReadonly = ref(true)
+    const open = () => {
+        reset()
+        showAddEmailModal.value = true
+        nextTick(() => {
+            setTimeout(() => {
+                isReadonly.value = false
+            }, 500)
+        })
+    }
+
+    const isEdit = ref(false)
+    const form = ref({
+        id: undefined,
+        emailAddress: '',
+        emailPassword: '',
+        smtpServer: '',
+        useDefault: true,
+        receiveSsl: false,
+        receiveServer: '',
+        smtpSsl: false,
+        protocolType: '',
+        receivePort: '',
+        pullDay: '365',
+    })
+    const emailTypeName = ref('IMAP/POP3')
+    const changeType = (val) => {
+        emailTypeName.value = val
+        submitDisabled.value = true
+        if(portData.value) {
+            form.value.receiveServer = portData.value[val == 'IMAP' ? 'imapServer' : 'popServer']
+            if(form.value.receiveSsl) {
+                form.value.receivePort = portData.value[val == 'IMAP' ? 'imapPortSsl' : 'popPortSsl']
+            }else {
+                form.value.receivePort = portData.value[val == 'IMAP' ? 'imapPort' : 'popPort']
+            }
+        }
+    }
+    const rules = ref({
+        emailAddress: [
+            { required: true, message: "邮件地址不能为空", trigger: "change" }
+        ],
+        emailPassword: [
+            { required: true, message: "密码不能为空", trigger: "change" }
+        ],
+        smtpServer: [
+            { required: true, message: "SMTP服务器不能为空", trigger: "change" }
+        ],
+        receiveServer: [
+            { required: true, message: "IMAP/POP3不能为空", trigger: "change" }
+        ],
+        senderNickName: [
+            { required: true, message: "邮件发件人不能为空", trigger: "change" }
+        ],
+        protocolType: [
+            { required: true, message: "邮件类型不能为空", trigger: "change" }
+        ]
+    })
+
+    const portData = ref(null)
+    const getPort = () => {
+        if(form.value.emailAddress) {
+            getMailsPort(form.value.emailAddress).then(res => {
+                if(res.success && res.result) {
+                    portData.value = res.result
+                    if(!isEdit.value) {
+                        form.value.smtpServer = res.result.smtpServer
+                        form.value.smtpPort = res.result.smtpPortSsl
+                        form.value.smtpSsl = true
+                        form.value.receiveSsl = true
+                        form.value.protocolType = 'IMAP'
+                        changeType('IMAP')
+                        form.value.receiveServer = res.result.imapServer
+                        form.value.receivePort = res.result.imapPortSsl
+                    }
+                }
+            })
+        }
+    }
+
+    const changePort = (type) => {
+        if(portData.value) {
+            if(type == 'smtp') {
+                form.value.smtpPort = portData.value[form.value.smtpSsl ? 'smtpPortSsl' : 'smtpPort']
+            }else {
+                if(form.value.receiveSsl) {
+                    form.value.receivePort = portData.value[form.value.protocolType == 'IMAP' ? 'imapPortSsl' : 'popPortSsl']
+                }else{
+                    form.value.receivePort = portData.value[form.value.protocolType == 'IMAP' ? 'imapPort' : 'popPort']
+                }
+            }
+        }
+    }
+
+    const submitDisabled = ref(true)
+    const buttonLoading = ref(false)
+    const settingsFormRef = ref()
+    const submitForm = (type) => {
+        settingsFormRef.value?.validate(async (valid) => {
+            if(valid) {
+                let params = JSON.parse(JSON.stringify(form.value))
+                params.useDefault = params.useDefault ? 1 : 0
+                params.receiveSsl = params.receiveSsl ? 1 : 0
+                params.smtpSsl = params.smtpSsl ? 1 :0
+                params.enabled = 1 // 前端无状态按钮,默认给开启
+                buttonLoading.value = true;
+                let requset = type == 'test' ? emailsTest : addEmailsSetting
+                await requset(params).finally(() => buttonLoading.value = false);
+                ElMessage.success((type == 'test' ? '检测' : '新增') + "成功")
+                if(type == 'test') {
+                    submitDisabled.value = false
+                }else {
+                    emits('refresh')
+                    showAddEmailModal.value = false
+                }
+            }
+        })
+    }
+
+    const reset = () => {
+        settingsFormRef.value?.resetFields();
+        form.value.receivePort = ''
+        form.value.smtpPort = ''
+        form.value.smtpSsl = false
+        form.value.receiveSsl = false
+        form.value.id = undefined
+    }
+
+    defineExpose({
+        open
+    })
+</script>
+
+<style scoped>
+    @import '../../assets/styles/settings.css';
+
+    :deep(.el-form-item__label), :deep(.el-radio__label), :deep(.el-checkbox__label) {
+        color: var(--text-secondary);
+    }
+    :deep(.el-input__inner) {
+        color: var(--text-primary);
+    }
+    :deep(.el-input__wrapper){
+        background: var(--bg-dark);
+        border: 1px solid var(--border);
+        box-shadow: none;
+        border-radius: 8px;
+        color: var(--text-primary);
+    }
+    :deep(.senior-item){
+        .el-input{
+            width: 150px;
+            margin-right: 20px;
+        }
+    }
+    :deep(.btn){
+        height: 40px;
+    }
+    .el-button+.el-button{
+        margin-left: 0;
+    }
+</style>

+ 301 - 0
ui/smarttrade-platform/src/components/email/email.vue

@@ -0,0 +1,301 @@
+<template>
+    <div v-if="showEmailModal" class="modal-overlay" @click.self="showEmailModal = false">
+      <div class="modal settings-modal extra-wide">
+        <div class="modal-header">
+          <div class="modal-title"><i class="fas fa-envelope"></i> 企业邮箱管理中心</div>
+          <button class="modal-close" @click="showEmailModal = false"><i class="fas fa-times"></i></button>
+        </div>
+        <div class="modal-body">
+          <!-- 邮箱统计概览 -->
+          <div class="email-overview">
+            <div class="overview-card">
+              <div class="overview-icon email"><i class="fas fa-envelope"></i></div>
+              <div class="overview-info">
+                <div class="overview-value">{{ emailList.length }}</div>
+                <div class="overview-label">邮箱账号</div>
+              </div>
+            </div>
+            <div class="overview-card">
+              <div class="overview-icon"><i class="fas fa-paper-plane"></i></div>
+              <div class="overview-info">
+                <div class="overview-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday, 0) }}</div>
+                <div class="overview-label">今日发送</div>
+              </div>
+            </div>
+            <div class="overview-card">
+              <div class="overview-icon"><i class="fas fa-reply"></i></div>
+              <div class="overview-info">
+                <div class="overview-value">{{ Math.round(emailAccounts.reduce((sum, a) => sum + a.replyRate, 0) / emailAccounts.length) }}%</div>
+                <div class="overview-label">平均回复率</div>
+              </div>
+            </div>
+            <div class="overview-card">
+              <div class="overview-icon"><i class="fas fa-shield-alt"></i></div>
+              <div class="overview-info">
+                <div class="overview-value">3/3</div>
+                <div class="overview-label">安全认证</div>
+              </div>
+            </div>
+          </div>
+
+          <!-- 标签页导航 -->
+          <div class="email-tabs">
+            <button class="email-tab" :class="tabTyps === 'email' ? 'active' : ''" @click="tabTyps = 'email'"><i class="fas fa-envelope"></i> 邮箱账号</button>
+            <button class="email-tab" :class="tabTyps === 'stats' ? 'active' : ''" @click="tabTyps = 'stats'"><i class="fas fa-chart-bar"></i> 发送统计</button>
+          </div>
+          
+          <div class="email-accounts-list" v-if="tabTyps == 'email'">
+            <div v-for="account in emailList" :key="account.id" class="email-account-item" :class="{selected: selectedEmailAccount?.id === account.id}" @click="getDetails(account)">
+              <div class="account-icon"><i class="fas fa-envelope"></i></div>
+              <div class="account-info">
+                <div class="account-email">{{ account.mailAccount }}</div>
+                <div class="account-name">销售邮箱</div>
+                <div class="account-stats">
+                  <span><i class="fas fa-paper-plane"></i> 今日: 45</span>
+                  <span><i class="fas fa-reply"></i> 回复率: 32%</span>
+                  <span><i class="fas fa-sync"></i>  2026-03-24 09:00</span>
+                </div>
+              </div>
+              <div class="account-auth">
+                <span class="auth-badge" :class="account.SPF ? 'active' : ''"><i class="fas fa-check"></i> SPF</span>
+                <span class="auth-badge" :class="account.DKIM ? 'active' : ''"><i class="fas fa-check"></i> DKIM</span>
+                <span class="auth-badge" :class="account.DMARC ? 'active' : ''"><i class="fas fa-check"></i> DMARC</span>
+              </div>
+            </div>
+          </div>
+
+          <!-- 发送统计标签页 -->
+          <div class="email-tab-content" v-if="tabTyps == 'stats'">
+            <div class="stats-overview">
+              <div class="stat-card">
+                <div class="stat-icon"><i class="fas fa-paper-plane"></i></div>
+                <div class="stat-info">
+                  <div class="stat-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday, 0) }}</div>
+                  <div class="stat-label">今日发送</div>
+                </div>
+              </div>
+              <div class="stat-card">
+                <div class="stat-icon"><i class="fas fa-envelope-open"></i></div>
+                <div class="stat-info">
+                  <div class="stat-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday * 0.45, 0).toFixed(0) }}</div>
+                  <div class="stat-label">今日打开</div>
+                </div>
+              </div>
+              <div class="stat-card">
+                <div class="stat-icon"><i class="fas fa-reply"></i></div>
+                <div class="stat-info">
+                  <div class="stat-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday * a.replyRate / 100, 0).toFixed(0) }}</div>
+                  <div class="stat-label">今日回复</div>
+                </div>
+              </div>
+              <div class="stat-card">
+                <div class="stat-icon"><i class="fas fa-mouse-pointer"></i></div>
+                <div class="stat-info">
+                  <div class="stat-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday * 0.15, 0).toFixed(0) }}</div>
+                  <div class="stat-label">今日点击</div>
+                </div>
+              </div>
+            </div>
+            <div class="chart-section">
+              <h5><i class="fas fa-chart-line"></i> 最近7天发送趋势</h5>
+              <div class="simple-chart">
+                <div class="chart-bar" style="height: 45%"><span>周一</span></div>
+                <div class="chart-bar" style="height: 62%"><span>周二</span></div>
+                <div class="chart-bar" style="height: 58%"><span>周三</span></div>
+                <div class="chart-bar" style="height: 75%"><span>周四</span></div>
+                <div class="chart-bar" style="height: 82%"><span>周五</span></div>
+                <div class="chart-bar" style="height: 40%"><span>周六</span></div>
+                <div class="chart-bar" style="height: 35%"><span>周日</span></div>
+              </div>
+            </div>
+            <div class="top-performers">
+              <h5><i class="fas fa-trophy"></i> 热门模板</h5>
+              <div class="template-list">
+                <div class="template-item">
+                  <span class="template-name">产品介绍邮件</span>
+                  <span class="template-stats">发送 1,234 · 打开率 52%</span>
+                </div>
+                <div class="template-item">
+                  <span class="template-name">节日祝福</span>
+                  <span class="template-stats">发送 856 · 打开率 68%</span>
+                </div>
+                <div class="template-item">
+                  <span class="template-name">跟进邮件</span>
+                  <span class="template-stats">发送 654 · 打开率 45%</span>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <button class="btn btn-primary add-account-btn" @click="addEmail()">
+            <i class="fas fa-plus"></i> 添加邮箱账号
+          </button>
+        </div>
+        <div class="modal-footer">
+          <button class="btn btn-secondary" @click="showEmailModal = false">关闭</button>
+        </div>
+      </div>
+    </div>
+
+    <AddEmailModal ref="addEmailRef" />
+
+    <!-- 邮箱账号详情弹窗 -->
+    <div v-if="showEmailDetailModal" class="modal-overlay" @click.self="showEmailDetailModal = false">
+      <div class="modal settings-modal extra-wide">
+        <div class="modal-header">
+          <div class="modal-title">
+            <i class="fas fa-envelope"></i> {{ selectedEmailAccount?.mailAccount }} - 详细配置
+          </div>
+          <button class="modal-close" @click="showEmailDetailModal = false"><i class="fas fa-times"></i></button>
+        </div>
+        <div class="modal-body" v-if="selectedEmailAccount">
+          <!-- 服务器配置 -->
+          <div class="detail-section">
+            <h5><i class="fas fa-server"></i> SMTP / IMAP 服务器配置</h5>
+            <div class="config-grid-2col">
+              <div class="config-card">
+                <div class="config-card-header">
+                  <i class="fas fa-upload"></i> SMTP (发送)
+                </div>
+                <div class="config-card-body">
+                  <div class="config-row">
+                    <span class="config-label">服务器地址</span>
+                    <span class="config-value">{{ portData.smtpServer }}</span>
+                  </div>
+                  <div class="config-row">
+                    <span class="config-label">端口</span>
+                    <span class="config-value">{{ portData.smtpPortSsl }}</span>
+                  </div>
+                  <div class="config-row">
+                    <span class="config-label">加密方式</span>
+                    <span class="config-value">TLS</span>
+                  </div>
+                  <div class="config-row">
+                    <span class="config-label">认证方式</span>
+                    <span class="config-value">OAuth 2.0 / SMTPAuth</span>
+                  </div>
+                </div>
+              </div>
+              <div class="config-card">
+                <div class="config-card-header">
+                  <i class="fas fa-download"></i> IMAP / POP3 (接收)
+                </div>
+                <div class="config-card-body">
+                  <div class="config-row">
+                    <span class="config-label">服务器地址</span>
+                    <span class="config-value">{{ portData.imapServer }}</span>
+                  </div>
+                  <div class="config-row">
+                    <span class="config-label">端口</span>
+                    <span class="config-value">{{ portData.imapPortSsl }}</span>
+                  </div>
+                  <div class="config-row">
+                    <span class="config-label">加密方式</span>
+                    <span class="config-value">SSL</span>
+                  </div>
+                  <div class="config-row">
+                    <span class="config-label">同步文件夹</span>
+                    <span class="config-value">INBOX, Sent, Drafts</span>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <!-- 安全认证 -->
+          <div class="detail-section">
+            <h5><i class="fas fa-shield-alt"></i> 邮件安全认证状态</h5>
+            <div class="auth-grid">
+              <div class="auth-card" :class="selectedEmailAccount.SPF ? 'pass' : 'fail'">
+                <div class="auth-icon"><i class="fas fa-shield-alt"></i></div>
+                <div class="auth-info">
+                  <div class="auth-name">SPF</div>
+                  <div class="auth-desc">发件人策略框架</div>
+                </div>
+                <div class="auth-status">{{ selectedEmailAccount.SPF ? '已配置' : '未配置' }}</div>
+              </div>
+              <div class="auth-card" :class="selectedEmailAccount.DKIM ? 'pass' : 'fail'">
+                <div class="auth-icon"><i class="fas fa-key"></i></div>
+                <div class="auth-info">
+                  <div class="auth-name">DKIM</div>
+                  <div class="auth-desc">域名密钥识别邮件</div>
+                </div>
+                <div class="auth-status">{{ selectedEmailAccount.DKIM ? '已配置' : '未配置' }}</div>
+              </div>
+              <div class="auth-card" :class="selectedEmailAccount.DMARC ? 'pass' : 'fail'">
+                <div class="auth-icon"><i class="fas fa-lock"></i></div>
+                <div class="auth-info">
+                  <div class="auth-name">DMARC</div>
+                  <div class="auth-desc">基于域的消息认证</div>
+                </div>
+                <div class="auth-status">{{ selectedEmailAccount.DMARC ? '已配置' : '未配置' }}</div>
+              </div>
+            </div>
+          </div>
+
+          <!-- 邮件签名 -->
+          <div class="detail-section">
+            <h5><i class="fas fa-pen"></i> 邮件签名</h5>
+            <div class="signature-preview">
+              <div class="signature-label">预览效果:</div>
+              <div class="signature-content">
+                <pre>{{ selectedEmailAccount.signature }}</pre>
+              </div>
+            </div>
+            <textarea class="form-textarea signature-textarea" rows="6">{{ selectedEmailAccount.signature }}</textarea>
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button class="btn btn-secondary" @click="showEmailDetailModal = false">关闭</button>
+        </div>
+      </div>
+    </div>
+</template>
+
+<script setup>
+    import { ref } from 'vue'
+    import AddEmailModal from './addEmail.vue'
+    import { getMailsPort } from '@/api/emails'
+
+    const showEmailModal = ref(false)
+    // 企业邮箱列表
+    const emailAccounts = ref([
+        { id: 1, email: 'sales@company.com', name: '销售邮箱', signature: 'Best regards,\nZhang Manager\nSales Director', forward: true, autoReply: false, autoReplyContent: '', forwardTo: 'manager@company.com', lastSync: '2026-03-24 09:00', sendToday: 45, replyRate: 32, monthlyLimit: 5000, monthlyUsed: 1280,SPF: true, DKIM: true, DMARC: true, smtp: { host: 'smtp.company.com', port: 587, encryption: 'TLS' }, imap: { host: 'imap.company.com', port: 993, encryption: 'SSL' } },
+        { id: 2, email: 'marketing@company.com', name: '市场邮箱', signature: 'Thanks,\nMarketing Team', forward: true, autoReply: true, autoReplyContent: '感谢您的邮件,我们将在工作时间内尽快回复。', forwardTo: 'sales@company.com', lastSync: '2026-03-24 08:30', sendToday: 128, replyRate: 18, monthlyLimit: 10000, monthlyUsed: 3560,SPF: true, DKIM: true, DMARC: true, smtp: { host: 'smtp.company.com', port: 587, encryption: 'TLS' }, imap: { host: 'imap.company.com', port: 993, encryption: 'SSL' } }
+    ])
+
+    const emailList = ref([])
+    const open = (list) => {
+        showEmailModal.value = true
+        emailList.value = list || []
+    }
+
+    const tabTyps = ref('email')
+
+    const selectedEmailAccount = ref()
+
+    const addEmailRef = ref()
+    const addEmail = () => {
+        addEmailRef.value.open()
+    }
+
+    const showEmailDetailModal = ref(false)
+    const portData = ref()
+    const getDetails = (data) => {
+      selectedEmailAccount.value = data
+      getMailsPort(data.mailAccount).then(res => {
+          if(res.success && res.result) {
+              portData.value = res.result
+          }
+      })
+      showEmailDetailModal.value = true
+    }
+
+    defineExpose({
+        open
+    })
+</script>
+
+<style scoped>
+  @import '../../assets/styles/settings.css';
+</style>

+ 254 - 15
ui/smarttrade-platform/src/components/layout/Sidebar.vue

@@ -20,19 +20,19 @@
           <i class="fas fa-brain nav-icon"></i>
           <span class="nav-text">企业大脑</span>
         </router-link> -->
-        <router-link to="/prospect" class="nav-item" :class="{ active: $route.path === '/prospect' }">
+        <!-- <router-link to="/prospect" class="nav-item" :class="{ active: $route.path === '/prospect' }">
           <i class="fas fa-crosshairs nav-icon"></i>
           <span class="nav-text">自动寻客</span>
           <span class="nav-badge">新</span>
-        </router-link>
-        <router-link to="/marketing" class="nav-item" :class="{ active: $route.path === '/marketing' }">
+        </router-link> -->
+        <router-link to="/marketing" class="nav-item" :class="{ active: $route.path === '/marketing' || $route.path === '/' }">
           <i class="fas fa-paper-plane nav-icon"></i>
           <span class="nav-text">自动营销</span>
         </router-link>
-        <router-link to="/strategy" class="nav-item" :class="{ active: $route.path === '/strategy' }">
+        <!-- <router-link to="/strategy" class="nav-item" :class="{ active: $route.path === '/strategy' }">
           <i class="fas fa-lightbulb nav-icon"></i>
           <span class="nav-text">AI策略中心</span>
-        </router-link>
+        </router-link> -->
       </div>
 
       <!-- 客户管理 -->
@@ -89,11 +89,11 @@
     <div class="sidebar-footer">
       <div class="user-card" @click="toggleUserMenu">
         <div class="user-avatar-wrapper">
-          <div class="user-avatar"></div>
+          <div class="user-avatar">{{ userData?.realName?.charAt(0) }}</div>
           <div class="online-indicator"></div>
         </div>
         <div class="user-info">
-          <div class="user-name">张经理</div>
+          <div class="user-name">{{ userData?.realName }}</div>
           <div class="user-status">
             <span class="status-dot"></span>
             在线
@@ -106,17 +106,17 @@
       <transition name="dropdown">
         <div v-if="showUserMenu" class="user-menu">
           <div class="menu-header">
-            <div class="menu-avatar"></div>
+            <div class="menu-avatar">{{ userData?.realName?.charAt(0) }}</div>
             <div class="menu-user-info">
-              <div class="menu-user-name">张经理</div>
-              <div class="menu-user-email">zhang@company.com</div>
+              <div class="menu-user-name">{{ userData?.realName }}</div>
+              <div class="menu-user-email">{{ userData?.email }}</div>
             </div>
           </div>
           
           <div class="menu-divider"></div>
           
           <div class="menu-items">
-            <router-link to="/settings" class="menu-item" @click="showUserMenu = false">
+            <div class="menu-item" @click="showProfileModal = true">
               <div class="menu-item-icon" style="background: rgba(99, 102, 241, 0.2); color: var(--primary);">
                 <i class="fas fa-user"></i>
               </div>
@@ -124,13 +124,13 @@
                 <span class="menu-item-title">个人资料</span>
                 <span class="menu-item-desc">编辑头像、姓名等信息</span>
               </div>
-            </router-link>
+            </div>
           </div>
           
           <div class="menu-divider"></div>
           
           <div class="menu-items">
-            <div class="menu-item" @click="toggleTheme">
+            <div class="menu-item" @click="openPwdModal">
               <div class="menu-item-icon" style="background: rgba(245, 158, 11, 0.2); color: var(--warning);">
                 <i :class="isDarkMode ? 'fas fa-sun' : 'fas fa-moon'"></i>
               </div>
@@ -139,7 +139,7 @@
               </div>
             </div>
             
-            <div class="menu-item" @click="showHelpModal = true">
+            <div class="menu-item" @click="openHistoryModal">
               <div class="menu-item-icon" style="background: rgba(6, 182, 212, 0.2); color: var(--info);">
                 <i class="fas fa-question-circle"></i>
               </div>
@@ -222,18 +222,145 @@
       </div>
     </div>
 
+    <!-- 个人信息弹窗 -->
+    <div v-if="showProfileModal" class="modal-overlay" @click.self="showProfileModal = false">
+      <div class="modal settings-modal">
+        <div class="modal-header">
+          <div class="modal-title"><i class="fas fa-user-edit"></i> 编辑个人信息</div>
+          <button class="modal-close" @click="showProfileModal = false"><i class="fas fa-times"></i></button>
+        </div>
+        <div class="modal-body">
+          <el-form ref="settingsFormRef" label-width="100px">
+            <el-form-item label="姓名">
+              <el-input readonly v-model="userData.realName" autocomplete="off" />
+            </el-form-item>
+            <el-form-item label="职位">
+              <el-input readonly v-model="userData.jobName" autocomplete="off" />
+            </el-form-item>
+            <el-form-item label="邮箱">
+              <el-input readonly v-model="userData.email" autocomplete="off" />
+            </el-form-item>
+            <el-form-item label="电话">
+              <el-input readonly v-model="userData.userName" autocomplete="off" />
+            </el-form-item>
+            <el-form-item label="所属部门">
+              <el-input readonly v-model="userData.deptName" autocomplete="off" />
+            </el-form-item>
+            <el-form-item label="个人简介">
+              <el-input type="textarea" v-model="userData.remark" :rows="3" autocomplete="off" placeholder="请输入个人简介" />
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="modal-footer">
+          <button class="btn btn-secondary" @click="showProfileModal = false">取消</button>
+          <button class="btn btn-primary" @click="saveRemark">保存</button>
+        </div>
+      </div>
+    </div>
+
+    <!-- 修改密码弹窗 -->
+    <div v-if="showPasswordModal" class="modal-overlay" @click.self="showPasswordModal = false">
+      <div class="modal settings-modal">
+        <div class="modal-header">
+          <div class="modal-title"><i class="fas fa-key"></i> 修改密码</div>
+          <button class="modal-close" @click="showPasswordModal = false"><i class="fas fa-times"></i></button>
+        </div>
+        <div class="modal-body">
+          <el-form ref="resetPwdformRef" :rules="rules" :model="pwdForm" label-width="120px">
+            <el-form-item label="当前密码" prop="password">
+                <el-input type='password' v-model="pwdForm.password" placeholder="请输入当前密码" @input="getPassword"></el-input>
+            </el-form-item>
+            <el-form-item label="新密码" prop="newPass">
+                <el-input type='password' v-model="pwdForm.newPass" placeholder="请输入新密码"
+                    @input="getNPassword"></el-input>
+            </el-form-item>
+            <el-form-item label="确认新密码" prop="newPassAgain">
+                <el-input type='password' v-model="pwdForm.newPassAgain" placeholder="请再次输入新密码"
+                    @input="getNPasswordA"></el-input>
+            </el-form-item>
+            <div class="password-hint">
+              <i class="fas fa-info-circle"></i> 密码要求:至少8位,包含字母和数字
+            </div>
+          </el-form>
+        </div>
+        <div class="modal-footer">
+          <button class="btn btn-secondary" @click="showPasswordModal = false">取消</button>
+          <button class="btn btn-primary" @click="submitForm">确认修改</button>
+        </div>
+      </div>
+    </div>
+
+    <!-- 登录历史弹窗 -->
+    <div v-if="showLoginHistoryModal" class="modal-overlay" @click.self="showLoginHistoryModal = false">
+      <div class="modal settings-modal wide" style="max-width: 520px;">
+        <div class="modal-header">
+          <div class="modal-title"><i class="fas fa-history"></i> 登录历史记录</div>
+          <button class="modal-close" @click="showLoginHistoryModal = false"><i class="fas fa-times"></i></button>
+        </div>
+        <div class="modal-body">
+          <div class="login-history-list">
+            <div v-for="login in loginHistory" :key="login.id" class="login-history-item">
+              <div class="login-icon" :class="login.status == 1 ? 'success' : 'error'">
+                <i :class="login.status === 1 ? 'fas fa-check-circle' : 'fas fa-times-circle'"></i>
+              </div>
+              <div class="login-info">
+                <div class="login-time">{{ login.createTime }}</div>
+                <div class="login-details">
+                  <span><i class="fas fa-map-marker-alt"></i> {{ login.city }}</span>
+                  <span><i class="fas fa-desktop"></i> {{ login.browser }} / {{ login.os.split(' ')[0] }}</span>
+                  <span><i class="fas fa-network-wired"></i> {{ login.ip }}</span>
+                </div>
+              </div>
+              <div class="login-status" :class="login.status == 1 ? 'success' : 'error'">{{ login.status == 1 ? '成功' : '失败' }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button class="btn btn-secondary" @click="showLoginHistoryModal = false">关闭</button>
+        </div>
+      </div>
+    </div>
+
     <!-- Click outside to close menu -->
     <div v-if="showUserMenu" class="menu-backdrop" @click="showUserMenu = false"></div>
   </aside>
 </template>
 
 <script setup>
-import { ref } from 'vue'
+import { ref, onMounted } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
+import { getUserInfo, updateUserPwd, getLoginData, updateRemark } from '@/api/layout'
 
 const route = useRoute()
 const router = useRouter()
 
+const showProfileModal = ref(false)
+const showPasswordModal = ref(false)
+const showLoginHistoryModal = ref(false)
+// 登录历史数据
+const loginHistory = ref([])
+
+const openHistoryModal = () => {
+  getHistoryData()
+  showLoginHistoryModal.value = true
+}
+const getHistoryData = () => {
+  getLoginData({ pageIndex: 1, pageSize: 10000 }).then(res => {
+    if(res.code === 200){
+      loginHistory.value = res.result.records
+    }
+  })
+}
+
+const saveRemark = () => {
+  updateRemark({ remark: userData.value.remark, id: userData.value.id }).then(res => {
+    ElMessage.success("个人信息已更新");
+    showProfileModal.value = false
+  }).catch(err => {
+    ElMessage.error(err.message);
+  })
+}
+
 const showUserMenu = ref(false)
 const showHelpModal = ref(false)
 const isDarkMode = ref(true)
@@ -257,6 +384,83 @@ const handleLogout = () => {
   // Handle logout
   console.log('Logout')
 }
+
+const pwdForm = ref({
+    password: '',
+    newPass: '',
+    newPassAgain: ''
+});
+const resetPwdformRef = ref();
+const getPassword = (data) => {
+    pwdForm.value.password = data.replace(/\s+/g, '')
+}
+const getNPassword = (data) => {
+    pwdForm.value.newPass = data.replace(/\s+/g, '')
+}
+const getNPasswordA = (data) => {
+    pwdForm.value.newPassAgain = data.replace(/\s+/g, '')
+}
+const openPwdModal = () => {
+    showPasswordModal.value = true
+    resetPwdformRef.value?.resetFields();
+    pwdForm.value.password = ''
+    pwdForm.value.newPass = ''
+    pwdForm.value.newPassAgain = ''
+}
+var validatePass1 = (rule, value, callback) => {
+    const reg = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\W]{8,}$/;
+    if (value === '') {
+        callback(new Error('请输入新密码'));
+    } else if (!reg.test(value)) {
+        callback(new Error('密码须包含字母+数字且长度大于8位!'));
+    } else {
+        callback();
+    }
+};
+var validatePass2 = (rule, value, callback) => {
+    if (value === '') {
+        callback(new Error('请再次输入新密码'));
+    } else if (value !== pwdForm.value.newPass) {
+        callback(new Error('两次输入密码不一致!'));
+    } else {
+        callback();
+    }
+};
+const rules = ref({
+    password: [
+        { required: true, message: '请输入现在使用的密码', trigger: 'blur' },
+        { min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
+    ],
+    newPass: [
+        { required: true, validator: validatePass1, trigger: 'blur' },
+    ],
+    newPassAgain: [
+        { required: true, validator: validatePass2, trigger: 'blur' },
+    ],
+});
+const submitForm = () => {
+    resetPwdformRef.value?.validate((valid) => {
+        if (valid) {
+            updateUserPwd(pwdForm.value).then(res => {
+              localStorage.clear()
+              ElMessage.success("修改成功");
+              router.push({ path: '/login' })
+            }).catch(err => {
+              ElMessage.error(err.message);
+            })
+        } else {
+        }
+    });
+}
+
+const userData = ref()
+onMounted(() => {
+  getUserInfo().then((res) => {
+    if(res.code == 200) {
+      userData.value = res.result
+    }
+  })
+})
 </script>
 
 <style scoped>
@@ -727,4 +931,39 @@ const handleLogout = () => {
   font-size: 13px;
   font-weight: 500;
 }
+
+/* Login History Modal */
+.login-history-list { display: flex; flex-direction: column; gap: 12px; }
+.login-history-item { display: flex; align-items: center; gap: 14px; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
+.login-icon { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 16px; }
+.login-icon.success { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+.login-icon.error { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
+.login-info { flex: 1; }
+.login-time { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
+.login-details { display: flex; gap: 16px; font-size: 12px; color: var(--text-muted); }
+.login-details span { display: flex; align-items: center; gap: 4px; }
+.login-status { font-size: 12px; padding: 4px 10px; border-radius: 10px; }
+.login-status.success { background: rgba(16, 185, 129, 0.2); color: var(--success); }
+.login-status.error { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
+
+:deep(.el-form-item){
+    display: flex;
+    flex-direction: column;
+}
+:deep(.el-form-item .el-form-item__label){
+    justify-content: flex-start;
+}
+:deep(.el-form-item__label), :deep(.el-radio__label), :deep(.el-checkbox__label) {
+    color: var(--text-secondary);
+}
+:deep(.el-input__inner) {
+    color: var(--text-primary);
+}
+:deep(.el-input__wrapper), :deep(.el-textarea__inner), :deep(.el-select__wrapper){
+    background: var(--bg-dark);
+    border: 1px solid var(--border);
+    box-shadow: none;
+    border-radius: 8px;
+    color: var(--text-primary);
+}
 </style>

+ 93 - 2
ui/smarttrade-platform/src/components/layout/TopBar.vue

@@ -578,12 +578,51 @@
   </header>
 
   <AddMarketing ref="addMarketingRef" />
+
+  <div v-if="showSettings" class="modal-overlay" @click.self="showSettings = false">
+    <div class="modal create-modal">
+      <div class="modal-header">
+          <div class="modal-title"><i class="fas fa-bell"></i> 通知设置</div>
+          <button class="modal-close" @click="showSettings = false"><i class="fas fa-times"></i></button>
+      </div>
+      <div class="modal-body">
+        <div class="settings-list">
+          <div class="settings-item" style="padding-top: 0;">
+            <div class="item-icon" style="background: rgba(99, 102, 241, 0.2); color: var(--primary);">
+              <i class="fas fa-envelope"></i>
+            </div>
+            <div class="item-content">
+              <div class="item-title">邮件通知</div>
+              <div class="item-desc">重要通知发送到邮箱</div>
+            </div>
+            <div class="item-action">
+              <el-switch v-model="settings.emailNotify" style="--el-switch-on-color: #13ce66;" />
+            </div>
+          </div>
+
+          <div class="settings-item">
+            <div class="item-icon" style="background: rgba(16, 185, 129, 0.2); color: var(--success);">
+              <i class="fas fa-reply"></i>
+            </div>
+            <div class="item-content">
+              <div class="item-title">客户回复提醒</div>
+              <div class="item-desc">客户回复邮件、消息时即时提醒</div>
+            </div>
+            <div class="item-action">
+              <el-switch v-model="settings.replyNotify" style="--el-switch-on-color: #13ce66;" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script setup>
-import { ref, computed } from 'vue'
+import { ref, computed, onMounted } from 'vue'
 import { useRoute } from 'vue-router'
 import AddMarketing from '../addMarketing.vue'
+import { getNoReadCount } from '@/api/layout'
 
 const route = useRoute()
 const showQuickActions = ref(false)
@@ -596,6 +635,11 @@ const showProspectModal = ref(false)
 const showMarketingModal = ref(false)
 const showReportModal = ref(false)
 
+const settings = ref({
+  emailNotify: true,
+  replyNotify: true
+})
+
 // 寻客表单
 const prospectForm = ref({
   name: '',
@@ -1061,6 +1105,12 @@ const showTerms = () => {
 const showPrivacy = () => {
   console.log('Show privacy')
 }
+
+onMounted(() => {
+  getNoReadCount().then(res => {
+    console.log('Unread notifications count:', res)
+  })
+})
 </script>
 
 <style scoped>
@@ -1650,7 +1700,6 @@ const showPrivacy = () => {
   border-bottom: 1px solid var(--border);
   position: sticky;
   top: 0;
-  background: var(--bg-card);
   z-index: 10;
 }
 
@@ -2307,6 +2356,48 @@ const showPrivacy = () => {
   font-size: 14px;
 }
 
+.settings-item {
+  display: flex;
+  align-items: center;
+  gap: 14px;
+  padding: 14px 0;
+  cursor: pointer;
+}
+
+.item-icon {
+  width: 40px;
+  height: 40px;
+  border-radius: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 16px;
+  flex-shrink: 0;
+}
+
+.item-content {
+  flex: 1;
+  min-width: 0;
+}
+
+.item-title {
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 2px;
+}
+
+.item-desc {
+  font-size: 12px;
+  color: var(--text-secondary);
+}
+
+.item-action {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  flex-shrink: 0;
+}
+
 /* Responsive */
 @media (max-width: 640px) {
   .business-modal {

+ 9 - 1
ui/smarttrade-platform/src/main.js

@@ -1,6 +1,6 @@
 import { createApp } from 'vue'
 import { createPinia } from 'pinia'
-import ElementPlus from 'element-plus'
+import ElementPlus, { ElMessage } from 'element-plus'
 import zhCn from 'element-plus/es/locale/lang/zh-cn'
 import 'element-plus/dist/index.css'
 import App from './App.vue'
@@ -13,4 +13,12 @@ app.use(createPinia())
 app.use(router)
 app.use(ElementPlus, { locale: zhCn })
 
+app.config.globalProperties.$message = ElMessage
+app.config.globalProperties.ElMessage = ElMessage
+if (typeof window !== 'undefined') {
+  window.ElMessage = ElMessage
+}
+
+globalThis.ElMessage = ElMessage
+
 app.mount('#app')

+ 1 - 1
ui/smarttrade-platform/src/router/index.js

@@ -11,7 +11,7 @@ const routes = [
   {
     path: '/',
     name: 'home',
-    component: () => import('@/views/HomeView.vue')
+    component: () => import('@/views/MarketingView.vue')
   },
   {
     path: '/prospect',

+ 24 - 2
ui/smarttrade-platform/src/utils/request.js

@@ -1,9 +1,19 @@
 import axios from 'axios'
-import { getToken } from '@/utils/auth'
+import { getToken, removeToken } from '@/utils/auth'
 
 const BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api'
 const TIMEOUT = 30000
 const SUCCESS_CODES = [0, 200, 20000]
+let isRedirectingToLogin = false
+
+function redirectToLogin() {
+  if (isRedirectingToLogin) return
+  isRedirectingToLogin = true
+  removeToken()
+  if (typeof window !== 'undefined' && window.location.pathname !== '/login') {
+    window.location.replace('/login')
+  }
+}
 
 function normalizeError(error) {
   if (error?.response) {
@@ -48,6 +58,10 @@ service.interceptors.response.use(
       return data
     }
     if (data && typeof data === 'object' && 'code' in data) {
+      if (data.code === 401) {
+        redirectToLogin()
+        return Promise.reject(new Error(data.message || '登录已过期,请重新登录'))
+      }
       if (SUCCESS_CODES.includes(data.code)) {
         return data
       }
@@ -55,7 +69,15 @@ service.interceptors.response.use(
     }
     return data
   },
-  (error) => Promise.reject(normalizeError(error))
+  (error) => {
+    const status = error?.response?.status
+    const code = error?.response?.data?.code
+    if (status === 401 || code === 401) {
+      redirectToLogin()
+      return Promise.reject(new Error(error?.response?.data?.message || '登录已过期,请重新登录'))
+    }
+    return Promise.reject(normalizeError(error))
+  }
 )
 
 export function request({ url, method = 'get', params = {}, data = {}, headers = {}, ...config }) {

+ 71 - 93
ui/smarttrade-platform/src/views/MarketingView.vue

@@ -76,44 +76,44 @@
       </div>
     </div>
 
-    <!-- Campaigns Grid -->
+    <!-- Campaigns Grid campaigns marketingList-->
     <div class="campaigns-grid">
-      <div v-for="campaign in filteredCampaigns" :key="campaign.id" 
+      <div v-for="campaign in filteredMarketingList" :key="campaign.id" 
            class="campaign-card" @click="showCampaignDetail(campaign)">
         <div class="card-header">
-          <div class="card-icon" :style="{ background: campaign.iconBg }">
-            <i :class="campaign.icon" :style="{ color: campaign.iconColor }"></i>
+          <div class="card-icon" :style="{ background: 'rgba(99, 102, 241, 0.2)' }">
+            <i class="fas fa-globe" :style="{ color: 'var(--primary)' }"></i>
           </div>
-          <span class="status-badge" :class="campaign.status">{{ getStatusLabel(campaign.status) }}</span>
+          <span class="status-badge" :class="campaign.status == 0 ? 'info' : campaign.status == 1 ? 'active' : 'paused'">{{ getStatusLabel(campaign.status || 0) }}</span>
         </div>
         <div class="card-title">{{ campaign.name }}</div>
         <div class="card-desc">{{ campaign.description }}</div>
         <div class="card-channels">
-          <span v-for="ch in campaign.channels" :key="ch" class="channel-tag">
-            <i :class="getChannelIcon(ch)"></i> {{ ch }}
+          <span class="channel-tag">
+            <i class="fas fa-envelope"></i> 邮件
           </span>
         </div>
         <div class="card-stats">
           <div class="stat-item">
-            <span class="stat-value">{{ formatNumber(campaign.stats.sent) }}</span>
+            <span class="stat-value">{{ formatNumber(campaign.sendVolume) }}</span>
             <span class="stat-label">已发送</span>
           </div>
           <div class="stat-item">
-            <span class="stat-value success">{{ campaign.stats.openRate }}%</span>
+            <span class="stat-value success">{{ campaign.openRate }}%</span>
             <span class="stat-label">打开率</span>
           </div>
           <div class="stat-item">
-            <span class="stat-value primary">{{ campaign.stats.replyRate }}%</span>
+            <span class="stat-value primary">{{ campaign.replyRate }}%</span>
             <span class="stat-label">回复率</span>
           </div>
         </div>
         <div class="card-progress">
           <div class="progress-header">
             <span>进度</span>
-            <span>{{ campaign.progress }}%</span>
+            <span>{{ campaign.progressPercent || 0 }}%</span>
           </div>
           <div class="progress-bar">
-            <div class="progress-fill" :style="{ width: campaign.progress + '%' }"></div>
+            <div class="progress-fill" :style="{ width: (campaign.progressPercent || 0) + '%' }"></div>
           </div>
         </div>
         <div class="card-actions" @click.stop>
@@ -156,11 +156,11 @@
               </div>
               <div class="detail-item">
                 <label>活动类型</label>
-                <span>{{ selectedCampaign.type || '潜客开发' }}</span>
+                <span>{{ getTypeLabel(selectedCampaign.type) }}</span>
               </div>
               <div class="detail-item">
                 <label>优先级</label>
-                <span class="priority-badge" :class="selectedCampaign.priority || 'medium'">{{ getPriorityLabel(selectedCampaign.priority || 'medium') }}</span>
+                <span>{{ getPriorityLabel(selectedCampaign.priority) }}</span>
               </div>
               <div class="detail-item">
                 <label>负责人</label>
@@ -168,11 +168,11 @@
               </div>
               <div class="detail-item">
                 <label>创建时间</label>
-                <span>{{ selectedCampaign.createdAt || '2026-03-15 10:30' }}</span>
+                <span>{{ selectedCampaign.createTime }}</span>
               </div>
               <div class="detail-item">
                 <label>活动周期</label>
-                <span>{{ selectedCampaign.dateRange || '2026-03-15 至 2026-04-15' }}</span>
+                <span>{{ selectedCampaign.beginData }} 至 {{ selectedCampaign.endDate }}</span>
               </div>
               <div class="detail-item full-width">
                 <label>活动描述</label>
@@ -185,31 +185,31 @@
           <div class="detail-section">
             <div class="section-header">
               <h4><i class="fas fa-chart-line"></i> 核心数据</h4>
-              <div class="progress-info">达成 {{ selectedCampaign.progress }}%</div>
+              <div class="progress-info">达成 {{ selectedCampaign.progressPercent || 0 }}%</div>
             </div>
             <div class="detail-progress-bar">
-              <div class="progress-fill" :style="{ width: selectedCampaign.progress + '%' }"></div>
+              <div class="progress-fill" :style="{ width: (selectedCampaign.progressPercent || 0) + '%' }"></div>
             </div>
             <div class="metrics-grid">
               <div class="metric-card">
                 <div class="metric-icon blue"><i class="fas fa-paper-plane"></i></div>
                 <div class="metric-content">
-                  <div class="metric-value">{{ formatNumber(selectedCampaign.stats.sent) }}</div>
+                  <div class="metric-value">{{ formatNumber(selectedCampaign.sendVolume) }}</div>
                   <div class="metric-label">已发送</div>
                 </div>
               </div>
               <div class="metric-card">
                 <div class="metric-icon green"><i class="fas fa-envelope-open"></i></div>
                 <div class="metric-content">
-                  <div class="metric-value">{{ Math.round(selectedCampaign.stats.sent * selectedCampaign.stats.openRate / 100) }}</div>
-                  <div class="metric-label">打开数 ({{ selectedCampaign.stats.openRate }}%)</div>
+                  <div class="metric-value">{{ Math.round(selectedCampaign.sendVolume * selectedCampaign.openRate / 100) }}</div>
+                  <div class="metric-label">打开数 ({{ selectedCampaign.openRate }}%)</div>
                 </div>
               </div>
               <div class="metric-card">
                 <div class="metric-icon purple"><i class="fas fa-reply"></i></div>
                 <div class="metric-content">
-                  <div class="metric-value">{{ Math.round(selectedCampaign.stats.sent * selectedCampaign.stats.replyRate / 100) }}</div>
-                  <div class="metric-label">回复数 ({{ selectedCampaign.stats.replyRate }}%)</div>
+                  <div class="metric-value">{{ Math.round(selectedCampaign.sendVolume * selectedCampaign.replyRate / 100) }}</div>
+                  <div class="metric-label">回复数 ({{ selectedCampaign.replyRate }}%)</div>
                 </div>
               </div>
             </div>
@@ -221,16 +221,16 @@
               <h4><i class="fas fa-bullhorn"></i> 触达渠道</h4>
             </div>
             <div class="channel-detail-list">
-              <div v-for="ch in selectedCampaign.channels.filter(ch => ch !== 'WhatsApp' && ch !== 'LinkedIn')" :key="ch" class="channel-detail-item">
-                <div class="channel-icon-wrapper" :style="getChannelStyleByName(ch)">
-                  <i :class="getChannelIcon(ch)"></i>
+              <div class="channel-detail-item">
+                <div class="channel-icon-wrapper" :style="getChannelStyleByName('邮件')">
+                  <i :class="getChannelIcon('邮件')"></i>
                 </div>
                 <div class="channel-detail-info">
-                  <div class="channel-detail-name">{{ ch }}</div>
+                  <div class="channel-detail-name">邮件</div>
                   <div class="channel-detail-stats">
-                    <span>发送: {{ Math.round(selectedCampaign.stats.sent / selectedCampaign.channels.length) }}</span>
-                    <span>打开率: {{ selectedCampaign.stats.openRate }}%</span>
-                    <span>回复率: {{ selectedCampaign.stats.replyRate }}%</span>
+                    <span>发送: {{ Math.round(selectedCampaign.sendVolume) }}</span>
+                    <span>打开率: {{ selectedCampaign.openRate }}%</span>
+                    <span>回复率: {{ selectedCampaign.replyRate }}%</span>
                   </div>
                 </div>
                 <div class="channel-status">
@@ -268,36 +268,15 @@
             </div>
             <div class="sop-detail">
               <div class="sop-header-info">
-                <span class="sop-name">{{ selectedCampaign.sopTemplate || '标准开发序列' }}</span>
-                <span class="sop-steps">4 步序列</span>
+                <span class="sop-name">{{ sopDetails.name }}</span>
+                <span class="sop-steps">{{ sopDetails.details.length }} 步序列</span>
               </div>
               <div class="sop-timeline-detail">
-                <div class="sop-step-item completed">
-                  <div class="step-marker"><i class="fas fa-check"></i></div>
-                  <div class="step-content">
-                    <div class="step-title">首封介绍邮件</div>
-                    <div class="step-meta">第1天 · 邮件 · 已完成</div>
-                  </div>
-                </div>
-                <div class="sop-step-item completed">
-                  <div class="step-marker"><i class="fas fa-check"></i></div>
-                  <div class="step-content">
-                    <div class="step-title">产品优势介绍</div>
-                    <div class="step-meta">第3天 · 邮件 · 已完成</div>
-                  </div>
-                </div>
-                <div class="sop-step-item current">
-                  <div class="step-marker">3</div>
-                  <div class="step-content">
-                    <div class="step-title">案例分享</div>
-                    <div class="step-meta">第7天 · LinkedIn · 进行中</div>
-                  </div>
-                </div>
-                <div class="sop-step-item pending">
-                  <div class="step-marker">4</div>
+                <div class="sop-step-item pending" v-for="item in sopDetails.details" :key="item.id">
+                  <div class="step-marker">{{ item.step }}</div>
                   <div class="step-content">
-                    <div class="step-title">电话跟进</div>
-                    <div class="step-meta">第14天 · 电话 · 待执行</div>
+                    <div class="step-title">{{ item.name }}</div>
+                    <div class="step-meta">第{{ item.days }}天 · 邮件 · 待执行</div>
                   </div>
                 </div>
               </div>
@@ -436,7 +415,7 @@
     </div>
 
     <!-- Create Campaign Modal -->
-    <AddMarketing ref="addMarketingRef" />
+    <AddMarketing ref="addMarketingRef" @refresh="getData()" />
 
     <!-- AI Email Generator Modal -->
     <div v-if="showAIModal" class="modal-overlay" @click.self="showAIModal = false">
@@ -1275,9 +1254,9 @@
 </template>
 
 <script setup>
-import { ref, computed } from 'vue'
+import { ref, computed, onMounted } from 'vue'
 import AddMarketing from '../components/addMarketing.vue'
-import { getMarketingList } from '../api/marketing'
+import { getMarketingList, getSopById } from '../api/marketing'
 
 const filterTab = ref('all')
 
@@ -1309,10 +1288,27 @@ const openCreateModal = () => {
   addMarketingRef.value.open()
 }
 
-getMarketingList({ pageIndex: 1, pageSize: 10 }).then(res => {
-  console.log('res :>> ', res);
+const marketingList = ref([])
+onMounted(() => {
+  getData()
 })
 
+const getData = () => {
+  getMarketingList({ pageIndex: 1, pageSize: 1000 }).then(res => {
+    if(res.code == 200) {
+      marketingList.value = res.result.result.records || []
+      tabs.value = [
+        { key: 'all', label: '全部活动', count: marketingList.value.length },
+        { key: 0, label: '未开始', count: marketingList.value.filter(item => item.status === 0).length },
+        { key: 1, label: '进行中', count: marketingList.value.filter(item => item.status === 1).length },
+        { key: 2, label: '已暂停', count: marketingList.value.filter(item => item.status === 2).length },
+        { key: 3, label: '已完成', count: marketingList.value.filter(item => item.status === 3).length }
+      ]
+    }
+  })
+}
+
+
 // History filters
 const historySearch = ref('')
 const historyFilter = ref({ status: '', type: '', dateRange: '' })
@@ -1321,35 +1317,9 @@ const templateTab = ref('all')
 const templateSort = ref('popular')
 
 const marketingStats = { totalSent: 2847, openRate: 45, clickRate: 12, replyRate: 8, protectedCustomers: 156, pendingReview: 23, activeCampaigns: 5 }
-const tabs = [
-  { key: 'all', label: '全部活动', count: 12 },
-  { key: 'active', label: '进行中', count: 5 },
-  { key: 'paused', label: '已暂停', count: 2 },
-  { key: 'completed', label: '已完成', count: 5 }
-]
+const tabs = ref()
 
-const campaigns = ref([
-  // ===== 进行中 =====
-  { id: 1, name: '中东潜客开发活动', description: '针对中东地区 SSD 进口商', status: 'active', progress: 68, icon: 'fas fa-globe', iconBg: 'rgba(99, 102, 241, 0.2)', iconColor: 'var(--primary)', channels: ['邮件', 'LinkedIn'], stats: { sent: 312, openRate: 48, replyRate: 12 }, openedCustomers: 150, repliedCustomers: 37 },
-  { id: 2, name: '欧洲企业级存储推广', description: '面向欧洲数据中心客户', status: 'active', progress: 45, icon: 'fas fa-server', iconBg: 'rgba(16, 185, 129, 0.2)', iconColor: 'var(--success)', channels: ['邮件', 'WhatsApp'], stats: { sent: 178, openRate: 52, replyRate: 15 }, openedCustomers: 93, repliedCustomers: 27 },
-  { id: 3, name: '沉默客户唤醒计划', description: '重新激活90天未互动客户', status: 'active', progress: 32, icon: 'fas fa-moon', iconBg: 'rgba(139, 92, 246, 0.2)', iconColor: 'var(--secondary)', channels: ['邮件'], stats: { sent: 89, openRate: 35, replyRate: 8 }, openedCustomers: 31, repliedCustomers: 7 },
-  { id: 5, name: '东南亚分销商招募', description: '招募东南亚电子产品分销商', status: 'active', progress: 55, icon: 'fas fa-handshake', iconBg: 'rgba(6, 182, 212, 0.2)', iconColor: 'var(--info)', channels: ['邮件', 'WhatsApp'], stats: { sent: 234, openRate: 38, replyRate: 11 }, openedCustomers: 89, repliedCustomers: 26 },
-  { id: 6, name: '非洲新兴市场开拓', description: '开拓非洲电子产品进口商资源', status: 'active', progress: 22, icon: 'fas fa-map-marker-alt', iconBg: 'rgba(239, 68, 68, 0.2)', iconColor: 'var(--danger)', channels: ['邮件', 'WhatsApp'], stats: { sent: 145, openRate: 31, replyRate: 7 }, openedCustomers: 45, repliedCustomers: 10 },
-  { id: 7, name: '2026春季产品推广', description: '推广最新一代企业级SSD产品线', status: 'active', progress: 60, icon: 'fas fa-box-open', iconBg: 'rgba(251, 191, 36, 0.2)', iconColor: '#FBBF24', channels: ['邮件', 'LinkedIn', 'WhatsApp'], stats: { sent: 420, openRate: 55, replyRate: 18 }, openedCustomers: 231, repliedCustomers: 76 },
-  { id: 8, name: '展会客户跟进计划', description: '跟进2026广交会收集的名片客户', status: 'active', progress: 78, icon: 'fas fa-id-card', iconBg: 'rgba(16, 185, 129, 0.2)', iconColor: 'var(--success)', channels: ['邮件', 'WhatsApp'], stats: { sent: 267, openRate: 61, replyRate: 22 }, openedCustomers: 163, repliedCustomers: 59 },
-  // ===== 已暂停 =====
-  { id: 4, name: '北美市场拓展', description: '针对美国和加拿大市场', status: 'paused', progress: 25, icon: 'fas fa-flag-usa', iconBg: 'rgba(245, 158, 11, 0.2)', iconColor: 'var(--warning)', channels: ['邮件', 'LinkedIn'], stats: { sent: 156, openRate: 42, replyRate: 10 }, openedCustomers: 65, repliedCustomers: 16 },
-  { id: 9, name: '日韩高端客户培育', description: '针对日本和韩国高端企业客户', status: 'paused', progress: 40, icon: 'fas fa-gem', iconBg: 'rgba(139, 92, 246, 0.2)', iconColor: 'var(--secondary)', channels: ['邮件', 'LinkedIn'], stats: { sent: 98, openRate: 44, replyRate: 9 }, openedCustomers: 43, repliedCustomers: 9 },
-  { id: 10, name: '南美分销渠道建设', description: '在巴西、阿根廷等地寻找分销商', status: 'paused', progress: 15, icon: 'fas fa-route', iconBg: 'rgba(6, 182, 212, 0.2)', iconColor: 'var(--info)', channels: ['邮件'], stats: { sent: 72, openRate: 28, replyRate: 5 }, openedCustomers: 20, repliedCustomers: 4 },
-  { id: 11, name: '印度IT采购季活动', description: '针对印度IT企业Q2采购季', status: 'paused', progress: 50, icon: 'fas fa-rupee-sign', iconBg: 'rgba(245, 158, 11, 0.2)', iconColor: 'var(--warning)', channels: ['邮件', 'WhatsApp'], stats: { sent: 189, openRate: 37, replyRate: 11 }, openedCustomers: 70, repliedCustomers: 21 },
-  // ===== 已完成 =====
-  { id: 12, name: '2025年终大促活动', description: '2025年Q4年终促销,清库存冲业绩', status: 'completed', progress: 100, icon: 'fas fa-trophy', iconBg: 'rgba(251, 191, 36, 0.2)', iconColor: '#FBBF24', channels: ['邮件', 'WhatsApp', 'LinkedIn'], stats: { sent: 856, openRate: 62, replyRate: 24 }, openedCustomers: 531, repliedCustomers: 205 },
-  { id: 13, name: '欧洲圣诞节日营销', description: '圣诞节前针对欧洲客户的节日促销', status: 'completed', progress: 100, icon: 'fas fa-snowflake', iconBg: 'rgba(99, 102, 241, 0.2)', iconColor: 'var(--primary)', channels: ['邮件', 'LinkedIn'], stats: { sent: 412, openRate: 57, replyRate: 19 }, openedCustomers: 235, repliedCustomers: 78 },
-  { id: 14, name: '中东斋月特别活动', description: '斋月期间针对中东客户的专项营销', status: 'completed', progress: 100, icon: 'fas fa-star-and-crescent', iconBg: 'rgba(16, 185, 129, 0.2)', iconColor: 'var(--success)', channels: ['邮件', 'WhatsApp'], stats: { sent: 298, openRate: 53, replyRate: 17 }, openedCustomers: 158, repliedCustomers: 51 },
-  { id: 15, name: '2025广交会前期预热', description: '广交会前向目标客户发送邀请函', status: 'completed', progress: 100, icon: 'fas fa-handshake', iconBg: 'rgba(6, 182, 212, 0.2)', iconColor: 'var(--info)', channels: ['邮件', 'LinkedIn', 'WhatsApp'], stats: { sent: 634, openRate: 68, replyRate: 28 }, openedCustomers: 431, repliedCustomers: 177 }
-])
-
-const filteredCampaigns = computed(() => filterTab.value === 'all' ? campaigns.value : campaigns.value.filter(c => c.status === filterTab.value))
+const filteredMarketingList = computed(() => filterTab.value === 'all' ? marketingList.value : marketingList.value.filter(c => c.status === filterTab.value))
 
 // 打开邮件的客户列表 - 需要人工跟进
 const openedCustomers = ref([
@@ -1482,10 +1452,11 @@ const emailTemplates = ref([
 // })
 
 const formatNumber = (n) => n >= 1000 ? (n / 1000).toFixed(1) + 'K' : n.toLocaleString()
-const getStatusLabel = (s) => ({ active: '进行中', paused: '已暂停', completed: '已完成' }[s] || s)
+const getStatusLabel = (s) => ({ 0: '未开始', 1: '进行中', 2: '已暂停', 3: '已完成' }[s] || s)
 const getChannelIcon = (c) => ({ '邮件': 'fas fa-envelope', 'WhatsApp': 'fab fa-whatsapp', 'LinkedIn': 'fab fa-linkedin' }[c] || 'fas fa-comment')
 
-const getPriorityLabel = (priority) => ({ high: '高', medium: '中', low: '低' }[priority] || priority)
+const getTypeLabel = (type) => ({ 1: '潜客开发', 2: '客户培养', 3: '客户唤醒', 4: '产品推广', 5: '节日营销', 6: '展会跟进' }[type] || type)
+const getPriorityLabel = (priority) => ({ 1: '紧急', 2: '高优先', 3: '中等', 4: '低优先' }[priority] || priority)
 const getRegionLabel = (region) => ({ 'middle-east': '中东', 'europe': '欧洲', 'north-america': '北美', 'southeast-asia': '东南亚', 'africa': '非洲', 'south-america': '南美' }[region] || '全部地区')
 const getIndustryLabel = (industry) => ({ 'datacenter': '数据中心', 'consumer': '消费电子', 'distributor': '电子分销', 'retail': '零售', 'manufacturing': '制造业' }[industry] || '全部行业')
 const getChannelName = (id) => ({ email: '邮件营销', whatsapp: 'WhatsApp', linkedin: 'LinkedIn', wechat: '微信企业号' }[id] || id)
@@ -1524,8 +1495,15 @@ const copyEmail = () => {
 const useEmail = () => { showAIModal.value = false; toast('邮件已应用到活动', 'success') }
 const useTemplate = (tpl) => { showTemplatesModal.value = false; toast(`已应用模板: ${tpl.subject}`, 'success') }
 const toggleCampaign = (c) => { c.status = c.status === 'paused' ? 'active' : 'paused'; toast(c.status === 'paused' ? '已暂停' : '已恢复', 'success') }
+
+const sopDetails = ref()
 const showCampaignDetail = (campaign) => {
   selectedCampaign.value = campaign
+  getSopById(campaign.sopId).then(res => {
+    if(res.code == 200){
+      sopDetails.value = res.result
+    }
+  })
   showCampaignDetailModal.value = true
 }
 
@@ -1793,7 +1771,7 @@ const exportCampaignReport = (campaign) => {
 
 const editCampaign = (campaign) => {
   showCampaignDetailModal.value = false
-  toast('正在打开活动编辑...', 'info')
+  addMarketingRef.value.open(campaign)
 }
 </script>
 

+ 24 - 1268
ui/smarttrade-platform/src/views/SettingsView.vue

@@ -279,13 +279,13 @@
               </div>
               <div class="channel-content">
                 <div class="channel-title">企业邮箱</div>
-                <div class="channel-desc">{{ channels.email.connected ? channels.email.accounts + '个账号已绑定' : '未绑定' }}</div>
+                <div class="channel-desc">{{ emailList.length > 0 ? emailList.length + '个账号已绑定' : '未绑定' }}</div>
               </div>
               <div class="channel-action">
-                <button v-if="channels.email.connected" class="btn btn-secondary btn-sm" @click="showEmailModal = true">
+                <button v-if="channels.email.connected" class="btn btn-secondary btn-sm" @click="openEmailModal">
                   <i class="fas fa-cog"></i> 管理
                 </button>
-                <button v-else class="btn btn-primary btn-sm" @click="showEmailModal = true">
+                <button v-else class="btn btn-primary btn-sm" @click="openEmailModal">
                   <i class="fas fa-plus"></i> 绑定
                 </button>
               </div>
@@ -396,112 +396,6 @@
       </div>
     </transition>
 
-    <!-- 个人信息弹窗 -->
-    <div v-if="showProfileModal" class="modal-overlay" @click.self="showProfileModal = false">
-      <div class="modal settings-modal">
-        <div class="modal-header">
-          <div class="modal-title"><i class="fas fa-user-edit"></i> 编辑个人信息</div>
-          <button class="modal-close" @click="showProfileModal = false"><i class="fas fa-times"></i></button>
-        </div>
-        <div class="modal-body">
-          <div class="form-group">
-            <label class="form-label">姓名</label>
-            <input type="text" class="form-input" value="张经理" placeholder="请输入姓名">
-          </div>
-          <div class="form-group">
-            <label class="form-label">职位</label>
-            <input type="text" class="form-input" value="销售总监" placeholder="请输入职位">
-          </div>
-          <div class="form-group">
-            <label class="form-label">邮箱</label>
-            <input type="email" class="form-input" value="zhang@company.com" placeholder="请输入邮箱">
-          </div>
-          <div class="form-group">
-            <label class="form-label">电话</label>
-            <input type="tel" class="form-input" value="+86 138****8888" placeholder="请输入电话">
-          </div>
-          <div class="form-group">
-            <label class="form-label">所属部门</label>
-            <select class="form-select">
-              <option>销售部</option>
-              <option>市场部</option>
-              <option>商务部</option>
-            </select>
-          </div>
-          <div class="form-group">
-            <label class="form-label">个人简介</label>
-            <textarea class="form-textarea" rows="3" placeholder="请输入个人简介">负责公司SSD产品在中东、欧洲市场的销售工作,拥有10年电子元器件出口经验。</textarea>
-          </div>
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" @click="showProfileModal = false">取消</button>
-          <button class="btn btn-primary" @click="showProfileModal = false; showToastMessage('个人信息已更新', 'success')">保存</button>
-        </div>
-      </div>
-    </div>
-
-    <!-- 修改密码弹窗 -->
-    <div v-if="showPasswordModal" class="modal-overlay" @click.self="showPasswordModal = false">
-      <div class="modal settings-modal">
-        <div class="modal-header">
-          <div class="modal-title"><i class="fas fa-key"></i> 修改密码</div>
-          <button class="modal-close" @click="showPasswordModal = false"><i class="fas fa-times"></i></button>
-        </div>
-        <div class="modal-body">
-          <div class="form-group">
-            <label class="form-label">当前密码</label>
-            <input type="password" class="form-input" placeholder="请输入当前密码">
-          </div>
-          <div class="form-group">
-            <label class="form-label">新密码</label>
-            <input type="password" class="form-input" placeholder="请输入新密码">
-          </div>
-          <div class="form-group">
-            <label class="form-label">确认新密码</label>
-            <input type="password" class="form-input" placeholder="请再次输入新密码">
-          </div>
-          <div class="password-hint">
-            <i class="fas fa-info-circle"></i> 密码要求:至少8位,包含字母和数字
-          </div>
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" @click="showPasswordModal = false">取消</button>
-          <button class="btn btn-primary" @click="showPasswordModal = false; showToastMessage('密码已修改', 'success')">确认修改</button>
-        </div>
-      </div>
-    </div>
-
-    <!-- 登录历史弹窗 -->
-    <div v-if="showLoginHistoryModal" class="modal-overlay" @click.self="showLoginHistoryModal = false">
-      <div class="modal settings-modal wide">
-        <div class="modal-header">
-          <div class="modal-title"><i class="fas fa-history"></i> 登录历史记录</div>
-          <button class="modal-close" @click="showLoginHistoryModal = false"><i class="fas fa-times"></i></button>
-        </div>
-        <div class="modal-body">
-          <div class="login-history-list">
-            <div v-for="login in loginHistory" :key="login.id" class="login-history-item">
-              <div class="login-icon" :class="login.status">
-                <i :class="login.status === '成功' ? 'fas fa-check-circle' : 'fas fa-times-circle'"></i>
-              </div>
-              <div class="login-info">
-                <div class="login-time">{{ login.time }}</div>
-                <div class="login-details">
-                  <span><i class="fas fa-map-marker-alt"></i> {{ login.location }}</span>
-                  <span><i class="fas fa-desktop"></i> {{ login.device }}</span>
-                  <span><i class="fas fa-network-wired"></i> {{ login.ip }}</span>
-                </div>
-              </div>
-              <div class="login-status" :class="login.status">{{ login.status }}</div>
-            </div>
-          </div>
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" @click="showLoginHistoryModal = false">关闭</button>
-        </div>
-      </div>
-    </div>
-
     <!-- 模型微调弹窗 -->
     <div v-if="showModelModal" class="modal-overlay" @click.self="showModelModal = false">
       <div class="modal settings-modal wide">
@@ -1042,256 +936,7 @@
     </div>
 
     <!-- 企业邮箱弹窗 -->
-    <div v-if="showEmailModal" class="modal-overlay" @click.self="showEmailModal = false">
-      <div class="modal settings-modal extra-wide">
-        <div class="modal-header">
-          <div class="modal-title"><i class="fas fa-envelope"></i> 企业邮箱管理中心</div>
-          <button class="modal-close" @click="showEmailModal = false"><i class="fas fa-times"></i></button>
-        </div>
-        <div class="modal-body">
-          <!-- 邮箱统计概览 -->
-          <div class="email-overview">
-            <div class="overview-card">
-              <div class="overview-icon email"><i class="fas fa-envelope"></i></div>
-              <div class="overview-info">
-                <div class="overview-value">{{ emailAccounts.length }}</div>
-                <div class="overview-label">邮箱账号</div>
-              </div>
-            </div>
-            <div class="overview-card">
-              <div class="overview-icon"><i class="fas fa-paper-plane"></i></div>
-              <div class="overview-info">
-                <div class="overview-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday, 0) }}</div>
-                <div class="overview-label">今日发送</div>
-              </div>
-            </div>
-            <div class="overview-card">
-              <div class="overview-icon"><i class="fas fa-reply"></i></div>
-              <div class="overview-info">
-                <div class="overview-value">{{ Math.round(emailAccounts.reduce((sum, a) => sum + a.replyRate, 0) / emailAccounts.length) }}%</div>
-                <div class="overview-label">平均回复率</div>
-              </div>
-            </div>
-            <div class="overview-card">
-              <div class="overview-icon"><i class="fas fa-shield-alt"></i></div>
-              <div class="overview-info">
-                <div class="overview-value">3/3</div>
-                <div class="overview-label">安全认证</div>
-              </div>
-            </div>
-          </div>
-
-          <!-- 标签页导航 -->
-          <div class="email-tabs">
-            <button class="email-tab active"><i class="fas fa-envelope"></i> 邮箱账号</button>
-            <button class="email-tab"><i class="fas fa-chart-bar"></i> 发送统计</button>
-          </div>
-          
-          <div class="email-accounts-list">
-            <div v-for="account in emailAccounts" :key="account.id" class="email-account-item" :class="{selected: selectedEmailAccount?.id === account.id}" @click="selectedEmailAccount = account; showEmailDetailModal = true">
-              <div class="account-icon"><i class="fas fa-envelope"></i></div>
-              <div class="account-info">
-                <div class="account-email">{{ account.email }}</div>
-                <div class="account-name">{{ account.name }}</div>
-                <div class="account-stats">
-                  <span><i class="fas fa-paper-plane"></i> 今日: {{ account.sendToday }}</span>
-                  <span><i class="fas fa-reply"></i> 回复率: {{ account.replyRate }}%</span>
-                  <span><i class="fas fa-sync"></i> {{ account.lastSync }}</span>
-                </div>
-              </div>
-              <div class="account-auth">
-                <span class="auth-badge" :class="account.SPF ? 'active' : ''"><i class="fas fa-check"></i> SPF</span>
-                <span class="auth-badge" :class="account.DKIM ? 'active' : ''"><i class="fas fa-check"></i> DKIM</span>
-                <span class="auth-badge" :class="account.DMARC ? 'active' : ''"><i class="fas fa-check"></i> DMARC</span>
-              </div>
-            </div>
-          </div>
-
-          <!-- 发送统计标签页 -->
-          <div class="email-tab-content" v-if="false">
-            <div class="stats-overview">
-              <div class="stat-card">
-                <div class="stat-icon"><i class="fas fa-paper-plane"></i></div>
-                <div class="stat-info">
-                  <div class="stat-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday, 0) }}</div>
-                  <div class="stat-label">今日发送</div>
-                </div>
-              </div>
-              <div class="stat-card">
-                <div class="stat-icon"><i class="fas fa-envelope-open"></i></div>
-                <div class="stat-info">
-                  <div class="stat-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday * 0.45, 0).toFixed(0) }}</div>
-                  <div class="stat-label">今日打开</div>
-                </div>
-              </div>
-              <div class="stat-card">
-                <div class="stat-icon"><i class="fas fa-reply"></i></div>
-                <div class="stat-info">
-                  <div class="stat-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday * a.replyRate / 100, 0).toFixed(0) }}</div>
-                  <div class="stat-label">今日回复</div>
-                </div>
-              </div>
-              <div class="stat-card">
-                <div class="stat-icon"><i class="fas fa-mouse-pointer"></i></div>
-                <div class="stat-info">
-                  <div class="stat-value">{{ emailAccounts.reduce((sum, a) => sum + a.sendToday * 0.15, 0).toFixed(0) }}</div>
-                  <div class="stat-label">今日点击</div>
-                </div>
-              </div>
-            </div>
-            <div class="chart-section">
-              <h5><i class="fas fa-chart-line"></i> 最近7天发送趋势</h5>
-              <div class="simple-chart">
-                <div class="chart-bar" style="height: 45%"><span>周一</span></div>
-                <div class="chart-bar" style="height: 62%"><span>周二</span></div>
-                <div class="chart-bar" style="height: 58%"><span>周三</span></div>
-                <div class="chart-bar" style="height: 75%"><span>周四</span></div>
-                <div class="chart-bar" style="height: 82%"><span>周五</span></div>
-                <div class="chart-bar" style="height: 40%"><span>周六</span></div>
-                <div class="chart-bar" style="height: 35%"><span>周日</span></div>
-              </div>
-            </div>
-            <div class="top-performers">
-              <h5><i class="fas fa-trophy"></i> 热门模板</h5>
-              <div class="template-list">
-                <div class="template-item">
-                  <span class="template-name">产品介绍邮件</span>
-                  <span class="template-stats">发送 1,234 · 打开率 52%</span>
-                </div>
-                <div class="template-item">
-                  <span class="template-name">节日祝福</span>
-                  <span class="template-stats">发送 856 · 打开率 68%</span>
-                </div>
-                <div class="template-item">
-                  <span class="template-name">跟进邮件</span>
-                  <span class="template-stats">发送 654 · 打开率 45%</span>
-                </div>
-              </div>
-            </div>
-          </div>
-
-          <!-- 域名配置标签页 -->
-          <div class="email-tab-content" v-if="false">
-            <div class="domain-config-section">
-              <h5><i class="fas fa-globe"></i> 已配置域名</h5>
-              <div class="domain-list">
-                <div class="domain-item">
-                  <div class="domain-icon"><i class="fas fa-atlas"></i></div>
-                  <div class="domain-info">
-                    <div class="domain-name">company.com</div>
-                    <div class="domain-meta">
-                      <span class="domain-status active"><i class="fas fa-check-circle"></i> 已验证</span>
-                      <span><i class="fas fa-user"></i> 5个邮箱</span>
-                    </div>
-                  </div>
-                  <button class="btn btn-sm btn-secondary">管理</button>
-                </div>
-              </div>
-            </div>
-            <div class="domain-config-section">
-              <h5><i class="fas fa-cog"></i> 域名配置指南</h5>
-              <div class="config-guide">
-                <div class="guide-step">
-                  <div class="step-num">1</div>
-                  <div class="step-content">
-                    <div class="step-title">添加域名</div>
-                    <div class="step-desc">在域名服务商处添加DNS记录验证所有权</div>
-                  </div>
-                </div>
-                <div class="guide-step">
-                  <div class="step-num">2</div>
-                  <div class="step-content">
-                    <div class="step-title">配置MX记录</div>
-                    <div class="step-desc">设置邮件交换记录指向您的邮件服务器</div>
-                  </div>
-                </div>
-                <div class="guide-step">
-                  <div class="step-num">3</div>
-                  <div class="step-content">
-                    <div class="step-title">配置SPF/DKIM/DMARC</div>
-                    <div class="step-desc">添加安全认证记录防止邮件伪造</div>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-
-          <!-- 安全设置标签页 -->
-          <div class="email-tab-content" v-if="false">
-            <div class="security-overview">
-              <div class="security-card">
-                <div class="security-header">
-                  <i class="fas fa-shield-alt"></i>
-                  <span>总体安全评分</span>
-                </div>
-                <div class="security-score">92/100</div>
-                <div class="security-desc">您的邮件安全配置良好</div>
-              </div>
-            </div>
-            <div class="security-section">
-              <h5><i class="fas fa-lock"></i> 安全策略</h5>
-              <div class="security-list">
-                <div class="security-item">
-                  <div class="security-item-info">
-                    <span class="security-item-title">SPF验证</span>
-                    <span class="security-item-desc">验证发件服务器授权</span>
-                  </div>
-                  <div class="toggle-switch active"><span class="toggle-slider"></span></div>
-                </div>
-                <div class="security-item">
-                  <div class="security-item-info">
-                    <span class="security-item-title">DKIM签名</span>
-                    <span class="security-item-desc">邮件内容数字签名</span>
-                  </div>
-                  <div class="toggle-switch active"><span class="toggle-slider"></span></div>
-                </div>
-                <div class="security-item">
-                  <div class="security-item-info">
-                    <span class="security-item-title">DMARC策略</span>
-                    <span class="security-item-desc">防止域名被伪造</span>
-                  </div>
-                  <div class="toggle-switch active"><span class="toggle-slider"></span></div>
-                </div>
-                <div class="security-item">
-                  <div class="security-item-info">
-                    <span class="security-item-title">TLS加密传输</span>
-                    <span class="security-item-desc">邮件传输过程加密</span>
-                  </div>
-                  <div class="toggle-switch active"><span class="toggle-slider"></span></div>
-                </div>
-              </div>
-            </div>
-            <div class="security-section">
-              <h5><i class="fas fa-history"></i> 安全日志</h5>
-              <div class="security-logs">
-                <div class="log-item">
-                  <span class="log-time">2026-03-24 08:00</span>
-                  <span class="log-event">SPF验证通过</span>
-                  <span class="log-status success">正常</span>
-                </div>
-                <div class="log-item">
-                  <span class="log-time">2026-03-23 14:30</span>
-                  <span class="log-event">DKIM签名验证</span>
-                  <span class="log-status success">正常</span>
-                </div>
-                <div class="log-item">
-                  <span class="log-time">2026-03-22 09:15</span>
-                  <span class="log-event">DMARC检查</span>
-                  <span class="log-status success">正常</span>
-                </div>
-              </div>
-            </div>
-          </div>
-
-          <button class="btn btn-primary add-account-btn" @click="showAddEmailModal = true">
-            <i class="fas fa-plus"></i> 添加邮箱账号
-          </button>
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" @click="showEmailModal = false">关闭</button>
-        </div>
-      </div>
-    </div>
+    <Email ref="emailRef" />
 
     <!-- LinkedIn弹窗 -->
     <div v-if="showLinkedInModal" class="modal-overlay" @click.self="showLinkedInModal = false">
@@ -1341,167 +986,6 @@
       </div>
     </div>
 
-    <!-- 添加邮箱账号弹窗 -->
-    <div v-if="showAddEmailModal" class="modal-overlay" @click.self="showAddEmailModal = false">
-      <div class="modal settings-modal">
-        <div class="modal-header">
-          <div class="modal-title"><i class="fas fa-plus-circle"></i> 添加邮箱账号</div>
-          <button class="modal-close" @click="showAddEmailModal = false"><i class="fas fa-times"></i></button>
-        </div>
-        <div class="modal-body">
-          <div class="form-group">
-            <label class="form-label">邮箱地址 <span class="required">*</span></label>
-            <input type="email" class="form-input" placeholder="例如: sales@company.com">
-          </div>
-          <div class="form-group">
-            <label class="form-label">显示名称</label>
-            <input type="text" class="form-input" placeholder="例如: 销售团队">
-          </div>
-          <div class="form-group">
-            <label class="form-label">SMTP 服务器 <span class="required">*</span></label>
-            <input type="text" class="form-input" placeholder="例如: smtp.company.com">
-          </div>
-          <div class="form-group">
-            <label class="form-label">SMTP 端口 <span class="required">*</span></label>
-            <input type="number" class="form-input" placeholder="587 (TLS) 或 465 (SSL)">
-          </div>
-          <div class="form-group">
-            <label class="form-label">SMTP 用户名 <span class="required">*</span></label>
-            <input type="text" class="form-input" placeholder="通常为完整邮箱地址">
-          </div>
-          <div class="form-group">
-            <label class="form-label">SMTP 密码 <span class="required">*</span></label>
-            <input type="password" class="form-input" placeholder="邮箱密码或应用专用密码">
-          </div>
-          <div class="form-group">
-            <label class="form-label">IMAP 服务器</label>
-            <input type="text" class="form-input" placeholder="例如: imap.company.com">
-          </div>
-          <div class="test-connection">
-            <button class="btn btn-secondary"><i class="fas fa-plug"></i> 测试连接</button>
-          </div>
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" @click="showAddEmailModal = false">取消</button>
-          <button class="btn btn-primary" @click="showAddEmailModal = false; showToastMessage('邮箱账号添加成功', 'success')">确认添加</button>
-        </div>
-      </div>
-    </div>
-
-    <!-- 邮箱账号详情弹窗 -->
-    <div v-if="showEmailDetailModal" class="modal-overlay" @click.self="showEmailDetailModal = false">
-      <div class="modal settings-modal extra-wide">
-        <div class="modal-header">
-          <div class="modal-title">
-            <i class="fas fa-envelope"></i> {{ selectedEmailAccount?.email }} - 详细配置
-          </div>
-          <button class="modal-close" @click="showEmailDetailModal = false"><i class="fas fa-times"></i></button>
-        </div>
-        <div class="modal-body" v-if="selectedEmailAccount">
-          <!-- 服务器配置 -->
-          <div class="detail-section">
-            <h5><i class="fas fa-server"></i> SMTP / IMAP 服务器配置</h5>
-            <div class="config-grid-2col">
-              <div class="config-card">
-                <div class="config-card-header">
-                  <i class="fas fa-upload"></i> SMTP (发送)
-                </div>
-                <div class="config-card-body">
-                  <div class="config-row">
-                    <span class="config-label">服务器地址</span>
-                    <span class="config-value">{{ selectedEmailAccount.smtp.host }}</span>
-                  </div>
-                  <div class="config-row">
-                    <span class="config-label">端口</span>
-                    <span class="config-value">{{ selectedEmailAccount.smtp.port }}</span>
-                  </div>
-                  <div class="config-row">
-                    <span class="config-label">加密方式</span>
-                    <span class="config-value">{{ selectedEmailAccount.smtp.encryption }}</span>
-                  </div>
-                  <div class="config-row">
-                    <span class="config-label">认证方式</span>
-                    <span class="config-value">OAuth 2.0 / SMTPAuth</span>
-                  </div>
-                </div>
-              </div>
-              <div class="config-card">
-                <div class="config-card-header">
-                  <i class="fas fa-download"></i> IMAP (接收)
-                </div>
-                <div class="config-card-body">
-                  <div class="config-row">
-                    <span class="config-label">服务器地址</span>
-                    <span class="config-value">{{ selectedEmailAccount.imap.host }}</span>
-                  </div>
-                  <div class="config-row">
-                    <span class="config-label">端口</span>
-                    <span class="config-value">{{ selectedEmailAccount.imap.port }}</span>
-                  </div>
-                  <div class="config-row">
-                    <span class="config-label">加密方式</span>
-                    <span class="config-value">{{ selectedEmailAccount.imap.encryption }}</span>
-                  </div>
-                  <div class="config-row">
-                    <span class="config-label">同步文件夹</span>
-                    <span class="config-value">INBOX, Sent, Drafts</span>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-
-          <!-- 安全认证 -->
-          <div class="detail-section">
-            <h5><i class="fas fa-shield-alt"></i> 邮件安全认证状态</h5>
-            <div class="auth-grid">
-              <div class="auth-card" :class="selectedEmailAccount.SPF ? 'pass' : 'fail'">
-                <div class="auth-icon"><i class="fas fa-shield-alt"></i></div>
-                <div class="auth-info">
-                  <div class="auth-name">SPF</div>
-                  <div class="auth-desc">发件人策略框架</div>
-                </div>
-                <div class="auth-status">{{ selectedEmailAccount.SPF ? '已配置' : '未配置' }}</div>
-              </div>
-              <div class="auth-card" :class="selectedEmailAccount.DKIM ? 'pass' : 'fail'">
-                <div class="auth-icon"><i class="fas fa-key"></i></div>
-                <div class="auth-info">
-                  <div class="auth-name">DKIM</div>
-                  <div class="auth-desc">域名密钥识别邮件</div>
-                </div>
-                <div class="auth-status">{{ selectedEmailAccount.DKIM ? '已配置' : '未配置' }}</div>
-              </div>
-              <div class="auth-card" :class="selectedEmailAccount.DMARC ? 'pass' : 'fail'">
-                <div class="auth-icon"><i class="fas fa-lock"></i></div>
-                <div class="auth-info">
-                  <div class="auth-name">DMARC</div>
-                  <div class="auth-desc">基于域的消息认证</div>
-                </div>
-                <div class="auth-status">{{ selectedEmailAccount.DMARC ? '已配置' : '未配置' }}</div>
-              </div>
-            </div>
-          </div>
-
-          <!-- 邮件签名 -->
-          <div class="detail-section">
-            <h5><i class="fas fa-pen"></i> 邮件签名</h5>
-            <div class="signature-preview">
-              <div class="signature-label">预览效果:</div>
-              <div class="signature-content">
-                <pre>{{ selectedEmailAccount.signature }}</pre>
-              </div>
-            </div>
-            <textarea class="form-textarea signature-textarea" rows="6">{{ selectedEmailAccount.signature }}</textarea>
-          </div>
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" @click="showEmailDetailModal = false">关闭</button>
-          <button class="btn btn-primary" @click="showEmailDetailModal = false">配置检测</button>
-          <button class="btn btn-primary" @click="showEmailDetailModal = false; showToastMessage('配置已保存', 'success')">保存配置</button>
-        </div>
-      </div>
-    </div>
-
     <!-- 企业微信弹窗 -->
     <div v-if="showWeChatModal" class="modal-overlay" @click.self="showWeChatModal = false">
       <div class="modal settings-modal">
@@ -1549,7 +1033,9 @@
 </template>
 
 <script setup>
-import { ref, reactive } from 'vue'
+import { ref, reactive, onMounted } from 'vue'
+import Email from '@/components/email/email.vue'
+import { getUserEmails } from '@/api/emails'
 
 const showToast = ref(false)
 const toastMessage = ref('')
@@ -1567,24 +1053,12 @@ const showDataSourceDetailModal = ref(false)
 const showAddDataSourceModal = ref(false)
 const showQuickSourceModal = ref(false)
 const selectedQuickSource = ref(null)
-const showEmailModal = ref(false)
+
 const showEmailDetailModal = ref(false)
-const showAddEmailModal = ref(false)
+
 const showLinkedInModal = ref(false)
 const showWeChatModal = ref(false)
 
-// 登录历史数据
-const loginHistory = ref([
-  { id: 1, time: '2026-03-24 09:30', ip: '192.168.1.100', location: '上海', device: 'Chrome / Windows', status: '成功' },
-  { id: 2, time: '2026-03-23 14:22', ip: '192.168.1.100', location: '上海', device: 'Chrome / Windows', status: '成功' },
-  { id: 3, time: '2026-03-22 10:15', ip: '223.104.3.25', location: '北京', device: 'Safari / macOS', status: '成功' },
-  { id: 4, time: '2026-03-21 16:45', ip: '192.168.1.100', location: '上海', device: 'Chrome / Windows', status: '成功' },
-  { id: 5, time: '2026-03-20 11:30', ip: '117.136.89.123', location: '广州', device: '手机App / iOS', status: '成功' },
-  { id: 6, time: '2026-03-19 08:00', ip: '192.168.1.100', location: '上海', device: 'Chrome / Windows', status: '成功' },
-  { id: 7, time: '2026-03-18 09:45', ip: '61.135.169.125', location: '深圳', device: 'Firefox / Windows', status: '失败' },
-  { id: 8, time: '2026-03-17 13:20', ip: '192.168.1.100', location: '上海', device: 'Chrome / Windows', status: '成功' }
-])
-
 // 数据源列表
 const dataSources = ref([
   { id: 1, name: '海关数据', type: 'trade', enabled: true, lastSync: '2026-03-24 08:00', records: '2,456,789', recordsNum: 2456789, status: '正常', description: '全球海关进出口数据,实时更新', coverage: '200+国家', updateFreq: '每日', quality: 95 },
@@ -1604,12 +1078,10 @@ const showDataSourceDetail = (source) => {
   showDataSourceDetailModal.value = true
 }
 
-// 企业邮箱列表
-const emailAccounts = ref([
-  { id: 1, email: 'sales@company.com', name: '销售邮箱', signature: 'Best regards,\nZhang Manager\nSales Director', forward: true, autoReply: false, autoReplyContent: '', forwardTo: 'manager@company.com', lastSync: '2026-03-24 09:00', sendToday: 45, replyRate: 32, monthlyLimit: 5000, monthlyUsed: 1280,SPF: true, DKIM: true, DMARC: true, smtp: { host: 'smtp.company.com', port: 587, encryption: 'TLS' }, imap: { host: 'imap.company.com', port: 993, encryption: 'SSL' } },
-  { id: 2, email: 'marketing@company.com', name: '市场邮箱', signature: 'Thanks,\nMarketing Team', forward: true, autoReply: true, autoReplyContent: '感谢您的邮件,我们将在工作时间内尽快回复。', forwardTo: 'sales@company.com', lastSync: '2026-03-24 08:30', sendToday: 128, replyRate: 18, monthlyLimit: 10000, monthlyUsed: 3560,SPF: true, DKIM: true, DMARC: true, smtp: { host: 'smtp.company.com', port: 587, encryption: 'TLS' }, imap: { host: 'imap.company.com', port: 993, encryption: 'SSL' } }
-])
-
+const emailRef = ref()
+const openEmailModal = () => {
+  emailRef.value.open(emailList.value)
+}
 // 选中的邮箱详情
 const selectedEmailAccount = ref(null)
 
@@ -1669,735 +1141,19 @@ const saveAllSettings = () => {
 const resetAllSettings = () => {
   showToastMessage('设置已重置为默认值', 'success')
 }
-</script>
-
-<style scoped>
-/* Modal Styles */
-.modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.6); display: flex; align-items: center; justify-content: center; z-index: 1000; }
-.modal { background: var(--bg-card); border-radius: 16px; width: 90%; max-width: 480px; max-height: 80vh; display: flex; flex-direction: column; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); }
-.modal.wide { max-width: 700px; }
-.modal.extra-wide { max-width: 1000px; }
-
-.modal-header { display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; border-bottom: 1px solid var(--border); }
-.modal-title { font-size: 16px; font-weight: 600; display: flex; align-items: center; gap: 10px; }
-.modal-title i { color: var(--primary); }
-.modal-close { width: 32px; height: 32px; background: var(--bg-hover); border: none; border-radius: 8px; color: var(--text-secondary); cursor: pointer; display: flex; align-items: center; justify-content: center; }
-.modal-close:hover { background: var(--danger); color: white; }
-.modal-body { flex: 1; overflow-y: auto; padding: 24px; }
-.modal-footer { display: flex; justify-content: flex-end; gap: 12px; padding: 16px 24px; border-top: 1px solid var(--border); }
-
-.form-group { margin-bottom: 16px; }
-.form-label { display: block; font-size: 13px; font-weight: 500; margin-bottom: 8px; color: var(--text-primary); }
-.form-input, .form-select, .form-textarea { width: 100%; padding: 10px 14px; background: var(--bg-dark); border: 1px solid var(--border); border-radius: 8px; color: var(--text-primary); font-size: 13px; }
-.form-input:focus, .form-select:focus, .form-textarea:focus { outline: none; border-color: var(--primary); }
-.form-textarea { resize: vertical; min-height: 80px; }
-
-.password-hint { font-size: 12px; color: var(--text-muted); padding: 12px; background: var(--bg-hover); border-radius: 8px; display: flex; align-items: center; gap: 8px; }
-.password-hint i { color: var(--primary); }
-
-/* Login History Modal */
-.login-history-list { display: flex; flex-direction: column; gap: 12px; }
-.login-history-item { display: flex; align-items: center; gap: 14px; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
-.login-icon { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 16px; }
-.login-icon.成功 { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-.login-icon.失败 { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
-.login-info { flex: 1; }
-.login-time { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
-.login-details { display: flex; gap: 16px; font-size: 12px; color: var(--text-muted); }
-.login-details span { display: flex; align-items: center; gap: 4px; }
-.login-status { font-size: 12px; padding: 4px 10px; border-radius: 10px; }
-.login-status.成功 { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-.login-status.失败 { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
-
-/* Model Fine Tune Modal */
-.model-info-card { padding: 20px; background: linear-gradient(135deg, rgba(99, 102, 241, 0.1), rgba(139, 92, 246, 0.1)); border-radius: 12px; margin-bottom: 20px; }
-.model-header { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
-.model-icon { width: 48px; height: 48px; background: var(--primary); border-radius: 12px; display: flex; align-items: center; justify-content: center; color: white; font-size: 20px; }
-.model-title h4 { font-size: 16px; margin-bottom: 4px; }
-.model-status { font-size: 11px; padding: 2px 8px; background: var(--success); color: white; border-radius: 10px; }
-.model-stats { display: flex; gap: 24px; }
-.model-stat { display: flex; flex-direction: column; }
-.model-stat .stat-label { font-size: 11px; color: var(--text-muted); }
-.model-stat .stat-value { font-size: 14px; font-weight: 600; }
-
-.fine-tune-section { padding: 16px; background: var(--bg-hover); border-radius: 10px; }
-.fine-tune-section h5 { font-size: 14px; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
-.fine-tune-section h5 i { color: var(--primary); }
-
-/* Data Source Modal */
-.data-source-list { display: flex; flex-direction: column; gap: 10px; }
-.data-source-item { display: flex; align-items: center; gap: 14px; padding: 14px; background: var(--bg-hover); border-radius: 10px; cursor: pointer; transition: all 0.2s; }
-.data-source-item:hover { background: rgba(99, 102, 241, 0.1); }
-.source-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 16px; }
-.source-icon.trade { background: rgba(99, 102, 241, 0.2); color: var(--primary); }
-.source-icon.linkedin { background: rgba(10, 102, 194, 0.2); color: #0A66C2; }
-.source-icon.maps { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-.source-icon.company { background: rgba(139, 92, 246, 0.2); color: var(--secondary); }
-.source-icon.exhibition { background: rgba(245, 158, 11, 0.2); color: var(--warning); }
-.source-icon.procurement { background: rgba(6, 182, 212, 0.2); color: var(--info); }
-.source-icon.social { background: rgba(236, 72, 153, 0.2); color: #EC4899; }
-.source-icon.association { background: rgba(107, 114, 128, 0.2); color: var(--text-muted); }
-.source-info { flex: 1; }
-.source-name { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
-.source-meta { display: flex; gap: 16px; font-size: 12px; color: var(--text-muted); }
-.source-meta i { margin-right: 4px; }
-.source-desc { font-size: 11px; color: var(--text-muted); margin-top: 6px; }
-.source-status i { margin-right: 4px; }
-
-/* Overview Cards */
-.sources-overview, .email-overview { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 24px; }
-.overview-card { display: flex; align-items: center; gap: 14px; padding: 18px; background: var(--bg-hover); border-radius: 12px; }
-.overview-icon { width: 48px; height: 48px; background: rgba(99, 102, 241, 0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 20px; color: var(--primary); }
-.overview-icon.email { background: rgba(99, 102, 241, 0.2); }
-.overview-info { flex: 1; }
-.overview-value { font-size: 22px; font-weight: 700; }
-.overview-label { font-size: 12px; color: var(--text-muted); }
-
-/* Quick Source Grid */
-.foreign-trade-section { margin-top: 24px; padding: 20px; background: linear-gradient(135deg, rgba(99, 102, 241, 0.05), rgba(139, 92, 246, 0.05)); border-radius: 12px; border: 1px solid rgba(99, 102, 241, 0.1); }
-.foreign-trade-section h4 { font-size: 14px; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
-.foreign-trade-section h4 i { color: var(--primary); }
-.quick-source-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
-.quick-source-card { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 16px; background: var(--bg-card); border-radius: 10px; text-align: center; }
-.quick-source-card i { font-size: 24px; color: var(--primary); }
-.quick-source-card span { font-size: 12px; font-weight: 500; }
-.quick-source-card .btn { margin-top: auto; }
-
-/* Add Data Source & Quick Source Modal */
-.required { color: var(--danger); margin-left: 4px; }
-.test-connection { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border); }
-.test-connection .btn { width: 100%; justify-content: center; }
-
-.quick-config-section { margin-bottom: 20px; padding: 16px; background: var(--bg-hover); border-radius: 10px; }
-.quick-config-section h5 { font-size: 14px; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
-.quick-config-section h5 i { color: var(--primary); }
-
-.checkbox-group { display: flex; flex-wrap: wrap; gap: 12px; }
-.checkbox-item { display: flex; align-items: center; gap: 6px; font-size: 13px; cursor: pointer; }
-.checkbox-item input { width: 16px; height: 16px; }
-
-/* Email Tab Content */
-.email-tab-content { padding: 16px 0; }
-.stats-overview { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 20px; }
-.stat-card { display: flex; align-items: center; gap: 14px; padding: 18px; background: var(--bg-hover); border-radius: 12px; }
-.stat-card .stat-icon { width: 44px; height: 44px; background: rgba(99, 102, 241, 0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 18px; }
-.stat-card .stat-info { flex: 1; }
-.stat-card .stat-value { font-size: 22px; font-weight: 700; }
-.stat-card .stat-label { font-size: 12px; color: var(--text-muted); }
-
-.chart-section, .top-performers { margin-top: 20px; }
-.chart-section h5, .top-performers h5 { font-size: 14px; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
-.chart-section h5 i, .top-performers h5 i { color: var(--primary); }
-
-.simple-chart { display: flex; align-items: flex-end; gap: 12px; height: 150px; padding: 20px; background: var(--bg-hover); border-radius: 12px; }
-.chart-bar { flex: 1; background: linear-gradient(to top, var(--primary), var(--secondary)); border-radius: 6px 6px 0 0; position: relative; min-height: 20px; display: flex; align-items: flex-end; justify-content: center; padding-bottom: 8px; }
-.chart-bar span { font-size: 11px; color: var(--text-muted); position: absolute; bottom: -24px; }
-
-.template-list { display: flex; flex-direction: column; gap: 10px; }
-.template-item { display: flex; justify-content: space-between; align-items: center; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
-.template-name { font-size: 14px; font-weight: 500; }
-.template-stats { font-size: 12px; color: var(--text-muted); }
-
-/* Domain Config */
-.domain-config-section { margin-bottom: 20px; }
-.domain-config-section h5 { font-size: 14px; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
-.domain-config-section h5 i { color: var(--primary); }
-
-.domain-list { display: flex; flex-direction: column; gap: 10px; }
-.domain-item { display: flex; align-items: center; gap: 14px; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
-.domain-icon { width: 44px; height: 44px; background: rgba(99, 102, 241, 0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 18px; }
-.domain-info { flex: 1; }
-.domain-name { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
-.domain-meta { display: flex; gap: 16px; font-size: 12px; color: var(--text-muted); }
-.domain-status { display: inline-flex; align-items: center; gap: 4px; }
-.domain-status.active { color: var(--success); }
-
-.config-guide { display: flex; flex-direction: column; gap: 14px; }
-.guide-step { display: flex; gap: 14px; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
-.step-num { width: 28px; height: 28px; background: var(--primary); color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; flex-shrink: 0; }
-.step-content { flex: 1; }
-.step-title { font-size: 14px; font-weight: 500; margin-bottom: 4px; }
-.step-desc { font-size: 12px; color: var(--text-muted); }
-
-/* Security */
-.security-overview { margin-bottom: 20px; }
-.security-card { padding: 24px; background: linear-gradient(135deg, rgba(16, 185, 129, 0.1), rgba(99, 102, 241, 0.1)); border-radius: 12px; text-align: center; }
-.security-header { display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 12px; font-size: 14px; color: var(--text-secondary); }
-.security-header i { color: var(--success); }
-.security-score { font-size: 36px; font-weight: 700; color: var(--success); margin-bottom: 8px; }
-.security-desc { font-size: 13px; color: var(--text-muted); }
-
-.security-section { margin-bottom: 20px; }
-.security-section h5 { font-size: 14px; margin-bottom: 14px; display: flex; align-items: center; gap: 8px; }
-.security-section h5 i { color: var(--primary); }
-
-.security-list { display: flex; flex-direction: column; gap: 10px; }
-.security-item { display: flex; justify-content: space-between; align-items: center; padding: 14px; background: var(--bg-hover); border-radius: 10px; }
-.security-item-info { display: flex; flex-direction: column; }
-.security-item-title { font-size: 14px; font-weight: 500; }
-.security-item-desc { font-size: 12px; color: var(--text-muted); }
-
-.security-logs { display: flex; flex-direction: column; gap: 8px; }
-.log-item { display: flex; align-items: center; gap: 16px; padding: 10px; background: var(--bg-hover); border-radius: 8px; font-size: 12px; }
-.log-item .log-time { color: var(--text-muted); min-width: 120px; }
-.log-item .log-event { flex: 1; }
-.log-item .log-status { padding: 2px 8px; border-radius: 10px; }
-.log-status.success { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-
-/* Email Enhanced */
-.email-account-item.selected { border: 2px solid var(--primary); background: rgba(99, 102, 241, 0.05); }
-.account-auth { display: flex; flex-direction: column; gap: 4px; }
-.auth-badge { display: inline-flex; align-items: center; gap: 4px; font-size: 10px; padding: 2px 6px; background: var(--bg-dark); border-radius: 4px; color: var(--text-muted); }
-.auth-badge.active { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-
-.detail-tabs { display: flex; gap: 8px; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
-.detail-tab { padding: 8px 14px; background: transparent; border: none; color: var(--text-secondary); font-size: 12px; cursor: pointer; border-radius: 8px; }
-.detail-tab:hover { background: var(--bg-hover); }
-.detail-tab.active { background: var(--primary); color: white; }
-
-.config-grid-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
-.config-card { background: var(--bg-card); border-radius: 10px; overflow: hidden; }
-.config-card-header { padding: 12px 16px; background: var(--bg-hover); font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 8px; }
-.config-card-body { padding: 16px; }
-.config-card-body .config-row { background: var(--bg-hover); padding: 10px; border-radius: 6px; margin-bottom: 8px; }
-.config-card-body .config-row:last-child { margin-bottom: 0; }
-
-.auth-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
-.auth-card { display: flex; align-items: center; gap: 12px; padding: 16px; background: var(--bg-card); border-radius: 10px; border: 1px solid var(--border); }
-.auth-card.pass { border-color: rgba(16, 185, 129, 0.3); }
-.auth-card.fail { border-color: rgba(239, 68, 68, 0.3); }
-.auth-card .auth-icon { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; }
-.auth-card.pass .auth-icon { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-.auth-card.fail .auth-icon { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
-.auth-card .auth-info { flex: 1; }
-.auth-card .auth-name { font-size: 14px; font-weight: 600; }
-.auth-card .auth-desc { font-size: 11px; color: var(--text-muted); }
-.auth-card .auth-status { font-size: 11px; padding: 3px 8px; border-radius: 10px; }
-.auth-card.pass .auth-status { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-.auth-card.fail .auth-status { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
-
-.config-row-flex { display: flex; gap: 24px; margin-bottom: 16px; }
-.config-row-flex .config-item { flex: 1; }
-
-.signature-preview { margin-bottom: 12px; padding: 16px; background: var(--bg-card); border-radius: 10px; border-left: 4px solid var(--primary); }
-.signature-label { font-size: 11px; color: var(--text-muted); margin-bottom: 8px; }
-.signature-content pre { font-size: 12px; white-space: pre-wrap; font-family: inherit; margin: 0; }
-.usage-label { font-size: 11px; color: var(--text-muted); margin-bottom: 4px; }
-
-/* Email Modal */
-.email-accounts-list { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
-.email-account-item { display: flex; align-items: center; gap: 14px; padding: 16px; background: var(--bg-hover); border-radius: 10px; }
-.account-icon { width: 44px; height: 44px; background: rgba(99, 102, 241, 0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 18px; }
-.account-info { flex: 1; }
-.account-email { font-size: 14px; font-weight: 500; margin-bottom: 2px; }
-.account-name { font-size: 12px; color: var(--text-muted); margin-bottom: 6px; }
-.account-stats { display: flex; gap: 16px; font-size: 11px; color: var(--text-muted); }
-.add-account-btn { width: 100%; }
-
-/* LinkedIn & WeChat Modal */
-.connect-prompt { text-align: center; padding: 40px 20px; }
-.connect-icon { width: 80px; height: 80px; background: rgba(10, 102, 194, 0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px; font-size: 36px; color: #0A66C2; }
-.connect-icon.wechat { background: rgba(7, 193, 96, 0.2); color: #07C160; }
-.connect-prompt h4 { font-size: 18px; margin-bottom: 10px; }
-.connect-prompt p { font-size: 13px; color: var(--text-muted); margin-bottom: 24px; }
-.wechat-btn { background: #07C160; }
-
-.linkedin-connected, .wechat-connected { padding: 20px; background: var(--bg-hover); border-radius: 12px; }
-.linkedin-stats, .wechat-stats { display: flex; gap: 24px; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }
-.stat-item { display: flex; flex-direction: column; align-items: center; flex: 1; }
-.stat-item .stat-label { font-size: 11px; color: var(--text-muted); margin-bottom: 4px; }
-.stat-item .stat-value { font-size: 18px; font-weight: 600; }
-
-/* Data Source Detail Modal */
-.source-detail-header { margin-bottom: 20px; }
-.source-detail-status { margin-bottom: 10px; }
-.status-badge { display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border-radius: 20px; font-size: 13px; }
-.status-badge.active { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-.status-badge.inactive { background: rgba(107, 114, 128, 0.2); color: var(--text-muted); }
-.source-description { font-size: 13px; color: var(--text-muted); }
-
-.source-stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 24px; }
-.source-stat-card { display: flex; align-items: center; gap: 12px; padding: 16px; background: var(--bg-hover); border-radius: 10px; }
-.source-stat-card .stat-icon { width: 40px; height: 40px; background: rgba(99, 102, 241, 0.2); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary); font-size: 16px; }
-.source-stat-card .stat-info { flex: 1; }
-.source-stat-card .stat-value { font-size: 16px; font-weight: 600; }
-.source-stat-card .stat-label { font-size: 11px; color: var(--text-muted); }
-
-.detail-section { margin-bottom: 20px; }
-.detail-section h5 { font-size: 14px; margin-bottom: 12px; display: flex; align-items: center; gap: 8px; }
-.detail-section h5 i { color: var(--primary); }
-
-.config-grid { display: flex; gap: 16px; flex-wrap: wrap; }
-.config-item { display: flex; flex-direction: column; gap: 6px; min-width: 120px; }
-.config-item label { font-size: 12px; color: var(--text-muted); }
-.config-item .form-select { padding: 8px 12px; font-size: 12px; }
-
-.fields-list { display: flex; flex-direction: column; gap: 8px; }
-.field-item { display: flex; align-items: center; gap: 12px; padding: 10px; background: var(--bg-hover); border-radius: 8px; font-size: 13px; }
-.field-name { color: var(--primary); font-weight: 500; }
-.field-item i { color: var(--text-muted); }
-.field-target { color: var(--text-secondary); font-family: monospace; }
-
-.sync-logs { display: flex; flex-direction: column; gap: 8px; }
-.sync-log-item { display: flex; align-items: center; gap: 16px; padding: 10px; background: var(--bg-hover); border-radius: 8px; font-size: 12px; }
-.log-time { color: var(--text-muted); min-width: 140px; }
-.log-status { padding: 2px 8px; border-radius: 10px; }
-.log-status.success { background: rgba(16, 185, 129, 0.2); color: var(--success); }
-.log-count { color: var(--text-secondary); }
-
-/* Email Modal Enhanced */
-.email-tabs { display: flex; gap: 8px; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
-.email-tab { padding: 8px 16px; background: transparent; border: none; color: var(--text-secondary); font-size: 13px; cursor: pointer; border-radius: 8px; }
-.email-tab:hover { background: var(--bg-hover); }
-.email-tab.active { background: var(--primary); color: white; }
-
-.account-usage { display: flex; flex-direction: column; gap: 4px; min-width: 100px; }
-.usage-bar { height: 6px; background: var(--bg-dark); border-radius: 3px; overflow: hidden; }
-.usage-fill { height: 100%; background: var(--primary); border-radius: 3px; }
-.usage-text { font-size: 10px; color: var(--text-muted); text-align: right; }
-
-.email-detail-panel { margin-top: 20px; padding: 20px; background: var(--bg-hover); border-radius: 12px; }
-.email-detail-panel .detail-header { margin-bottom: 16px; }
-.email-detail-panel .detail-header h4 { font-size: 14px; display: flex; align-items: center; gap: 8px; }
-
-.config-table { display: flex; flex-direction: column; gap: 8px; }
-.config-row { display: flex; justify-content: space-between; padding: 10px; background: var(--bg-card); border-radius: 8px; font-size: 12px; }
-.config-label { color: var(--text-muted); }
-.config-value { font-weight: 500; }
-
-.auth-status-grid { display: flex; gap: 12px; }
-.auth-status-item { display: flex; align-items: center; gap: 8px; padding: 10px 16px; background: var(--bg-card); border-radius: 8px; font-size: 12px; }
-.auth-status-item.active { color: var(--success); }
-.auth-status-item.inactive { color: var(--danger); }
-.auth-status-item i { font-size: 16px; }
-
-.auto-reply-config { display: flex; flex-direction: column; gap: 12px; }
-.auto-reply-config .config-item { flex-direction: row; align-items: center; justify-content: space-between; }
-.auto-reply-config textarea { min-height: 60px; }
-
-.signature-textarea { font-family: monospace; font-size: 12px; }
-
-.toggle-switch { width: 44px; height: 24px; background: var(--bg-dark); border-radius: 12px; position: relative; cursor: pointer; transition: all 0.2s; }
-.toggle-switch.active { background: var(--primary); }
-.toggle-slider { width: 20px; height: 20px; background: white; border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: all 0.2s; }
-.toggle-switch.active .toggle-slider { left: 22px; }
-
-.settings-page {
-  flex: 1;
-  display: flex;
-  flex-direction: column;
-  padding: 24px;
-  overflow-y: auto;
-  background: var(--bg-dark);
-}
-
-.settings-header {
-  display: flex;
-  justify-content: space-between;
-  align-items: flex-start;
-  margin-bottom: 24px;
-}
-
-.header-left {
-  display: flex;
-  flex-direction: column;
-  gap: 4px;
-}
-
-.data-title {
-  font-size: 20px;
-  font-weight: 600;
-}
-
-.header-desc {
-  font-size: 13px;
-  color: var(--text-secondary);
-}
-
-.header-actions {
-  display: flex;
-  gap: 12px;
-}
-
-/* Settings Grid */
-.settings-grid {
-  display: grid;
-  grid-template-columns: 1fr 1fr;
-  gap: 24px;
-}
-
-.settings-column {
-  display: flex;
-  flex-direction: column;
-  gap: 24px;
-}
-
-/* Settings Section */
-.settings-section {
-  background: var(--bg-card);
-  border: 1px solid var(--border);
-  border-radius: 16px;
-  overflow: hidden;
-}
-
-.section-header {
-  display: flex;
-  align-items: center;
-  gap: 14px;
-  padding: 20px;
-  background: var(--bg-hover);
-  border-bottom: 1px solid var(--border);
-}
-
-.section-icon {
-  width: 44px;
-  height: 44px;
-  border-radius: 12px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 18px;
-}
-
-.section-title h3 {
-  font-size: 15px;
-  font-weight: 600;
-  margin-bottom: 2px;
-}
-
-.section-title p {
-  font-size: 12px;
-  color: var(--text-secondary);
-}
-
-/* Settings List */
-.settings-list {
-  padding: 8px;
-}
-
-.settings-item {
-  display: flex;
-  align-items: center;
-  gap: 14px;
-  padding: 14px;
-  border-radius: 10px;
-  cursor: pointer;
-  transition: background 0.2s;
-}
-
-.settings-item:hover {
-  background: var(--bg-hover);
-}
-
-.item-icon {
-  width: 40px;
-  height: 40px;
-  border-radius: 10px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 16px;
-  flex-shrink: 0;
-}
-
-.item-content {
-  flex: 1;
-  min-width: 0;
-}
-
-.item-title {
-  font-size: 14px;
-  font-weight: 500;
-  margin-bottom: 2px;
-}
-
-.item-desc {
-  font-size: 12px;
-  color: var(--text-secondary);
-}
-
-.item-action {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  flex-shrink: 0;
-}
-
-.item-value {
-  font-size: 13px;
-  color: var(--text-secondary);
-}
 
-.item-value.success {
-  color: var(--success);
-}
-
-.item-value.warning {
-  color: var(--warning);
-}
-
-.item-action i {
-  color: var(--text-muted);
-  font-size: 12px;
-}
-
-/* Profile Card */
-.profile-card {
-  display: flex;
-  align-items: center;
-  gap: 16px;
-  padding: 20px;
-  margin: 8px;
-  background: var(--bg-hover);
-  border-radius: 12px;
-}
-
-.profile-avatar {
-  width: 64px;
-  height: 64px;
-  background: var(--gradient-1);
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 24px;
-  font-weight: 600;
-  color: white;
-  position: relative;
-}
-
-.avatar-edit {
-  position: absolute;
-  bottom: 0;
-  right: 0;
-  width: 24px;
-  height: 24px;
-  background: var(--primary);
-  border: 2px solid var(--bg-hover);
-  border-radius: 50%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 10px;
-  color: white;
-  cursor: pointer;
-}
-
-.profile-info {
-  flex: 1;
-}
-
-.profile-name {
-  font-size: 16px;
-  font-weight: 600;
-  margin-bottom: 2px;
-}
-
-.profile-role {
-  font-size: 13px;
-  color: var(--text-secondary);
-  margin-bottom: 2px;
-}
-
-.profile-email {
-  font-size: 12px;
-  color: var(--text-muted);
-}
-
-/* Toggle Switch */
-.toggle-switch {
-  width: 44px;
-  height: 24px;
-  background: var(--bg-dark);
-  border-radius: 12px;
-  position: relative;
-  cursor: pointer;
-  transition: all 0.2s;
-  flex-shrink: 0;
-}
-.toggle-switch.active {
-  background: var(--primary);
-}
-.toggle-slider {
-  position: absolute;
-  top: 2px;
-  left: 2px;
-  width: 20px;
-  height: 20px;
-  background: white;
-  border-radius: 50%;
-  transition: all 0.2s;
-  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
-}
-.toggle-switch.active .toggle-slider {
-  transform: translateX(20px);
+const emailList = ref([])
+const getEmails = () => {
+  getUserEmails().then(res => {
+    emailList.value = res.result
+  })
 }
 
-/* Global Toggle Fix - Override inline styles */
-.settings-item .toggle-switch,
-.channel-item .toggle-switch,
-.item-action .toggle-switch,
-.settings-modal .toggle-switch,
-.modal .toggle-switch,
-.detail-section .toggle-switch,
-.config-item .toggle-switch,
-.auto-reply-config .toggle-switch { 
-  margin-left: auto; 
-  background: var(--bg-dark) !important;
-}
-
-.settings-item .toggle-switch.active,
-.channel-item .toggle-switch.active,
-.item-action .toggle-switch.active,
-.settings-modal .toggle-switch.active,
-.modal .toggle-switch.active,
-.detail-section .toggle-switch.active,
-.config-item .toggle-switch.active,
-.auto-reply-config .toggle-switch.active {
-  background: var(--primary) !important;
-}
-
-/* Mini Select */
-.mini-select {
-  padding: 6px 12px;
-  background: var(--bg-hover);
-  border: 1px solid var(--border);
-  border-radius: 8px;
-  color: var(--text-primary);
-  font-size: 13px;
-  cursor: pointer;
-}
-
-.mini-select:focus {
-  outline: none;
-  border-color: var(--primary);
-}
-
-/* Channel List */
-.channel-list {
-  padding: 8px;
-}
-
-.channel-item {
-  display: flex;
-  align-items: center;
-  gap: 14px;
-  padding: 14px;
-  border-radius: 10px;
-  border: 1px solid var(--border);
-  margin-bottom: 8px;
-  background: var(--bg-dark);
-  transition: all 0.2s;
-}
-
-.channel-item:last-child {
-  margin-bottom: 0;
-}
-
-.channel-item.connected {
-  border-color: rgba(16, 185, 129, 0.3);
-}
-
-.channel-icon {
-  width: 40px;
-  height: 40px;
-  border-radius: 10px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-size: 18px;
-  flex-shrink: 0;
-}
-
-.channel-content {
-  flex: 1;
-}
-
-.channel-title {
-  font-size: 14px;
-  font-weight: 500;
-  margin-bottom: 2px;
-}
-
-.channel-desc {
-  font-size: 12px;
-  color: var(--text-secondary);
-}
-
-.channel-action {
-  flex-shrink: 0;
-}
-
-.status-badge {
-  display: inline-flex;
-  align-items: center;
-  gap: 4px;
-  padding: 4px 10px;
-  border-radius: 12px;
-  font-size: 11px;
-  font-weight: 500;
-}
-
-.status-badge.success {
-  background: rgba(16, 185, 129, 0.2);
-  color: var(--success);
-}
-
-/* Toast */
-.toast {
-  position: fixed;
-  bottom: 24px;
-  right: 24px;
-  padding: 12px 20px;
-  background: var(--bg-card);
-  border: 1px solid var(--border);
-  border-radius: 10px;
-  display: flex;
-  align-items: center;
-  gap: 10px;
-  font-size: 13px;
-  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
-  z-index: 2000;
-}
-
-.toast.success {
-  border-color: var(--success);
-}
-
-.toast.success i {
-  color: var(--success);
-}
-
-.toast-enter-active,
-.toast-leave-active {
-  transition: all 0.3s ease;
-}
-
-.toast-enter-from,
-.toast-leave-to {
-  opacity: 0;
-  transform: translateY(20px);
-}
-
-/* Responsive */
-@media (max-width: 1200px) {
-  .settings-grid {
-    grid-template-columns: 1fr;
-  }
-}
+onMounted(() => {
+  getEmails()
+})
+</script>
 
-@media (max-width: 768px) {
-  .settings-header {
-    flex-direction: column;
-    gap: 16px;
-  }
-  
-  .header-actions {
-    width: 100%;
-  }
-  
-  .header-actions .btn {
-    flex: 1;
-  }
-}
+<style scoped>
+  @import '../assets/styles/settings.css';
 </style>